1 /*-------------------------------------------------------------------------
2 *
3 * ruleutils.c
4 * Functions to convert stored expressions/querytrees back to
5 * source text
6 *
7 * Portions Copyright (c) 1996-2021, 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/parser.h"
57 #include "parser/parsetree.h"
58 #include "rewrite/rewriteHandler.h"
59 #include "rewrite/rewriteManip.h"
60 #include "rewrite/rewriteSupport.h"
61 #include "utils/array.h"
62 #include "utils/builtins.h"
63 #include "utils/fmgroids.h"
64 #include "utils/guc.h"
65 #include "utils/hsearch.h"
66 #include "utils/lsyscache.h"
67 #include "utils/partcache.h"
68 #include "utils/rel.h"
69 #include "utils/ruleutils.h"
70 #include "utils/snapmgr.h"
71 #include "utils/syscache.h"
72 #include "utils/typcache.h"
73 #include "utils/varlena.h"
74 #include "utils/xml.h"
75
76 /* ----------
77 * Pretty formatting constants
78 * ----------
79 */
80
81 /* Indent counts */
82 #define PRETTYINDENT_STD 8
83 #define PRETTYINDENT_JOIN 4
84 #define PRETTYINDENT_VAR 4
85
86 #define PRETTYINDENT_LIMIT 40 /* wrap limit */
87
88 /* Pretty flags */
89 #define PRETTYFLAG_PAREN 0x0001
90 #define PRETTYFLAG_INDENT 0x0002
91 #define PRETTYFLAG_SCHEMA 0x0004
92
93 /* Default line length for pretty-print wrapping: 0 means wrap always */
94 #define WRAP_COLUMN_DEFAULT 0
95
96 /* macros to test if pretty action needed */
97 #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
98 #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
99 #define PRETTY_SCHEMA(context) ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
100
101
102 /* ----------
103 * Local data types
104 * ----------
105 */
106
107 /* Context info needed for invoking a recursive querytree display routine */
108 typedef struct
109 {
110 StringInfo buf; /* output buffer to append to */
111 List *namespaces; /* List of deparse_namespace nodes */
112 List *windowClause; /* Current query level's WINDOW clause */
113 List *windowTList; /* targetlist for resolving WINDOW clause */
114 int prettyFlags; /* enabling of pretty-print functions */
115 int wrapColumn; /* max line length, or -1 for no limit */
116 int indentLevel; /* current indent level for pretty-print */
117 bool varprefix; /* true to print prefixes on Vars */
118 ParseExprKind special_exprkind; /* set only for exprkinds needing special
119 * handling */
120 Bitmapset *appendparents; /* if not null, map child Vars of these relids
121 * back to the parent rel */
122 } deparse_context;
123
124 /*
125 * Each level of query context around a subtree needs a level of Var namespace.
126 * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
127 * the current context's namespaces list.
128 *
129 * rtable is the list of actual RTEs from the Query or PlannedStmt.
130 * rtable_names holds the alias name to be used for each RTE (either a C
131 * string, or NULL for nameless RTEs such as unnamed joins).
132 * rtable_columns holds the column alias names to be used for each RTE.
133 *
134 * subplans is a list of Plan trees for SubPlans and CTEs (it's only used
135 * in the PlannedStmt case).
136 * ctes is a list of CommonTableExpr nodes (only used in the Query case).
137 * appendrels, if not null (it's only used in the PlannedStmt case), is an
138 * array of AppendRelInfo nodes, indexed by child relid. We use that to map
139 * child-table Vars to their inheritance parents.
140 *
141 * In some cases we need to make names of merged JOIN USING columns unique
142 * across the whole query, not only per-RTE. If so, unique_using is true
143 * and using_names is a list of C strings representing names already assigned
144 * to USING columns.
145 *
146 * When deparsing plan trees, there is always just a single item in the
147 * deparse_namespace list (since a plan tree never contains Vars with
148 * varlevelsup > 0). We store the Plan node that is the immediate
149 * parent of the expression to be deparsed, as well as a list of that
150 * Plan's ancestors. In addition, we store its outer and inner subplan nodes,
151 * as well as their targetlists, and the index tlist if the current plan node
152 * might contain INDEX_VAR Vars. (These fields could be derived on-the-fly
153 * from the current Plan node, but it seems notationally clearer to set them
154 * up as separate fields.)
155 */
156 typedef struct
157 {
158 List *rtable; /* List of RangeTblEntry nodes */
159 List *rtable_names; /* Parallel list of names for RTEs */
160 List *rtable_columns; /* Parallel list of deparse_columns structs */
161 List *subplans; /* List of Plan trees for SubPlans */
162 List *ctes; /* List of CommonTableExpr nodes */
163 AppendRelInfo **appendrels; /* Array of AppendRelInfo nodes, or NULL */
164 /* Workspace for column alias assignment: */
165 bool unique_using; /* Are we making USING names globally unique */
166 List *using_names; /* List of assigned names for USING columns */
167 /* Remaining fields are used only when deparsing a Plan tree: */
168 Plan *plan; /* immediate parent of current expression */
169 List *ancestors; /* ancestors of plan */
170 Plan *outer_plan; /* outer subnode, or NULL if none */
171 Plan *inner_plan; /* inner subnode, or NULL if none */
172 List *outer_tlist; /* referent for OUTER_VAR Vars */
173 List *inner_tlist; /* referent for INNER_VAR Vars */
174 List *index_tlist; /* referent for INDEX_VAR Vars */
175 /* Special namespace representing a function signature: */
176 char *funcname;
177 int numargs;
178 char **argnames;
179 } deparse_namespace;
180
181 /*
182 * Per-relation data about column alias names.
183 *
184 * Selecting aliases is unreasonably complicated because of the need to dump
185 * rules/views whose underlying tables may have had columns added, deleted, or
186 * renamed since the query was parsed. We must nonetheless print the rule/view
187 * in a form that can be reloaded and will produce the same results as before.
188 *
189 * For each RTE used in the query, we must assign column aliases that are
190 * unique within that RTE. SQL does not require this of the original query,
191 * but due to factors such as *-expansion we need to be able to uniquely
192 * reference every column in a decompiled query. As long as we qualify all
193 * column references, per-RTE uniqueness is sufficient for that.
194 *
195 * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
196 * since they just inherit column names from their input RTEs, and we can't
197 * rename the columns at the join level. Most of the time this isn't an issue
198 * because we don't need to reference the join's output columns as such; we
199 * can reference the input columns instead. That approach can fail for merged
200 * JOIN USING columns, however, so when we have one of those in an unnamed
201 * join, we have to make that column's alias globally unique across the whole
202 * query to ensure it can be referenced unambiguously.
203 *
204 * Another problem is that a JOIN USING clause requires the columns to be
205 * merged to have the same aliases in both input RTEs, and that no other
206 * columns in those RTEs or their children conflict with the USING names.
207 * To handle that, we do USING-column alias assignment in a recursive
208 * traversal of the query's jointree. When descending through a JOIN with
209 * USING, we preassign the USING column names to the child columns, overriding
210 * other rules for column alias assignment. We also mark each RTE with a list
211 * of all USING column names selected for joins containing that RTE, so that
212 * when we assign other columns' aliases later, we can avoid conflicts.
213 *
214 * Another problem is that if a JOIN's input tables have had columns added or
215 * deleted since the query was parsed, we must generate a column alias list
216 * for the join that matches the current set of input columns --- otherwise, a
217 * change in the number of columns in the left input would throw off matching
218 * of aliases to columns of the right input. Thus, positions in the printable
219 * column alias list are not necessarily one-for-one with varattnos of the
220 * JOIN, so we need a separate new_colnames[] array for printing purposes.
221 */
222 typedef struct
223 {
224 /*
225 * colnames is an array containing column aliases to use for columns that
226 * existed when the query was parsed. Dropped columns have NULL entries.
227 * This array can be directly indexed by varattno to get a Var's name.
228 *
229 * Non-NULL entries are guaranteed unique within the RTE, *except* when
230 * this is for an unnamed JOIN RTE. In that case we merely copy up names
231 * from the two input RTEs.
232 *
233 * During the recursive descent in set_using_names(), forcible assignment
234 * of a child RTE's column name is represented by pre-setting that element
235 * of the child's colnames array. So at that stage, NULL entries in this
236 * array just mean that no name has been preassigned, not necessarily that
237 * the column is dropped.
238 */
239 int num_cols; /* length of colnames[] array */
240 char **colnames; /* array of C strings and NULLs */
241
242 /*
243 * new_colnames is an array containing column aliases to use for columns
244 * that would exist if the query was re-parsed against the current
245 * definitions of its base tables. This is what to print as the column
246 * alias list for the RTE. This array does not include dropped columns,
247 * but it will include columns added since original parsing. Indexes in
248 * it therefore have little to do with current varattno values. As above,
249 * entries are unique unless this is for an unnamed JOIN RTE. (In such an
250 * RTE, we never actually print this array, but we must compute it anyway
251 * for possible use in computing column names of upper joins.) The
252 * parallel array is_new_col marks which of these columns are new since
253 * original parsing. Entries with is_new_col false must match the
254 * non-NULL colnames entries one-for-one.
255 */
256 int num_new_cols; /* length of new_colnames[] array */
257 char **new_colnames; /* array of C strings */
258 bool *is_new_col; /* array of bool flags */
259
260 /* This flag tells whether we should actually print a column alias list */
261 bool printaliases;
262
263 /* This list has all names used as USING names in joins above this RTE */
264 List *parentUsing; /* names assigned to parent merged columns */
265
266 /*
267 * If this struct is for a JOIN RTE, we fill these fields during the
268 * set_using_names() pass to describe its relationship to its child RTEs.
269 *
270 * leftattnos and rightattnos are arrays with one entry per existing
271 * output column of the join (hence, indexable by join varattno). For a
272 * simple reference to a column of the left child, leftattnos[i] is the
273 * child RTE's attno and rightattnos[i] is zero; and conversely for a
274 * column of the right child. But for merged columns produced by JOIN
275 * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
276 * Note that a simple reference might be to a child RTE column that's been
277 * dropped; but that's OK since the column could not be used in the query.
278 *
279 * If it's a JOIN USING, usingNames holds the alias names selected for the
280 * merged columns (these might be different from the original USING list,
281 * if we had to modify names to achieve uniqueness).
282 */
283 int leftrti; /* rangetable index of left child */
284 int rightrti; /* rangetable index of right child */
285 int *leftattnos; /* left-child varattnos of join cols, or 0 */
286 int *rightattnos; /* right-child varattnos of join cols, or 0 */
287 List *usingNames; /* names assigned to merged columns */
288 } deparse_columns;
289
290 /* This macro is analogous to rt_fetch(), but for deparse_columns structs */
291 #define deparse_columns_fetch(rangetable_index, dpns) \
292 ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
293
294 /*
295 * Entry in set_rtable_names' hash table
296 */
297 typedef struct
298 {
299 char name[NAMEDATALEN]; /* Hash key --- must be first */
300 int counter; /* Largest addition used so far for name */
301 } NameHashEntry;
302
303 /* Callback signature for resolve_special_varno() */
304 typedef void (*rsv_callback) (Node *node, deparse_context *context,
305 void *callback_arg);
306
307
308 /* ----------
309 * Global data
310 * ----------
311 */
312 static SPIPlanPtr plan_getrulebyoid = NULL;
313 static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
314 static SPIPlanPtr plan_getviewrule = NULL;
315 static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
316
317 /* GUC parameters */
318 bool quote_all_identifiers = false;
319
320
321 /* ----------
322 * Local functions
323 *
324 * Most of these functions used to use fixed-size buffers to build their
325 * results. Now, they take an (already initialized) StringInfo object
326 * as a parameter, and append their text output to its contents.
327 * ----------
328 */
329 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
330 bool forceprefix, bool showimplicit,
331 int prettyFlags, int startIndent);
332 static char *pg_get_viewdef_worker(Oid viewoid,
333 int prettyFlags, int wrapColumn);
334 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
335 static int decompile_column_index_array(Datum column_index_array, Oid relId,
336 StringInfo buf);
337 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
338 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
339 const Oid *excludeOps,
340 bool attrsOnly, bool keysOnly,
341 bool showTblSpc, bool inherits,
342 int prettyFlags, bool missing_ok);
343 static char *pg_get_statisticsobj_worker(Oid statextid, bool columns_only,
344 bool missing_ok);
345 static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
346 bool attrsOnly, bool missing_ok);
347 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
348 int prettyFlags, bool missing_ok);
349 static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
350 int prettyFlags);
351 static int print_function_arguments(StringInfo buf, HeapTuple proctup,
352 bool print_table_args, bool print_defaults);
353 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
354 static void print_function_trftypes(StringInfo buf, HeapTuple proctup);
355 static void print_function_sqlbody(StringInfo buf, HeapTuple proctup);
356 static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
357 Bitmapset *rels_used);
358 static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
359 List *parent_namespaces);
360 static void set_simple_column_names(deparse_namespace *dpns);
361 static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode);
362 static void set_using_names(deparse_namespace *dpns, Node *jtnode,
363 List *parentUsing);
364 static void set_relation_column_names(deparse_namespace *dpns,
365 RangeTblEntry *rte,
366 deparse_columns *colinfo);
367 static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
368 deparse_columns *colinfo);
369 static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
370 deparse_columns *colinfo);
371 static char *make_colname_unique(char *colname, deparse_namespace *dpns,
372 deparse_columns *colinfo);
373 static void expand_colnames_array_to(deparse_columns *colinfo, int n);
374 static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
375 deparse_columns *colinfo);
376 static char *get_rtable_name(int rtindex, deparse_context *context);
377 static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
378 static Plan *find_recursive_union(deparse_namespace *dpns,
379 WorkTableScan *wtscan);
380 static void push_child_plan(deparse_namespace *dpns, Plan *plan,
381 deparse_namespace *save_dpns);
382 static void pop_child_plan(deparse_namespace *dpns,
383 deparse_namespace *save_dpns);
384 static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
385 deparse_namespace *save_dpns);
386 static void pop_ancestor_plan(deparse_namespace *dpns,
387 deparse_namespace *save_dpns);
388 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
389 int prettyFlags);
390 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
391 int prettyFlags, int wrapColumn);
392 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
393 TupleDesc resultDesc,
394 int prettyFlags, int wrapColumn, int startIndent);
395 static void get_values_def(List *values_lists, deparse_context *context);
396 static void get_with_clause(Query *query, deparse_context *context);
397 static void get_select_query_def(Query *query, deparse_context *context,
398 TupleDesc resultDesc);
399 static void get_insert_query_def(Query *query, deparse_context *context);
400 static void get_update_query_def(Query *query, deparse_context *context);
401 static void get_update_query_targetlist_def(Query *query, List *targetList,
402 deparse_context *context,
403 RangeTblEntry *rte);
404 static void get_delete_query_def(Query *query, deparse_context *context);
405 static void get_utility_query_def(Query *query, deparse_context *context);
406 static void get_basic_select_query(Query *query, deparse_context *context,
407 TupleDesc resultDesc);
408 static void get_target_list(List *targetList, deparse_context *context,
409 TupleDesc resultDesc);
410 static void get_setop_query(Node *setOp, Query *query,
411 deparse_context *context,
412 TupleDesc resultDesc);
413 static Node *get_rule_sortgroupclause(Index ref, List *tlist,
414 bool force_colno,
415 deparse_context *context);
416 static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
417 bool omit_parens, deparse_context *context);
418 static void get_rule_orderby(List *orderList, List *targetList,
419 bool force_colno, deparse_context *context);
420 static void get_rule_windowclause(Query *query, deparse_context *context);
421 static void get_rule_windowspec(WindowClause *wc, List *targetList,
422 deparse_context *context);
423 static char *get_variable(Var *var, int levelsup, bool istoplevel,
424 deparse_context *context);
425 static void get_special_variable(Node *node, deparse_context *context,
426 void *callback_arg);
427 static void resolve_special_varno(Node *node, deparse_context *context,
428 rsv_callback callback, void *callback_arg);
429 static Node *find_param_referent(Param *param, deparse_context *context,
430 deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
431 static void get_parameter(Param *param, deparse_context *context);
432 static const char *get_simple_binary_op_name(OpExpr *expr);
433 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
434 static void appendContextKeyword(deparse_context *context, const char *str,
435 int indentBefore, int indentAfter, int indentPlus);
436 static void removeStringInfoSpaces(StringInfo str);
437 static void get_rule_expr(Node *node, deparse_context *context,
438 bool showimplicit);
439 static void get_rule_expr_toplevel(Node *node, deparse_context *context,
440 bool showimplicit);
441 static void get_rule_expr_funccall(Node *node, deparse_context *context,
442 bool showimplicit);
443 static bool looks_like_function(Node *node);
444 static void get_oper_expr(OpExpr *expr, deparse_context *context);
445 static void get_func_expr(FuncExpr *expr, deparse_context *context,
446 bool showimplicit);
447 static void get_agg_expr(Aggref *aggref, deparse_context *context,
448 Aggref *original_aggref);
449 static void get_agg_combine_expr(Node *node, deparse_context *context,
450 void *callback_arg);
451 static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
452 static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context);
453 static void get_coercion_expr(Node *arg, deparse_context *context,
454 Oid resulttype, int32 resulttypmod,
455 Node *parentNode);
456 static void get_const_expr(Const *constval, deparse_context *context,
457 int showtype);
458 static void get_const_collation(Const *constval, deparse_context *context);
459 static void simple_quote_literal(StringInfo buf, const char *val);
460 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
461 static void get_tablefunc(TableFunc *tf, deparse_context *context,
462 bool showimplicit);
463 static void get_from_clause(Query *query, const char *prefix,
464 deparse_context *context);
465 static void get_from_clause_item(Node *jtnode, Query *query,
466 deparse_context *context);
467 static void get_column_alias_list(deparse_columns *colinfo,
468 deparse_context *context);
469 static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
470 deparse_columns *colinfo,
471 deparse_context *context);
472 static void get_tablesample_def(TableSampleClause *tablesample,
473 deparse_context *context);
474 static void get_opclass_name(Oid opclass, Oid actual_datatype,
475 StringInfo buf);
476 static Node *processIndirection(Node *node, deparse_context *context);
477 static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
478 static char *get_relation_name(Oid relid);
479 static char *generate_relation_name(Oid relid, List *namespaces);
480 static char *generate_qualified_relation_name(Oid relid);
481 static char *generate_function_name(Oid funcid, int nargs,
482 List *argnames, Oid *argtypes,
483 bool has_variadic, bool *use_variadic_p,
484 ParseExprKind special_exprkind);
485 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
486 static void add_cast_to(StringInfo buf, Oid typid);
487 static char *generate_qualified_type_name(Oid typid);
488 static text *string_to_text(char *str);
489 static char *flatten_reloptions(Oid relid);
490 static void get_reloptions(StringInfo buf, Datum reloptions);
491
492 #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
493
494
495 /* ----------
496 * pg_get_ruledef - Do it all and return a text
497 * that could be used as a statement
498 * to recreate the rule
499 * ----------
500 */
501 Datum
pg_get_ruledef(PG_FUNCTION_ARGS)502 pg_get_ruledef(PG_FUNCTION_ARGS)
503 {
504 Oid ruleoid = PG_GETARG_OID(0);
505 int prettyFlags;
506 char *res;
507
508 prettyFlags = PRETTYFLAG_INDENT;
509
510 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
511
512 if (res == NULL)
513 PG_RETURN_NULL();
514
515 PG_RETURN_TEXT_P(string_to_text(res));
516 }
517
518
519 Datum
pg_get_ruledef_ext(PG_FUNCTION_ARGS)520 pg_get_ruledef_ext(PG_FUNCTION_ARGS)
521 {
522 Oid ruleoid = PG_GETARG_OID(0);
523 bool pretty = PG_GETARG_BOOL(1);
524 int prettyFlags;
525 char *res;
526
527 prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT;
528
529 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
530
531 if (res == NULL)
532 PG_RETURN_NULL();
533
534 PG_RETURN_TEXT_P(string_to_text(res));
535 }
536
537
538 static char *
pg_get_ruledef_worker(Oid ruleoid,int prettyFlags)539 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
540 {
541 Datum args[1];
542 char nulls[1];
543 int spirc;
544 HeapTuple ruletup;
545 TupleDesc rulettc;
546 StringInfoData buf;
547
548 /*
549 * Do this first so that string is alloc'd in outer context not SPI's.
550 */
551 initStringInfo(&buf);
552
553 /*
554 * Connect to SPI manager
555 */
556 if (SPI_connect() != SPI_OK_CONNECT)
557 elog(ERROR, "SPI_connect failed");
558
559 /*
560 * On the first call prepare the plan to lookup pg_rewrite. We read
561 * pg_rewrite over the SPI manager instead of using the syscache to be
562 * checked for read access on pg_rewrite.
563 */
564 if (plan_getrulebyoid == NULL)
565 {
566 Oid argtypes[1];
567 SPIPlanPtr plan;
568
569 argtypes[0] = OIDOID;
570 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
571 if (plan == NULL)
572 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
573 SPI_keepplan(plan);
574 plan_getrulebyoid = plan;
575 }
576
577 /*
578 * Get the pg_rewrite tuple for this rule
579 */
580 args[0] = ObjectIdGetDatum(ruleoid);
581 nulls[0] = ' ';
582 spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
583 if (spirc != SPI_OK_SELECT)
584 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
585 if (SPI_processed != 1)
586 {
587 /*
588 * There is no tuple data available here, just keep the output buffer
589 * empty.
590 */
591 }
592 else
593 {
594 /*
595 * Get the rule's definition and put it into executor's memory
596 */
597 ruletup = SPI_tuptable->vals[0];
598 rulettc = SPI_tuptable->tupdesc;
599 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
600 }
601
602 /*
603 * Disconnect from SPI manager
604 */
605 if (SPI_finish() != SPI_OK_FINISH)
606 elog(ERROR, "SPI_finish failed");
607
608 if (buf.len == 0)
609 return NULL;
610
611 return buf.data;
612 }
613
614
615 /* ----------
616 * pg_get_viewdef - Mainly the same thing, but we
617 * only return the SELECT part of a view
618 * ----------
619 */
620 Datum
pg_get_viewdef(PG_FUNCTION_ARGS)621 pg_get_viewdef(PG_FUNCTION_ARGS)
622 {
623 /* By OID */
624 Oid viewoid = PG_GETARG_OID(0);
625 int prettyFlags;
626 char *res;
627
628 prettyFlags = PRETTYFLAG_INDENT;
629
630 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
631
632 if (res == NULL)
633 PG_RETURN_NULL();
634
635 PG_RETURN_TEXT_P(string_to_text(res));
636 }
637
638
639 Datum
pg_get_viewdef_ext(PG_FUNCTION_ARGS)640 pg_get_viewdef_ext(PG_FUNCTION_ARGS)
641 {
642 /* By OID */
643 Oid viewoid = PG_GETARG_OID(0);
644 bool pretty = PG_GETARG_BOOL(1);
645 int prettyFlags;
646 char *res;
647
648 prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT;
649
650 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
651
652 if (res == NULL)
653 PG_RETURN_NULL();
654
655 PG_RETURN_TEXT_P(string_to_text(res));
656 }
657
658 Datum
pg_get_viewdef_wrap(PG_FUNCTION_ARGS)659 pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
660 {
661 /* By OID */
662 Oid viewoid = PG_GETARG_OID(0);
663 int wrap = PG_GETARG_INT32(1);
664 int prettyFlags;
665 char *res;
666
667 /* calling this implies we want pretty printing */
668 prettyFlags = PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA;
669
670 res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
671
672 if (res == NULL)
673 PG_RETURN_NULL();
674
675 PG_RETURN_TEXT_P(string_to_text(res));
676 }
677
678 Datum
pg_get_viewdef_name(PG_FUNCTION_ARGS)679 pg_get_viewdef_name(PG_FUNCTION_ARGS)
680 {
681 /* By qualified name */
682 text *viewname = PG_GETARG_TEXT_PP(0);
683 int prettyFlags;
684 RangeVar *viewrel;
685 Oid viewoid;
686 char *res;
687
688 prettyFlags = PRETTYFLAG_INDENT;
689
690 /* Look up view name. Can't lock it - we might not have privileges. */
691 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
692 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
693
694 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
695
696 if (res == NULL)
697 PG_RETURN_NULL();
698
699 PG_RETURN_TEXT_P(string_to_text(res));
700 }
701
702
703 Datum
pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)704 pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
705 {
706 /* By qualified name */
707 text *viewname = PG_GETARG_TEXT_PP(0);
708 bool pretty = PG_GETARG_BOOL(1);
709 int prettyFlags;
710 RangeVar *viewrel;
711 Oid viewoid;
712 char *res;
713
714 prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT;
715
716 /* Look up view name. Can't lock it - we might not have privileges. */
717 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
718 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
719
720 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
721
722 if (res == NULL)
723 PG_RETURN_NULL();
724
725 PG_RETURN_TEXT_P(string_to_text(res));
726 }
727
728 /*
729 * Common code for by-OID and by-name variants of pg_get_viewdef
730 */
731 static char *
pg_get_viewdef_worker(Oid viewoid,int prettyFlags,int wrapColumn)732 pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
733 {
734 Datum args[2];
735 char nulls[2];
736 int spirc;
737 HeapTuple ruletup;
738 TupleDesc rulettc;
739 StringInfoData buf;
740
741 /*
742 * Do this first so that string is alloc'd in outer context not SPI's.
743 */
744 initStringInfo(&buf);
745
746 /*
747 * Connect to SPI manager
748 */
749 if (SPI_connect() != SPI_OK_CONNECT)
750 elog(ERROR, "SPI_connect failed");
751
752 /*
753 * On the first call prepare the plan to lookup pg_rewrite. We read
754 * pg_rewrite over the SPI manager instead of using the syscache to be
755 * checked for read access on pg_rewrite.
756 */
757 if (plan_getviewrule == NULL)
758 {
759 Oid argtypes[2];
760 SPIPlanPtr plan;
761
762 argtypes[0] = OIDOID;
763 argtypes[1] = NAMEOID;
764 plan = SPI_prepare(query_getviewrule, 2, argtypes);
765 if (plan == NULL)
766 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
767 SPI_keepplan(plan);
768 plan_getviewrule = plan;
769 }
770
771 /*
772 * Get the pg_rewrite tuple for the view's SELECT rule
773 */
774 args[0] = ObjectIdGetDatum(viewoid);
775 args[1] = DirectFunctionCall1(namein, CStringGetDatum(ViewSelectRuleName));
776 nulls[0] = ' ';
777 nulls[1] = ' ';
778 spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
779 if (spirc != SPI_OK_SELECT)
780 elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
781 if (SPI_processed != 1)
782 {
783 /*
784 * There is no tuple data available here, just keep the output buffer
785 * empty.
786 */
787 }
788 else
789 {
790 /*
791 * Get the rule's definition and put it into executor's memory
792 */
793 ruletup = SPI_tuptable->vals[0];
794 rulettc = SPI_tuptable->tupdesc;
795 make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
796 }
797
798 /*
799 * Disconnect from SPI manager
800 */
801 if (SPI_finish() != SPI_OK_FINISH)
802 elog(ERROR, "SPI_finish failed");
803
804 if (buf.len == 0)
805 return NULL;
806
807 return buf.data;
808 }
809
810 /* ----------
811 * pg_get_triggerdef - Get the definition of a trigger
812 * ----------
813 */
814 Datum
pg_get_triggerdef(PG_FUNCTION_ARGS)815 pg_get_triggerdef(PG_FUNCTION_ARGS)
816 {
817 Oid trigid = PG_GETARG_OID(0);
818 char *res;
819
820 res = pg_get_triggerdef_worker(trigid, false);
821
822 if (res == NULL)
823 PG_RETURN_NULL();
824
825 PG_RETURN_TEXT_P(string_to_text(res));
826 }
827
828 Datum
pg_get_triggerdef_ext(PG_FUNCTION_ARGS)829 pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
830 {
831 Oid trigid = PG_GETARG_OID(0);
832 bool pretty = PG_GETARG_BOOL(1);
833 char *res;
834
835 res = pg_get_triggerdef_worker(trigid, pretty);
836
837 if (res == NULL)
838 PG_RETURN_NULL();
839
840 PG_RETURN_TEXT_P(string_to_text(res));
841 }
842
843 static char *
pg_get_triggerdef_worker(Oid trigid,bool pretty)844 pg_get_triggerdef_worker(Oid trigid, bool pretty)
845 {
846 HeapTuple ht_trig;
847 Form_pg_trigger trigrec;
848 StringInfoData buf;
849 Relation tgrel;
850 ScanKeyData skey[1];
851 SysScanDesc tgscan;
852 int findx = 0;
853 char *tgname;
854 char *tgoldtable;
855 char *tgnewtable;
856 Datum value;
857 bool isnull;
858
859 /*
860 * Fetch the pg_trigger tuple by the Oid of the trigger
861 */
862 tgrel = table_open(TriggerRelationId, AccessShareLock);
863
864 ScanKeyInit(&skey[0],
865 Anum_pg_trigger_oid,
866 BTEqualStrategyNumber, F_OIDEQ,
867 ObjectIdGetDatum(trigid));
868
869 tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
870 NULL, 1, skey);
871
872 ht_trig = systable_getnext(tgscan);
873
874 if (!HeapTupleIsValid(ht_trig))
875 {
876 systable_endscan(tgscan);
877 table_close(tgrel, AccessShareLock);
878 return NULL;
879 }
880
881 trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
882
883 /*
884 * Start the trigger definition. Note that the trigger's name should never
885 * be schema-qualified, but the trigger rel's name may be.
886 */
887 initStringInfo(&buf);
888
889 tgname = NameStr(trigrec->tgname);
890 appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
891 OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
892 quote_identifier(tgname));
893
894 if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
895 appendStringInfoString(&buf, "BEFORE");
896 else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
897 appendStringInfoString(&buf, "AFTER");
898 else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
899 appendStringInfoString(&buf, "INSTEAD OF");
900 else
901 elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
902
903 if (TRIGGER_FOR_INSERT(trigrec->tgtype))
904 {
905 appendStringInfoString(&buf, " INSERT");
906 findx++;
907 }
908 if (TRIGGER_FOR_DELETE(trigrec->tgtype))
909 {
910 if (findx > 0)
911 appendStringInfoString(&buf, " OR DELETE");
912 else
913 appendStringInfoString(&buf, " DELETE");
914 findx++;
915 }
916 if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
917 {
918 if (findx > 0)
919 appendStringInfoString(&buf, " OR UPDATE");
920 else
921 appendStringInfoString(&buf, " UPDATE");
922 findx++;
923 /* tgattr is first var-width field, so OK to access directly */
924 if (trigrec->tgattr.dim1 > 0)
925 {
926 int i;
927
928 appendStringInfoString(&buf, " OF ");
929 for (i = 0; i < trigrec->tgattr.dim1; i++)
930 {
931 char *attname;
932
933 if (i > 0)
934 appendStringInfoString(&buf, ", ");
935 attname = get_attname(trigrec->tgrelid,
936 trigrec->tgattr.values[i], false);
937 appendStringInfoString(&buf, quote_identifier(attname));
938 }
939 }
940 }
941 if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
942 {
943 if (findx > 0)
944 appendStringInfoString(&buf, " OR TRUNCATE");
945 else
946 appendStringInfoString(&buf, " TRUNCATE");
947 findx++;
948 }
949
950 /*
951 * In non-pretty mode, always schema-qualify the target table name for
952 * safety. In pretty mode, schema-qualify only if not visible.
953 */
954 appendStringInfo(&buf, " ON %s ",
955 pretty ?
956 generate_relation_name(trigrec->tgrelid, NIL) :
957 generate_qualified_relation_name(trigrec->tgrelid));
958
959 if (OidIsValid(trigrec->tgconstraint))
960 {
961 if (OidIsValid(trigrec->tgconstrrelid))
962 appendStringInfo(&buf, "FROM %s ",
963 generate_relation_name(trigrec->tgconstrrelid, NIL));
964 if (!trigrec->tgdeferrable)
965 appendStringInfoString(&buf, "NOT ");
966 appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
967 if (trigrec->tginitdeferred)
968 appendStringInfoString(&buf, "DEFERRED ");
969 else
970 appendStringInfoString(&buf, "IMMEDIATE ");
971 }
972
973 value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
974 tgrel->rd_att, &isnull);
975 if (!isnull)
976 tgoldtable = NameStr(*DatumGetName(value));
977 else
978 tgoldtable = NULL;
979 value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
980 tgrel->rd_att, &isnull);
981 if (!isnull)
982 tgnewtable = NameStr(*DatumGetName(value));
983 else
984 tgnewtable = NULL;
985 if (tgoldtable != NULL || tgnewtable != NULL)
986 {
987 appendStringInfoString(&buf, "REFERENCING ");
988 if (tgoldtable != NULL)
989 appendStringInfo(&buf, "OLD TABLE AS %s ",
990 quote_identifier(tgoldtable));
991 if (tgnewtable != NULL)
992 appendStringInfo(&buf, "NEW TABLE AS %s ",
993 quote_identifier(tgnewtable));
994 }
995
996 if (TRIGGER_FOR_ROW(trigrec->tgtype))
997 appendStringInfoString(&buf, "FOR EACH ROW ");
998 else
999 appendStringInfoString(&buf, "FOR EACH STATEMENT ");
1000
1001 /* If the trigger has a WHEN qualification, add that */
1002 value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
1003 tgrel->rd_att, &isnull);
1004 if (!isnull)
1005 {
1006 Node *qual;
1007 char relkind;
1008 deparse_context context;
1009 deparse_namespace dpns;
1010 RangeTblEntry *oldrte;
1011 RangeTblEntry *newrte;
1012
1013 appendStringInfoString(&buf, "WHEN (");
1014
1015 qual = stringToNode(TextDatumGetCString(value));
1016
1017 relkind = get_rel_relkind(trigrec->tgrelid);
1018
1019 /* Build minimal OLD and NEW RTEs for the rel */
1020 oldrte = makeNode(RangeTblEntry);
1021 oldrte->rtekind = RTE_RELATION;
1022 oldrte->relid = trigrec->tgrelid;
1023 oldrte->relkind = relkind;
1024 oldrte->rellockmode = AccessShareLock;
1025 oldrte->alias = makeAlias("old", NIL);
1026 oldrte->eref = oldrte->alias;
1027 oldrte->lateral = false;
1028 oldrte->inh = false;
1029 oldrte->inFromCl = true;
1030
1031 newrte = makeNode(RangeTblEntry);
1032 newrte->rtekind = RTE_RELATION;
1033 newrte->relid = trigrec->tgrelid;
1034 newrte->relkind = relkind;
1035 newrte->rellockmode = AccessShareLock;
1036 newrte->alias = makeAlias("new", NIL);
1037 newrte->eref = newrte->alias;
1038 newrte->lateral = false;
1039 newrte->inh = false;
1040 newrte->inFromCl = true;
1041
1042 /* Build two-element rtable */
1043 memset(&dpns, 0, sizeof(dpns));
1044 dpns.rtable = list_make2(oldrte, newrte);
1045 dpns.subplans = NIL;
1046 dpns.ctes = NIL;
1047 dpns.appendrels = NULL;
1048 set_rtable_names(&dpns, NIL, NULL);
1049 set_simple_column_names(&dpns);
1050
1051 /* Set up context with one-deep namespace stack */
1052 context.buf = &buf;
1053 context.namespaces = list_make1(&dpns);
1054 context.windowClause = NIL;
1055 context.windowTList = NIL;
1056 context.varprefix = true;
1057 context.prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT;
1058 context.wrapColumn = WRAP_COLUMN_DEFAULT;
1059 context.indentLevel = PRETTYINDENT_STD;
1060 context.special_exprkind = EXPR_KIND_NONE;
1061 context.appendparents = NULL;
1062
1063 get_rule_expr(qual, &context, false);
1064
1065 appendStringInfoString(&buf, ") ");
1066 }
1067
1068 appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
1069 generate_function_name(trigrec->tgfoid, 0,
1070 NIL, NULL,
1071 false, NULL, EXPR_KIND_NONE));
1072
1073 if (trigrec->tgnargs > 0)
1074 {
1075 char *p;
1076 int i;
1077
1078 value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
1079 tgrel->rd_att, &isnull);
1080 if (isnull)
1081 elog(ERROR, "tgargs is null for trigger %u", trigid);
1082 p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1083 for (i = 0; i < trigrec->tgnargs; i++)
1084 {
1085 if (i > 0)
1086 appendStringInfoString(&buf, ", ");
1087 simple_quote_literal(&buf, p);
1088 /* advance p to next string embedded in tgargs */
1089 while (*p)
1090 p++;
1091 p++;
1092 }
1093 }
1094
1095 /* We deliberately do not put semi-colon at end */
1096 appendStringInfoChar(&buf, ')');
1097
1098 /* Clean up */
1099 systable_endscan(tgscan);
1100
1101 table_close(tgrel, AccessShareLock);
1102
1103 return buf.data;
1104 }
1105
1106 /* ----------
1107 * pg_get_indexdef - Get the definition of an index
1108 *
1109 * In the extended version, there is a colno argument as well as pretty bool.
1110 * if colno == 0, we want a complete index definition.
1111 * if colno > 0, we only want the Nth index key's variable or expression.
1112 *
1113 * Note that the SQL-function versions of this omit any info about the
1114 * index tablespace; this is intentional because pg_dump wants it that way.
1115 * However pg_get_indexdef_string() includes the index tablespace.
1116 * ----------
1117 */
1118 Datum
pg_get_indexdef(PG_FUNCTION_ARGS)1119 pg_get_indexdef(PG_FUNCTION_ARGS)
1120 {
1121 Oid indexrelid = PG_GETARG_OID(0);
1122 int prettyFlags;
1123 char *res;
1124
1125 prettyFlags = PRETTYFLAG_INDENT;
1126
1127 res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1128 false, false,
1129 false, false,
1130 prettyFlags, true);
1131
1132 if (res == NULL)
1133 PG_RETURN_NULL();
1134
1135 PG_RETURN_TEXT_P(string_to_text(res));
1136 }
1137
1138 Datum
pg_get_indexdef_ext(PG_FUNCTION_ARGS)1139 pg_get_indexdef_ext(PG_FUNCTION_ARGS)
1140 {
1141 Oid indexrelid = PG_GETARG_OID(0);
1142 int32 colno = PG_GETARG_INT32(1);
1143 bool pretty = PG_GETARG_BOOL(2);
1144 int prettyFlags;
1145 char *res;
1146
1147 prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT;
1148
1149 res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1150 colno != 0, false,
1151 false, false,
1152 prettyFlags, true);
1153
1154 if (res == NULL)
1155 PG_RETURN_NULL();
1156
1157 PG_RETURN_TEXT_P(string_to_text(res));
1158 }
1159
1160 /*
1161 * Internal version for use by ALTER TABLE.
1162 * Includes a tablespace clause in the result.
1163 * Returns a palloc'd C string; no pretty-printing.
1164 */
1165 char *
pg_get_indexdef_string(Oid indexrelid)1166 pg_get_indexdef_string(Oid indexrelid)
1167 {
1168 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1169 false, false,
1170 true, true,
1171 0, false);
1172 }
1173
1174 /* Internal version that just reports the key-column definitions */
1175 char *
pg_get_indexdef_columns(Oid indexrelid,bool pretty)1176 pg_get_indexdef_columns(Oid indexrelid, bool pretty)
1177 {
1178 int prettyFlags;
1179
1180 prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT;
1181
1182 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1183 true, true,
1184 false, false,
1185 prettyFlags, false);
1186 }
1187
1188 /*
1189 * Internal workhorse to decompile an index definition.
1190 *
1191 * This is now used for exclusion constraints as well: if excludeOps is not
1192 * NULL then it points to an array of exclusion operator OIDs.
1193 */
1194 static char *
pg_get_indexdef_worker(Oid indexrelid,int colno,const Oid * excludeOps,bool attrsOnly,bool keysOnly,bool showTblSpc,bool inherits,int prettyFlags,bool missing_ok)1195 pg_get_indexdef_worker(Oid indexrelid, int colno,
1196 const Oid *excludeOps,
1197 bool attrsOnly, bool keysOnly,
1198 bool showTblSpc, bool inherits,
1199 int prettyFlags, bool missing_ok)
1200 {
1201 /* might want a separate isConstraint parameter later */
1202 bool isConstraint = (excludeOps != NULL);
1203 HeapTuple ht_idx;
1204 HeapTuple ht_idxrel;
1205 HeapTuple ht_am;
1206 Form_pg_index idxrec;
1207 Form_pg_class idxrelrec;
1208 Form_pg_am amrec;
1209 IndexAmRoutine *amroutine;
1210 List *indexprs;
1211 ListCell *indexpr_item;
1212 List *context;
1213 Oid indrelid;
1214 int keyno;
1215 Datum indcollDatum;
1216 Datum indclassDatum;
1217 Datum indoptionDatum;
1218 bool isnull;
1219 oidvector *indcollation;
1220 oidvector *indclass;
1221 int2vector *indoption;
1222 StringInfoData buf;
1223 char *str;
1224 char *sep;
1225
1226 /*
1227 * Fetch the pg_index tuple by the Oid of the index
1228 */
1229 ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
1230 if (!HeapTupleIsValid(ht_idx))
1231 {
1232 if (missing_ok)
1233 return NULL;
1234 elog(ERROR, "cache lookup failed for index %u", indexrelid);
1235 }
1236 idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1237
1238 indrelid = idxrec->indrelid;
1239 Assert(indexrelid == idxrec->indexrelid);
1240
1241 /* Must get indcollation, indclass, and indoption the hard way */
1242 indcollDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1243 Anum_pg_index_indcollation, &isnull);
1244 Assert(!isnull);
1245 indcollation = (oidvector *) DatumGetPointer(indcollDatum);
1246
1247 indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1248 Anum_pg_index_indclass, &isnull);
1249 Assert(!isnull);
1250 indclass = (oidvector *) DatumGetPointer(indclassDatum);
1251
1252 indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1253 Anum_pg_index_indoption, &isnull);
1254 Assert(!isnull);
1255 indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1256
1257 /*
1258 * Fetch the pg_class tuple of the index relation
1259 */
1260 ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
1261 if (!HeapTupleIsValid(ht_idxrel))
1262 elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1263 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1264
1265 /*
1266 * Fetch the pg_am tuple of the index' access method
1267 */
1268 ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1269 if (!HeapTupleIsValid(ht_am))
1270 elog(ERROR, "cache lookup failed for access method %u",
1271 idxrelrec->relam);
1272 amrec = (Form_pg_am) GETSTRUCT(ht_am);
1273
1274 /* Fetch the index AM's API struct */
1275 amroutine = GetIndexAmRoutine(amrec->amhandler);
1276
1277 /*
1278 * Get the index expressions, if any. (NOTE: we do not use the relcache
1279 * versions of the expressions and predicate, because we want to display
1280 * non-const-folded expressions.)
1281 */
1282 if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
1283 {
1284 Datum exprsDatum;
1285 bool isnull;
1286 char *exprsString;
1287
1288 exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1289 Anum_pg_index_indexprs, &isnull);
1290 Assert(!isnull);
1291 exprsString = TextDatumGetCString(exprsDatum);
1292 indexprs = (List *) stringToNode(exprsString);
1293 pfree(exprsString);
1294 }
1295 else
1296 indexprs = NIL;
1297
1298 indexpr_item = list_head(indexprs);
1299
1300 context = deparse_context_for(get_relation_name(indrelid), indrelid);
1301
1302 /*
1303 * Start the index definition. Note that the index's name should never be
1304 * schema-qualified, but the indexed rel's name may be.
1305 */
1306 initStringInfo(&buf);
1307
1308 if (!attrsOnly)
1309 {
1310 if (!isConstraint)
1311 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
1312 idxrec->indisunique ? "UNIQUE " : "",
1313 quote_identifier(NameStr(idxrelrec->relname)),
1314 idxrelrec->relkind == RELKIND_PARTITIONED_INDEX
1315 && !inherits ? "ONLY " : "",
1316 (prettyFlags & PRETTYFLAG_SCHEMA) ?
1317 generate_relation_name(indrelid, NIL) :
1318 generate_qualified_relation_name(indrelid),
1319 quote_identifier(NameStr(amrec->amname)));
1320 else /* currently, must be EXCLUDE constraint */
1321 appendStringInfo(&buf, "EXCLUDE USING %s (",
1322 quote_identifier(NameStr(amrec->amname)));
1323 }
1324
1325 /*
1326 * Report the indexed attributes
1327 */
1328 sep = "";
1329 for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1330 {
1331 AttrNumber attnum = idxrec->indkey.values[keyno];
1332 Oid keycoltype;
1333 Oid keycolcollation;
1334
1335 /*
1336 * Ignore non-key attributes if told to.
1337 */
1338 if (keysOnly && keyno >= idxrec->indnkeyatts)
1339 break;
1340
1341 /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1342 if (!colno && keyno == idxrec->indnkeyatts)
1343 {
1344 appendStringInfoString(&buf, ") INCLUDE (");
1345 sep = "";
1346 }
1347
1348 if (!colno)
1349 appendStringInfoString(&buf, sep);
1350 sep = ", ";
1351
1352 if (attnum != 0)
1353 {
1354 /* Simple index column */
1355 char *attname;
1356 int32 keycoltypmod;
1357
1358 attname = get_attname(indrelid, attnum, false);
1359 if (!colno || colno == keyno + 1)
1360 appendStringInfoString(&buf, quote_identifier(attname));
1361 get_atttypetypmodcoll(indrelid, attnum,
1362 &keycoltype, &keycoltypmod,
1363 &keycolcollation);
1364 }
1365 else
1366 {
1367 /* expressional index */
1368 Node *indexkey;
1369
1370 if (indexpr_item == NULL)
1371 elog(ERROR, "too few entries in indexprs list");
1372 indexkey = (Node *) lfirst(indexpr_item);
1373 indexpr_item = lnext(indexprs, indexpr_item);
1374 /* Deparse */
1375 str = deparse_expression_pretty(indexkey, context, false, false,
1376 prettyFlags, 0);
1377 if (!colno || colno == keyno + 1)
1378 {
1379 /* Need parens if it's not a bare function call */
1380 if (looks_like_function(indexkey))
1381 appendStringInfoString(&buf, str);
1382 else
1383 appendStringInfo(&buf, "(%s)", str);
1384 }
1385 keycoltype = exprType(indexkey);
1386 keycolcollation = exprCollation(indexkey);
1387 }
1388
1389 /* Print additional decoration for (selected) key columns */
1390 if (!attrsOnly && keyno < idxrec->indnkeyatts &&
1391 (!colno || colno == keyno + 1))
1392 {
1393 int16 opt = indoption->values[keyno];
1394 Oid indcoll = indcollation->values[keyno];
1395 Datum attoptions = get_attoptions(indexrelid, keyno + 1);
1396 bool has_options = attoptions != (Datum) 0;
1397
1398 /* Add collation, if not default for column */
1399 if (OidIsValid(indcoll) && indcoll != keycolcollation)
1400 appendStringInfo(&buf, " COLLATE %s",
1401 generate_collation_name((indcoll)));
1402
1403 /* Add the operator class name, if not default */
1404 get_opclass_name(indclass->values[keyno],
1405 has_options ? InvalidOid : keycoltype, &buf);
1406
1407 if (has_options)
1408 {
1409 appendStringInfoString(&buf, " (");
1410 get_reloptions(&buf, attoptions);
1411 appendStringInfoChar(&buf, ')');
1412 }
1413
1414 /* Add options if relevant */
1415 if (amroutine->amcanorder)
1416 {
1417 /* if it supports sort ordering, report DESC and NULLS opts */
1418 if (opt & INDOPTION_DESC)
1419 {
1420 appendStringInfoString(&buf, " DESC");
1421 /* NULLS FIRST is the default in this case */
1422 if (!(opt & INDOPTION_NULLS_FIRST))
1423 appendStringInfoString(&buf, " NULLS LAST");
1424 }
1425 else
1426 {
1427 if (opt & INDOPTION_NULLS_FIRST)
1428 appendStringInfoString(&buf, " NULLS FIRST");
1429 }
1430 }
1431
1432 /* Add the exclusion operator if relevant */
1433 if (excludeOps != NULL)
1434 appendStringInfo(&buf, " WITH %s",
1435 generate_operator_name(excludeOps[keyno],
1436 keycoltype,
1437 keycoltype));
1438 }
1439 }
1440
1441 if (!attrsOnly)
1442 {
1443 appendStringInfoChar(&buf, ')');
1444
1445 /*
1446 * If it has options, append "WITH (options)"
1447 */
1448 str = flatten_reloptions(indexrelid);
1449 if (str)
1450 {
1451 appendStringInfo(&buf, " WITH (%s)", str);
1452 pfree(str);
1453 }
1454
1455 /*
1456 * Print tablespace, but only if requested
1457 */
1458 if (showTblSpc)
1459 {
1460 Oid tblspc;
1461
1462 tblspc = get_rel_tablespace(indexrelid);
1463 if (OidIsValid(tblspc))
1464 {
1465 if (isConstraint)
1466 appendStringInfoString(&buf, " USING INDEX");
1467 appendStringInfo(&buf, " TABLESPACE %s",
1468 quote_identifier(get_tablespace_name(tblspc)));
1469 }
1470 }
1471
1472 /*
1473 * If it's a partial index, decompile and append the predicate
1474 */
1475 if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
1476 {
1477 Node *node;
1478 Datum predDatum;
1479 bool isnull;
1480 char *predString;
1481
1482 /* Convert text string to node tree */
1483 predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1484 Anum_pg_index_indpred, &isnull);
1485 Assert(!isnull);
1486 predString = TextDatumGetCString(predDatum);
1487 node = (Node *) stringToNode(predString);
1488 pfree(predString);
1489
1490 /* Deparse */
1491 str = deparse_expression_pretty(node, context, false, false,
1492 prettyFlags, 0);
1493 if (isConstraint)
1494 appendStringInfo(&buf, " WHERE (%s)", str);
1495 else
1496 appendStringInfo(&buf, " WHERE %s", str);
1497 }
1498 }
1499
1500 /* Clean up */
1501 ReleaseSysCache(ht_idx);
1502 ReleaseSysCache(ht_idxrel);
1503 ReleaseSysCache(ht_am);
1504
1505 return buf.data;
1506 }
1507
1508 /*
1509 * pg_get_statisticsobjdef
1510 * Get the definition of an extended statistics object
1511 */
1512 Datum
pg_get_statisticsobjdef(PG_FUNCTION_ARGS)1513 pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
1514 {
1515 Oid statextid = PG_GETARG_OID(0);
1516 char *res;
1517
1518 res = pg_get_statisticsobj_worker(statextid, false, true);
1519
1520 if (res == NULL)
1521 PG_RETURN_NULL();
1522
1523 PG_RETURN_TEXT_P(string_to_text(res));
1524 }
1525
1526 /*
1527 * Internal version for use by ALTER TABLE.
1528 * Includes a tablespace clause in the result.
1529 * Returns a palloc'd C string; no pretty-printing.
1530 */
1531 char *
pg_get_statisticsobjdef_string(Oid statextid)1532 pg_get_statisticsobjdef_string(Oid statextid)
1533 {
1534 return pg_get_statisticsobj_worker(statextid, false, false);
1535 }
1536
1537 /*
1538 * pg_get_statisticsobjdef_columns
1539 * Get columns and expressions for an extended statistics object
1540 */
1541 Datum
pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)1542 pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)
1543 {
1544 Oid statextid = PG_GETARG_OID(0);
1545 char *res;
1546
1547 res = pg_get_statisticsobj_worker(statextid, true, true);
1548
1549 if (res == NULL)
1550 PG_RETURN_NULL();
1551
1552 PG_RETURN_TEXT_P(string_to_text(res));
1553 }
1554
1555 /*
1556 * Internal workhorse to decompile an extended statistics object.
1557 */
1558 static char *
pg_get_statisticsobj_worker(Oid statextid,bool columns_only,bool missing_ok)1559 pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
1560 {
1561 Form_pg_statistic_ext statextrec;
1562 HeapTuple statexttup;
1563 StringInfoData buf;
1564 int colno;
1565 char *nsp;
1566 ArrayType *arr;
1567 char *enabled;
1568 Datum datum;
1569 bool isnull;
1570 bool ndistinct_enabled;
1571 bool dependencies_enabled;
1572 bool mcv_enabled;
1573 int i;
1574 List *context;
1575 ListCell *lc;
1576 List *exprs = NIL;
1577 bool has_exprs;
1578 int ncolumns;
1579
1580 statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1581
1582 if (!HeapTupleIsValid(statexttup))
1583 {
1584 if (missing_ok)
1585 return NULL;
1586 elog(ERROR, "cache lookup failed for statistics object %u", statextid);
1587 }
1588
1589 /* has the statistics expressions? */
1590 has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1591
1592 statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1593
1594 /*
1595 * Get the statistics expressions, if any. (NOTE: we do not use the
1596 * relcache versions of the expressions, because we want to display
1597 * non-const-folded expressions.)
1598 */
1599 if (has_exprs)
1600 {
1601 Datum exprsDatum;
1602 bool isnull;
1603 char *exprsString;
1604
1605 exprsDatum = SysCacheGetAttr(STATEXTOID, statexttup,
1606 Anum_pg_statistic_ext_stxexprs, &isnull);
1607 Assert(!isnull);
1608 exprsString = TextDatumGetCString(exprsDatum);
1609 exprs = (List *) stringToNode(exprsString);
1610 pfree(exprsString);
1611 }
1612 else
1613 exprs = NIL;
1614
1615 /* count the number of columns (attributes and expressions) */
1616 ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
1617
1618 initStringInfo(&buf);
1619
1620 if (!columns_only)
1621 {
1622 nsp = get_namespace_name(statextrec->stxnamespace);
1623 appendStringInfo(&buf, "CREATE STATISTICS %s",
1624 quote_qualified_identifier(nsp,
1625 NameStr(statextrec->stxname)));
1626
1627 /*
1628 * Decode the stxkind column so that we know which stats types to
1629 * print.
1630 */
1631 datum = SysCacheGetAttr(STATEXTOID, statexttup,
1632 Anum_pg_statistic_ext_stxkind, &isnull);
1633 Assert(!isnull);
1634 arr = DatumGetArrayTypeP(datum);
1635 if (ARR_NDIM(arr) != 1 ||
1636 ARR_HASNULL(arr) ||
1637 ARR_ELEMTYPE(arr) != CHAROID)
1638 elog(ERROR, "stxkind is not a 1-D char array");
1639 enabled = (char *) ARR_DATA_PTR(arr);
1640
1641 ndistinct_enabled = false;
1642 dependencies_enabled = false;
1643 mcv_enabled = false;
1644
1645 for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1646 {
1647 if (enabled[i] == STATS_EXT_NDISTINCT)
1648 ndistinct_enabled = true;
1649 else if (enabled[i] == STATS_EXT_DEPENDENCIES)
1650 dependencies_enabled = true;
1651 else if (enabled[i] == STATS_EXT_MCV)
1652 mcv_enabled = true;
1653
1654 /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
1655 }
1656
1657 /*
1658 * If any option is disabled, then we'll need to append the types
1659 * clause to show which options are enabled. We omit the types clause
1660 * on purpose when all options are enabled, so a pg_dump/pg_restore
1661 * will create all statistics types on a newer postgres version, if
1662 * the statistics had all options enabled on the original version.
1663 *
1664 * But if the statistics is defined on just a single column, it has to
1665 * be an expression statistics. In that case we don't need to specify
1666 * kinds.
1667 */
1668 if ((!ndistinct_enabled || !dependencies_enabled || !mcv_enabled) &&
1669 (ncolumns > 1))
1670 {
1671 bool gotone = false;
1672
1673 appendStringInfoString(&buf, " (");
1674
1675 if (ndistinct_enabled)
1676 {
1677 appendStringInfoString(&buf, "ndistinct");
1678 gotone = true;
1679 }
1680
1681 if (dependencies_enabled)
1682 {
1683 appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
1684 gotone = true;
1685 }
1686
1687 if (mcv_enabled)
1688 appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
1689
1690 appendStringInfoChar(&buf, ')');
1691 }
1692
1693 appendStringInfoString(&buf, " ON ");
1694 }
1695
1696 /* decode simple column references */
1697 for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
1698 {
1699 AttrNumber attnum = statextrec->stxkeys.values[colno];
1700 char *attname;
1701
1702 if (colno > 0)
1703 appendStringInfoString(&buf, ", ");
1704
1705 attname = get_attname(statextrec->stxrelid, attnum, false);
1706
1707 appendStringInfoString(&buf, quote_identifier(attname));
1708 }
1709
1710 context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1711 statextrec->stxrelid);
1712
1713 foreach(lc, exprs)
1714 {
1715 Node *expr = (Node *) lfirst(lc);
1716 char *str;
1717 int prettyFlags = PRETTYFLAG_PAREN;
1718
1719 str = deparse_expression_pretty(expr, context, false, false,
1720 prettyFlags, 0);
1721
1722 if (colno > 0)
1723 appendStringInfoString(&buf, ", ");
1724
1725 /* Need parens if it's not a bare function call */
1726 if (looks_like_function(expr))
1727 appendStringInfoString(&buf, str);
1728 else
1729 appendStringInfo(&buf, "(%s)", str);
1730
1731 colno++;
1732 }
1733
1734 if (!columns_only)
1735 appendStringInfo(&buf, " FROM %s",
1736 generate_relation_name(statextrec->stxrelid, NIL));
1737
1738 ReleaseSysCache(statexttup);
1739
1740 return buf.data;
1741 }
1742
1743 /*
1744 * Generate text array of expressions for statistics object.
1745 */
1746 Datum
pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)1747 pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
1748 {
1749 Oid statextid = PG_GETARG_OID(0);
1750 Form_pg_statistic_ext statextrec;
1751 HeapTuple statexttup;
1752 Datum datum;
1753 bool isnull;
1754 List *context;
1755 ListCell *lc;
1756 List *exprs = NIL;
1757 bool has_exprs;
1758 char *tmp;
1759 ArrayBuildState *astate = NULL;
1760
1761 statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1762
1763 if (!HeapTupleIsValid(statexttup))
1764 PG_RETURN_NULL();
1765
1766 /* Does the stats object have expressions? */
1767 has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1768
1769 /* no expressions? we're done */
1770 if (!has_exprs)
1771 {
1772 ReleaseSysCache(statexttup);
1773 PG_RETURN_NULL();
1774 }
1775
1776 statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1777
1778 /*
1779 * Get the statistics expressions, and deparse them into text values.
1780 */
1781 datum = SysCacheGetAttr(STATEXTOID, statexttup,
1782 Anum_pg_statistic_ext_stxexprs, &isnull);
1783
1784 Assert(!isnull);
1785 tmp = TextDatumGetCString(datum);
1786 exprs = (List *) stringToNode(tmp);
1787 pfree(tmp);
1788
1789 context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1790 statextrec->stxrelid);
1791
1792 foreach(lc, exprs)
1793 {
1794 Node *expr = (Node *) lfirst(lc);
1795 char *str;
1796 int prettyFlags = PRETTYFLAG_INDENT;
1797
1798 str = deparse_expression_pretty(expr, context, false, false,
1799 prettyFlags, 0);
1800
1801 astate = accumArrayResult(astate,
1802 PointerGetDatum(cstring_to_text(str)),
1803 false,
1804 TEXTOID,
1805 CurrentMemoryContext);
1806 }
1807
1808 ReleaseSysCache(statexttup);
1809
1810 PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
1811 }
1812
1813 /*
1814 * pg_get_partkeydef
1815 *
1816 * Returns the partition key specification, ie, the following:
1817 *
1818 * PARTITION BY { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
1819 */
1820 Datum
pg_get_partkeydef(PG_FUNCTION_ARGS)1821 pg_get_partkeydef(PG_FUNCTION_ARGS)
1822 {
1823 Oid relid = PG_GETARG_OID(0);
1824 char *res;
1825
1826 res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1827
1828 if (res == NULL)
1829 PG_RETURN_NULL();
1830
1831 PG_RETURN_TEXT_P(string_to_text(res));
1832 }
1833
1834 /* Internal version that just reports the column definitions */
1835 char *
pg_get_partkeydef_columns(Oid relid,bool pretty)1836 pg_get_partkeydef_columns(Oid relid, bool pretty)
1837 {
1838 int prettyFlags;
1839
1840 prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT;
1841
1842 return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1843 }
1844
1845 /*
1846 * Internal workhorse to decompile a partition key definition.
1847 */
1848 static char *
pg_get_partkeydef_worker(Oid relid,int prettyFlags,bool attrsOnly,bool missing_ok)1849 pg_get_partkeydef_worker(Oid relid, int prettyFlags,
1850 bool attrsOnly, bool missing_ok)
1851 {
1852 Form_pg_partitioned_table form;
1853 HeapTuple tuple;
1854 oidvector *partclass;
1855 oidvector *partcollation;
1856 List *partexprs;
1857 ListCell *partexpr_item;
1858 List *context;
1859 Datum datum;
1860 bool isnull;
1861 StringInfoData buf;
1862 int keyno;
1863 char *str;
1864 char *sep;
1865
1866 tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
1867 if (!HeapTupleIsValid(tuple))
1868 {
1869 if (missing_ok)
1870 return NULL;
1871 elog(ERROR, "cache lookup failed for partition key of %u", relid);
1872 }
1873
1874 form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
1875
1876 Assert(form->partrelid == relid);
1877
1878 /* Must get partclass and partcollation the hard way */
1879 datum = SysCacheGetAttr(PARTRELID, tuple,
1880 Anum_pg_partitioned_table_partclass, &isnull);
1881 Assert(!isnull);
1882 partclass = (oidvector *) DatumGetPointer(datum);
1883
1884 datum = SysCacheGetAttr(PARTRELID, tuple,
1885 Anum_pg_partitioned_table_partcollation, &isnull);
1886 Assert(!isnull);
1887 partcollation = (oidvector *) DatumGetPointer(datum);
1888
1889
1890 /*
1891 * Get the expressions, if any. (NOTE: we do not use the relcache
1892 * versions of the expressions, because we want to display
1893 * non-const-folded expressions.)
1894 */
1895 if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
1896 {
1897 Datum exprsDatum;
1898 bool isnull;
1899 char *exprsString;
1900
1901 exprsDatum = SysCacheGetAttr(PARTRELID, tuple,
1902 Anum_pg_partitioned_table_partexprs, &isnull);
1903 Assert(!isnull);
1904 exprsString = TextDatumGetCString(exprsDatum);
1905 partexprs = (List *) stringToNode(exprsString);
1906
1907 if (!IsA(partexprs, List))
1908 elog(ERROR, "unexpected node type found in partexprs: %d",
1909 (int) nodeTag(partexprs));
1910
1911 pfree(exprsString);
1912 }
1913 else
1914 partexprs = NIL;
1915
1916 partexpr_item = list_head(partexprs);
1917 context = deparse_context_for(get_relation_name(relid), relid);
1918
1919 initStringInfo(&buf);
1920
1921 switch (form->partstrat)
1922 {
1923 case PARTITION_STRATEGY_HASH:
1924 if (!attrsOnly)
1925 appendStringInfoString(&buf, "HASH");
1926 break;
1927 case PARTITION_STRATEGY_LIST:
1928 if (!attrsOnly)
1929 appendStringInfoString(&buf, "LIST");
1930 break;
1931 case PARTITION_STRATEGY_RANGE:
1932 if (!attrsOnly)
1933 appendStringInfoString(&buf, "RANGE");
1934 break;
1935 default:
1936 elog(ERROR, "unexpected partition strategy: %d",
1937 (int) form->partstrat);
1938 }
1939
1940 if (!attrsOnly)
1941 appendStringInfoString(&buf, " (");
1942 sep = "";
1943 for (keyno = 0; keyno < form->partnatts; keyno++)
1944 {
1945 AttrNumber attnum = form->partattrs.values[keyno];
1946 Oid keycoltype;
1947 Oid keycolcollation;
1948 Oid partcoll;
1949
1950 appendStringInfoString(&buf, sep);
1951 sep = ", ";
1952 if (attnum != 0)
1953 {
1954 /* Simple attribute reference */
1955 char *attname;
1956 int32 keycoltypmod;
1957
1958 attname = get_attname(relid, attnum, false);
1959 appendStringInfoString(&buf, quote_identifier(attname));
1960 get_atttypetypmodcoll(relid, attnum,
1961 &keycoltype, &keycoltypmod,
1962 &keycolcollation);
1963 }
1964 else
1965 {
1966 /* Expression */
1967 Node *partkey;
1968
1969 if (partexpr_item == NULL)
1970 elog(ERROR, "too few entries in partexprs list");
1971 partkey = (Node *) lfirst(partexpr_item);
1972 partexpr_item = lnext(partexprs, partexpr_item);
1973
1974 /* Deparse */
1975 str = deparse_expression_pretty(partkey, context, false, false,
1976 prettyFlags, 0);
1977 /* Need parens if it's not a bare function call */
1978 if (looks_like_function(partkey))
1979 appendStringInfoString(&buf, str);
1980 else
1981 appendStringInfo(&buf, "(%s)", str);
1982
1983 keycoltype = exprType(partkey);
1984 keycolcollation = exprCollation(partkey);
1985 }
1986
1987 /* Add collation, if not default for column */
1988 partcoll = partcollation->values[keyno];
1989 if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
1990 appendStringInfo(&buf, " COLLATE %s",
1991 generate_collation_name((partcoll)));
1992
1993 /* Add the operator class name, if not default */
1994 if (!attrsOnly)
1995 get_opclass_name(partclass->values[keyno], keycoltype, &buf);
1996 }
1997
1998 if (!attrsOnly)
1999 appendStringInfoChar(&buf, ')');
2000
2001 /* Clean up */
2002 ReleaseSysCache(tuple);
2003
2004 return buf.data;
2005 }
2006
2007 /*
2008 * pg_get_partition_constraintdef
2009 *
2010 * Returns partition constraint expression as a string for the input relation
2011 */
2012 Datum
pg_get_partition_constraintdef(PG_FUNCTION_ARGS)2013 pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
2014 {
2015 Oid relationId = PG_GETARG_OID(0);
2016 Expr *constr_expr;
2017 int prettyFlags;
2018 List *context;
2019 char *consrc;
2020
2021 constr_expr = get_partition_qual_relid(relationId);
2022
2023 /* Quick exit if no partition constraint */
2024 if (constr_expr == NULL)
2025 PG_RETURN_NULL();
2026
2027 /*
2028 * Deparse and return the constraint expression.
2029 */
2030 prettyFlags = PRETTYFLAG_INDENT;
2031 context = deparse_context_for(get_relation_name(relationId), relationId);
2032 consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2033 false, prettyFlags, 0);
2034
2035 PG_RETURN_TEXT_P(string_to_text(consrc));
2036 }
2037
2038 /*
2039 * pg_get_partconstrdef_string
2040 *
2041 * Returns the partition constraint as a C-string for the input relation, with
2042 * the given alias. No pretty-printing.
2043 */
2044 char *
pg_get_partconstrdef_string(Oid partitionId,char * aliasname)2045 pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
2046 {
2047 Expr *constr_expr;
2048 List *context;
2049
2050 constr_expr = get_partition_qual_relid(partitionId);
2051 context = deparse_context_for(aliasname, partitionId);
2052
2053 return deparse_expression((Node *) constr_expr, context, true, false);
2054 }
2055
2056 /*
2057 * pg_get_constraintdef
2058 *
2059 * Returns the definition for the constraint, ie, everything that needs to
2060 * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
2061 */
2062 Datum
pg_get_constraintdef(PG_FUNCTION_ARGS)2063 pg_get_constraintdef(PG_FUNCTION_ARGS)
2064 {
2065 Oid constraintId = PG_GETARG_OID(0);
2066 int prettyFlags;
2067 char *res;
2068
2069 prettyFlags = PRETTYFLAG_INDENT;
2070
2071 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2072
2073 if (res == NULL)
2074 PG_RETURN_NULL();
2075
2076 PG_RETURN_TEXT_P(string_to_text(res));
2077 }
2078
2079 Datum
pg_get_constraintdef_ext(PG_FUNCTION_ARGS)2080 pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
2081 {
2082 Oid constraintId = PG_GETARG_OID(0);
2083 bool pretty = PG_GETARG_BOOL(1);
2084 int prettyFlags;
2085 char *res;
2086
2087 prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT;
2088
2089 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2090
2091 if (res == NULL)
2092 PG_RETURN_NULL();
2093
2094 PG_RETURN_TEXT_P(string_to_text(res));
2095 }
2096
2097 /*
2098 * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
2099 */
2100 char *
pg_get_constraintdef_command(Oid constraintId)2101 pg_get_constraintdef_command(Oid constraintId)
2102 {
2103 return pg_get_constraintdef_worker(constraintId, true, 0, false);
2104 }
2105
2106 /*
2107 * As of 9.4, we now use an MVCC snapshot for this.
2108 */
2109 static char *
pg_get_constraintdef_worker(Oid constraintId,bool fullCommand,int prettyFlags,bool missing_ok)2110 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
2111 int prettyFlags, bool missing_ok)
2112 {
2113 HeapTuple tup;
2114 Form_pg_constraint conForm;
2115 StringInfoData buf;
2116 SysScanDesc scandesc;
2117 ScanKeyData scankey[1];
2118 Snapshot snapshot = RegisterSnapshot(GetTransactionSnapshot());
2119 Relation relation = table_open(ConstraintRelationId, AccessShareLock);
2120
2121 ScanKeyInit(&scankey[0],
2122 Anum_pg_constraint_oid,
2123 BTEqualStrategyNumber, F_OIDEQ,
2124 ObjectIdGetDatum(constraintId));
2125
2126 scandesc = systable_beginscan(relation,
2127 ConstraintOidIndexId,
2128 true,
2129 snapshot,
2130 1,
2131 scankey);
2132
2133 /*
2134 * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2135 * via SearchSysCache, which works fine.
2136 */
2137 tup = systable_getnext(scandesc);
2138
2139 UnregisterSnapshot(snapshot);
2140
2141 if (!HeapTupleIsValid(tup))
2142 {
2143 if (missing_ok)
2144 {
2145 systable_endscan(scandesc);
2146 table_close(relation, AccessShareLock);
2147 return NULL;
2148 }
2149 elog(ERROR, "could not find tuple for constraint %u", constraintId);
2150 }
2151
2152 conForm = (Form_pg_constraint) GETSTRUCT(tup);
2153
2154 initStringInfo(&buf);
2155
2156 if (fullCommand)
2157 {
2158 if (OidIsValid(conForm->conrelid))
2159 {
2160 /*
2161 * Currently, callers want ALTER TABLE (without ONLY) for CHECK
2162 * constraints, and other types of constraints don't inherit
2163 * anyway so it doesn't matter whether we say ONLY or not. Someday
2164 * we might need to let callers specify whether to put ONLY in the
2165 * command.
2166 */
2167 appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2168 generate_qualified_relation_name(conForm->conrelid),
2169 quote_identifier(NameStr(conForm->conname)));
2170 }
2171 else
2172 {
2173 /* Must be a domain constraint */
2174 Assert(OidIsValid(conForm->contypid));
2175 appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
2176 generate_qualified_type_name(conForm->contypid),
2177 quote_identifier(NameStr(conForm->conname)));
2178 }
2179 }
2180
2181 switch (conForm->contype)
2182 {
2183 case CONSTRAINT_FOREIGN:
2184 {
2185 Datum val;
2186 bool isnull;
2187 const char *string;
2188
2189 /* Start off the constraint definition */
2190 appendStringInfoString(&buf, "FOREIGN KEY (");
2191
2192 /* Fetch and build referencing-column list */
2193 val = SysCacheGetAttr(CONSTROID, tup,
2194 Anum_pg_constraint_conkey, &isnull);
2195 if (isnull)
2196 elog(ERROR, "null conkey for constraint %u",
2197 constraintId);
2198
2199 decompile_column_index_array(val, conForm->conrelid, &buf);
2200
2201 /* add foreign relation name */
2202 appendStringInfo(&buf, ") REFERENCES %s(",
2203 generate_relation_name(conForm->confrelid,
2204 NIL));
2205
2206 /* Fetch and build referenced-column list */
2207 val = SysCacheGetAttr(CONSTROID, tup,
2208 Anum_pg_constraint_confkey, &isnull);
2209 if (isnull)
2210 elog(ERROR, "null confkey for constraint %u",
2211 constraintId);
2212
2213 decompile_column_index_array(val, conForm->confrelid, &buf);
2214
2215 appendStringInfoChar(&buf, ')');
2216
2217 /* Add match type */
2218 switch (conForm->confmatchtype)
2219 {
2220 case FKCONSTR_MATCH_FULL:
2221 string = " MATCH FULL";
2222 break;
2223 case FKCONSTR_MATCH_PARTIAL:
2224 string = " MATCH PARTIAL";
2225 break;
2226 case FKCONSTR_MATCH_SIMPLE:
2227 string = "";
2228 break;
2229 default:
2230 elog(ERROR, "unrecognized confmatchtype: %d",
2231 conForm->confmatchtype);
2232 string = ""; /* keep compiler quiet */
2233 break;
2234 }
2235 appendStringInfoString(&buf, string);
2236
2237 /* Add ON UPDATE and ON DELETE clauses, if needed */
2238 switch (conForm->confupdtype)
2239 {
2240 case FKCONSTR_ACTION_NOACTION:
2241 string = NULL; /* suppress default */
2242 break;
2243 case FKCONSTR_ACTION_RESTRICT:
2244 string = "RESTRICT";
2245 break;
2246 case FKCONSTR_ACTION_CASCADE:
2247 string = "CASCADE";
2248 break;
2249 case FKCONSTR_ACTION_SETNULL:
2250 string = "SET NULL";
2251 break;
2252 case FKCONSTR_ACTION_SETDEFAULT:
2253 string = "SET DEFAULT";
2254 break;
2255 default:
2256 elog(ERROR, "unrecognized confupdtype: %d",
2257 conForm->confupdtype);
2258 string = NULL; /* keep compiler quiet */
2259 break;
2260 }
2261 if (string)
2262 appendStringInfo(&buf, " ON UPDATE %s", string);
2263
2264 switch (conForm->confdeltype)
2265 {
2266 case FKCONSTR_ACTION_NOACTION:
2267 string = NULL; /* suppress default */
2268 break;
2269 case FKCONSTR_ACTION_RESTRICT:
2270 string = "RESTRICT";
2271 break;
2272 case FKCONSTR_ACTION_CASCADE:
2273 string = "CASCADE";
2274 break;
2275 case FKCONSTR_ACTION_SETNULL:
2276 string = "SET NULL";
2277 break;
2278 case FKCONSTR_ACTION_SETDEFAULT:
2279 string = "SET DEFAULT";
2280 break;
2281 default:
2282 elog(ERROR, "unrecognized confdeltype: %d",
2283 conForm->confdeltype);
2284 string = NULL; /* keep compiler quiet */
2285 break;
2286 }
2287 if (string)
2288 appendStringInfo(&buf, " ON DELETE %s", string);
2289
2290 break;
2291 }
2292 case CONSTRAINT_PRIMARY:
2293 case CONSTRAINT_UNIQUE:
2294 {
2295 Datum val;
2296 bool isnull;
2297 Oid indexId;
2298 int keyatts;
2299 HeapTuple indtup;
2300
2301 /* Start off the constraint definition */
2302 if (conForm->contype == CONSTRAINT_PRIMARY)
2303 appendStringInfoString(&buf, "PRIMARY KEY (");
2304 else
2305 appendStringInfoString(&buf, "UNIQUE (");
2306
2307 /* Fetch and build target column list */
2308 val = SysCacheGetAttr(CONSTROID, tup,
2309 Anum_pg_constraint_conkey, &isnull);
2310 if (isnull)
2311 elog(ERROR, "null conkey for constraint %u",
2312 constraintId);
2313
2314 keyatts = decompile_column_index_array(val, conForm->conrelid, &buf);
2315
2316 appendStringInfoChar(&buf, ')');
2317
2318 indexId = conForm->conindid;
2319
2320 /* Build including column list (from pg_index.indkeys) */
2321 indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2322 if (!HeapTupleIsValid(indtup))
2323 elog(ERROR, "cache lookup failed for index %u", indexId);
2324 val = SysCacheGetAttr(INDEXRELID, indtup,
2325 Anum_pg_index_indnatts, &isnull);
2326 if (isnull)
2327 elog(ERROR, "null indnatts for index %u", indexId);
2328 if (DatumGetInt32(val) > keyatts)
2329 {
2330 Datum cols;
2331 Datum *keys;
2332 int nKeys;
2333 int j;
2334
2335 appendStringInfoString(&buf, " INCLUDE (");
2336
2337 cols = SysCacheGetAttr(INDEXRELID, indtup,
2338 Anum_pg_index_indkey, &isnull);
2339 if (isnull)
2340 elog(ERROR, "null indkey for index %u", indexId);
2341
2342 deconstruct_array(DatumGetArrayTypeP(cols),
2343 INT2OID, 2, true, TYPALIGN_SHORT,
2344 &keys, NULL, &nKeys);
2345
2346 for (j = keyatts; j < nKeys; j++)
2347 {
2348 char *colName;
2349
2350 colName = get_attname(conForm->conrelid,
2351 DatumGetInt16(keys[j]), false);
2352 if (j > keyatts)
2353 appendStringInfoString(&buf, ", ");
2354 appendStringInfoString(&buf, quote_identifier(colName));
2355 }
2356
2357 appendStringInfoChar(&buf, ')');
2358 }
2359 ReleaseSysCache(indtup);
2360
2361 /* XXX why do we only print these bits if fullCommand? */
2362 if (fullCommand && OidIsValid(indexId))
2363 {
2364 char *options = flatten_reloptions(indexId);
2365 Oid tblspc;
2366
2367 if (options)
2368 {
2369 appendStringInfo(&buf, " WITH (%s)", options);
2370 pfree(options);
2371 }
2372
2373 /*
2374 * Print the tablespace, unless it's the database default.
2375 * This is to help ALTER TABLE usage of this facility,
2376 * which needs this behavior to recreate exact catalog
2377 * state.
2378 */
2379 tblspc = get_rel_tablespace(indexId);
2380 if (OidIsValid(tblspc))
2381 appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2382 quote_identifier(get_tablespace_name(tblspc)));
2383 }
2384
2385 break;
2386 }
2387 case CONSTRAINT_CHECK:
2388 {
2389 Datum val;
2390 bool isnull;
2391 char *conbin;
2392 char *consrc;
2393 Node *expr;
2394 List *context;
2395
2396 /* Fetch constraint expression in parsetree form */
2397 val = SysCacheGetAttr(CONSTROID, tup,
2398 Anum_pg_constraint_conbin, &isnull);
2399 if (isnull)
2400 elog(ERROR, "null conbin for constraint %u",
2401 constraintId);
2402
2403 conbin = TextDatumGetCString(val);
2404 expr = stringToNode(conbin);
2405
2406 /* Set up deparsing context for Var nodes in constraint */
2407 if (conForm->conrelid != InvalidOid)
2408 {
2409 /* relation constraint */
2410 context = deparse_context_for(get_relation_name(conForm->conrelid),
2411 conForm->conrelid);
2412 }
2413 else
2414 {
2415 /* domain constraint --- can't have Vars */
2416 context = NIL;
2417 }
2418
2419 consrc = deparse_expression_pretty(expr, context, false, false,
2420 prettyFlags, 0);
2421
2422 /*
2423 * Now emit the constraint definition, adding NO INHERIT if
2424 * necessary.
2425 *
2426 * There are cases where the constraint expression will be
2427 * fully parenthesized and we don't need the outer parens ...
2428 * but there are other cases where we do need 'em. Be
2429 * conservative for now.
2430 *
2431 * Note that simply checking for leading '(' and trailing ')'
2432 * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2433 */
2434 appendStringInfo(&buf, "CHECK (%s)%s",
2435 consrc,
2436 conForm->connoinherit ? " NO INHERIT" : "");
2437 break;
2438 }
2439 case CONSTRAINT_TRIGGER:
2440
2441 /*
2442 * There isn't an ALTER TABLE syntax for creating a user-defined
2443 * constraint trigger, but it seems better to print something than
2444 * throw an error; if we throw error then this function couldn't
2445 * safely be applied to all rows of pg_constraint.
2446 */
2447 appendStringInfoString(&buf, "TRIGGER");
2448 break;
2449 case CONSTRAINT_EXCLUSION:
2450 {
2451 Oid indexOid = conForm->conindid;
2452 Datum val;
2453 bool isnull;
2454 Datum *elems;
2455 int nElems;
2456 int i;
2457 Oid *operators;
2458
2459 /* Extract operator OIDs from the pg_constraint tuple */
2460 val = SysCacheGetAttr(CONSTROID, tup,
2461 Anum_pg_constraint_conexclop,
2462 &isnull);
2463 if (isnull)
2464 elog(ERROR, "null conexclop for constraint %u",
2465 constraintId);
2466
2467 deconstruct_array(DatumGetArrayTypeP(val),
2468 OIDOID, sizeof(Oid), true, TYPALIGN_INT,
2469 &elems, NULL, &nElems);
2470
2471 operators = (Oid *) palloc(nElems * sizeof(Oid));
2472 for (i = 0; i < nElems; i++)
2473 operators[i] = DatumGetObjectId(elems[i]);
2474
2475 /* pg_get_indexdef_worker does the rest */
2476 /* suppress tablespace because pg_dump wants it that way */
2477 appendStringInfoString(&buf,
2478 pg_get_indexdef_worker(indexOid,
2479 0,
2480 operators,
2481 false,
2482 false,
2483 false,
2484 false,
2485 prettyFlags,
2486 false));
2487 break;
2488 }
2489 default:
2490 elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2491 break;
2492 }
2493
2494 if (conForm->condeferrable)
2495 appendStringInfoString(&buf, " DEFERRABLE");
2496 if (conForm->condeferred)
2497 appendStringInfoString(&buf, " INITIALLY DEFERRED");
2498 if (!conForm->convalidated)
2499 appendStringInfoString(&buf, " NOT VALID");
2500
2501 /* Cleanup */
2502 systable_endscan(scandesc);
2503 table_close(relation, AccessShareLock);
2504
2505 return buf.data;
2506 }
2507
2508
2509 /*
2510 * Convert an int16[] Datum into a comma-separated list of column names
2511 * for the indicated relation; append the list to buf. Returns the number
2512 * of keys.
2513 */
2514 static int
decompile_column_index_array(Datum column_index_array,Oid relId,StringInfo buf)2515 decompile_column_index_array(Datum column_index_array, Oid relId,
2516 StringInfo buf)
2517 {
2518 Datum *keys;
2519 int nKeys;
2520 int j;
2521
2522 /* Extract data from array of int16 */
2523 deconstruct_array(DatumGetArrayTypeP(column_index_array),
2524 INT2OID, 2, true, TYPALIGN_SHORT,
2525 &keys, NULL, &nKeys);
2526
2527 for (j = 0; j < nKeys; j++)
2528 {
2529 char *colName;
2530
2531 colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2532
2533 if (j == 0)
2534 appendStringInfoString(buf, quote_identifier(colName));
2535 else
2536 appendStringInfo(buf, ", %s", quote_identifier(colName));
2537 }
2538
2539 return nKeys;
2540 }
2541
2542
2543 /* ----------
2544 * pg_get_expr - Decompile an expression tree
2545 *
2546 * Input: an expression tree in nodeToString form, and a relation OID
2547 *
2548 * Output: reverse-listed expression
2549 *
2550 * Currently, the expression can only refer to a single relation, namely
2551 * the one specified by the second parameter. This is sufficient for
2552 * partial indexes, column default expressions, etc. We also support
2553 * Var-free expressions, for which the OID can be InvalidOid.
2554 * ----------
2555 */
2556 Datum
pg_get_expr(PG_FUNCTION_ARGS)2557 pg_get_expr(PG_FUNCTION_ARGS)
2558 {
2559 text *expr = PG_GETARG_TEXT_PP(0);
2560 Oid relid = PG_GETARG_OID(1);
2561 int prettyFlags;
2562 char *relname;
2563
2564 prettyFlags = PRETTYFLAG_INDENT;
2565
2566 if (OidIsValid(relid))
2567 {
2568 /* Get the name for the relation */
2569 relname = get_rel_name(relid);
2570
2571 /*
2572 * If the OID isn't actually valid, don't throw an error, just return
2573 * NULL. This is a bit questionable, but it's what we've done
2574 * historically, and it can help avoid unwanted failures when
2575 * examining catalog entries for just-deleted relations.
2576 */
2577 if (relname == NULL)
2578 PG_RETURN_NULL();
2579 }
2580 else
2581 relname = NULL;
2582
2583 PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
2584 }
2585
2586 Datum
pg_get_expr_ext(PG_FUNCTION_ARGS)2587 pg_get_expr_ext(PG_FUNCTION_ARGS)
2588 {
2589 text *expr = PG_GETARG_TEXT_PP(0);
2590 Oid relid = PG_GETARG_OID(1);
2591 bool pretty = PG_GETARG_BOOL(2);
2592 int prettyFlags;
2593 char *relname;
2594
2595 prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT;
2596
2597 if (OidIsValid(relid))
2598 {
2599 /* Get the name for the relation */
2600 relname = get_rel_name(relid);
2601 /* See notes above */
2602 if (relname == NULL)
2603 PG_RETURN_NULL();
2604 }
2605 else
2606 relname = NULL;
2607
2608 PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
2609 }
2610
2611 static text *
pg_get_expr_worker(text * expr,Oid relid,const char * relname,int prettyFlags)2612 pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
2613 {
2614 Node *node;
2615 List *context;
2616 char *exprstr;
2617 char *str;
2618
2619 /* Convert input TEXT object to C string */
2620 exprstr = text_to_cstring(expr);
2621
2622 /* Convert expression to node tree */
2623 node = (Node *) stringToNode(exprstr);
2624
2625 pfree(exprstr);
2626
2627 /* Prepare deparse context if needed */
2628 if (OidIsValid(relid))
2629 context = deparse_context_for(relname, relid);
2630 else
2631 context = NIL;
2632
2633 /* Deparse */
2634 str = deparse_expression_pretty(node, context, false, false,
2635 prettyFlags, 0);
2636
2637 return string_to_text(str);
2638 }
2639
2640
2641 /* ----------
2642 * pg_get_userbyid - Get a user name by roleid and
2643 * fallback to 'unknown (OID=n)'
2644 * ----------
2645 */
2646 Datum
pg_get_userbyid(PG_FUNCTION_ARGS)2647 pg_get_userbyid(PG_FUNCTION_ARGS)
2648 {
2649 Oid roleid = PG_GETARG_OID(0);
2650 Name result;
2651 HeapTuple roletup;
2652 Form_pg_authid role_rec;
2653
2654 /*
2655 * Allocate space for the result
2656 */
2657 result = (Name) palloc(NAMEDATALEN);
2658 memset(NameStr(*result), 0, NAMEDATALEN);
2659
2660 /*
2661 * Get the pg_authid entry and print the result
2662 */
2663 roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2664 if (HeapTupleIsValid(roletup))
2665 {
2666 role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2667 *result = role_rec->rolname;
2668 ReleaseSysCache(roletup);
2669 }
2670 else
2671 sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2672
2673 PG_RETURN_NAME(result);
2674 }
2675
2676
2677 /*
2678 * pg_get_serial_sequence
2679 * Get the name of the sequence used by an identity or serial column,
2680 * formatted suitably for passing to setval, nextval or currval.
2681 * First parameter is not treated as double-quoted, second parameter
2682 * is --- see documentation for reason.
2683 */
2684 Datum
pg_get_serial_sequence(PG_FUNCTION_ARGS)2685 pg_get_serial_sequence(PG_FUNCTION_ARGS)
2686 {
2687 text *tablename = PG_GETARG_TEXT_PP(0);
2688 text *columnname = PG_GETARG_TEXT_PP(1);
2689 RangeVar *tablerv;
2690 Oid tableOid;
2691 char *column;
2692 AttrNumber attnum;
2693 Oid sequenceId = InvalidOid;
2694 Relation depRel;
2695 ScanKeyData key[3];
2696 SysScanDesc scan;
2697 HeapTuple tup;
2698
2699 /* Look up table name. Can't lock it - we might not have privileges. */
2700 tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2701 tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2702
2703 /* Get the number of the column */
2704 column = text_to_cstring(columnname);
2705
2706 attnum = get_attnum(tableOid, column);
2707 if (attnum == InvalidAttrNumber)
2708 ereport(ERROR,
2709 (errcode(ERRCODE_UNDEFINED_COLUMN),
2710 errmsg("column \"%s\" of relation \"%s\" does not exist",
2711 column, tablerv->relname)));
2712
2713 /* Search the dependency table for the dependent sequence */
2714 depRel = table_open(DependRelationId, AccessShareLock);
2715
2716 ScanKeyInit(&key[0],
2717 Anum_pg_depend_refclassid,
2718 BTEqualStrategyNumber, F_OIDEQ,
2719 ObjectIdGetDatum(RelationRelationId));
2720 ScanKeyInit(&key[1],
2721 Anum_pg_depend_refobjid,
2722 BTEqualStrategyNumber, F_OIDEQ,
2723 ObjectIdGetDatum(tableOid));
2724 ScanKeyInit(&key[2],
2725 Anum_pg_depend_refobjsubid,
2726 BTEqualStrategyNumber, F_INT4EQ,
2727 Int32GetDatum(attnum));
2728
2729 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2730 NULL, 3, key);
2731
2732 while (HeapTupleIsValid(tup = systable_getnext(scan)))
2733 {
2734 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2735
2736 /*
2737 * Look for an auto dependency (serial column) or internal dependency
2738 * (identity column) of a sequence on a column. (We need the relkind
2739 * test because indexes can also have auto dependencies on columns.)
2740 */
2741 if (deprec->classid == RelationRelationId &&
2742 deprec->objsubid == 0 &&
2743 (deprec->deptype == DEPENDENCY_AUTO ||
2744 deprec->deptype == DEPENDENCY_INTERNAL) &&
2745 get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2746 {
2747 sequenceId = deprec->objid;
2748 break;
2749 }
2750 }
2751
2752 systable_endscan(scan);
2753 table_close(depRel, AccessShareLock);
2754
2755 if (OidIsValid(sequenceId))
2756 {
2757 char *result;
2758
2759 result = generate_qualified_relation_name(sequenceId);
2760
2761 PG_RETURN_TEXT_P(string_to_text(result));
2762 }
2763
2764 PG_RETURN_NULL();
2765 }
2766
2767
2768 /*
2769 * pg_get_functiondef
2770 * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
2771 * the specified function.
2772 *
2773 * Note: if you change the output format of this function, be careful not
2774 * to break psql's rules (in \ef and \sf) for identifying the start of the
2775 * function body. To wit: the function body starts on a line that begins
2776 * with "AS ", and no preceding line will look like that.
2777 */
2778 Datum
pg_get_functiondef(PG_FUNCTION_ARGS)2779 pg_get_functiondef(PG_FUNCTION_ARGS)
2780 {
2781 Oid funcid = PG_GETARG_OID(0);
2782 StringInfoData buf;
2783 StringInfoData dq;
2784 HeapTuple proctup;
2785 Form_pg_proc proc;
2786 bool isfunction;
2787 Datum tmp;
2788 bool isnull;
2789 const char *prosrc;
2790 const char *name;
2791 const char *nsp;
2792 float4 procost;
2793 int oldlen;
2794
2795 initStringInfo(&buf);
2796
2797 /* Look up the function */
2798 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2799 if (!HeapTupleIsValid(proctup))
2800 PG_RETURN_NULL();
2801
2802 proc = (Form_pg_proc) GETSTRUCT(proctup);
2803 name = NameStr(proc->proname);
2804
2805 if (proc->prokind == PROKIND_AGGREGATE)
2806 ereport(ERROR,
2807 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2808 errmsg("\"%s\" is an aggregate function", name)));
2809
2810 isfunction = (proc->prokind != PROKIND_PROCEDURE);
2811
2812 /*
2813 * We always qualify the function name, to ensure the right function gets
2814 * replaced.
2815 */
2816 nsp = get_namespace_name(proc->pronamespace);
2817 appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
2818 isfunction ? "FUNCTION" : "PROCEDURE",
2819 quote_qualified_identifier(nsp, name));
2820 (void) print_function_arguments(&buf, proctup, false, true);
2821 appendStringInfoString(&buf, ")\n");
2822 if (isfunction)
2823 {
2824 appendStringInfoString(&buf, " RETURNS ");
2825 print_function_rettype(&buf, proctup);
2826 appendStringInfoChar(&buf, '\n');
2827 }
2828
2829 print_function_trftypes(&buf, proctup);
2830
2831 appendStringInfo(&buf, " LANGUAGE %s\n",
2832 quote_identifier(get_language_name(proc->prolang, false)));
2833
2834 /* Emit some miscellaneous options on one line */
2835 oldlen = buf.len;
2836
2837 if (proc->prokind == PROKIND_WINDOW)
2838 appendStringInfoString(&buf, " WINDOW");
2839 switch (proc->provolatile)
2840 {
2841 case PROVOLATILE_IMMUTABLE:
2842 appendStringInfoString(&buf, " IMMUTABLE");
2843 break;
2844 case PROVOLATILE_STABLE:
2845 appendStringInfoString(&buf, " STABLE");
2846 break;
2847 case PROVOLATILE_VOLATILE:
2848 break;
2849 }
2850
2851 switch (proc->proparallel)
2852 {
2853 case PROPARALLEL_SAFE:
2854 appendStringInfoString(&buf, " PARALLEL SAFE");
2855 break;
2856 case PROPARALLEL_RESTRICTED:
2857 appendStringInfoString(&buf, " PARALLEL RESTRICTED");
2858 break;
2859 case PROPARALLEL_UNSAFE:
2860 break;
2861 }
2862
2863 if (proc->proisstrict)
2864 appendStringInfoString(&buf, " STRICT");
2865 if (proc->prosecdef)
2866 appendStringInfoString(&buf, " SECURITY DEFINER");
2867 if (proc->proleakproof)
2868 appendStringInfoString(&buf, " LEAKPROOF");
2869
2870 /* This code for the default cost and rows should match functioncmds.c */
2871 if (proc->prolang == INTERNALlanguageId ||
2872 proc->prolang == ClanguageId)
2873 procost = 1;
2874 else
2875 procost = 100;
2876 if (proc->procost != procost)
2877 appendStringInfo(&buf, " COST %g", proc->procost);
2878
2879 if (proc->prorows > 0 && proc->prorows != 1000)
2880 appendStringInfo(&buf, " ROWS %g", proc->prorows);
2881
2882 if (proc->prosupport)
2883 {
2884 Oid argtypes[1];
2885
2886 /*
2887 * We should qualify the support function's name if it wouldn't be
2888 * resolved by lookup in the current search path.
2889 */
2890 argtypes[0] = INTERNALOID;
2891 appendStringInfo(&buf, " SUPPORT %s",
2892 generate_function_name(proc->prosupport, 1,
2893 NIL, argtypes,
2894 false, NULL, EXPR_KIND_NONE));
2895 }
2896
2897 if (oldlen != buf.len)
2898 appendStringInfoChar(&buf, '\n');
2899
2900 /* Emit any proconfig options, one per line */
2901 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
2902 if (!isnull)
2903 {
2904 ArrayType *a = DatumGetArrayTypeP(tmp);
2905 int i;
2906
2907 Assert(ARR_ELEMTYPE(a) == TEXTOID);
2908 Assert(ARR_NDIM(a) == 1);
2909 Assert(ARR_LBOUND(a)[0] == 1);
2910
2911 for (i = 1; i <= ARR_DIMS(a)[0]; i++)
2912 {
2913 Datum d;
2914
2915 d = array_ref(a, 1, &i,
2916 -1 /* varlenarray */ ,
2917 -1 /* TEXT's typlen */ ,
2918 false /* TEXT's typbyval */ ,
2919 TYPALIGN_INT /* TEXT's typalign */ ,
2920 &isnull);
2921 if (!isnull)
2922 {
2923 char *configitem = TextDatumGetCString(d);
2924 char *pos;
2925
2926 pos = strchr(configitem, '=');
2927 if (pos == NULL)
2928 continue;
2929 *pos++ = '\0';
2930
2931 appendStringInfo(&buf, " SET %s TO ",
2932 quote_identifier(configitem));
2933
2934 /*
2935 * Variables that are marked GUC_LIST_QUOTE were already fully
2936 * quoted by flatten_set_variable_args() before they were put
2937 * into the proconfig array. However, because the quoting
2938 * rules used there aren't exactly like SQL's, we have to
2939 * break the list value apart and then quote the elements as
2940 * string literals. (The elements may be double-quoted as-is,
2941 * but we can't just feed them to the SQL parser; it would do
2942 * the wrong thing with elements that are zero-length or
2943 * longer than NAMEDATALEN.)
2944 *
2945 * Variables that are not so marked should just be emitted as
2946 * simple string literals. If the variable is not known to
2947 * guc.c, we'll do that; this makes it unsafe to use
2948 * GUC_LIST_QUOTE for extension variables.
2949 */
2950 if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
2951 {
2952 List *namelist;
2953 ListCell *lc;
2954
2955 /* Parse string into list of identifiers */
2956 if (!SplitGUCList(pos, ',', &namelist))
2957 {
2958 /* this shouldn't fail really */
2959 elog(ERROR, "invalid list syntax in proconfig item");
2960 }
2961 foreach(lc, namelist)
2962 {
2963 char *curname = (char *) lfirst(lc);
2964
2965 simple_quote_literal(&buf, curname);
2966 if (lnext(namelist, lc))
2967 appendStringInfoString(&buf, ", ");
2968 }
2969 }
2970 else
2971 simple_quote_literal(&buf, pos);
2972 appendStringInfoChar(&buf, '\n');
2973 }
2974 }
2975 }
2976
2977 /* And finally the function definition ... */
2978 (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
2979 if (proc->prolang == SQLlanguageId && !isnull)
2980 {
2981 print_function_sqlbody(&buf, proctup);
2982 }
2983 else
2984 {
2985 appendStringInfoString(&buf, "AS ");
2986
2987 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
2988 if (!isnull)
2989 {
2990 simple_quote_literal(&buf, TextDatumGetCString(tmp));
2991 appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
2992 }
2993
2994 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosrc, &isnull);
2995 if (isnull)
2996 elog(ERROR, "null prosrc");
2997 prosrc = TextDatumGetCString(tmp);
2998
2999 /*
3000 * We always use dollar quoting. Figure out a suitable delimiter.
3001 *
3002 * Since the user is likely to be editing the function body string, we
3003 * shouldn't use a short delimiter that he might easily create a
3004 * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3005 * if needed.
3006 */
3007 initStringInfo(&dq);
3008 appendStringInfoChar(&dq, '$');
3009 appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3010 while (strstr(prosrc, dq.data) != NULL)
3011 appendStringInfoChar(&dq, 'x');
3012 appendStringInfoChar(&dq, '$');
3013
3014 appendBinaryStringInfo(&buf, dq.data, dq.len);
3015 appendStringInfoString(&buf, prosrc);
3016 appendBinaryStringInfo(&buf, dq.data, dq.len);
3017 }
3018
3019 appendStringInfoChar(&buf, '\n');
3020
3021 ReleaseSysCache(proctup);
3022
3023 PG_RETURN_TEXT_P(string_to_text(buf.data));
3024 }
3025
3026 /*
3027 * pg_get_function_arguments
3028 * Get a nicely-formatted list of arguments for a function.
3029 * This is everything that would go between the parentheses in
3030 * CREATE FUNCTION.
3031 */
3032 Datum
pg_get_function_arguments(PG_FUNCTION_ARGS)3033 pg_get_function_arguments(PG_FUNCTION_ARGS)
3034 {
3035 Oid funcid = PG_GETARG_OID(0);
3036 StringInfoData buf;
3037 HeapTuple proctup;
3038
3039 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3040 if (!HeapTupleIsValid(proctup))
3041 PG_RETURN_NULL();
3042
3043 initStringInfo(&buf);
3044
3045 (void) print_function_arguments(&buf, proctup, false, true);
3046
3047 ReleaseSysCache(proctup);
3048
3049 PG_RETURN_TEXT_P(string_to_text(buf.data));
3050 }
3051
3052 /*
3053 * pg_get_function_identity_arguments
3054 * Get a formatted list of arguments for a function.
3055 * This is everything that would go between the parentheses in
3056 * ALTER FUNCTION, etc. In particular, don't print defaults.
3057 */
3058 Datum
pg_get_function_identity_arguments(PG_FUNCTION_ARGS)3059 pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
3060 {
3061 Oid funcid = PG_GETARG_OID(0);
3062 StringInfoData buf;
3063 HeapTuple proctup;
3064
3065 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3066 if (!HeapTupleIsValid(proctup))
3067 PG_RETURN_NULL();
3068
3069 initStringInfo(&buf);
3070
3071 (void) print_function_arguments(&buf, proctup, false, false);
3072
3073 ReleaseSysCache(proctup);
3074
3075 PG_RETURN_TEXT_P(string_to_text(buf.data));
3076 }
3077
3078 /*
3079 * pg_get_function_result
3080 * Get a nicely-formatted version of the result type of a function.
3081 * This is what would appear after RETURNS in CREATE FUNCTION.
3082 */
3083 Datum
pg_get_function_result(PG_FUNCTION_ARGS)3084 pg_get_function_result(PG_FUNCTION_ARGS)
3085 {
3086 Oid funcid = PG_GETARG_OID(0);
3087 StringInfoData buf;
3088 HeapTuple proctup;
3089
3090 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3091 if (!HeapTupleIsValid(proctup))
3092 PG_RETURN_NULL();
3093
3094 if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3095 {
3096 ReleaseSysCache(proctup);
3097 PG_RETURN_NULL();
3098 }
3099
3100 initStringInfo(&buf);
3101
3102 print_function_rettype(&buf, proctup);
3103
3104 ReleaseSysCache(proctup);
3105
3106 PG_RETURN_TEXT_P(string_to_text(buf.data));
3107 }
3108
3109 /*
3110 * Guts of pg_get_function_result: append the function's return type
3111 * to the specified buffer.
3112 */
3113 static void
print_function_rettype(StringInfo buf,HeapTuple proctup)3114 print_function_rettype(StringInfo buf, HeapTuple proctup)
3115 {
3116 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3117 int ntabargs = 0;
3118 StringInfoData rbuf;
3119
3120 initStringInfo(&rbuf);
3121
3122 if (proc->proretset)
3123 {
3124 /* It might be a table function; try to print the arguments */
3125 appendStringInfoString(&rbuf, "TABLE(");
3126 ntabargs = print_function_arguments(&rbuf, proctup, true, false);
3127 if (ntabargs > 0)
3128 appendStringInfoChar(&rbuf, ')');
3129 else
3130 resetStringInfo(&rbuf);
3131 }
3132
3133 if (ntabargs == 0)
3134 {
3135 /* Not a table function, so do the normal thing */
3136 if (proc->proretset)
3137 appendStringInfoString(&rbuf, "SETOF ");
3138 appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3139 }
3140
3141 appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3142 }
3143
3144 /*
3145 * Common code for pg_get_function_arguments and pg_get_function_result:
3146 * append the desired subset of arguments to buf. We print only TABLE
3147 * arguments when print_table_args is true, and all the others when it's false.
3148 * We print argument defaults only if print_defaults is true.
3149 * Function return value is the number of arguments printed.
3150 */
3151 static int
print_function_arguments(StringInfo buf,HeapTuple proctup,bool print_table_args,bool print_defaults)3152 print_function_arguments(StringInfo buf, HeapTuple proctup,
3153 bool print_table_args, bool print_defaults)
3154 {
3155 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3156 int numargs;
3157 Oid *argtypes;
3158 char **argnames;
3159 char *argmodes;
3160 int insertorderbyat = -1;
3161 int argsprinted;
3162 int inputargno;
3163 int nlackdefaults;
3164 List *argdefaults = NIL;
3165 ListCell *nextargdefault = NULL;
3166 int i;
3167
3168 numargs = get_func_arg_info(proctup,
3169 &argtypes, &argnames, &argmodes);
3170
3171 nlackdefaults = numargs;
3172 if (print_defaults && proc->pronargdefaults > 0)
3173 {
3174 Datum proargdefaults;
3175 bool isnull;
3176
3177 proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3178 Anum_pg_proc_proargdefaults,
3179 &isnull);
3180 if (!isnull)
3181 {
3182 char *str;
3183
3184 str = TextDatumGetCString(proargdefaults);
3185 argdefaults = castNode(List, stringToNode(str));
3186 pfree(str);
3187 nextargdefault = list_head(argdefaults);
3188 /* nlackdefaults counts only *input* arguments lacking defaults */
3189 nlackdefaults = proc->pronargs - list_length(argdefaults);
3190 }
3191 }
3192
3193 /* Check for special treatment of ordered-set aggregates */
3194 if (proc->prokind == PROKIND_AGGREGATE)
3195 {
3196 HeapTuple aggtup;
3197 Form_pg_aggregate agg;
3198
3199 aggtup = SearchSysCache1(AGGFNOID, proc->oid);
3200 if (!HeapTupleIsValid(aggtup))
3201 elog(ERROR, "cache lookup failed for aggregate %u",
3202 proc->oid);
3203 agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
3204 if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3205 insertorderbyat = agg->aggnumdirectargs;
3206 ReleaseSysCache(aggtup);
3207 }
3208
3209 argsprinted = 0;
3210 inputargno = 0;
3211 for (i = 0; i < numargs; i++)
3212 {
3213 Oid argtype = argtypes[i];
3214 char *argname = argnames ? argnames[i] : NULL;
3215 char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
3216 const char *modename;
3217 bool isinput;
3218
3219 switch (argmode)
3220 {
3221 case PROARGMODE_IN:
3222
3223 /*
3224 * For procedures, explicitly mark all argument modes, so as
3225 * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3226 */
3227 if (proc->prokind == PROKIND_PROCEDURE)
3228 modename = "IN ";
3229 else
3230 modename = "";
3231 isinput = true;
3232 break;
3233 case PROARGMODE_INOUT:
3234 modename = "INOUT ";
3235 isinput = true;
3236 break;
3237 case PROARGMODE_OUT:
3238 modename = "OUT ";
3239 isinput = false;
3240 break;
3241 case PROARGMODE_VARIADIC:
3242 modename = "VARIADIC ";
3243 isinput = true;
3244 break;
3245 case PROARGMODE_TABLE:
3246 modename = "";
3247 isinput = false;
3248 break;
3249 default:
3250 elog(ERROR, "invalid parameter mode '%c'", argmode);
3251 modename = NULL; /* keep compiler quiet */
3252 isinput = false;
3253 break;
3254 }
3255 if (isinput)
3256 inputargno++; /* this is a 1-based counter */
3257
3258 if (print_table_args != (argmode == PROARGMODE_TABLE))
3259 continue;
3260
3261 if (argsprinted == insertorderbyat)
3262 {
3263 if (argsprinted)
3264 appendStringInfoChar(buf, ' ');
3265 appendStringInfoString(buf, "ORDER BY ");
3266 }
3267 else if (argsprinted)
3268 appendStringInfoString(buf, ", ");
3269
3270 appendStringInfoString(buf, modename);
3271 if (argname && argname[0])
3272 appendStringInfo(buf, "%s ", quote_identifier(argname));
3273 appendStringInfoString(buf, format_type_be(argtype));
3274 if (print_defaults && isinput && inputargno > nlackdefaults)
3275 {
3276 Node *expr;
3277
3278 Assert(nextargdefault != NULL);
3279 expr = (Node *) lfirst(nextargdefault);
3280 nextargdefault = lnext(argdefaults, nextargdefault);
3281
3282 appendStringInfo(buf, " DEFAULT %s",
3283 deparse_expression(expr, NIL, false, false));
3284 }
3285 argsprinted++;
3286
3287 /* nasty hack: print the last arg twice for variadic ordered-set agg */
3288 if (argsprinted == insertorderbyat && i == numargs - 1)
3289 {
3290 i--;
3291 /* aggs shouldn't have defaults anyway, but just to be sure ... */
3292 print_defaults = false;
3293 }
3294 }
3295
3296 return argsprinted;
3297 }
3298
3299 static bool
is_input_argument(int nth,const char * argmodes)3300 is_input_argument(int nth, const char *argmodes)
3301 {
3302 return (!argmodes
3303 || argmodes[nth] == PROARGMODE_IN
3304 || argmodes[nth] == PROARGMODE_INOUT
3305 || argmodes[nth] == PROARGMODE_VARIADIC);
3306 }
3307
3308 /*
3309 * Append used transformed types to specified buffer
3310 */
3311 static void
print_function_trftypes(StringInfo buf,HeapTuple proctup)3312 print_function_trftypes(StringInfo buf, HeapTuple proctup)
3313 {
3314 Oid *trftypes;
3315 int ntypes;
3316
3317 ntypes = get_func_trftypes(proctup, &trftypes);
3318 if (ntypes > 0)
3319 {
3320 int i;
3321
3322 appendStringInfoString(buf, " TRANSFORM ");
3323 for (i = 0; i < ntypes; i++)
3324 {
3325 if (i != 0)
3326 appendStringInfoString(buf, ", ");
3327 appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3328 }
3329 appendStringInfoChar(buf, '\n');
3330 }
3331 }
3332
3333 /*
3334 * Get textual representation of a function argument's default value. The
3335 * second argument of this function is the argument number among all arguments
3336 * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3337 * how information_schema.sql uses it.
3338 */
3339 Datum
pg_get_function_arg_default(PG_FUNCTION_ARGS)3340 pg_get_function_arg_default(PG_FUNCTION_ARGS)
3341 {
3342 Oid funcid = PG_GETARG_OID(0);
3343 int32 nth_arg = PG_GETARG_INT32(1);
3344 HeapTuple proctup;
3345 Form_pg_proc proc;
3346 int numargs;
3347 Oid *argtypes;
3348 char **argnames;
3349 char *argmodes;
3350 int i;
3351 List *argdefaults;
3352 Node *node;
3353 char *str;
3354 int nth_inputarg;
3355 Datum proargdefaults;
3356 bool isnull;
3357 int nth_default;
3358
3359 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3360 if (!HeapTupleIsValid(proctup))
3361 PG_RETURN_NULL();
3362
3363 numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3364 if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3365 {
3366 ReleaseSysCache(proctup);
3367 PG_RETURN_NULL();
3368 }
3369
3370 nth_inputarg = 0;
3371 for (i = 0; i < nth_arg; i++)
3372 if (is_input_argument(i, argmodes))
3373 nth_inputarg++;
3374
3375 proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3376 Anum_pg_proc_proargdefaults,
3377 &isnull);
3378 if (isnull)
3379 {
3380 ReleaseSysCache(proctup);
3381 PG_RETURN_NULL();
3382 }
3383
3384 str = TextDatumGetCString(proargdefaults);
3385 argdefaults = castNode(List, stringToNode(str));
3386 pfree(str);
3387
3388 proc = (Form_pg_proc) GETSTRUCT(proctup);
3389
3390 /*
3391 * Calculate index into proargdefaults: proargdefaults corresponds to the
3392 * last N input arguments, where N = pronargdefaults.
3393 */
3394 nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3395
3396 if (nth_default < 0 || nth_default >= list_length(argdefaults))
3397 {
3398 ReleaseSysCache(proctup);
3399 PG_RETURN_NULL();
3400 }
3401 node = list_nth(argdefaults, nth_default);
3402 str = deparse_expression(node, NIL, false, false);
3403
3404 ReleaseSysCache(proctup);
3405
3406 PG_RETURN_TEXT_P(string_to_text(str));
3407 }
3408
3409 static void
print_function_sqlbody(StringInfo buf,HeapTuple proctup)3410 print_function_sqlbody(StringInfo buf, HeapTuple proctup)
3411 {
3412 int numargs;
3413 Oid *argtypes;
3414 char **argnames;
3415 char *argmodes;
3416 deparse_namespace dpns = {0};
3417 Datum tmp;
3418 bool isnull;
3419 Node *n;
3420
3421 dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
3422 numargs = get_func_arg_info(proctup,
3423 &argtypes, &argnames, &argmodes);
3424 dpns.numargs = numargs;
3425 dpns.argnames = argnames;
3426
3427 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3428 Assert(!isnull);
3429 n = stringToNode(TextDatumGetCString(tmp));
3430
3431 if (IsA(n, List))
3432 {
3433 List *stmts;
3434 ListCell *lc;
3435
3436 stmts = linitial(castNode(List, n));
3437
3438 appendStringInfoString(buf, "BEGIN ATOMIC\n");
3439
3440 foreach(lc, stmts)
3441 {
3442 Query *query = lfirst_node(Query, lc);
3443
3444 /* It seems advisable to get at least AccessShareLock on rels */
3445 AcquireRewriteLocks(query, false, false);
3446 get_query_def(query, buf, list_make1(&dpns), NULL,
3447 PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 1);
3448 appendStringInfoChar(buf, ';');
3449 appendStringInfoChar(buf, '\n');
3450 }
3451
3452 appendStringInfoString(buf, "END");
3453 }
3454 else
3455 {
3456 Query *query = castNode(Query, n);
3457
3458 /* It seems advisable to get at least AccessShareLock on rels */
3459 AcquireRewriteLocks(query, false, false);
3460 get_query_def(query, buf, list_make1(&dpns), NULL,
3461 0, WRAP_COLUMN_DEFAULT, 0);
3462 }
3463 }
3464
3465 Datum
pg_get_function_sqlbody(PG_FUNCTION_ARGS)3466 pg_get_function_sqlbody(PG_FUNCTION_ARGS)
3467 {
3468 Oid funcid = PG_GETARG_OID(0);
3469 StringInfoData buf;
3470 HeapTuple proctup;
3471 bool isnull;
3472
3473 initStringInfo(&buf);
3474
3475 /* Look up the function */
3476 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3477 if (!HeapTupleIsValid(proctup))
3478 PG_RETURN_NULL();
3479
3480 (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3481 if (isnull)
3482 {
3483 ReleaseSysCache(proctup);
3484 PG_RETURN_NULL();
3485 }
3486
3487 print_function_sqlbody(&buf, proctup);
3488
3489 ReleaseSysCache(proctup);
3490
3491 PG_RETURN_TEXT_P(cstring_to_text(buf.data));
3492 }
3493
3494
3495 /*
3496 * deparse_expression - General utility for deparsing expressions
3497 *
3498 * calls deparse_expression_pretty with all prettyPrinting disabled
3499 */
3500 char *
deparse_expression(Node * expr,List * dpcontext,bool forceprefix,bool showimplicit)3501 deparse_expression(Node *expr, List *dpcontext,
3502 bool forceprefix, bool showimplicit)
3503 {
3504 return deparse_expression_pretty(expr, dpcontext, forceprefix,
3505 showimplicit, 0, 0);
3506 }
3507
3508 /* ----------
3509 * deparse_expression_pretty - General utility for deparsing expressions
3510 *
3511 * expr is the node tree to be deparsed. It must be a transformed expression
3512 * tree (ie, not the raw output of gram.y).
3513 *
3514 * dpcontext is a list of deparse_namespace nodes representing the context
3515 * for interpreting Vars in the node tree. It can be NIL if no Vars are
3516 * expected.
3517 *
3518 * forceprefix is true to force all Vars to be prefixed with their table names.
3519 *
3520 * showimplicit is true to force all implicit casts to be shown explicitly.
3521 *
3522 * Tries to pretty up the output according to prettyFlags and startIndent.
3523 *
3524 * The result is a palloc'd string.
3525 * ----------
3526 */
3527 static char *
deparse_expression_pretty(Node * expr,List * dpcontext,bool forceprefix,bool showimplicit,int prettyFlags,int startIndent)3528 deparse_expression_pretty(Node *expr, List *dpcontext,
3529 bool forceprefix, bool showimplicit,
3530 int prettyFlags, int startIndent)
3531 {
3532 StringInfoData buf;
3533 deparse_context context;
3534
3535 initStringInfo(&buf);
3536 context.buf = &buf;
3537 context.namespaces = dpcontext;
3538 context.windowClause = NIL;
3539 context.windowTList = NIL;
3540 context.varprefix = forceprefix;
3541 context.prettyFlags = prettyFlags;
3542 context.wrapColumn = WRAP_COLUMN_DEFAULT;
3543 context.indentLevel = startIndent;
3544 context.special_exprkind = EXPR_KIND_NONE;
3545 context.appendparents = NULL;
3546
3547 get_rule_expr(expr, &context, showimplicit);
3548
3549 return buf.data;
3550 }
3551
3552 /* ----------
3553 * deparse_context_for - Build deparse context for a single relation
3554 *
3555 * Given the reference name (alias) and OID of a relation, build deparsing
3556 * context for an expression referencing only that relation (as varno 1,
3557 * varlevelsup 0). This is sufficient for many uses of deparse_expression.
3558 * ----------
3559 */
3560 List *
deparse_context_for(const char * aliasname,Oid relid)3561 deparse_context_for(const char *aliasname, Oid relid)
3562 {
3563 deparse_namespace *dpns;
3564 RangeTblEntry *rte;
3565
3566 dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3567
3568 /* Build a minimal RTE for the rel */
3569 rte = makeNode(RangeTblEntry);
3570 rte->rtekind = RTE_RELATION;
3571 rte->relid = relid;
3572 rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3573 rte->rellockmode = AccessShareLock;
3574 rte->alias = makeAlias(aliasname, NIL);
3575 rte->eref = rte->alias;
3576 rte->lateral = false;
3577 rte->inh = false;
3578 rte->inFromCl = true;
3579
3580 /* Build one-element rtable */
3581 dpns->rtable = list_make1(rte);
3582 dpns->subplans = NIL;
3583 dpns->ctes = NIL;
3584 dpns->appendrels = NULL;
3585 set_rtable_names(dpns, NIL, NULL);
3586 set_simple_column_names(dpns);
3587
3588 /* Return a one-deep namespace stack */
3589 return list_make1(dpns);
3590 }
3591
3592 /*
3593 * deparse_context_for_plan_tree - Build deparse context for a Plan tree
3594 *
3595 * When deparsing an expression in a Plan tree, we use the plan's rangetable
3596 * to resolve names of simple Vars. The initialization of column names for
3597 * this is rather expensive if the rangetable is large, and it'll be the same
3598 * for every expression in the Plan tree; so we do it just once and re-use
3599 * the result of this function for each expression. (Note that the result
3600 * is not usable until set_deparse_context_plan() is applied to it.)
3601 *
3602 * In addition to the PlannedStmt, pass the per-RTE alias names
3603 * assigned by a previous call to select_rtable_names_for_explain.
3604 */
3605 List *
deparse_context_for_plan_tree(PlannedStmt * pstmt,List * rtable_names)3606 deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
3607 {
3608 deparse_namespace *dpns;
3609
3610 dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3611
3612 /* Initialize fields that stay the same across the whole plan tree */
3613 dpns->rtable = pstmt->rtable;
3614 dpns->rtable_names = rtable_names;
3615 dpns->subplans = pstmt->subplans;
3616 dpns->ctes = NIL;
3617 if (pstmt->appendRelations)
3618 {
3619 /* Set up the array, indexed by child relid */
3620 int ntables = list_length(dpns->rtable);
3621 ListCell *lc;
3622
3623 dpns->appendrels = (AppendRelInfo **)
3624 palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3625 foreach(lc, pstmt->appendRelations)
3626 {
3627 AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3628 Index crelid = appinfo->child_relid;
3629
3630 Assert(crelid > 0 && crelid <= ntables);
3631 Assert(dpns->appendrels[crelid] == NULL);
3632 dpns->appendrels[crelid] = appinfo;
3633 }
3634 }
3635 else
3636 dpns->appendrels = NULL; /* don't need it */
3637
3638 /*
3639 * Set up column name aliases. We will get rather bogus results for join
3640 * RTEs, but that doesn't matter because plan trees don't contain any join
3641 * alias Vars.
3642 */
3643 set_simple_column_names(dpns);
3644
3645 /* Return a one-deep namespace stack */
3646 return list_make1(dpns);
3647 }
3648
3649 /*
3650 * set_deparse_context_plan - Specify Plan node containing expression
3651 *
3652 * When deparsing an expression in a Plan tree, we might have to resolve
3653 * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
3654 * provide the parent Plan node. Then OUTER_VAR and INNER_VAR references
3655 * can be resolved by drilling down into the left and right child plans.
3656 * Similarly, INDEX_VAR references can be resolved by reference to the
3657 * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
3658 * ForeignScan and CustomScan nodes. (Note that we don't currently support
3659 * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
3660 * for those, we can only deparse the indexqualorig fields, which won't
3661 * contain INDEX_VAR Vars.)
3662 *
3663 * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
3664 * the most-closely-nested first. This is needed to resolve PARAM_EXEC
3665 * Params. Note we assume that all the Plan nodes share the same rtable.
3666 *
3667 * Once this function has been called, deparse_expression() can be called on
3668 * subsidiary expression(s) of the specified Plan node. To deparse
3669 * expressions of a different Plan node in the same Plan tree, re-call this
3670 * function to identify the new parent Plan node.
3671 *
3672 * The result is the same List passed in; this is a notational convenience.
3673 */
3674 List *
set_deparse_context_plan(List * dpcontext,Plan * plan,List * ancestors)3675 set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
3676 {
3677 deparse_namespace *dpns;
3678
3679 /* Should always have one-entry namespace list for Plan deparsing */
3680 Assert(list_length(dpcontext) == 1);
3681 dpns = (deparse_namespace *) linitial(dpcontext);
3682
3683 /* Set our attention on the specific plan node passed in */
3684 dpns->ancestors = ancestors;
3685 set_deparse_plan(dpns, plan);
3686
3687 return dpcontext;
3688 }
3689
3690 /*
3691 * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
3692 *
3693 * Determine the relation aliases we'll use during an EXPLAIN operation.
3694 * This is just a frontend to set_rtable_names. We have to expose the aliases
3695 * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
3696 */
3697 List *
select_rtable_names_for_explain(List * rtable,Bitmapset * rels_used)3698 select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
3699 {
3700 deparse_namespace dpns;
3701
3702 memset(&dpns, 0, sizeof(dpns));
3703 dpns.rtable = rtable;
3704 dpns.subplans = NIL;
3705 dpns.ctes = NIL;
3706 dpns.appendrels = NULL;
3707 set_rtable_names(&dpns, NIL, rels_used);
3708 /* We needn't bother computing column aliases yet */
3709
3710 return dpns.rtable_names;
3711 }
3712
3713 /*
3714 * set_rtable_names: select RTE aliases to be used in printing a query
3715 *
3716 * We fill in dpns->rtable_names with a list of names that is one-for-one with
3717 * the already-filled dpns->rtable list. Each RTE name is unique among those
3718 * in the new namespace plus any ancestor namespaces listed in
3719 * parent_namespaces.
3720 *
3721 * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
3722 *
3723 * Note that this function is only concerned with relation names, not column
3724 * names.
3725 */
3726 static void
set_rtable_names(deparse_namespace * dpns,List * parent_namespaces,Bitmapset * rels_used)3727 set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
3728 Bitmapset *rels_used)
3729 {
3730 HASHCTL hash_ctl;
3731 HTAB *names_hash;
3732 NameHashEntry *hentry;
3733 bool found;
3734 int rtindex;
3735 ListCell *lc;
3736
3737 dpns->rtable_names = NIL;
3738 /* nothing more to do if empty rtable */
3739 if (dpns->rtable == NIL)
3740 return;
3741
3742 /*
3743 * We use a hash table to hold known names, so that this process is O(N)
3744 * not O(N^2) for N names.
3745 */
3746 hash_ctl.keysize = NAMEDATALEN;
3747 hash_ctl.entrysize = sizeof(NameHashEntry);
3748 hash_ctl.hcxt = CurrentMemoryContext;
3749 names_hash = hash_create("set_rtable_names names",
3750 list_length(dpns->rtable),
3751 &hash_ctl,
3752 HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
3753
3754 /* Preload the hash table with names appearing in parent_namespaces */
3755 foreach(lc, parent_namespaces)
3756 {
3757 deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3758 ListCell *lc2;
3759
3760 foreach(lc2, olddpns->rtable_names)
3761 {
3762 char *oldname = (char *) lfirst(lc2);
3763
3764 if (oldname == NULL)
3765 continue;
3766 hentry = (NameHashEntry *) hash_search(names_hash,
3767 oldname,
3768 HASH_ENTER,
3769 &found);
3770 /* we do not complain about duplicate names in parent namespaces */
3771 hentry->counter = 0;
3772 }
3773 }
3774
3775 /* Now we can scan the rtable */
3776 rtindex = 1;
3777 foreach(lc, dpns->rtable)
3778 {
3779 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3780 char *refname;
3781
3782 /* Just in case this takes an unreasonable amount of time ... */
3783 CHECK_FOR_INTERRUPTS();
3784
3785 if (rels_used && !bms_is_member(rtindex, rels_used))
3786 {
3787 /* Ignore unreferenced RTE */
3788 refname = NULL;
3789 }
3790 else if (rte->alias)
3791 {
3792 /* If RTE has a user-defined alias, prefer that */
3793 refname = rte->alias->aliasname;
3794 }
3795 else if (rte->rtekind == RTE_RELATION)
3796 {
3797 /* Use the current actual name of the relation */
3798 refname = get_rel_name(rte->relid);
3799 }
3800 else if (rte->rtekind == RTE_JOIN)
3801 {
3802 /* Unnamed join has no refname */
3803 refname = NULL;
3804 }
3805 else
3806 {
3807 /* Otherwise use whatever the parser assigned */
3808 refname = rte->eref->aliasname;
3809 }
3810
3811 /*
3812 * If the selected name isn't unique, append digits to make it so, and
3813 * make a new hash entry for it once we've got a unique name. For a
3814 * very long input name, we might have to truncate to stay within
3815 * NAMEDATALEN.
3816 */
3817 if (refname)
3818 {
3819 hentry = (NameHashEntry *) hash_search(names_hash,
3820 refname,
3821 HASH_ENTER,
3822 &found);
3823 if (found)
3824 {
3825 /* Name already in use, must choose a new one */
3826 int refnamelen = strlen(refname);
3827 char *modname = (char *) palloc(refnamelen + 16);
3828 NameHashEntry *hentry2;
3829
3830 do
3831 {
3832 hentry->counter++;
3833 for (;;)
3834 {
3835 memcpy(modname, refname, refnamelen);
3836 sprintf(modname + refnamelen, "_%d", hentry->counter);
3837 if (strlen(modname) < NAMEDATALEN)
3838 break;
3839 /* drop chars from refname to keep all the digits */
3840 refnamelen = pg_mbcliplen(refname, refnamelen,
3841 refnamelen - 1);
3842 }
3843 hentry2 = (NameHashEntry *) hash_search(names_hash,
3844 modname,
3845 HASH_ENTER,
3846 &found);
3847 } while (found);
3848 hentry2->counter = 0; /* init new hash entry */
3849 refname = modname;
3850 }
3851 else
3852 {
3853 /* Name not previously used, need only initialize hentry */
3854 hentry->counter = 0;
3855 }
3856 }
3857
3858 dpns->rtable_names = lappend(dpns->rtable_names, refname);
3859 rtindex++;
3860 }
3861
3862 hash_destroy(names_hash);
3863 }
3864
3865 /*
3866 * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
3867 *
3868 * For convenience, this is defined to initialize the deparse_namespace struct
3869 * from scratch.
3870 */
3871 static void
set_deparse_for_query(deparse_namespace * dpns,Query * query,List * parent_namespaces)3872 set_deparse_for_query(deparse_namespace *dpns, Query *query,
3873 List *parent_namespaces)
3874 {
3875 ListCell *lc;
3876 ListCell *lc2;
3877
3878 /* Initialize *dpns and fill rtable/ctes links */
3879 memset(dpns, 0, sizeof(deparse_namespace));
3880 dpns->rtable = query->rtable;
3881 dpns->subplans = NIL;
3882 dpns->ctes = query->cteList;
3883 dpns->appendrels = NULL;
3884
3885 /* Assign a unique relation alias to each RTE */
3886 set_rtable_names(dpns, parent_namespaces, NULL);
3887
3888 /* Initialize dpns->rtable_columns to contain zeroed structs */
3889 dpns->rtable_columns = NIL;
3890 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
3891 dpns->rtable_columns = lappend(dpns->rtable_columns,
3892 palloc0(sizeof(deparse_columns)));
3893
3894 /* If it's a utility query, it won't have a jointree */
3895 if (query->jointree)
3896 {
3897 /* Detect whether global uniqueness of USING names is needed */
3898 dpns->unique_using =
3899 has_dangerous_join_using(dpns, (Node *) query->jointree);
3900
3901 /*
3902 * Select names for columns merged by USING, via a recursive pass over
3903 * the query jointree.
3904 */
3905 set_using_names(dpns, (Node *) query->jointree, NIL);
3906 }
3907
3908 /*
3909 * Now assign remaining column aliases for each RTE. We do this in a
3910 * linear scan of the rtable, so as to process RTEs whether or not they
3911 * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
3912 * etc). JOIN RTEs must be processed after their children, but this is
3913 * okay because they appear later in the rtable list than their children
3914 * (cf Asserts in identify_join_columns()).
3915 */
3916 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
3917 {
3918 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3919 deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
3920
3921 if (rte->rtekind == RTE_JOIN)
3922 set_join_column_names(dpns, rte, colinfo);
3923 else
3924 set_relation_column_names(dpns, rte, colinfo);
3925 }
3926 }
3927
3928 /*
3929 * set_simple_column_names: fill in column aliases for non-query situations
3930 *
3931 * This handles EXPLAIN and cases where we only have relation RTEs. Without
3932 * a join tree, we can't do anything smart about join RTEs, but we don't
3933 * need to (note that EXPLAIN should never see join alias Vars anyway).
3934 * If we do hit a join RTE we'll just process it like a non-table base RTE.
3935 */
3936 static void
set_simple_column_names(deparse_namespace * dpns)3937 set_simple_column_names(deparse_namespace *dpns)
3938 {
3939 ListCell *lc;
3940 ListCell *lc2;
3941
3942 /* Initialize dpns->rtable_columns to contain zeroed structs */
3943 dpns->rtable_columns = NIL;
3944 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
3945 dpns->rtable_columns = lappend(dpns->rtable_columns,
3946 palloc0(sizeof(deparse_columns)));
3947
3948 /* Assign unique column aliases within each RTE */
3949 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
3950 {
3951 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3952 deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
3953
3954 set_relation_column_names(dpns, rte, colinfo);
3955 }
3956 }
3957
3958 /*
3959 * has_dangerous_join_using: search jointree for unnamed JOIN USING
3960 *
3961 * Merged columns of a JOIN USING may act differently from either of the input
3962 * columns, either because they are merged with COALESCE (in a FULL JOIN) or
3963 * because an implicit coercion of the underlying input column is required.
3964 * In such a case the column must be referenced as a column of the JOIN not as
3965 * a column of either input. And this is problematic if the join is unnamed
3966 * (alias-less): we cannot qualify the column's name with an RTE name, since
3967 * there is none. (Forcibly assigning an alias to the join is not a solution,
3968 * since that will prevent legal references to tables below the join.)
3969 * To ensure that every column in the query is unambiguously referenceable,
3970 * we must assign such merged columns names that are globally unique across
3971 * the whole query, aliasing other columns out of the way as necessary.
3972 *
3973 * Because the ensuing re-aliasing is fairly damaging to the readability of
3974 * the query, we don't do this unless we have to. So, we must pre-scan
3975 * the join tree to see if we have to, before starting set_using_names().
3976 */
3977 static bool
has_dangerous_join_using(deparse_namespace * dpns,Node * jtnode)3978 has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
3979 {
3980 if (IsA(jtnode, RangeTblRef))
3981 {
3982 /* nothing to do here */
3983 }
3984 else if (IsA(jtnode, FromExpr))
3985 {
3986 FromExpr *f = (FromExpr *) jtnode;
3987 ListCell *lc;
3988
3989 foreach(lc, f->fromlist)
3990 {
3991 if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
3992 return true;
3993 }
3994 }
3995 else if (IsA(jtnode, JoinExpr))
3996 {
3997 JoinExpr *j = (JoinExpr *) jtnode;
3998
3999 /* Is it an unnamed JOIN with USING? */
4000 if (j->alias == NULL && j->usingClause)
4001 {
4002 /*
4003 * Yes, so check each join alias var to see if any of them are not
4004 * simple references to underlying columns. If so, we have a
4005 * dangerous situation and must pick unique aliases.
4006 */
4007 RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4008
4009 /* We need only examine the merged columns */
4010 for (int i = 0; i < jrte->joinmergedcols; i++)
4011 {
4012 Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4013
4014 if (!IsA(aliasvar, Var))
4015 return true;
4016 }
4017 }
4018
4019 /* Nope, but inspect children */
4020 if (has_dangerous_join_using(dpns, j->larg))
4021 return true;
4022 if (has_dangerous_join_using(dpns, j->rarg))
4023 return true;
4024 }
4025 else
4026 elog(ERROR, "unrecognized node type: %d",
4027 (int) nodeTag(jtnode));
4028 return false;
4029 }
4030
4031 /*
4032 * set_using_names: select column aliases to be used for merged USING columns
4033 *
4034 * We do this during a recursive descent of the query jointree.
4035 * dpns->unique_using must already be set to determine the global strategy.
4036 *
4037 * Column alias info is saved in the dpns->rtable_columns list, which is
4038 * assumed to be filled with pre-zeroed deparse_columns structs.
4039 *
4040 * parentUsing is a list of all USING aliases assigned in parent joins of
4041 * the current jointree node. (The passed-in list must not be modified.)
4042 */
4043 static void
set_using_names(deparse_namespace * dpns,Node * jtnode,List * parentUsing)4044 set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
4045 {
4046 if (IsA(jtnode, RangeTblRef))
4047 {
4048 /* nothing to do now */
4049 }
4050 else if (IsA(jtnode, FromExpr))
4051 {
4052 FromExpr *f = (FromExpr *) jtnode;
4053 ListCell *lc;
4054
4055 foreach(lc, f->fromlist)
4056 set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4057 }
4058 else if (IsA(jtnode, JoinExpr))
4059 {
4060 JoinExpr *j = (JoinExpr *) jtnode;
4061 RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4062 deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
4063 int *leftattnos;
4064 int *rightattnos;
4065 deparse_columns *leftcolinfo;
4066 deparse_columns *rightcolinfo;
4067 int i;
4068 ListCell *lc;
4069
4070 /* Get info about the shape of the join */
4071 identify_join_columns(j, rte, colinfo);
4072 leftattnos = colinfo->leftattnos;
4073 rightattnos = colinfo->rightattnos;
4074
4075 /* Look up the not-yet-filled-in child deparse_columns structs */
4076 leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4077 rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4078
4079 /*
4080 * If this join is unnamed, then we cannot substitute new aliases at
4081 * this level, so any name requirements pushed down to here must be
4082 * pushed down again to the children.
4083 */
4084 if (rte->alias == NULL)
4085 {
4086 for (i = 0; i < colinfo->num_cols; i++)
4087 {
4088 char *colname = colinfo->colnames[i];
4089
4090 if (colname == NULL)
4091 continue;
4092
4093 /* Push down to left column, unless it's a system column */
4094 if (leftattnos[i] > 0)
4095 {
4096 expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4097 leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4098 }
4099
4100 /* Same on the righthand side */
4101 if (rightattnos[i] > 0)
4102 {
4103 expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4104 rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4105 }
4106 }
4107 }
4108
4109 /*
4110 * If there's a USING clause, select the USING column names and push
4111 * those names down to the children. We have two strategies:
4112 *
4113 * If dpns->unique_using is true, we force all USING names to be
4114 * unique across the whole query level. In principle we'd only need
4115 * the names of dangerous USING columns to be globally unique, but to
4116 * safely assign all USING names in a single pass, we have to enforce
4117 * the same uniqueness rule for all of them. However, if a USING
4118 * column's name has been pushed down from the parent, we should use
4119 * it as-is rather than making a uniqueness adjustment. This is
4120 * necessary when we're at an unnamed join, and it creates no risk of
4121 * ambiguity. Also, if there's a user-written output alias for a
4122 * merged column, we prefer to use that rather than the input name;
4123 * this simplifies the logic and seems likely to lead to less aliasing
4124 * overall.
4125 *
4126 * If dpns->unique_using is false, we only need USING names to be
4127 * unique within their own join RTE. We still need to honor
4128 * pushed-down names, though.
4129 *
4130 * Though significantly different in results, these two strategies are
4131 * implemented by the same code, with only the difference of whether
4132 * to put assigned names into dpns->using_names.
4133 */
4134 if (j->usingClause)
4135 {
4136 /* Copy the input parentUsing list so we don't modify it */
4137 parentUsing = list_copy(parentUsing);
4138
4139 /* USING names must correspond to the first join output columns */
4140 expand_colnames_array_to(colinfo, list_length(j->usingClause));
4141 i = 0;
4142 foreach(lc, j->usingClause)
4143 {
4144 char *colname = strVal(lfirst(lc));
4145
4146 /* Assert it's a merged column */
4147 Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4148
4149 /* Adopt passed-down name if any, else select unique name */
4150 if (colinfo->colnames[i] != NULL)
4151 colname = colinfo->colnames[i];
4152 else
4153 {
4154 /* Prefer user-written output alias if any */
4155 if (rte->alias && i < list_length(rte->alias->colnames))
4156 colname = strVal(list_nth(rte->alias->colnames, i));
4157 /* Make it appropriately unique */
4158 colname = make_colname_unique(colname, dpns, colinfo);
4159 if (dpns->unique_using)
4160 dpns->using_names = lappend(dpns->using_names,
4161 colname);
4162 /* Save it as output column name, too */
4163 colinfo->colnames[i] = colname;
4164 }
4165
4166 /* Remember selected names for use later */
4167 colinfo->usingNames = lappend(colinfo->usingNames, colname);
4168 parentUsing = lappend(parentUsing, colname);
4169
4170 /* Push down to left column, unless it's a system column */
4171 if (leftattnos[i] > 0)
4172 {
4173 expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4174 leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4175 }
4176
4177 /* Same on the righthand side */
4178 if (rightattnos[i] > 0)
4179 {
4180 expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4181 rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4182 }
4183
4184 i++;
4185 }
4186 }
4187
4188 /* Mark child deparse_columns structs with correct parentUsing info */
4189 leftcolinfo->parentUsing = parentUsing;
4190 rightcolinfo->parentUsing = parentUsing;
4191
4192 /* Now recursively assign USING column names in children */
4193 set_using_names(dpns, j->larg, parentUsing);
4194 set_using_names(dpns, j->rarg, parentUsing);
4195 }
4196 else
4197 elog(ERROR, "unrecognized node type: %d",
4198 (int) nodeTag(jtnode));
4199 }
4200
4201 /*
4202 * set_relation_column_names: select column aliases for a non-join RTE
4203 *
4204 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4205 * If any colnames entries are already filled in, those override local
4206 * choices.
4207 */
4208 static void
set_relation_column_names(deparse_namespace * dpns,RangeTblEntry * rte,deparse_columns * colinfo)4209 set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4210 deparse_columns *colinfo)
4211 {
4212 int ncolumns;
4213 char **real_colnames;
4214 bool changed_any;
4215 int noldcolumns;
4216 int i;
4217 int j;
4218
4219 /*
4220 * Extract the RTE's "real" column names. This is comparable to
4221 * get_rte_attribute_name, except that it's important to disregard dropped
4222 * columns. We put NULL into the array for a dropped column.
4223 */
4224 if (rte->rtekind == RTE_RELATION)
4225 {
4226 /* Relation --- look to the system catalogs for up-to-date info */
4227 Relation rel;
4228 TupleDesc tupdesc;
4229
4230 rel = relation_open(rte->relid, AccessShareLock);
4231 tupdesc = RelationGetDescr(rel);
4232
4233 ncolumns = tupdesc->natts;
4234 real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4235
4236 for (i = 0; i < ncolumns; i++)
4237 {
4238 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4239
4240 if (attr->attisdropped)
4241 real_colnames[i] = NULL;
4242 else
4243 real_colnames[i] = pstrdup(NameStr(attr->attname));
4244 }
4245 relation_close(rel, AccessShareLock);
4246 }
4247 else
4248 {
4249 /* Otherwise use the column names from eref */
4250 ListCell *lc;
4251
4252 ncolumns = list_length(rte->eref->colnames);
4253 real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4254
4255 i = 0;
4256 foreach(lc, rte->eref->colnames)
4257 {
4258 /*
4259 * If the column name shown in eref is an empty string, then it's
4260 * a column that was dropped at the time of parsing the query, so
4261 * treat it as dropped.
4262 */
4263 char *cname = strVal(lfirst(lc));
4264
4265 if (cname[0] == '\0')
4266 cname = NULL;
4267 real_colnames[i] = cname;
4268 i++;
4269 }
4270 }
4271
4272 /*
4273 * Ensure colinfo->colnames has a slot for each column. (It could be long
4274 * enough already, if we pushed down a name for the last column.) Note:
4275 * it's possible that there are now more columns than there were when the
4276 * query was parsed, ie colnames could be longer than rte->eref->colnames.
4277 * We must assign unique aliases to the new columns too, else there could
4278 * be unresolved conflicts when the view/rule is reloaded.
4279 */
4280 expand_colnames_array_to(colinfo, ncolumns);
4281 Assert(colinfo->num_cols == ncolumns);
4282
4283 /*
4284 * Make sufficiently large new_colnames and is_new_col arrays, too.
4285 *
4286 * Note: because we leave colinfo->num_new_cols zero until after the loop,
4287 * colname_is_unique will not consult that array, which is fine because it
4288 * would only be duplicate effort.
4289 */
4290 colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4291 colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4292
4293 /*
4294 * Scan the columns, select a unique alias for each one, and store it in
4295 * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4296 * entries for dropped columns, the latter omits them. Also mark
4297 * new_colnames entries as to whether they are new since parse time; this
4298 * is the case for entries beyond the length of rte->eref->colnames.
4299 */
4300 noldcolumns = list_length(rte->eref->colnames);
4301 changed_any = false;
4302 j = 0;
4303 for (i = 0; i < ncolumns; i++)
4304 {
4305 char *real_colname = real_colnames[i];
4306 char *colname = colinfo->colnames[i];
4307
4308 /* Skip dropped columns */
4309 if (real_colname == NULL)
4310 {
4311 Assert(colname == NULL); /* colnames[i] is already NULL */
4312 continue;
4313 }
4314
4315 /* If alias already assigned, that's what to use */
4316 if (colname == NULL)
4317 {
4318 /* If user wrote an alias, prefer that over real column name */
4319 if (rte->alias && i < list_length(rte->alias->colnames))
4320 colname = strVal(list_nth(rte->alias->colnames, i));
4321 else
4322 colname = real_colname;
4323
4324 /* Unique-ify and insert into colinfo */
4325 colname = make_colname_unique(colname, dpns, colinfo);
4326
4327 colinfo->colnames[i] = colname;
4328 }
4329
4330 /* Put names of non-dropped columns in new_colnames[] too */
4331 colinfo->new_colnames[j] = colname;
4332 /* And mark them as new or not */
4333 colinfo->is_new_col[j] = (i >= noldcolumns);
4334 j++;
4335
4336 /* Remember if any assigned aliases differ from "real" name */
4337 if (!changed_any && strcmp(colname, real_colname) != 0)
4338 changed_any = true;
4339 }
4340
4341 /*
4342 * Set correct length for new_colnames[] array. (Note: if columns have
4343 * been added, colinfo->num_cols includes them, which is not really quite
4344 * right but is harmless, since any new columns must be at the end where
4345 * they won't affect varattnos of pre-existing columns.)
4346 */
4347 colinfo->num_new_cols = j;
4348
4349 /*
4350 * For a relation RTE, we need only print the alias column names if any
4351 * are different from the underlying "real" names. For a function RTE,
4352 * always emit a complete column alias list; this is to protect against
4353 * possible instability of the default column names (eg, from altering
4354 * parameter names). For tablefunc RTEs, we never print aliases, because
4355 * the column names are part of the clause itself. For other RTE types,
4356 * print if we changed anything OR if there were user-written column
4357 * aliases (since the latter would be part of the underlying "reality").
4358 */
4359 if (rte->rtekind == RTE_RELATION)
4360 colinfo->printaliases = changed_any;
4361 else if (rte->rtekind == RTE_FUNCTION)
4362 colinfo->printaliases = true;
4363 else if (rte->rtekind == RTE_TABLEFUNC)
4364 colinfo->printaliases = false;
4365 else if (rte->alias && rte->alias->colnames != NIL)
4366 colinfo->printaliases = true;
4367 else
4368 colinfo->printaliases = changed_any;
4369 }
4370
4371 /*
4372 * set_join_column_names: select column aliases for a join RTE
4373 *
4374 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4375 * If any colnames entries are already filled in, those override local
4376 * choices. Also, names for USING columns were already chosen by
4377 * set_using_names(). We further expect that column alias selection has been
4378 * completed for both input RTEs.
4379 */
4380 static void
set_join_column_names(deparse_namespace * dpns,RangeTblEntry * rte,deparse_columns * colinfo)4381 set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4382 deparse_columns *colinfo)
4383 {
4384 deparse_columns *leftcolinfo;
4385 deparse_columns *rightcolinfo;
4386 bool changed_any;
4387 int noldcolumns;
4388 int nnewcolumns;
4389 Bitmapset *leftmerged = NULL;
4390 Bitmapset *rightmerged = NULL;
4391 int i;
4392 int j;
4393 int ic;
4394 int jc;
4395
4396 /* Look up the previously-filled-in child deparse_columns structs */
4397 leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4398 rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4399
4400 /*
4401 * Ensure colinfo->colnames has a slot for each column. (It could be long
4402 * enough already, if we pushed down a name for the last column.) Note:
4403 * it's possible that one or both inputs now have more columns than there
4404 * were when the query was parsed, but we'll deal with that below. We
4405 * only need entries in colnames for pre-existing columns.
4406 */
4407 noldcolumns = list_length(rte->eref->colnames);
4408 expand_colnames_array_to(colinfo, noldcolumns);
4409 Assert(colinfo->num_cols == noldcolumns);
4410
4411 /*
4412 * Scan the join output columns, select an alias for each one, and store
4413 * it in colinfo->colnames. If there are USING columns, set_using_names()
4414 * already selected their names, so we can start the loop at the first
4415 * non-merged column.
4416 */
4417 changed_any = false;
4418 for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4419 {
4420 char *colname = colinfo->colnames[i];
4421 char *real_colname;
4422
4423 /* Join column must refer to at least one input column */
4424 Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4425
4426 /* Get the child column name */
4427 if (colinfo->leftattnos[i] > 0)
4428 real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4429 else if (colinfo->rightattnos[i] > 0)
4430 real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4431 else
4432 {
4433 /* We're joining system columns --- use eref name */
4434 real_colname = strVal(list_nth(rte->eref->colnames, i));
4435 }
4436
4437 /* If child col has been dropped, no need to assign a join colname */
4438 if (real_colname == NULL)
4439 {
4440 colinfo->colnames[i] = NULL;
4441 continue;
4442 }
4443
4444 /* In an unnamed join, just report child column names as-is */
4445 if (rte->alias == NULL)
4446 {
4447 colinfo->colnames[i] = real_colname;
4448 continue;
4449 }
4450
4451 /* If alias already assigned, that's what to use */
4452 if (colname == NULL)
4453 {
4454 /* If user wrote an alias, prefer that over real column name */
4455 if (rte->alias && i < list_length(rte->alias->colnames))
4456 colname = strVal(list_nth(rte->alias->colnames, i));
4457 else
4458 colname = real_colname;
4459
4460 /* Unique-ify and insert into colinfo */
4461 colname = make_colname_unique(colname, dpns, colinfo);
4462
4463 colinfo->colnames[i] = colname;
4464 }
4465
4466 /* Remember if any assigned aliases differ from "real" name */
4467 if (!changed_any && strcmp(colname, real_colname) != 0)
4468 changed_any = true;
4469 }
4470
4471 /*
4472 * Calculate number of columns the join would have if it were re-parsed
4473 * now, and create storage for the new_colnames and is_new_col arrays.
4474 *
4475 * Note: colname_is_unique will be consulting new_colnames[] during the
4476 * loops below, so its not-yet-filled entries must be zeroes.
4477 */
4478 nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4479 list_length(colinfo->usingNames);
4480 colinfo->num_new_cols = nnewcolumns;
4481 colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
4482 colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
4483
4484 /*
4485 * Generating the new_colnames array is a bit tricky since any new columns
4486 * added since parse time must be inserted in the right places. This code
4487 * must match the parser, which will order a join's columns as merged
4488 * columns first (in USING-clause order), then non-merged columns from the
4489 * left input (in attnum order), then non-merged columns from the right
4490 * input (ditto). If one of the inputs is itself a join, its columns will
4491 * be ordered according to the same rule, which means newly-added columns
4492 * might not be at the end. We can figure out what's what by consulting
4493 * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4494 *
4495 * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4496 * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4497 * meanings for the current child RTE.
4498 */
4499
4500 /* Handle merged columns; they are first and can't be new */
4501 i = j = 0;
4502 while (i < noldcolumns &&
4503 colinfo->leftattnos[i] != 0 &&
4504 colinfo->rightattnos[i] != 0)
4505 {
4506 /* column name is already determined and known unique */
4507 colinfo->new_colnames[j] = colinfo->colnames[i];
4508 colinfo->is_new_col[j] = false;
4509
4510 /* build bitmapsets of child attnums of merged columns */
4511 if (colinfo->leftattnos[i] > 0)
4512 leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
4513 if (colinfo->rightattnos[i] > 0)
4514 rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4515
4516 i++, j++;
4517 }
4518
4519 /* Handle non-merged left-child columns */
4520 ic = 0;
4521 for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4522 {
4523 char *child_colname = leftcolinfo->new_colnames[jc];
4524
4525 if (!leftcolinfo->is_new_col[jc])
4526 {
4527 /* Advance ic to next non-dropped old column of left child */
4528 while (ic < leftcolinfo->num_cols &&
4529 leftcolinfo->colnames[ic] == NULL)
4530 ic++;
4531 Assert(ic < leftcolinfo->num_cols);
4532 ic++;
4533 /* If it is a merged column, we already processed it */
4534 if (bms_is_member(ic, leftmerged))
4535 continue;
4536 /* Else, advance i to the corresponding existing join column */
4537 while (i < colinfo->num_cols &&
4538 colinfo->colnames[i] == NULL)
4539 i++;
4540 Assert(i < colinfo->num_cols);
4541 Assert(ic == colinfo->leftattnos[i]);
4542 /* Use the already-assigned name of this column */
4543 colinfo->new_colnames[j] = colinfo->colnames[i];
4544 i++;
4545 }
4546 else
4547 {
4548 /*
4549 * Unique-ify the new child column name and assign, unless we're
4550 * in an unnamed join, in which case just copy
4551 */
4552 if (rte->alias != NULL)
4553 {
4554 colinfo->new_colnames[j] =
4555 make_colname_unique(child_colname, dpns, colinfo);
4556 if (!changed_any &&
4557 strcmp(colinfo->new_colnames[j], child_colname) != 0)
4558 changed_any = true;
4559 }
4560 else
4561 colinfo->new_colnames[j] = child_colname;
4562 }
4563
4564 colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4565 j++;
4566 }
4567
4568 /* Handle non-merged right-child columns in exactly the same way */
4569 ic = 0;
4570 for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4571 {
4572 char *child_colname = rightcolinfo->new_colnames[jc];
4573
4574 if (!rightcolinfo->is_new_col[jc])
4575 {
4576 /* Advance ic to next non-dropped old column of right child */
4577 while (ic < rightcolinfo->num_cols &&
4578 rightcolinfo->colnames[ic] == NULL)
4579 ic++;
4580 Assert(ic < rightcolinfo->num_cols);
4581 ic++;
4582 /* If it is a merged column, we already processed it */
4583 if (bms_is_member(ic, rightmerged))
4584 continue;
4585 /* Else, advance i to the corresponding existing join column */
4586 while (i < colinfo->num_cols &&
4587 colinfo->colnames[i] == NULL)
4588 i++;
4589 Assert(i < colinfo->num_cols);
4590 Assert(ic == colinfo->rightattnos[i]);
4591 /* Use the already-assigned name of this column */
4592 colinfo->new_colnames[j] = colinfo->colnames[i];
4593 i++;
4594 }
4595 else
4596 {
4597 /*
4598 * Unique-ify the new child column name and assign, unless we're
4599 * in an unnamed join, in which case just copy
4600 */
4601 if (rte->alias != NULL)
4602 {
4603 colinfo->new_colnames[j] =
4604 make_colname_unique(child_colname, dpns, colinfo);
4605 if (!changed_any &&
4606 strcmp(colinfo->new_colnames[j], child_colname) != 0)
4607 changed_any = true;
4608 }
4609 else
4610 colinfo->new_colnames[j] = child_colname;
4611 }
4612
4613 colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4614 j++;
4615 }
4616
4617 /* Assert we processed the right number of columns */
4618 #ifdef USE_ASSERT_CHECKING
4619 while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4620 i++;
4621 Assert(i == colinfo->num_cols);
4622 Assert(j == nnewcolumns);
4623 #endif
4624
4625 /*
4626 * For a named join, print column aliases if we changed any from the child
4627 * names. Unnamed joins cannot print aliases.
4628 */
4629 if (rte->alias != NULL)
4630 colinfo->printaliases = changed_any;
4631 else
4632 colinfo->printaliases = false;
4633 }
4634
4635 /*
4636 * colname_is_unique: is colname distinct from already-chosen column names?
4637 *
4638 * dpns is query-wide info, colinfo is for the column's RTE
4639 */
4640 static bool
colname_is_unique(const char * colname,deparse_namespace * dpns,deparse_columns * colinfo)4641 colname_is_unique(const char *colname, deparse_namespace *dpns,
4642 deparse_columns *colinfo)
4643 {
4644 int i;
4645 ListCell *lc;
4646
4647 /* Check against already-assigned column aliases within RTE */
4648 for (i = 0; i < colinfo->num_cols; i++)
4649 {
4650 char *oldname = colinfo->colnames[i];
4651
4652 if (oldname && strcmp(oldname, colname) == 0)
4653 return false;
4654 }
4655
4656 /*
4657 * If we're building a new_colnames array, check that too (this will be
4658 * partially but not completely redundant with the previous checks)
4659 */
4660 for (i = 0; i < colinfo->num_new_cols; i++)
4661 {
4662 char *oldname = colinfo->new_colnames[i];
4663
4664 if (oldname && strcmp(oldname, colname) == 0)
4665 return false;
4666 }
4667
4668 /* Also check against USING-column names that must be globally unique */
4669 foreach(lc, dpns->using_names)
4670 {
4671 char *oldname = (char *) lfirst(lc);
4672
4673 if (strcmp(oldname, colname) == 0)
4674 return false;
4675 }
4676
4677 /* Also check against names already assigned for parent-join USING cols */
4678 foreach(lc, colinfo->parentUsing)
4679 {
4680 char *oldname = (char *) lfirst(lc);
4681
4682 if (strcmp(oldname, colname) == 0)
4683 return false;
4684 }
4685
4686 return true;
4687 }
4688
4689 /*
4690 * make_colname_unique: modify colname if necessary to make it unique
4691 *
4692 * dpns is query-wide info, colinfo is for the column's RTE
4693 */
4694 static char *
make_colname_unique(char * colname,deparse_namespace * dpns,deparse_columns * colinfo)4695 make_colname_unique(char *colname, deparse_namespace *dpns,
4696 deparse_columns *colinfo)
4697 {
4698 /*
4699 * If the selected name isn't unique, append digits to make it so. For a
4700 * very long input name, we might have to truncate to stay within
4701 * NAMEDATALEN.
4702 */
4703 if (!colname_is_unique(colname, dpns, colinfo))
4704 {
4705 int colnamelen = strlen(colname);
4706 char *modname = (char *) palloc(colnamelen + 16);
4707 int i = 0;
4708
4709 do
4710 {
4711 i++;
4712 for (;;)
4713 {
4714 memcpy(modname, colname, colnamelen);
4715 sprintf(modname + colnamelen, "_%d", i);
4716 if (strlen(modname) < NAMEDATALEN)
4717 break;
4718 /* drop chars from colname to keep all the digits */
4719 colnamelen = pg_mbcliplen(colname, colnamelen,
4720 colnamelen - 1);
4721 }
4722 } while (!colname_is_unique(modname, dpns, colinfo));
4723 colname = modname;
4724 }
4725 return colname;
4726 }
4727
4728 /*
4729 * expand_colnames_array_to: make colinfo->colnames at least n items long
4730 *
4731 * Any added array entries are initialized to zero.
4732 */
4733 static void
expand_colnames_array_to(deparse_columns * colinfo,int n)4734 expand_colnames_array_to(deparse_columns *colinfo, int n)
4735 {
4736 if (n > colinfo->num_cols)
4737 {
4738 if (colinfo->colnames == NULL)
4739 colinfo->colnames = (char **) palloc0(n * sizeof(char *));
4740 else
4741 {
4742 colinfo->colnames = (char **) repalloc(colinfo->colnames,
4743 n * sizeof(char *));
4744 memset(colinfo->colnames + colinfo->num_cols, 0,
4745 (n - colinfo->num_cols) * sizeof(char *));
4746 }
4747 colinfo->num_cols = n;
4748 }
4749 }
4750
4751 /*
4752 * identify_join_columns: figure out where columns of a join come from
4753 *
4754 * Fills the join-specific fields of the colinfo struct, except for
4755 * usingNames which is filled later.
4756 */
4757 static void
identify_join_columns(JoinExpr * j,RangeTblEntry * jrte,deparse_columns * colinfo)4758 identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
4759 deparse_columns *colinfo)
4760 {
4761 int numjoincols;
4762 int jcolno;
4763 int rcolno;
4764 ListCell *lc;
4765
4766 /* Extract left/right child RT indexes */
4767 if (IsA(j->larg, RangeTblRef))
4768 colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
4769 else if (IsA(j->larg, JoinExpr))
4770 colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
4771 else
4772 elog(ERROR, "unrecognized node type in jointree: %d",
4773 (int) nodeTag(j->larg));
4774 if (IsA(j->rarg, RangeTblRef))
4775 colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
4776 else if (IsA(j->rarg, JoinExpr))
4777 colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
4778 else
4779 elog(ERROR, "unrecognized node type in jointree: %d",
4780 (int) nodeTag(j->rarg));
4781
4782 /* Assert children will be processed earlier than join in second pass */
4783 Assert(colinfo->leftrti < j->rtindex);
4784 Assert(colinfo->rightrti < j->rtindex);
4785
4786 /* Initialize result arrays with zeroes */
4787 numjoincols = list_length(jrte->joinaliasvars);
4788 Assert(numjoincols == list_length(jrte->eref->colnames));
4789 colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
4790 colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
4791
4792 /*
4793 * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
4794 * Recall that the column(s) merged due to USING are the first column(s)
4795 * of the join output. We need not do anything special while scanning
4796 * joinleftcols, but while scanning joinrightcols we must distinguish
4797 * merged from unmerged columns.
4798 */
4799 jcolno = 0;
4800 foreach(lc, jrte->joinleftcols)
4801 {
4802 int leftattno = lfirst_int(lc);
4803
4804 colinfo->leftattnos[jcolno++] = leftattno;
4805 }
4806 rcolno = 0;
4807 foreach(lc, jrte->joinrightcols)
4808 {
4809 int rightattno = lfirst_int(lc);
4810
4811 if (rcolno < jrte->joinmergedcols) /* merged column? */
4812 colinfo->rightattnos[rcolno] = rightattno;
4813 else
4814 colinfo->rightattnos[jcolno++] = rightattno;
4815 rcolno++;
4816 }
4817 Assert(jcolno == numjoincols);
4818 }
4819
4820 /*
4821 * get_rtable_name: convenience function to get a previously assigned RTE alias
4822 *
4823 * The RTE must belong to the topmost namespace level in "context".
4824 */
4825 static char *
get_rtable_name(int rtindex,deparse_context * context)4826 get_rtable_name(int rtindex, deparse_context *context)
4827 {
4828 deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
4829
4830 Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
4831 return (char *) list_nth(dpns->rtable_names, rtindex - 1);
4832 }
4833
4834 /*
4835 * set_deparse_plan: set up deparse_namespace to parse subexpressions
4836 * of a given Plan node
4837 *
4838 * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
4839 * and index_tlist fields. Caller must already have adjusted the ancestors
4840 * list if necessary. Note that the rtable, subplans, and ctes fields do
4841 * not need to change when shifting attention to different plan nodes in a
4842 * single plan tree.
4843 */
4844 static void
set_deparse_plan(deparse_namespace * dpns,Plan * plan)4845 set_deparse_plan(deparse_namespace *dpns, Plan *plan)
4846 {
4847 dpns->plan = plan;
4848
4849 /*
4850 * We special-case Append and MergeAppend to pretend that the first child
4851 * plan is the OUTER referent; we have to interpret OUTER Vars in their
4852 * tlists according to one of the children, and the first one is the most
4853 * natural choice.
4854 */
4855 if (IsA(plan, Append))
4856 dpns->outer_plan = linitial(((Append *) plan)->appendplans);
4857 else if (IsA(plan, MergeAppend))
4858 dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
4859 else
4860 dpns->outer_plan = outerPlan(plan);
4861
4862 if (dpns->outer_plan)
4863 dpns->outer_tlist = dpns->outer_plan->targetlist;
4864 else
4865 dpns->outer_tlist = NIL;
4866
4867 /*
4868 * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
4869 * use OUTER because that could someday conflict with the normal meaning.)
4870 * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
4871 * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
4872 * that as INNER referent.
4873 *
4874 * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
4875 * excluded expression's tlist. (Similar to the SubqueryScan we don't want
4876 * to reuse OUTER, it's used for RETURNING in some modify table cases,
4877 * although not INSERT .. CONFLICT).
4878 */
4879 if (IsA(plan, SubqueryScan))
4880 dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
4881 else if (IsA(plan, CteScan))
4882 dpns->inner_plan = list_nth(dpns->subplans,
4883 ((CteScan *) plan)->ctePlanId - 1);
4884 else if (IsA(plan, WorkTableScan))
4885 dpns->inner_plan = find_recursive_union(dpns,
4886 (WorkTableScan *) plan);
4887 else if (IsA(plan, ModifyTable))
4888 dpns->inner_plan = plan;
4889 else
4890 dpns->inner_plan = innerPlan(plan);
4891
4892 if (IsA(plan, ModifyTable))
4893 dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
4894 else if (dpns->inner_plan)
4895 dpns->inner_tlist = dpns->inner_plan->targetlist;
4896 else
4897 dpns->inner_tlist = NIL;
4898
4899 /* Set up referent for INDEX_VAR Vars, if needed */
4900 if (IsA(plan, IndexOnlyScan))
4901 dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
4902 else if (IsA(plan, ForeignScan))
4903 dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
4904 else if (IsA(plan, CustomScan))
4905 dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
4906 else
4907 dpns->index_tlist = NIL;
4908 }
4909
4910 /*
4911 * Locate the ancestor plan node that is the RecursiveUnion generating
4912 * the WorkTableScan's work table. We can match on wtParam, since that
4913 * should be unique within the plan tree.
4914 */
4915 static Plan *
find_recursive_union(deparse_namespace * dpns,WorkTableScan * wtscan)4916 find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
4917 {
4918 ListCell *lc;
4919
4920 foreach(lc, dpns->ancestors)
4921 {
4922 Plan *ancestor = (Plan *) lfirst(lc);
4923
4924 if (IsA(ancestor, RecursiveUnion) &&
4925 ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
4926 return ancestor;
4927 }
4928 elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
4929 wtscan->wtParam);
4930 return NULL;
4931 }
4932
4933 /*
4934 * push_child_plan: temporarily transfer deparsing attention to a child plan
4935 *
4936 * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
4937 * deparse context in case the referenced expression itself uses
4938 * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
4939 * affecting levelsup issues (although in a Plan tree there really shouldn't
4940 * be any).
4941 *
4942 * Caller must provide a local deparse_namespace variable to save the
4943 * previous state for pop_child_plan.
4944 */
4945 static void
push_child_plan(deparse_namespace * dpns,Plan * plan,deparse_namespace * save_dpns)4946 push_child_plan(deparse_namespace *dpns, Plan *plan,
4947 deparse_namespace *save_dpns)
4948 {
4949 /* Save state for restoration later */
4950 *save_dpns = *dpns;
4951
4952 /* Link current plan node into ancestors list */
4953 dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
4954
4955 /* Set attention on selected child */
4956 set_deparse_plan(dpns, plan);
4957 }
4958
4959 /*
4960 * pop_child_plan: undo the effects of push_child_plan
4961 */
4962 static void
pop_child_plan(deparse_namespace * dpns,deparse_namespace * save_dpns)4963 pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
4964 {
4965 List *ancestors;
4966
4967 /* Get rid of ancestors list cell added by push_child_plan */
4968 ancestors = list_delete_first(dpns->ancestors);
4969
4970 /* Restore fields changed by push_child_plan */
4971 *dpns = *save_dpns;
4972
4973 /* Make sure dpns->ancestors is right (may be unnecessary) */
4974 dpns->ancestors = ancestors;
4975 }
4976
4977 /*
4978 * push_ancestor_plan: temporarily transfer deparsing attention to an
4979 * ancestor plan
4980 *
4981 * When expanding a Param reference, we must adjust the deparse context
4982 * to match the plan node that contains the expression being printed;
4983 * otherwise we'd fail if that expression itself contains a Param or
4984 * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
4985 *
4986 * The target ancestor is conveniently identified by the ListCell holding it
4987 * in dpns->ancestors.
4988 *
4989 * Caller must provide a local deparse_namespace variable to save the
4990 * previous state for pop_ancestor_plan.
4991 */
4992 static void
push_ancestor_plan(deparse_namespace * dpns,ListCell * ancestor_cell,deparse_namespace * save_dpns)4993 push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
4994 deparse_namespace *save_dpns)
4995 {
4996 Plan *plan = (Plan *) lfirst(ancestor_cell);
4997
4998 /* Save state for restoration later */
4999 *save_dpns = *dpns;
5000
5001 /* Build a new ancestor list with just this node's ancestors */
5002 dpns->ancestors =
5003 list_copy_tail(dpns->ancestors,
5004 list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5005
5006 /* Set attention on selected ancestor */
5007 set_deparse_plan(dpns, plan);
5008 }
5009
5010 /*
5011 * pop_ancestor_plan: undo the effects of push_ancestor_plan
5012 */
5013 static void
pop_ancestor_plan(deparse_namespace * dpns,deparse_namespace * save_dpns)5014 pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5015 {
5016 /* Free the ancestor list made in push_ancestor_plan */
5017 list_free(dpns->ancestors);
5018
5019 /* Restore fields changed by push_ancestor_plan */
5020 *dpns = *save_dpns;
5021 }
5022
5023
5024 /* ----------
5025 * make_ruledef - reconstruct the CREATE RULE command
5026 * for a given pg_rewrite tuple
5027 * ----------
5028 */
5029 static void
make_ruledef(StringInfo buf,HeapTuple ruletup,TupleDesc rulettc,int prettyFlags)5030 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5031 int prettyFlags)
5032 {
5033 char *rulename;
5034 char ev_type;
5035 Oid ev_class;
5036 bool is_instead;
5037 char *ev_qual;
5038 char *ev_action;
5039 List *actions;
5040 Relation ev_relation;
5041 TupleDesc viewResultDesc = NULL;
5042 int fno;
5043 Datum dat;
5044 bool isnull;
5045
5046 /*
5047 * Get the attribute values from the rules tuple
5048 */
5049 fno = SPI_fnumber(rulettc, "rulename");
5050 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5051 Assert(!isnull);
5052 rulename = NameStr(*(DatumGetName(dat)));
5053
5054 fno = SPI_fnumber(rulettc, "ev_type");
5055 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5056 Assert(!isnull);
5057 ev_type = DatumGetChar(dat);
5058
5059 fno = SPI_fnumber(rulettc, "ev_class");
5060 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5061 Assert(!isnull);
5062 ev_class = DatumGetObjectId(dat);
5063
5064 fno = SPI_fnumber(rulettc, "is_instead");
5065 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5066 Assert(!isnull);
5067 is_instead = DatumGetBool(dat);
5068
5069 fno = SPI_fnumber(rulettc, "ev_qual");
5070 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5071 Assert(ev_qual != NULL);
5072
5073 fno = SPI_fnumber(rulettc, "ev_action");
5074 ev_action = SPI_getvalue(ruletup, rulettc, fno);
5075 Assert(ev_action != NULL);
5076 actions = (List *) stringToNode(ev_action);
5077 if (actions == NIL)
5078 elog(ERROR, "invalid empty ev_action list");
5079
5080 ev_relation = table_open(ev_class, AccessShareLock);
5081
5082 /*
5083 * Build the rules definition text
5084 */
5085 appendStringInfo(buf, "CREATE RULE %s AS",
5086 quote_identifier(rulename));
5087
5088 if (prettyFlags & PRETTYFLAG_INDENT)
5089 appendStringInfoString(buf, "\n ON ");
5090 else
5091 appendStringInfoString(buf, " ON ");
5092
5093 /* The event the rule is fired for */
5094 switch (ev_type)
5095 {
5096 case '1':
5097 appendStringInfoString(buf, "SELECT");
5098 viewResultDesc = RelationGetDescr(ev_relation);
5099 break;
5100
5101 case '2':
5102 appendStringInfoString(buf, "UPDATE");
5103 break;
5104
5105 case '3':
5106 appendStringInfoString(buf, "INSERT");
5107 break;
5108
5109 case '4':
5110 appendStringInfoString(buf, "DELETE");
5111 break;
5112
5113 default:
5114 ereport(ERROR,
5115 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5116 errmsg("rule \"%s\" has unsupported event type %d",
5117 rulename, ev_type)));
5118 break;
5119 }
5120
5121 /* The relation the rule is fired on */
5122 appendStringInfo(buf, " TO %s",
5123 (prettyFlags & PRETTYFLAG_SCHEMA) ?
5124 generate_relation_name(ev_class, NIL) :
5125 generate_qualified_relation_name(ev_class));
5126
5127 /* If the rule has an event qualification, add it */
5128 if (strcmp(ev_qual, "<>") != 0)
5129 {
5130 Node *qual;
5131 Query *query;
5132 deparse_context context;
5133 deparse_namespace dpns;
5134
5135 if (prettyFlags & PRETTYFLAG_INDENT)
5136 appendStringInfoString(buf, "\n ");
5137 appendStringInfoString(buf, " WHERE ");
5138
5139 qual = stringToNode(ev_qual);
5140
5141 /*
5142 * We need to make a context for recognizing any Vars in the qual
5143 * (which can only be references to OLD and NEW). Use the rtable of
5144 * the first query in the action list for this purpose.
5145 */
5146 query = (Query *) linitial(actions);
5147
5148 /*
5149 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5150 * into the SELECT, and that's what we need to look at. (Ugly kluge
5151 * ... try to fix this when we redesign querytrees.)
5152 */
5153 query = getInsertSelectQuery(query, NULL);
5154
5155 /* Must acquire locks right away; see notes in get_query_def() */
5156 AcquireRewriteLocks(query, false, false);
5157
5158 context.buf = buf;
5159 context.namespaces = list_make1(&dpns);
5160 context.windowClause = NIL;
5161 context.windowTList = NIL;
5162 context.varprefix = (list_length(query->rtable) != 1);
5163 context.prettyFlags = prettyFlags;
5164 context.wrapColumn = WRAP_COLUMN_DEFAULT;
5165 context.indentLevel = PRETTYINDENT_STD;
5166 context.special_exprkind = EXPR_KIND_NONE;
5167 context.appendparents = NULL;
5168
5169 set_deparse_for_query(&dpns, query, NIL);
5170
5171 get_rule_expr(qual, &context, false);
5172 }
5173
5174 appendStringInfoString(buf, " DO ");
5175
5176 /* The INSTEAD keyword (if so) */
5177 if (is_instead)
5178 appendStringInfoString(buf, "INSTEAD ");
5179
5180 /* Finally the rules actions */
5181 if (list_length(actions) > 1)
5182 {
5183 ListCell *action;
5184 Query *query;
5185
5186 appendStringInfoChar(buf, '(');
5187 foreach(action, actions)
5188 {
5189 query = (Query *) lfirst(action);
5190 get_query_def(query, buf, NIL, viewResultDesc,
5191 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5192 if (prettyFlags)
5193 appendStringInfoString(buf, ";\n");
5194 else
5195 appendStringInfoString(buf, "; ");
5196 }
5197 appendStringInfoString(buf, ");");
5198 }
5199 else
5200 {
5201 Query *query;
5202
5203 query = (Query *) linitial(actions);
5204 get_query_def(query, buf, NIL, viewResultDesc,
5205 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5206 appendStringInfoChar(buf, ';');
5207 }
5208
5209 table_close(ev_relation, AccessShareLock);
5210 }
5211
5212
5213 /* ----------
5214 * make_viewdef - reconstruct the SELECT part of a
5215 * view rewrite rule
5216 * ----------
5217 */
5218 static void
make_viewdef(StringInfo buf,HeapTuple ruletup,TupleDesc rulettc,int prettyFlags,int wrapColumn)5219 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5220 int prettyFlags, int wrapColumn)
5221 {
5222 Query *query;
5223 char ev_type;
5224 Oid ev_class;
5225 bool is_instead;
5226 char *ev_qual;
5227 char *ev_action;
5228 List *actions;
5229 Relation ev_relation;
5230 int fno;
5231 Datum dat;
5232 bool isnull;
5233
5234 /*
5235 * Get the attribute values from the rules tuple
5236 */
5237 fno = SPI_fnumber(rulettc, "ev_type");
5238 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5239 Assert(!isnull);
5240 ev_type = DatumGetChar(dat);
5241
5242 fno = SPI_fnumber(rulettc, "ev_class");
5243 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5244 Assert(!isnull);
5245 ev_class = DatumGetObjectId(dat);
5246
5247 fno = SPI_fnumber(rulettc, "is_instead");
5248 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5249 Assert(!isnull);
5250 is_instead = DatumGetBool(dat);
5251
5252 fno = SPI_fnumber(rulettc, "ev_qual");
5253 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5254 Assert(ev_qual != NULL);
5255
5256 fno = SPI_fnumber(rulettc, "ev_action");
5257 ev_action = SPI_getvalue(ruletup, rulettc, fno);
5258 Assert(ev_action != NULL);
5259 actions = (List *) stringToNode(ev_action);
5260
5261 if (list_length(actions) != 1)
5262 {
5263 /* keep output buffer empty and leave */
5264 return;
5265 }
5266
5267 query = (Query *) linitial(actions);
5268
5269 if (ev_type != '1' || !is_instead ||
5270 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5271 {
5272 /* keep output buffer empty and leave */
5273 return;
5274 }
5275
5276 ev_relation = table_open(ev_class, AccessShareLock);
5277
5278 get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
5279 prettyFlags, wrapColumn, 0);
5280 appendStringInfoChar(buf, ';');
5281
5282 table_close(ev_relation, AccessShareLock);
5283 }
5284
5285
5286 /* ----------
5287 * get_query_def - Parse back one query parsetree
5288 *
5289 * If resultDesc is not NULL, then it is the output tuple descriptor for
5290 * the view represented by a SELECT query.
5291 * ----------
5292 */
5293 static void
get_query_def(Query * query,StringInfo buf,List * parentnamespace,TupleDesc resultDesc,int prettyFlags,int wrapColumn,int startIndent)5294 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
5295 TupleDesc resultDesc,
5296 int prettyFlags, int wrapColumn, int startIndent)
5297 {
5298 deparse_context context;
5299 deparse_namespace dpns;
5300
5301 /* Guard against excessively long or deeply-nested queries */
5302 CHECK_FOR_INTERRUPTS();
5303 check_stack_depth();
5304
5305 /*
5306 * Before we begin to examine the query, acquire locks on referenced
5307 * relations, and fix up deleted columns in JOIN RTEs. This ensures
5308 * consistent results. Note we assume it's OK to scribble on the passed
5309 * querytree!
5310 *
5311 * We are only deparsing the query (we are not about to execute it), so we
5312 * only need AccessShareLock on the relations it mentions.
5313 */
5314 AcquireRewriteLocks(query, false, false);
5315
5316 context.buf = buf;
5317 context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5318 context.windowClause = NIL;
5319 context.windowTList = NIL;
5320 context.varprefix = (parentnamespace != NIL ||
5321 list_length(query->rtable) != 1);
5322 context.prettyFlags = prettyFlags;
5323 context.wrapColumn = wrapColumn;
5324 context.indentLevel = startIndent;
5325 context.special_exprkind = EXPR_KIND_NONE;
5326 context.appendparents = NULL;
5327
5328 set_deparse_for_query(&dpns, query, parentnamespace);
5329
5330 switch (query->commandType)
5331 {
5332 case CMD_SELECT:
5333 get_select_query_def(query, &context, resultDesc);
5334 break;
5335
5336 case CMD_UPDATE:
5337 get_update_query_def(query, &context);
5338 break;
5339
5340 case CMD_INSERT:
5341 get_insert_query_def(query, &context);
5342 break;
5343
5344 case CMD_DELETE:
5345 get_delete_query_def(query, &context);
5346 break;
5347
5348 case CMD_NOTHING:
5349 appendStringInfoString(buf, "NOTHING");
5350 break;
5351
5352 case CMD_UTILITY:
5353 get_utility_query_def(query, &context);
5354 break;
5355
5356 default:
5357 elog(ERROR, "unrecognized query command type: %d",
5358 query->commandType);
5359 break;
5360 }
5361 }
5362
5363 /* ----------
5364 * get_values_def - Parse back a VALUES list
5365 * ----------
5366 */
5367 static void
get_values_def(List * values_lists,deparse_context * context)5368 get_values_def(List *values_lists, deparse_context *context)
5369 {
5370 StringInfo buf = context->buf;
5371 bool first_list = true;
5372 ListCell *vtl;
5373
5374 appendStringInfoString(buf, "VALUES ");
5375
5376 foreach(vtl, values_lists)
5377 {
5378 List *sublist = (List *) lfirst(vtl);
5379 bool first_col = true;
5380 ListCell *lc;
5381
5382 if (first_list)
5383 first_list = false;
5384 else
5385 appendStringInfoString(buf, ", ");
5386
5387 appendStringInfoChar(buf, '(');
5388 foreach(lc, sublist)
5389 {
5390 Node *col = (Node *) lfirst(lc);
5391
5392 if (first_col)
5393 first_col = false;
5394 else
5395 appendStringInfoChar(buf, ',');
5396
5397 /*
5398 * Print the value. Whole-row Vars need special treatment.
5399 */
5400 get_rule_expr_toplevel(col, context, false);
5401 }
5402 appendStringInfoChar(buf, ')');
5403 }
5404 }
5405
5406 /* ----------
5407 * get_with_clause - Parse back a WITH clause
5408 * ----------
5409 */
5410 static void
get_with_clause(Query * query,deparse_context * context)5411 get_with_clause(Query *query, deparse_context *context)
5412 {
5413 StringInfo buf = context->buf;
5414 const char *sep;
5415 ListCell *l;
5416
5417 if (query->cteList == NIL)
5418 return;
5419
5420 if (PRETTY_INDENT(context))
5421 {
5422 context->indentLevel += PRETTYINDENT_STD;
5423 appendStringInfoChar(buf, ' ');
5424 }
5425
5426 if (query->hasRecursive)
5427 sep = "WITH RECURSIVE ";
5428 else
5429 sep = "WITH ";
5430 foreach(l, query->cteList)
5431 {
5432 CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5433
5434 appendStringInfoString(buf, sep);
5435 appendStringInfoString(buf, quote_identifier(cte->ctename));
5436 if (cte->aliascolnames)
5437 {
5438 bool first = true;
5439 ListCell *col;
5440
5441 appendStringInfoChar(buf, '(');
5442 foreach(col, cte->aliascolnames)
5443 {
5444 if (first)
5445 first = false;
5446 else
5447 appendStringInfoString(buf, ", ");
5448 appendStringInfoString(buf,
5449 quote_identifier(strVal(lfirst(col))));
5450 }
5451 appendStringInfoChar(buf, ')');
5452 }
5453 appendStringInfoString(buf, " AS ");
5454 switch (cte->ctematerialized)
5455 {
5456 case CTEMaterializeDefault:
5457 break;
5458 case CTEMaterializeAlways:
5459 appendStringInfoString(buf, "MATERIALIZED ");
5460 break;
5461 case CTEMaterializeNever:
5462 appendStringInfoString(buf, "NOT MATERIALIZED ");
5463 break;
5464 }
5465 appendStringInfoChar(buf, '(');
5466 if (PRETTY_INDENT(context))
5467 appendContextKeyword(context, "", 0, 0, 0);
5468 get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5469 context->prettyFlags, context->wrapColumn,
5470 context->indentLevel);
5471 if (PRETTY_INDENT(context))
5472 appendContextKeyword(context, "", 0, 0, 0);
5473 appendStringInfoChar(buf, ')');
5474
5475 if (cte->search_clause)
5476 {
5477 bool first = true;
5478 ListCell *lc;
5479
5480 appendStringInfo(buf, " SEARCH %s FIRST BY ",
5481 cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
5482
5483 foreach(lc, cte->search_clause->search_col_list)
5484 {
5485 if (first)
5486 first = false;
5487 else
5488 appendStringInfoString(buf, ", ");
5489 appendStringInfoString(buf,
5490 quote_identifier(strVal(lfirst(lc))));
5491 }
5492
5493 appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
5494 }
5495
5496 if (cte->cycle_clause)
5497 {
5498 bool first = true;
5499 ListCell *lc;
5500
5501 appendStringInfoString(buf, " CYCLE ");
5502
5503 foreach(lc, cte->cycle_clause->cycle_col_list)
5504 {
5505 if (first)
5506 first = false;
5507 else
5508 appendStringInfoString(buf, ", ");
5509 appendStringInfoString(buf,
5510 quote_identifier(strVal(lfirst(lc))));
5511 }
5512
5513 appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5514
5515 {
5516 Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5517 Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5518
5519 if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5520 cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5521 {
5522 appendStringInfoString(buf, " TO ");
5523 get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
5524 appendStringInfoString(buf, " DEFAULT ");
5525 get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
5526 }
5527 }
5528
5529 appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5530 }
5531
5532 sep = ", ";
5533 }
5534
5535 if (PRETTY_INDENT(context))
5536 {
5537 context->indentLevel -= PRETTYINDENT_STD;
5538 appendContextKeyword(context, "", 0, 0, 0);
5539 }
5540 else
5541 appendStringInfoChar(buf, ' ');
5542 }
5543
5544 /* ----------
5545 * get_select_query_def - Parse back a SELECT parsetree
5546 * ----------
5547 */
5548 static void
get_select_query_def(Query * query,deparse_context * context,TupleDesc resultDesc)5549 get_select_query_def(Query *query, deparse_context *context,
5550 TupleDesc resultDesc)
5551 {
5552 StringInfo buf = context->buf;
5553 List *save_windowclause;
5554 List *save_windowtlist;
5555 bool force_colno;
5556 ListCell *l;
5557
5558 /* Insert the WITH clause if given */
5559 get_with_clause(query, context);
5560
5561 /* Set up context for possible window functions */
5562 save_windowclause = context->windowClause;
5563 context->windowClause = query->windowClause;
5564 save_windowtlist = context->windowTList;
5565 context->windowTList = query->targetList;
5566
5567 /*
5568 * If the Query node has a setOperations tree, then it's the top level of
5569 * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5570 * fields are interesting in the top query itself.
5571 */
5572 if (query->setOperations)
5573 {
5574 get_setop_query(query->setOperations, query, context, resultDesc);
5575 /* ORDER BY clauses must be simple in this case */
5576 force_colno = true;
5577 }
5578 else
5579 {
5580 get_basic_select_query(query, context, resultDesc);
5581 force_colno = false;
5582 }
5583
5584 /* Add the ORDER BY clause if given */
5585 if (query->sortClause != NIL)
5586 {
5587 appendContextKeyword(context, " ORDER BY ",
5588 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5589 get_rule_orderby(query->sortClause, query->targetList,
5590 force_colno, context);
5591 }
5592
5593 /*
5594 * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5595 * standard spelling of LIMIT.
5596 */
5597 if (query->limitOffset != NULL)
5598 {
5599 appendContextKeyword(context, " OFFSET ",
5600 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5601 get_rule_expr(query->limitOffset, context, false);
5602 }
5603 if (query->limitCount != NULL)
5604 {
5605 if (query->limitOption == LIMIT_OPTION_WITH_TIES)
5606 {
5607 appendContextKeyword(context, " FETCH FIRST ",
5608 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5609 get_rule_expr(query->limitCount, context, false);
5610 appendStringInfoString(buf, " ROWS WITH TIES");
5611 }
5612 else
5613 {
5614 appendContextKeyword(context, " LIMIT ",
5615 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5616 if (IsA(query->limitCount, Const) &&
5617 ((Const *) query->limitCount)->constisnull)
5618 appendStringInfoString(buf, "ALL");
5619 else
5620 get_rule_expr(query->limitCount, context, false);
5621 }
5622 }
5623
5624 /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5625 if (query->hasForUpdate)
5626 {
5627 foreach(l, query->rowMarks)
5628 {
5629 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5630
5631 /* don't print implicit clauses */
5632 if (rc->pushedDown)
5633 continue;
5634
5635 switch (rc->strength)
5636 {
5637 case LCS_NONE:
5638 /* we intentionally throw an error for LCS_NONE */
5639 elog(ERROR, "unrecognized LockClauseStrength %d",
5640 (int) rc->strength);
5641 break;
5642 case LCS_FORKEYSHARE:
5643 appendContextKeyword(context, " FOR KEY SHARE",
5644 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5645 break;
5646 case LCS_FORSHARE:
5647 appendContextKeyword(context, " FOR SHARE",
5648 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5649 break;
5650 case LCS_FORNOKEYUPDATE:
5651 appendContextKeyword(context, " FOR NO KEY UPDATE",
5652 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5653 break;
5654 case LCS_FORUPDATE:
5655 appendContextKeyword(context, " FOR UPDATE",
5656 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5657 break;
5658 }
5659
5660 appendStringInfo(buf, " OF %s",
5661 quote_identifier(get_rtable_name(rc->rti,
5662 context)));
5663 if (rc->waitPolicy == LockWaitError)
5664 appendStringInfoString(buf, " NOWAIT");
5665 else if (rc->waitPolicy == LockWaitSkip)
5666 appendStringInfoString(buf, " SKIP LOCKED");
5667 }
5668 }
5669
5670 context->windowClause = save_windowclause;
5671 context->windowTList = save_windowtlist;
5672 }
5673
5674 /*
5675 * Detect whether query looks like SELECT ... FROM VALUES(),
5676 * with no need to rename the output columns of the VALUES RTE.
5677 * If so, return the VALUES RTE. Otherwise return NULL.
5678 */
5679 static RangeTblEntry *
get_simple_values_rte(Query * query,TupleDesc resultDesc)5680 get_simple_values_rte(Query *query, TupleDesc resultDesc)
5681 {
5682 RangeTblEntry *result = NULL;
5683 ListCell *lc;
5684
5685 /*
5686 * We want to detect a match even if the Query also contains OLD or NEW
5687 * rule RTEs. So the idea is to scan the rtable and see if there is only
5688 * one inFromCl RTE that is a VALUES RTE.
5689 */
5690 foreach(lc, query->rtable)
5691 {
5692 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
5693
5694 if (rte->rtekind == RTE_VALUES && rte->inFromCl)
5695 {
5696 if (result)
5697 return NULL; /* multiple VALUES (probably not possible) */
5698 result = rte;
5699 }
5700 else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
5701 continue; /* ignore rule entries */
5702 else
5703 return NULL; /* something else -> not simple VALUES */
5704 }
5705
5706 /*
5707 * We don't need to check the targetlist in any great detail, because
5708 * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
5709 * appear inside auto-generated sub-queries with very restricted
5710 * structure. However, DefineView might have modified the tlist by
5711 * injecting new column aliases, or we might have some other column
5712 * aliases forced by a resultDesc. We can only simplify if the RTE's
5713 * column names match the names that get_target_list() would select.
5714 */
5715 if (result)
5716 {
5717 ListCell *lcn;
5718 int colno;
5719
5720 if (list_length(query->targetList) != list_length(result->eref->colnames))
5721 return NULL; /* this probably cannot happen */
5722 colno = 0;
5723 forboth(lc, query->targetList, lcn, result->eref->colnames)
5724 {
5725 TargetEntry *tle = (TargetEntry *) lfirst(lc);
5726 char *cname = strVal(lfirst(lcn));
5727 char *colname;
5728
5729 if (tle->resjunk)
5730 return NULL; /* this probably cannot happen */
5731
5732 /* compute name that get_target_list would use for column */
5733 colno++;
5734 if (resultDesc && colno <= resultDesc->natts)
5735 colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
5736 else
5737 colname = tle->resname;
5738
5739 /* does it match the VALUES RTE? */
5740 if (colname == NULL || strcmp(colname, cname) != 0)
5741 return NULL; /* column name has been changed */
5742 }
5743 }
5744
5745 return result;
5746 }
5747
5748 static void
get_basic_select_query(Query * query,deparse_context * context,TupleDesc resultDesc)5749 get_basic_select_query(Query *query, deparse_context *context,
5750 TupleDesc resultDesc)
5751 {
5752 StringInfo buf = context->buf;
5753 RangeTblEntry *values_rte;
5754 char *sep;
5755 ListCell *l;
5756
5757 if (PRETTY_INDENT(context))
5758 {
5759 context->indentLevel += PRETTYINDENT_STD;
5760 appendStringInfoChar(buf, ' ');
5761 }
5762
5763 /*
5764 * If the query looks like SELECT * FROM (VALUES ...), then print just the
5765 * VALUES part. This reverses what transformValuesClause() did at parse
5766 * time.
5767 */
5768 values_rte = get_simple_values_rte(query, resultDesc);
5769 if (values_rte)
5770 {
5771 get_values_def(values_rte->values_lists, context);
5772 return;
5773 }
5774
5775 /*
5776 * Build up the query string - first we say SELECT
5777 */
5778 if (query->isReturn)
5779 appendStringInfoString(buf, "RETURN");
5780 else
5781 appendStringInfoString(buf, "SELECT");
5782
5783 /* Add the DISTINCT clause if given */
5784 if (query->distinctClause != NIL)
5785 {
5786 if (query->hasDistinctOn)
5787 {
5788 appendStringInfoString(buf, " DISTINCT ON (");
5789 sep = "";
5790 foreach(l, query->distinctClause)
5791 {
5792 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5793
5794 appendStringInfoString(buf, sep);
5795 get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList,
5796 false, context);
5797 sep = ", ";
5798 }
5799 appendStringInfoChar(buf, ')');
5800 }
5801 else
5802 appendStringInfoString(buf, " DISTINCT");
5803 }
5804
5805 /* Then we tell what to select (the targetlist) */
5806 get_target_list(query->targetList, context, resultDesc);
5807
5808 /* Add the FROM clause if needed */
5809 get_from_clause(query, " FROM ", context);
5810
5811 /* Add the WHERE clause if given */
5812 if (query->jointree->quals != NULL)
5813 {
5814 appendContextKeyword(context, " WHERE ",
5815 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5816 get_rule_expr(query->jointree->quals, context, false);
5817 }
5818
5819 /* Add the GROUP BY clause if given */
5820 if (query->groupClause != NULL || query->groupingSets != NULL)
5821 {
5822 ParseExprKind save_exprkind;
5823
5824 appendContextKeyword(context, " GROUP BY ",
5825 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5826 if (query->groupDistinct)
5827 appendStringInfoString(buf, "DISTINCT ");
5828
5829 save_exprkind = context->special_exprkind;
5830 context->special_exprkind = EXPR_KIND_GROUP_BY;
5831
5832 if (query->groupingSets == NIL)
5833 {
5834 sep = "";
5835 foreach(l, query->groupClause)
5836 {
5837 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
5838
5839 appendStringInfoString(buf, sep);
5840 get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList,
5841 false, context);
5842 sep = ", ";
5843 }
5844 }
5845 else
5846 {
5847 sep = "";
5848 foreach(l, query->groupingSets)
5849 {
5850 GroupingSet *grp = lfirst(l);
5851
5852 appendStringInfoString(buf, sep);
5853 get_rule_groupingset(grp, query->targetList, true, context);
5854 sep = ", ";
5855 }
5856 }
5857
5858 context->special_exprkind = save_exprkind;
5859 }
5860
5861 /* Add the HAVING clause if given */
5862 if (query->havingQual != NULL)
5863 {
5864 appendContextKeyword(context, " HAVING ",
5865 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5866 get_rule_expr(query->havingQual, context, false);
5867 }
5868
5869 /* Add the WINDOW clause if needed */
5870 if (query->windowClause != NIL)
5871 get_rule_windowclause(query, context);
5872 }
5873
5874 /* ----------
5875 * get_target_list - Parse back a SELECT target list
5876 *
5877 * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
5878 * ----------
5879 */
5880 static void
get_target_list(List * targetList,deparse_context * context,TupleDesc resultDesc)5881 get_target_list(List *targetList, deparse_context *context,
5882 TupleDesc resultDesc)
5883 {
5884 StringInfo buf = context->buf;
5885 StringInfoData targetbuf;
5886 bool last_was_multiline = false;
5887 char *sep;
5888 int colno;
5889 ListCell *l;
5890
5891 /* we use targetbuf to hold each TLE's text temporarily */
5892 initStringInfo(&targetbuf);
5893
5894 sep = " ";
5895 colno = 0;
5896 foreach(l, targetList)
5897 {
5898 TargetEntry *tle = (TargetEntry *) lfirst(l);
5899 char *colname;
5900 char *attname;
5901
5902 if (tle->resjunk)
5903 continue; /* ignore junk entries */
5904
5905 appendStringInfoString(buf, sep);
5906 sep = ", ";
5907 colno++;
5908
5909 /*
5910 * Put the new field text into targetbuf so we can decide after we've
5911 * got it whether or not it needs to go on a new line.
5912 */
5913 resetStringInfo(&targetbuf);
5914 context->buf = &targetbuf;
5915
5916 /*
5917 * We special-case Var nodes rather than using get_rule_expr. This is
5918 * needed because get_rule_expr will display a whole-row Var as
5919 * "foo.*", which is the preferred notation in most contexts, but at
5920 * the top level of a SELECT list it's not right (the parser will
5921 * expand that notation into multiple columns, yielding behavior
5922 * different from a whole-row Var). We need to call get_variable
5923 * directly so that we can tell it to do the right thing, and so that
5924 * we can get the attribute name which is the default AS label.
5925 */
5926 if (tle->expr && (IsA(tle->expr, Var)))
5927 {
5928 attname = get_variable((Var *) tle->expr, 0, true, context);
5929 }
5930 else
5931 {
5932 get_rule_expr((Node *) tle->expr, context, true);
5933 /* We'll show the AS name unless it's this: */
5934 attname = "?column?";
5935 }
5936
5937 /*
5938 * Figure out what the result column should be called. In the context
5939 * of a view, use the view's tuple descriptor (so as to pick up the
5940 * effects of any column RENAME that's been done on the view).
5941 * Otherwise, just use what we can find in the TLE.
5942 */
5943 if (resultDesc && colno <= resultDesc->natts)
5944 colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
5945 else
5946 colname = tle->resname;
5947
5948 /* Show AS unless the column's name is correct as-is */
5949 if (colname) /* resname could be NULL */
5950 {
5951 if (attname == NULL || strcmp(attname, colname) != 0)
5952 appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
5953 }
5954
5955 /* Restore context's output buffer */
5956 context->buf = buf;
5957
5958 /* Consider line-wrapping if enabled */
5959 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
5960 {
5961 int leading_nl_pos;
5962
5963 /* Does the new field start with a new line? */
5964 if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
5965 leading_nl_pos = 0;
5966 else
5967 leading_nl_pos = -1;
5968
5969 /* If so, we shouldn't add anything */
5970 if (leading_nl_pos >= 0)
5971 {
5972 /* instead, remove any trailing spaces currently in buf */
5973 removeStringInfoSpaces(buf);
5974 }
5975 else
5976 {
5977 char *trailing_nl;
5978
5979 /* Locate the start of the current line in the output buffer */
5980 trailing_nl = strrchr(buf->data, '\n');
5981 if (trailing_nl == NULL)
5982 trailing_nl = buf->data;
5983 else
5984 trailing_nl++;
5985
5986 /*
5987 * Add a newline, plus some indentation, if the new field is
5988 * not the first and either the new field would cause an
5989 * overflow or the last field used more than one line.
5990 */
5991 if (colno > 1 &&
5992 ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
5993 last_was_multiline))
5994 appendContextKeyword(context, "", -PRETTYINDENT_STD,
5995 PRETTYINDENT_STD, PRETTYINDENT_VAR);
5996 }
5997
5998 /* Remember this field's multiline status for next iteration */
5999 last_was_multiline =
6000 (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6001 }
6002
6003 /* Add the new field */
6004 appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
6005 }
6006
6007 /* clean up */
6008 pfree(targetbuf.data);
6009 }
6010
6011 static void
get_setop_query(Node * setOp,Query * query,deparse_context * context,TupleDesc resultDesc)6012 get_setop_query(Node *setOp, Query *query, deparse_context *context,
6013 TupleDesc resultDesc)
6014 {
6015 StringInfo buf = context->buf;
6016 bool need_paren;
6017
6018 /* Guard against excessively long or deeply-nested queries */
6019 CHECK_FOR_INTERRUPTS();
6020 check_stack_depth();
6021
6022 if (IsA(setOp, RangeTblRef))
6023 {
6024 RangeTblRef *rtr = (RangeTblRef *) setOp;
6025 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6026 Query *subquery = rte->subquery;
6027
6028 Assert(subquery != NULL);
6029 Assert(subquery->setOperations == NULL);
6030 /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
6031 need_paren = (subquery->cteList ||
6032 subquery->sortClause ||
6033 subquery->rowMarks ||
6034 subquery->limitOffset ||
6035 subquery->limitCount);
6036 if (need_paren)
6037 appendStringInfoChar(buf, '(');
6038 get_query_def(subquery, buf, context->namespaces, resultDesc,
6039 context->prettyFlags, context->wrapColumn,
6040 context->indentLevel);
6041 if (need_paren)
6042 appendStringInfoChar(buf, ')');
6043 }
6044 else if (IsA(setOp, SetOperationStmt))
6045 {
6046 SetOperationStmt *op = (SetOperationStmt *) setOp;
6047 int subindent;
6048
6049 /*
6050 * We force parens when nesting two SetOperationStmts, except when the
6051 * lefthand input is another setop of the same kind. Syntactically,
6052 * we could omit parens in rather more cases, but it seems best to use
6053 * parens to flag cases where the setop operator changes. If we use
6054 * parens, we also increase the indentation level for the child query.
6055 *
6056 * There are some cases in which parens are needed around a leaf query
6057 * too, but those are more easily handled at the next level down (see
6058 * code above).
6059 */
6060 if (IsA(op->larg, SetOperationStmt))
6061 {
6062 SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6063
6064 if (op->op == lop->op && op->all == lop->all)
6065 need_paren = false;
6066 else
6067 need_paren = true;
6068 }
6069 else
6070 need_paren = false;
6071
6072 if (need_paren)
6073 {
6074 appendStringInfoChar(buf, '(');
6075 subindent = PRETTYINDENT_STD;
6076 appendContextKeyword(context, "", subindent, 0, 0);
6077 }
6078 else
6079 subindent = 0;
6080
6081 get_setop_query(op->larg, query, context, resultDesc);
6082
6083 if (need_paren)
6084 appendContextKeyword(context, ") ", -subindent, 0, 0);
6085 else if (PRETTY_INDENT(context))
6086 appendContextKeyword(context, "", -subindent, 0, 0);
6087 else
6088 appendStringInfoChar(buf, ' ');
6089
6090 switch (op->op)
6091 {
6092 case SETOP_UNION:
6093 appendStringInfoString(buf, "UNION ");
6094 break;
6095 case SETOP_INTERSECT:
6096 appendStringInfoString(buf, "INTERSECT ");
6097 break;
6098 case SETOP_EXCEPT:
6099 appendStringInfoString(buf, "EXCEPT ");
6100 break;
6101 default:
6102 elog(ERROR, "unrecognized set op: %d",
6103 (int) op->op);
6104 }
6105 if (op->all)
6106 appendStringInfoString(buf, "ALL ");
6107
6108 /* Always parenthesize if RHS is another setop */
6109 need_paren = IsA(op->rarg, SetOperationStmt);
6110
6111 /*
6112 * The indentation code here is deliberately a bit different from that
6113 * for the lefthand input, because we want the line breaks in
6114 * different places.
6115 */
6116 if (need_paren)
6117 {
6118 appendStringInfoChar(buf, '(');
6119 subindent = PRETTYINDENT_STD;
6120 }
6121 else
6122 subindent = 0;
6123 appendContextKeyword(context, "", subindent, 0, 0);
6124
6125 get_setop_query(op->rarg, query, context, resultDesc);
6126
6127 if (PRETTY_INDENT(context))
6128 context->indentLevel -= subindent;
6129 if (need_paren)
6130 appendContextKeyword(context, ")", 0, 0, 0);
6131 }
6132 else
6133 {
6134 elog(ERROR, "unrecognized node type: %d",
6135 (int) nodeTag(setOp));
6136 }
6137 }
6138
6139 /*
6140 * Display a sort/group clause.
6141 *
6142 * Also returns the expression tree, so caller need not find it again.
6143 */
6144 static Node *
get_rule_sortgroupclause(Index ref,List * tlist,bool force_colno,deparse_context * context)6145 get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
6146 deparse_context *context)
6147 {
6148 StringInfo buf = context->buf;
6149 TargetEntry *tle;
6150 Node *expr;
6151
6152 tle = get_sortgroupref_tle(ref, tlist);
6153 expr = (Node *) tle->expr;
6154
6155 /*
6156 * Use column-number form if requested by caller. Otherwise, if
6157 * expression is a constant, force it to be dumped with an explicit cast
6158 * as decoration --- this is because a simple integer constant is
6159 * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
6160 * dump it without any decoration. If it's anything more complex than a
6161 * simple Var, then force extra parens around it, to ensure it can't be
6162 * misinterpreted as a cube() or rollup() construct.
6163 */
6164 if (force_colno)
6165 {
6166 Assert(!tle->resjunk);
6167 appendStringInfo(buf, "%d", tle->resno);
6168 }
6169 else if (expr && IsA(expr, Const))
6170 get_const_expr((Const *) expr, context, 1);
6171 else if (!expr || IsA(expr, Var))
6172 get_rule_expr(expr, context, true);
6173 else
6174 {
6175 /*
6176 * We must force parens for function-like expressions even if
6177 * PRETTY_PAREN is off, since those are the ones in danger of
6178 * misparsing. For other expressions we need to force them only if
6179 * PRETTY_PAREN is on, since otherwise the expression will output them
6180 * itself. (We can't skip the parens.)
6181 */
6182 bool need_paren = (PRETTY_PAREN(context)
6183 || IsA(expr, FuncExpr)
6184 || IsA(expr, Aggref)
6185 || IsA(expr, WindowFunc));
6186
6187 if (need_paren)
6188 appendStringInfoChar(context->buf, '(');
6189 get_rule_expr(expr, context, true);
6190 if (need_paren)
6191 appendStringInfoChar(context->buf, ')');
6192 }
6193
6194 return expr;
6195 }
6196
6197 /*
6198 * Display a GroupingSet
6199 */
6200 static void
get_rule_groupingset(GroupingSet * gset,List * targetlist,bool omit_parens,deparse_context * context)6201 get_rule_groupingset(GroupingSet *gset, List *targetlist,
6202 bool omit_parens, deparse_context *context)
6203 {
6204 ListCell *l;
6205 StringInfo buf = context->buf;
6206 bool omit_child_parens = true;
6207 char *sep = "";
6208
6209 switch (gset->kind)
6210 {
6211 case GROUPING_SET_EMPTY:
6212 appendStringInfoString(buf, "()");
6213 return;
6214
6215 case GROUPING_SET_SIMPLE:
6216 {
6217 if (!omit_parens || list_length(gset->content) != 1)
6218 appendStringInfoChar(buf, '(');
6219
6220 foreach(l, gset->content)
6221 {
6222 Index ref = lfirst_int(l);
6223
6224 appendStringInfoString(buf, sep);
6225 get_rule_sortgroupclause(ref, targetlist,
6226 false, context);
6227 sep = ", ";
6228 }
6229
6230 if (!omit_parens || list_length(gset->content) != 1)
6231 appendStringInfoChar(buf, ')');
6232 }
6233 return;
6234
6235 case GROUPING_SET_ROLLUP:
6236 appendStringInfoString(buf, "ROLLUP(");
6237 break;
6238 case GROUPING_SET_CUBE:
6239 appendStringInfoString(buf, "CUBE(");
6240 break;
6241 case GROUPING_SET_SETS:
6242 appendStringInfoString(buf, "GROUPING SETS (");
6243 omit_child_parens = false;
6244 break;
6245 }
6246
6247 foreach(l, gset->content)
6248 {
6249 appendStringInfoString(buf, sep);
6250 get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6251 sep = ", ";
6252 }
6253
6254 appendStringInfoChar(buf, ')');
6255 }
6256
6257 /*
6258 * Display an ORDER BY list.
6259 */
6260 static void
get_rule_orderby(List * orderList,List * targetList,bool force_colno,deparse_context * context)6261 get_rule_orderby(List *orderList, List *targetList,
6262 bool force_colno, deparse_context *context)
6263 {
6264 StringInfo buf = context->buf;
6265 const char *sep;
6266 ListCell *l;
6267
6268 sep = "";
6269 foreach(l, orderList)
6270 {
6271 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6272 Node *sortexpr;
6273 Oid sortcoltype;
6274 TypeCacheEntry *typentry;
6275
6276 appendStringInfoString(buf, sep);
6277 sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6278 force_colno, context);
6279 sortcoltype = exprType(sortexpr);
6280 /* See whether operator is default < or > for datatype */
6281 typentry = lookup_type_cache(sortcoltype,
6282 TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
6283 if (srt->sortop == typentry->lt_opr)
6284 {
6285 /* ASC is default, so emit nothing for it */
6286 if (srt->nulls_first)
6287 appendStringInfoString(buf, " NULLS FIRST");
6288 }
6289 else if (srt->sortop == typentry->gt_opr)
6290 {
6291 appendStringInfoString(buf, " DESC");
6292 /* DESC defaults to NULLS FIRST */
6293 if (!srt->nulls_first)
6294 appendStringInfoString(buf, " NULLS LAST");
6295 }
6296 else
6297 {
6298 appendStringInfo(buf, " USING %s",
6299 generate_operator_name(srt->sortop,
6300 sortcoltype,
6301 sortcoltype));
6302 /* be specific to eliminate ambiguity */
6303 if (srt->nulls_first)
6304 appendStringInfoString(buf, " NULLS FIRST");
6305 else
6306 appendStringInfoString(buf, " NULLS LAST");
6307 }
6308 sep = ", ";
6309 }
6310 }
6311
6312 /*
6313 * Display a WINDOW clause.
6314 *
6315 * Note that the windowClause list might contain only anonymous window
6316 * specifications, in which case we should print nothing here.
6317 */
6318 static void
get_rule_windowclause(Query * query,deparse_context * context)6319 get_rule_windowclause(Query *query, deparse_context *context)
6320 {
6321 StringInfo buf = context->buf;
6322 const char *sep;
6323 ListCell *l;
6324
6325 sep = NULL;
6326 foreach(l, query->windowClause)
6327 {
6328 WindowClause *wc = (WindowClause *) lfirst(l);
6329
6330 if (wc->name == NULL)
6331 continue; /* ignore anonymous windows */
6332
6333 if (sep == NULL)
6334 appendContextKeyword(context, " WINDOW ",
6335 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6336 else
6337 appendStringInfoString(buf, sep);
6338
6339 appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6340
6341 get_rule_windowspec(wc, query->targetList, context);
6342
6343 sep = ", ";
6344 }
6345 }
6346
6347 /*
6348 * Display a window definition
6349 */
6350 static void
get_rule_windowspec(WindowClause * wc,List * targetList,deparse_context * context)6351 get_rule_windowspec(WindowClause *wc, List *targetList,
6352 deparse_context *context)
6353 {
6354 StringInfo buf = context->buf;
6355 bool needspace = false;
6356 const char *sep;
6357 ListCell *l;
6358
6359 appendStringInfoChar(buf, '(');
6360 if (wc->refname)
6361 {
6362 appendStringInfoString(buf, quote_identifier(wc->refname));
6363 needspace = true;
6364 }
6365 /* partition clauses are always inherited, so only print if no refname */
6366 if (wc->partitionClause && !wc->refname)
6367 {
6368 if (needspace)
6369 appendStringInfoChar(buf, ' ');
6370 appendStringInfoString(buf, "PARTITION BY ");
6371 sep = "";
6372 foreach(l, wc->partitionClause)
6373 {
6374 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6375
6376 appendStringInfoString(buf, sep);
6377 get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
6378 false, context);
6379 sep = ", ";
6380 }
6381 needspace = true;
6382 }
6383 /* print ordering clause only if not inherited */
6384 if (wc->orderClause && !wc->copiedOrder)
6385 {
6386 if (needspace)
6387 appendStringInfoChar(buf, ' ');
6388 appendStringInfoString(buf, "ORDER BY ");
6389 get_rule_orderby(wc->orderClause, targetList, false, context);
6390 needspace = true;
6391 }
6392 /* framing clause is never inherited, so print unless it's default */
6393 if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
6394 {
6395 if (needspace)
6396 appendStringInfoChar(buf, ' ');
6397 if (wc->frameOptions & FRAMEOPTION_RANGE)
6398 appendStringInfoString(buf, "RANGE ");
6399 else if (wc->frameOptions & FRAMEOPTION_ROWS)
6400 appendStringInfoString(buf, "ROWS ");
6401 else if (wc->frameOptions & FRAMEOPTION_GROUPS)
6402 appendStringInfoString(buf, "GROUPS ");
6403 else
6404 Assert(false);
6405 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
6406 appendStringInfoString(buf, "BETWEEN ");
6407 if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
6408 appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
6409 else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
6410 appendStringInfoString(buf, "CURRENT ROW ");
6411 else if (wc->frameOptions & FRAMEOPTION_START_OFFSET)
6412 {
6413 get_rule_expr(wc->startOffset, context, false);
6414 if (wc->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
6415 appendStringInfoString(buf, " PRECEDING ");
6416 else if (wc->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
6417 appendStringInfoString(buf, " FOLLOWING ");
6418 else
6419 Assert(false);
6420 }
6421 else
6422 Assert(false);
6423 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
6424 {
6425 appendStringInfoString(buf, "AND ");
6426 if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
6427 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
6428 else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
6429 appendStringInfoString(buf, "CURRENT ROW ");
6430 else if (wc->frameOptions & FRAMEOPTION_END_OFFSET)
6431 {
6432 get_rule_expr(wc->endOffset, context, false);
6433 if (wc->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
6434 appendStringInfoString(buf, " PRECEDING ");
6435 else if (wc->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
6436 appendStringInfoString(buf, " FOLLOWING ");
6437 else
6438 Assert(false);
6439 }
6440 else
6441 Assert(false);
6442 }
6443 if (wc->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
6444 appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6445 else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6446 appendStringInfoString(buf, "EXCLUDE GROUP ");
6447 else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
6448 appendStringInfoString(buf, "EXCLUDE TIES ");
6449 /* we will now have a trailing space; remove it */
6450 buf->len--;
6451 }
6452 appendStringInfoChar(buf, ')');
6453 }
6454
6455 /* ----------
6456 * get_insert_query_def - Parse back an INSERT parsetree
6457 * ----------
6458 */
6459 static void
get_insert_query_def(Query * query,deparse_context * context)6460 get_insert_query_def(Query *query, deparse_context *context)
6461 {
6462 StringInfo buf = context->buf;
6463 RangeTblEntry *select_rte = NULL;
6464 RangeTblEntry *values_rte = NULL;
6465 RangeTblEntry *rte;
6466 char *sep;
6467 ListCell *l;
6468 List *strippedexprs;
6469
6470 /* Insert the WITH clause if given */
6471 get_with_clause(query, context);
6472
6473 /*
6474 * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6475 * single RTE for the SELECT or VALUES. Plain VALUES has neither.
6476 */
6477 foreach(l, query->rtable)
6478 {
6479 rte = (RangeTblEntry *) lfirst(l);
6480
6481 if (rte->rtekind == RTE_SUBQUERY)
6482 {
6483 if (select_rte)
6484 elog(ERROR, "too many subquery RTEs in INSERT");
6485 select_rte = rte;
6486 }
6487
6488 if (rte->rtekind == RTE_VALUES)
6489 {
6490 if (values_rte)
6491 elog(ERROR, "too many values RTEs in INSERT");
6492 values_rte = rte;
6493 }
6494 }
6495 if (select_rte && values_rte)
6496 elog(ERROR, "both subquery and values RTEs in INSERT");
6497
6498 /*
6499 * Start the query with INSERT INTO relname
6500 */
6501 rte = rt_fetch(query->resultRelation, query->rtable);
6502 Assert(rte->rtekind == RTE_RELATION);
6503
6504 if (PRETTY_INDENT(context))
6505 {
6506 context->indentLevel += PRETTYINDENT_STD;
6507 appendStringInfoChar(buf, ' ');
6508 }
6509 appendStringInfo(buf, "INSERT INTO %s ",
6510 generate_relation_name(rte->relid, NIL));
6511 /* INSERT requires AS keyword for target alias */
6512 if (rte->alias != NULL)
6513 appendStringInfo(buf, "AS %s ",
6514 quote_identifier(rte->alias->aliasname));
6515
6516 /*
6517 * Add the insert-column-names list. Any indirection decoration needed on
6518 * the column names can be inferred from the top targetlist.
6519 */
6520 strippedexprs = NIL;
6521 sep = "";
6522 if (query->targetList)
6523 appendStringInfoChar(buf, '(');
6524 foreach(l, query->targetList)
6525 {
6526 TargetEntry *tle = (TargetEntry *) lfirst(l);
6527
6528 if (tle->resjunk)
6529 continue; /* ignore junk entries */
6530
6531 appendStringInfoString(buf, sep);
6532 sep = ", ";
6533
6534 /*
6535 * Put out name of target column; look in the catalogs, not at
6536 * tle->resname, since resname will fail to track RENAME.
6537 */
6538 appendStringInfoString(buf,
6539 quote_identifier(get_attname(rte->relid,
6540 tle->resno,
6541 false)));
6542
6543 /*
6544 * Print any indirection needed (subfields or subscripts), and strip
6545 * off the top-level nodes representing the indirection assignments.
6546 * Add the stripped expressions to strippedexprs. (If it's a
6547 * single-VALUES statement, the stripped expressions are the VALUES to
6548 * print below. Otherwise they're just Vars and not really
6549 * interesting.)
6550 */
6551 strippedexprs = lappend(strippedexprs,
6552 processIndirection((Node *) tle->expr,
6553 context));
6554 }
6555 if (query->targetList)
6556 appendStringInfoString(buf, ") ");
6557
6558 if (query->override)
6559 {
6560 if (query->override == OVERRIDING_SYSTEM_VALUE)
6561 appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
6562 else if (query->override == OVERRIDING_USER_VALUE)
6563 appendStringInfoString(buf, "OVERRIDING USER VALUE ");
6564 }
6565
6566 if (select_rte)
6567 {
6568 /* Add the SELECT */
6569 get_query_def(select_rte->subquery, buf, NIL, NULL,
6570 context->prettyFlags, context->wrapColumn,
6571 context->indentLevel);
6572 }
6573 else if (values_rte)
6574 {
6575 /* Add the multi-VALUES expression lists */
6576 get_values_def(values_rte->values_lists, context);
6577 }
6578 else if (strippedexprs)
6579 {
6580 /* Add the single-VALUES expression list */
6581 appendContextKeyword(context, "VALUES (",
6582 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
6583 get_rule_expr((Node *) strippedexprs, context, false);
6584 appendStringInfoChar(buf, ')');
6585 }
6586 else
6587 {
6588 /* No expressions, so it must be DEFAULT VALUES */
6589 appendStringInfoString(buf, "DEFAULT VALUES");
6590 }
6591
6592 /* Add ON CONFLICT if present */
6593 if (query->onConflict)
6594 {
6595 OnConflictExpr *confl = query->onConflict;
6596
6597 appendStringInfoString(buf, " ON CONFLICT");
6598
6599 if (confl->arbiterElems)
6600 {
6601 /* Add the single-VALUES expression list */
6602 appendStringInfoChar(buf, '(');
6603 get_rule_expr((Node *) confl->arbiterElems, context, false);
6604 appendStringInfoChar(buf, ')');
6605
6606 /* Add a WHERE clause (for partial indexes) if given */
6607 if (confl->arbiterWhere != NULL)
6608 {
6609 bool save_varprefix;
6610
6611 /*
6612 * Force non-prefixing of Vars, since parser assumes that they
6613 * belong to target relation. WHERE clause does not use
6614 * InferenceElem, so this is separately required.
6615 */
6616 save_varprefix = context->varprefix;
6617 context->varprefix = false;
6618
6619 appendContextKeyword(context, " WHERE ",
6620 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6621 get_rule_expr(confl->arbiterWhere, context, false);
6622
6623 context->varprefix = save_varprefix;
6624 }
6625 }
6626 else if (OidIsValid(confl->constraint))
6627 {
6628 char *constraint = get_constraint_name(confl->constraint);
6629
6630 if (!constraint)
6631 elog(ERROR, "cache lookup failed for constraint %u",
6632 confl->constraint);
6633 appendStringInfo(buf, " ON CONSTRAINT %s",
6634 quote_identifier(constraint));
6635 }
6636
6637 if (confl->action == ONCONFLICT_NOTHING)
6638 {
6639 appendStringInfoString(buf, " DO NOTHING");
6640 }
6641 else
6642 {
6643 appendStringInfoString(buf, " DO UPDATE SET ");
6644 /* Deparse targetlist */
6645 get_update_query_targetlist_def(query, confl->onConflictSet,
6646 context, rte);
6647
6648 /* Add a WHERE clause if given */
6649 if (confl->onConflictWhere != NULL)
6650 {
6651 appendContextKeyword(context, " WHERE ",
6652 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6653 get_rule_expr(confl->onConflictWhere, context, false);
6654 }
6655 }
6656 }
6657
6658 /* Add RETURNING if present */
6659 if (query->returningList)
6660 {
6661 appendContextKeyword(context, " RETURNING",
6662 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6663 get_target_list(query->returningList, context, NULL);
6664 }
6665 }
6666
6667
6668 /* ----------
6669 * get_update_query_def - Parse back an UPDATE parsetree
6670 * ----------
6671 */
6672 static void
get_update_query_def(Query * query,deparse_context * context)6673 get_update_query_def(Query *query, deparse_context *context)
6674 {
6675 StringInfo buf = context->buf;
6676 RangeTblEntry *rte;
6677
6678 /* Insert the WITH clause if given */
6679 get_with_clause(query, context);
6680
6681 /*
6682 * Start the query with UPDATE relname SET
6683 */
6684 rte = rt_fetch(query->resultRelation, query->rtable);
6685 Assert(rte->rtekind == RTE_RELATION);
6686 if (PRETTY_INDENT(context))
6687 {
6688 appendStringInfoChar(buf, ' ');
6689 context->indentLevel += PRETTYINDENT_STD;
6690 }
6691 appendStringInfo(buf, "UPDATE %s%s",
6692 only_marker(rte),
6693 generate_relation_name(rte->relid, NIL));
6694 if (rte->alias != NULL)
6695 appendStringInfo(buf, " %s",
6696 quote_identifier(rte->alias->aliasname));
6697 appendStringInfoString(buf, " SET ");
6698
6699 /* Deparse targetlist */
6700 get_update_query_targetlist_def(query, query->targetList, context, rte);
6701
6702 /* Add the FROM clause if needed */
6703 get_from_clause(query, " FROM ", context);
6704
6705 /* Add a WHERE clause if given */
6706 if (query->jointree->quals != NULL)
6707 {
6708 appendContextKeyword(context, " WHERE ",
6709 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6710 get_rule_expr(query->jointree->quals, context, false);
6711 }
6712
6713 /* Add RETURNING if present */
6714 if (query->returningList)
6715 {
6716 appendContextKeyword(context, " RETURNING",
6717 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6718 get_target_list(query->returningList, context, NULL);
6719 }
6720 }
6721
6722
6723 /* ----------
6724 * get_update_query_targetlist_def - Parse back an UPDATE targetlist
6725 * ----------
6726 */
6727 static void
get_update_query_targetlist_def(Query * query,List * targetList,deparse_context * context,RangeTblEntry * rte)6728 get_update_query_targetlist_def(Query *query, List *targetList,
6729 deparse_context *context, RangeTblEntry *rte)
6730 {
6731 StringInfo buf = context->buf;
6732 ListCell *l;
6733 ListCell *next_ma_cell;
6734 int remaining_ma_columns;
6735 const char *sep;
6736 SubLink *cur_ma_sublink;
6737 List *ma_sublinks;
6738
6739 /*
6740 * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
6741 * into a list. We expect them to appear, in ID order, in resjunk tlist
6742 * entries.
6743 */
6744 ma_sublinks = NIL;
6745 if (query->hasSubLinks) /* else there can't be any */
6746 {
6747 foreach(l, targetList)
6748 {
6749 TargetEntry *tle = (TargetEntry *) lfirst(l);
6750
6751 if (tle->resjunk && IsA(tle->expr, SubLink))
6752 {
6753 SubLink *sl = (SubLink *) tle->expr;
6754
6755 if (sl->subLinkType == MULTIEXPR_SUBLINK)
6756 {
6757 ma_sublinks = lappend(ma_sublinks, sl);
6758 Assert(sl->subLinkId == list_length(ma_sublinks));
6759 }
6760 }
6761 }
6762 }
6763 next_ma_cell = list_head(ma_sublinks);
6764 cur_ma_sublink = NULL;
6765 remaining_ma_columns = 0;
6766
6767 /* Add the comma separated list of 'attname = value' */
6768 sep = "";
6769 foreach(l, targetList)
6770 {
6771 TargetEntry *tle = (TargetEntry *) lfirst(l);
6772 Node *expr;
6773
6774 if (tle->resjunk)
6775 continue; /* ignore junk entries */
6776
6777 /* Emit separator (OK whether we're in multiassignment or not) */
6778 appendStringInfoString(buf, sep);
6779 sep = ", ";
6780
6781 /*
6782 * Check to see if we're starting a multiassignment group: if so,
6783 * output a left paren.
6784 */
6785 if (next_ma_cell != NULL && cur_ma_sublink == NULL)
6786 {
6787 /*
6788 * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
6789 * Param. That could be buried under FieldStores and
6790 * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
6791 * and underneath those there could be an implicit type coercion.
6792 * Because we would ignore implicit type coercions anyway, we
6793 * don't need to be as careful as processIndirection() is about
6794 * descending past implicit CoerceToDomains.
6795 */
6796 expr = (Node *) tle->expr;
6797 while (expr)
6798 {
6799 if (IsA(expr, FieldStore))
6800 {
6801 FieldStore *fstore = (FieldStore *) expr;
6802
6803 expr = (Node *) linitial(fstore->newvals);
6804 }
6805 else if (IsA(expr, SubscriptingRef))
6806 {
6807 SubscriptingRef *sbsref = (SubscriptingRef *) expr;
6808
6809 if (sbsref->refassgnexpr == NULL)
6810 break;
6811
6812 expr = (Node *) sbsref->refassgnexpr;
6813 }
6814 else if (IsA(expr, CoerceToDomain))
6815 {
6816 CoerceToDomain *cdomain = (CoerceToDomain *) expr;
6817
6818 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
6819 break;
6820 expr = (Node *) cdomain->arg;
6821 }
6822 else
6823 break;
6824 }
6825 expr = strip_implicit_coercions(expr);
6826
6827 if (expr && IsA(expr, Param) &&
6828 ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
6829 {
6830 cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
6831 next_ma_cell = lnext(ma_sublinks, next_ma_cell);
6832 remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
6833 Assert(((Param *) expr)->paramid ==
6834 ((cur_ma_sublink->subLinkId << 16) | 1));
6835 appendStringInfoChar(buf, '(');
6836 }
6837 }
6838
6839 /*
6840 * Put out name of target column; look in the catalogs, not at
6841 * tle->resname, since resname will fail to track RENAME.
6842 */
6843 appendStringInfoString(buf,
6844 quote_identifier(get_attname(rte->relid,
6845 tle->resno,
6846 false)));
6847
6848 /*
6849 * Print any indirection needed (subfields or subscripts), and strip
6850 * off the top-level nodes representing the indirection assignments.
6851 */
6852 expr = processIndirection((Node *) tle->expr, context);
6853
6854 /*
6855 * If we're in a multiassignment, skip printing anything more, unless
6856 * this is the last column; in which case, what we print should be the
6857 * sublink, not the Param.
6858 */
6859 if (cur_ma_sublink != NULL)
6860 {
6861 if (--remaining_ma_columns > 0)
6862 continue; /* not the last column of multiassignment */
6863 appendStringInfoChar(buf, ')');
6864 expr = (Node *) cur_ma_sublink;
6865 cur_ma_sublink = NULL;
6866 }
6867
6868 appendStringInfoString(buf, " = ");
6869
6870 get_rule_expr(expr, context, false);
6871 }
6872 }
6873
6874
6875 /* ----------
6876 * get_delete_query_def - Parse back a DELETE parsetree
6877 * ----------
6878 */
6879 static void
get_delete_query_def(Query * query,deparse_context * context)6880 get_delete_query_def(Query *query, deparse_context *context)
6881 {
6882 StringInfo buf = context->buf;
6883 RangeTblEntry *rte;
6884
6885 /* Insert the WITH clause if given */
6886 get_with_clause(query, context);
6887
6888 /*
6889 * Start the query with DELETE FROM relname
6890 */
6891 rte = rt_fetch(query->resultRelation, query->rtable);
6892 Assert(rte->rtekind == RTE_RELATION);
6893 if (PRETTY_INDENT(context))
6894 {
6895 appendStringInfoChar(buf, ' ');
6896 context->indentLevel += PRETTYINDENT_STD;
6897 }
6898 appendStringInfo(buf, "DELETE FROM %s%s",
6899 only_marker(rte),
6900 generate_relation_name(rte->relid, NIL));
6901 if (rte->alias != NULL)
6902 appendStringInfo(buf, " %s",
6903 quote_identifier(rte->alias->aliasname));
6904
6905 /* Add the USING clause if given */
6906 get_from_clause(query, " USING ", context);
6907
6908 /* Add a WHERE clause if given */
6909 if (query->jointree->quals != NULL)
6910 {
6911 appendContextKeyword(context, " WHERE ",
6912 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6913 get_rule_expr(query->jointree->quals, context, false);
6914 }
6915
6916 /* Add RETURNING if present */
6917 if (query->returningList)
6918 {
6919 appendContextKeyword(context, " RETURNING",
6920 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6921 get_target_list(query->returningList, context, NULL);
6922 }
6923 }
6924
6925
6926 /* ----------
6927 * get_utility_query_def - Parse back a UTILITY parsetree
6928 * ----------
6929 */
6930 static void
get_utility_query_def(Query * query,deparse_context * context)6931 get_utility_query_def(Query *query, deparse_context *context)
6932 {
6933 StringInfo buf = context->buf;
6934
6935 if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
6936 {
6937 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
6938
6939 appendContextKeyword(context, "",
6940 0, PRETTYINDENT_STD, 1);
6941 appendStringInfo(buf, "NOTIFY %s",
6942 quote_identifier(stmt->conditionname));
6943 if (stmt->payload)
6944 {
6945 appendStringInfoString(buf, ", ");
6946 simple_quote_literal(buf, stmt->payload);
6947 }
6948 }
6949 else
6950 {
6951 /* Currently only NOTIFY utility commands can appear in rules */
6952 elog(ERROR, "unexpected utility statement type");
6953 }
6954 }
6955
6956 /*
6957 * Display a Var appropriately.
6958 *
6959 * In some cases (currently only when recursing into an unnamed join)
6960 * the Var's varlevelsup has to be interpreted with respect to a context
6961 * above the current one; levelsup indicates the offset.
6962 *
6963 * If istoplevel is true, the Var is at the top level of a SELECT's
6964 * targetlist, which means we need special treatment of whole-row Vars.
6965 * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
6966 * dirty hack to prevent "tab.*" from being expanded into multiple columns.
6967 * (The parser will strip the useless coercion, so no inefficiency is added in
6968 * dump and reload.) We used to print just "tab" in such cases, but that is
6969 * ambiguous and will yield the wrong result if "tab" is also a plain column
6970 * name in the query.
6971 *
6972 * Returns the attname of the Var, or NULL if the Var has no attname (because
6973 * it is a whole-row Var or a subplan output reference).
6974 */
6975 static char *
get_variable(Var * var,int levelsup,bool istoplevel,deparse_context * context)6976 get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
6977 {
6978 StringInfo buf = context->buf;
6979 RangeTblEntry *rte;
6980 AttrNumber attnum;
6981 int netlevelsup;
6982 deparse_namespace *dpns;
6983 Index varno;
6984 AttrNumber varattno;
6985 deparse_columns *colinfo;
6986 char *refname;
6987 char *attname;
6988
6989 /* Find appropriate nesting depth */
6990 netlevelsup = var->varlevelsup + levelsup;
6991 if (netlevelsup >= list_length(context->namespaces))
6992 elog(ERROR, "bogus varlevelsup: %d offset %d",
6993 var->varlevelsup, levelsup);
6994 dpns = (deparse_namespace *) list_nth(context->namespaces,
6995 netlevelsup);
6996
6997 /*
6998 * If we have a syntactic referent for the Var, and we're working from a
6999 * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7000 * on the semantic referent. (Forcing use of the semantic referent when
7001 * printing plan trees is a design choice that's perhaps more motivated by
7002 * backwards compatibility than anything else. But it does have the
7003 * advantage of making plans more explicit.)
7004 */
7005 if (var->varnosyn > 0 && dpns->plan == NULL)
7006 {
7007 varno = var->varnosyn;
7008 varattno = var->varattnosyn;
7009 }
7010 else
7011 {
7012 varno = var->varno;
7013 varattno = var->varattno;
7014 }
7015
7016 /*
7017 * Try to find the relevant RTE in this rtable. In a plan tree, it's
7018 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7019 * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7020 * find the aliases previously assigned for this RTE.
7021 */
7022 if (varno >= 1 && varno <= list_length(dpns->rtable))
7023 {
7024 /*
7025 * We might have been asked to map child Vars to some parent relation.
7026 */
7027 if (context->appendparents && dpns->appendrels)
7028 {
7029 Index pvarno = varno;
7030 AttrNumber pvarattno = varattno;
7031 AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7032 bool found = false;
7033
7034 /* Only map up to inheritance parents, not UNION ALL appendrels */
7035 while (appinfo &&
7036 rt_fetch(appinfo->parent_relid,
7037 dpns->rtable)->rtekind == RTE_RELATION)
7038 {
7039 found = false;
7040 if (pvarattno > 0) /* system columns stay as-is */
7041 {
7042 if (pvarattno > appinfo->num_child_cols)
7043 break; /* safety check */
7044 pvarattno = appinfo->parent_colnos[pvarattno - 1];
7045 if (pvarattno == 0)
7046 break; /* Var is local to child */
7047 }
7048
7049 pvarno = appinfo->parent_relid;
7050 found = true;
7051
7052 /* If the parent is itself a child, continue up. */
7053 Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7054 appinfo = dpns->appendrels[pvarno];
7055 }
7056
7057 /*
7058 * If we found an ancestral rel, and that rel is included in
7059 * appendparents, print that column not the original one.
7060 */
7061 if (found && bms_is_member(pvarno, context->appendparents))
7062 {
7063 varno = pvarno;
7064 varattno = pvarattno;
7065 }
7066 }
7067
7068 rte = rt_fetch(varno, dpns->rtable);
7069 refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7070 colinfo = deparse_columns_fetch(varno, dpns);
7071 attnum = varattno;
7072 }
7073 else
7074 {
7075 resolve_special_varno((Node *) var, context,
7076 get_special_variable, NULL);
7077 return NULL;
7078 }
7079
7080 /*
7081 * The planner will sometimes emit Vars referencing resjunk elements of a
7082 * subquery's target list (this is currently only possible if it chooses
7083 * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7084 * Although we prefer to print subquery-referencing Vars using the
7085 * subquery's alias, that's not possible for resjunk items since they have
7086 * no alias. So in that case, drill down to the subplan and print the
7087 * contents of the referenced tlist item. This works because in a plan
7088 * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
7089 * we'll have set dpns->inner_plan to reference the child plan node.
7090 */
7091 if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7092 attnum > list_length(rte->eref->colnames) &&
7093 dpns->inner_plan)
7094 {
7095 TargetEntry *tle;
7096 deparse_namespace save_dpns;
7097
7098 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7099 if (!tle)
7100 elog(ERROR, "invalid attnum %d for relation \"%s\"",
7101 attnum, rte->eref->aliasname);
7102
7103 Assert(netlevelsup == 0);
7104 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7105
7106 /*
7107 * Force parentheses because our caller probably assumed a Var is a
7108 * simple expression.
7109 */
7110 if (!IsA(tle->expr, Var))
7111 appendStringInfoChar(buf, '(');
7112 get_rule_expr((Node *) tle->expr, context, true);
7113 if (!IsA(tle->expr, Var))
7114 appendStringInfoChar(buf, ')');
7115
7116 pop_child_plan(dpns, &save_dpns);
7117 return NULL;
7118 }
7119
7120 /*
7121 * If it's an unnamed join, look at the expansion of the alias variable.
7122 * If it's a simple reference to one of the input vars, then recursively
7123 * print the name of that var instead. When it's not a simple reference,
7124 * we have to just print the unqualified join column name. (This can only
7125 * happen with "dangerous" merged columns in a JOIN USING; we took pains
7126 * previously to make the unqualified column name unique in such cases.)
7127 *
7128 * This wouldn't work in decompiling plan trees, because we don't store
7129 * joinaliasvars lists after planning; but a plan tree should never
7130 * contain a join alias variable.
7131 */
7132 if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7133 {
7134 if (rte->joinaliasvars == NIL)
7135 elog(ERROR, "cannot decompile join alias var in plan tree");
7136 if (attnum > 0)
7137 {
7138 Var *aliasvar;
7139
7140 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7141 /* we intentionally don't strip implicit coercions here */
7142 if (aliasvar && IsA(aliasvar, Var))
7143 {
7144 return get_variable(aliasvar, var->varlevelsup + levelsup,
7145 istoplevel, context);
7146 }
7147 }
7148
7149 /*
7150 * Unnamed join has no refname. (Note: since it's unnamed, there is
7151 * no way the user could have referenced it to create a whole-row Var
7152 * for it. So we don't have to cover that case below.)
7153 */
7154 Assert(refname == NULL);
7155 }
7156
7157 if (attnum == InvalidAttrNumber)
7158 attname = NULL;
7159 else if (attnum > 0)
7160 {
7161 /* Get column name to use from the colinfo struct */
7162 if (attnum > colinfo->num_cols)
7163 elog(ERROR, "invalid attnum %d for relation \"%s\"",
7164 attnum, rte->eref->aliasname);
7165 attname = colinfo->colnames[attnum - 1];
7166 if (attname == NULL) /* dropped column? */
7167 elog(ERROR, "invalid attnum %d for relation \"%s\"",
7168 attnum, rte->eref->aliasname);
7169 }
7170 else
7171 {
7172 /* System column - name is fixed, get it from the catalog */
7173 attname = get_rte_attribute_name(rte, attnum);
7174 }
7175
7176 if (refname && (context->varprefix || attname == NULL))
7177 {
7178 appendStringInfoString(buf, quote_identifier(refname));
7179 appendStringInfoChar(buf, '.');
7180 }
7181 if (attname)
7182 appendStringInfoString(buf, quote_identifier(attname));
7183 else
7184 {
7185 appendStringInfoChar(buf, '*');
7186 if (istoplevel)
7187 appendStringInfo(buf, "::%s",
7188 format_type_with_typemod(var->vartype,
7189 var->vartypmod));
7190 }
7191
7192 return attname;
7193 }
7194
7195 /*
7196 * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
7197 * routine is actually a callback for resolve_special_varno, which handles
7198 * finding the correct TargetEntry. We get the expression contained in that
7199 * TargetEntry and just need to deparse it, a job we can throw back on
7200 * get_rule_expr.
7201 */
7202 static void
get_special_variable(Node * node,deparse_context * context,void * callback_arg)7203 get_special_variable(Node *node, deparse_context *context, void *callback_arg)
7204 {
7205 StringInfo buf = context->buf;
7206
7207 /*
7208 * For a non-Var referent, force parentheses because our caller probably
7209 * assumed a Var is a simple expression.
7210 */
7211 if (!IsA(node, Var))
7212 appendStringInfoChar(buf, '(');
7213 get_rule_expr(node, context, true);
7214 if (!IsA(node, Var))
7215 appendStringInfoChar(buf, ')');
7216 }
7217
7218 /*
7219 * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
7220 * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
7221 * invoke the callback provided.
7222 */
7223 static void
resolve_special_varno(Node * node,deparse_context * context,rsv_callback callback,void * callback_arg)7224 resolve_special_varno(Node *node, deparse_context *context,
7225 rsv_callback callback, void *callback_arg)
7226 {
7227 Var *var;
7228 deparse_namespace *dpns;
7229
7230 /* This function is recursive, so let's be paranoid. */
7231 check_stack_depth();
7232
7233 /* If it's not a Var, invoke the callback. */
7234 if (!IsA(node, Var))
7235 {
7236 (*callback) (node, context, callback_arg);
7237 return;
7238 }
7239
7240 /* Find appropriate nesting depth */
7241 var = (Var *) node;
7242 dpns = (deparse_namespace *) list_nth(context->namespaces,
7243 var->varlevelsup);
7244
7245 /*
7246 * If varno is special, recurse. (Don't worry about varnosyn; if we're
7247 * here, we already decided not to use that.)
7248 */
7249 if (var->varno == OUTER_VAR && dpns->outer_tlist)
7250 {
7251 TargetEntry *tle;
7252 deparse_namespace save_dpns;
7253 Bitmapset *save_appendparents;
7254
7255 tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
7256 if (!tle)
7257 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7258
7259 /*
7260 * If we're descending to the first child of an Append or MergeAppend,
7261 * update appendparents. This will affect deparsing of all Vars
7262 * appearing within the eventually-resolved subexpression.
7263 */
7264 save_appendparents = context->appendparents;
7265
7266 if (IsA(dpns->plan, Append))
7267 context->appendparents = bms_union(context->appendparents,
7268 ((Append *) dpns->plan)->apprelids);
7269 else if (IsA(dpns->plan, MergeAppend))
7270 context->appendparents = bms_union(context->appendparents,
7271 ((MergeAppend *) dpns->plan)->apprelids);
7272
7273 push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7274 resolve_special_varno((Node *) tle->expr, context,
7275 callback, callback_arg);
7276 pop_child_plan(dpns, &save_dpns);
7277 context->appendparents = save_appendparents;
7278 return;
7279 }
7280 else if (var->varno == INNER_VAR && dpns->inner_tlist)
7281 {
7282 TargetEntry *tle;
7283 deparse_namespace save_dpns;
7284
7285 tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
7286 if (!tle)
7287 elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7288
7289 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7290 resolve_special_varno((Node *) tle->expr, context,
7291 callback, callback_arg);
7292 pop_child_plan(dpns, &save_dpns);
7293 return;
7294 }
7295 else if (var->varno == INDEX_VAR && dpns->index_tlist)
7296 {
7297 TargetEntry *tle;
7298
7299 tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
7300 if (!tle)
7301 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
7302
7303 resolve_special_varno((Node *) tle->expr, context,
7304 callback, callback_arg);
7305 return;
7306 }
7307 else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
7308 elog(ERROR, "bogus varno: %d", var->varno);
7309
7310 /* Not special. Just invoke the callback. */
7311 (*callback) (node, context, callback_arg);
7312 }
7313
7314 /*
7315 * Get the name of a field of an expression of composite type. The
7316 * expression is usually a Var, but we handle other cases too.
7317 *
7318 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
7319 *
7320 * This is fairly straightforward when the expression has a named composite
7321 * type; we need only look up the type in the catalogs. However, the type
7322 * could also be RECORD. Since no actual table or view column is allowed to
7323 * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
7324 * or to a subquery output. We drill down to find the ultimate defining
7325 * expression and attempt to infer the field name from it. We ereport if we
7326 * can't determine the name.
7327 *
7328 * Similarly, a PARAM of type RECORD has to refer to some expression of
7329 * a determinable composite type.
7330 */
7331 static const char *
get_name_for_var_field(Var * var,int fieldno,int levelsup,deparse_context * context)7332 get_name_for_var_field(Var *var, int fieldno,
7333 int levelsup, deparse_context *context)
7334 {
7335 RangeTblEntry *rte;
7336 AttrNumber attnum;
7337 int netlevelsup;
7338 deparse_namespace *dpns;
7339 Index varno;
7340 AttrNumber varattno;
7341 TupleDesc tupleDesc;
7342 Node *expr;
7343
7344 /*
7345 * If it's a RowExpr that was expanded from a whole-row Var, use the
7346 * column names attached to it.
7347 */
7348 if (IsA(var, RowExpr))
7349 {
7350 RowExpr *r = (RowExpr *) var;
7351
7352 if (fieldno > 0 && fieldno <= list_length(r->colnames))
7353 return strVal(list_nth(r->colnames, fieldno - 1));
7354 }
7355
7356 /*
7357 * If it's a Param of type RECORD, try to find what the Param refers to.
7358 */
7359 if (IsA(var, Param))
7360 {
7361 Param *param = (Param *) var;
7362 ListCell *ancestor_cell;
7363
7364 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7365 if (expr)
7366 {
7367 /* Found a match, so recurse to decipher the field name */
7368 deparse_namespace save_dpns;
7369 const char *result;
7370
7371 push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7372 result = get_name_for_var_field((Var *) expr, fieldno,
7373 0, context);
7374 pop_ancestor_plan(dpns, &save_dpns);
7375 return result;
7376 }
7377 }
7378
7379 /*
7380 * If it's a Var of type RECORD, we have to find what the Var refers to;
7381 * if not, we can use get_expr_result_tupdesc().
7382 */
7383 if (!IsA(var, Var) ||
7384 var->vartype != RECORDOID)
7385 {
7386 tupleDesc = get_expr_result_tupdesc((Node *) var, false);
7387 /* Got the tupdesc, so we can extract the field name */
7388 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7389 return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7390 }
7391
7392 /* Find appropriate nesting depth */
7393 netlevelsup = var->varlevelsup + levelsup;
7394 if (netlevelsup >= list_length(context->namespaces))
7395 elog(ERROR, "bogus varlevelsup: %d offset %d",
7396 var->varlevelsup, levelsup);
7397 dpns = (deparse_namespace *) list_nth(context->namespaces,
7398 netlevelsup);
7399
7400 /*
7401 * If we have a syntactic referent for the Var, and we're working from a
7402 * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7403 * on the semantic referent. (See comments in get_variable().)
7404 */
7405 if (var->varnosyn > 0 && dpns->plan == NULL)
7406 {
7407 varno = var->varnosyn;
7408 varattno = var->varattnosyn;
7409 }
7410 else
7411 {
7412 varno = var->varno;
7413 varattno = var->varattno;
7414 }
7415
7416 /*
7417 * Try to find the relevant RTE in this rtable. In a plan tree, it's
7418 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7419 * down into the subplans, or INDEX_VAR, which is resolved similarly.
7420 *
7421 * Note: unlike get_variable and resolve_special_varno, we need not worry
7422 * about inheritance mapping: a child Var should have the same datatype as
7423 * its parent, and here we're really only interested in the Var's type.
7424 */
7425 if (varno >= 1 && varno <= list_length(dpns->rtable))
7426 {
7427 rte = rt_fetch(varno, dpns->rtable);
7428 attnum = varattno;
7429 }
7430 else if (varno == OUTER_VAR && dpns->outer_tlist)
7431 {
7432 TargetEntry *tle;
7433 deparse_namespace save_dpns;
7434 const char *result;
7435
7436 tle = get_tle_by_resno(dpns->outer_tlist, varattno);
7437 if (!tle)
7438 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
7439
7440 Assert(netlevelsup == 0);
7441 push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7442
7443 result = get_name_for_var_field((Var *) tle->expr, fieldno,
7444 levelsup, context);
7445
7446 pop_child_plan(dpns, &save_dpns);
7447 return result;
7448 }
7449 else if (varno == INNER_VAR && dpns->inner_tlist)
7450 {
7451 TargetEntry *tle;
7452 deparse_namespace save_dpns;
7453 const char *result;
7454
7455 tle = get_tle_by_resno(dpns->inner_tlist, varattno);
7456 if (!tle)
7457 elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
7458
7459 Assert(netlevelsup == 0);
7460 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7461
7462 result = get_name_for_var_field((Var *) tle->expr, fieldno,
7463 levelsup, context);
7464
7465 pop_child_plan(dpns, &save_dpns);
7466 return result;
7467 }
7468 else if (varno == INDEX_VAR && dpns->index_tlist)
7469 {
7470 TargetEntry *tle;
7471 const char *result;
7472
7473 tle = get_tle_by_resno(dpns->index_tlist, varattno);
7474 if (!tle)
7475 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
7476
7477 Assert(netlevelsup == 0);
7478
7479 result = get_name_for_var_field((Var *) tle->expr, fieldno,
7480 levelsup, context);
7481
7482 return result;
7483 }
7484 else
7485 {
7486 elog(ERROR, "bogus varno: %d", varno);
7487 return NULL; /* keep compiler quiet */
7488 }
7489
7490 if (attnum == InvalidAttrNumber)
7491 {
7492 /* Var is whole-row reference to RTE, so select the right field */
7493 return get_rte_attribute_name(rte, fieldno);
7494 }
7495
7496 /*
7497 * This part has essentially the same logic as the parser's
7498 * expandRecordVariable() function, but we are dealing with a different
7499 * representation of the input context, and we only need one field name
7500 * not a TupleDesc. Also, we need special cases for finding subquery and
7501 * CTE subplans when deparsing Plan trees.
7502 */
7503 expr = (Node *) var; /* default if we can't drill down */
7504
7505 switch (rte->rtekind)
7506 {
7507 case RTE_RELATION:
7508 case RTE_VALUES:
7509 case RTE_NAMEDTUPLESTORE:
7510 case RTE_RESULT:
7511
7512 /*
7513 * This case should not occur: a column of a table, values list,
7514 * or ENR shouldn't have type RECORD. Fall through and fail (most
7515 * likely) at the bottom.
7516 */
7517 break;
7518 case RTE_SUBQUERY:
7519 /* Subselect-in-FROM: examine sub-select's output expr */
7520 {
7521 if (rte->subquery)
7522 {
7523 TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
7524 attnum);
7525
7526 if (ste == NULL || ste->resjunk)
7527 elog(ERROR, "subquery %s does not have attribute %d",
7528 rte->eref->aliasname, attnum);
7529 expr = (Node *) ste->expr;
7530 if (IsA(expr, Var))
7531 {
7532 /*
7533 * Recurse into the sub-select to see what its Var
7534 * refers to. We have to build an additional level of
7535 * namespace to keep in step with varlevelsup in the
7536 * subselect.
7537 */
7538 deparse_namespace mydpns;
7539 const char *result;
7540
7541 set_deparse_for_query(&mydpns, rte->subquery,
7542 context->namespaces);
7543
7544 context->namespaces = lcons(&mydpns,
7545 context->namespaces);
7546
7547 result = get_name_for_var_field((Var *) expr, fieldno,
7548 0, context);
7549
7550 context->namespaces =
7551 list_delete_first(context->namespaces);
7552
7553 return result;
7554 }
7555 /* else fall through to inspect the expression */
7556 }
7557 else
7558 {
7559 /*
7560 * We're deparsing a Plan tree so we don't have complete
7561 * RTE entries (in particular, rte->subquery is NULL). But
7562 * the only place we'd see a Var directly referencing a
7563 * SUBQUERY RTE is in a SubqueryScan plan node, and we can
7564 * look into the child plan's tlist instead.
7565 */
7566 TargetEntry *tle;
7567 deparse_namespace save_dpns;
7568 const char *result;
7569
7570 if (!dpns->inner_plan)
7571 elog(ERROR, "failed to find plan for subquery %s",
7572 rte->eref->aliasname);
7573 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7574 if (!tle)
7575 elog(ERROR, "bogus varattno for subquery var: %d",
7576 attnum);
7577 Assert(netlevelsup == 0);
7578 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7579
7580 result = get_name_for_var_field((Var *) tle->expr, fieldno,
7581 levelsup, context);
7582
7583 pop_child_plan(dpns, &save_dpns);
7584 return result;
7585 }
7586 }
7587 break;
7588 case RTE_JOIN:
7589 /* Join RTE --- recursively inspect the alias variable */
7590 if (rte->joinaliasvars == NIL)
7591 elog(ERROR, "cannot decompile join alias var in plan tree");
7592 Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
7593 expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
7594 Assert(expr != NULL);
7595 /* we intentionally don't strip implicit coercions here */
7596 if (IsA(expr, Var))
7597 return get_name_for_var_field((Var *) expr, fieldno,
7598 var->varlevelsup + levelsup,
7599 context);
7600 /* else fall through to inspect the expression */
7601 break;
7602 case RTE_FUNCTION:
7603 case RTE_TABLEFUNC:
7604
7605 /*
7606 * We couldn't get here unless a function is declared with one of
7607 * its result columns as RECORD, which is not allowed.
7608 */
7609 break;
7610 case RTE_CTE:
7611 /* CTE reference: examine subquery's output expr */
7612 {
7613 CommonTableExpr *cte = NULL;
7614 Index ctelevelsup;
7615 ListCell *lc;
7616
7617 /*
7618 * Try to find the referenced CTE using the namespace stack.
7619 */
7620 ctelevelsup = rte->ctelevelsup + netlevelsup;
7621 if (ctelevelsup >= list_length(context->namespaces))
7622 lc = NULL;
7623 else
7624 {
7625 deparse_namespace *ctedpns;
7626
7627 ctedpns = (deparse_namespace *)
7628 list_nth(context->namespaces, ctelevelsup);
7629 foreach(lc, ctedpns->ctes)
7630 {
7631 cte = (CommonTableExpr *) lfirst(lc);
7632 if (strcmp(cte->ctename, rte->ctename) == 0)
7633 break;
7634 }
7635 }
7636 if (lc != NULL)
7637 {
7638 Query *ctequery = (Query *) cte->ctequery;
7639 TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte),
7640 attnum);
7641
7642 if (ste == NULL || ste->resjunk)
7643 elog(ERROR, "subquery %s does not have attribute %d",
7644 rte->eref->aliasname, attnum);
7645 expr = (Node *) ste->expr;
7646 if (IsA(expr, Var))
7647 {
7648 /*
7649 * Recurse into the CTE to see what its Var refers to.
7650 * We have to build an additional level of namespace
7651 * to keep in step with varlevelsup in the CTE.
7652 * Furthermore it could be an outer CTE, so we may
7653 * have to delete some levels of namespace.
7654 */
7655 List *save_nslist = context->namespaces;
7656 List *new_nslist;
7657 deparse_namespace mydpns;
7658 const char *result;
7659
7660 set_deparse_for_query(&mydpns, ctequery,
7661 context->namespaces);
7662
7663 new_nslist = list_copy_tail(context->namespaces,
7664 ctelevelsup);
7665 context->namespaces = lcons(&mydpns, new_nslist);
7666
7667 result = get_name_for_var_field((Var *) expr, fieldno,
7668 0, context);
7669
7670 context->namespaces = save_nslist;
7671
7672 return result;
7673 }
7674 /* else fall through to inspect the expression */
7675 }
7676 else
7677 {
7678 /*
7679 * We're deparsing a Plan tree so we don't have a CTE
7680 * list. But the only places we'd see a Var directly
7681 * referencing a CTE RTE are in CteScan or WorkTableScan
7682 * plan nodes. For those cases, set_deparse_plan arranged
7683 * for dpns->inner_plan to be the plan node that emits the
7684 * CTE or RecursiveUnion result, and we can look at its
7685 * tlist instead.
7686 */
7687 TargetEntry *tle;
7688 deparse_namespace save_dpns;
7689 const char *result;
7690
7691 if (!dpns->inner_plan)
7692 elog(ERROR, "failed to find plan for CTE %s",
7693 rte->eref->aliasname);
7694 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7695 if (!tle)
7696 elog(ERROR, "bogus varattno for subquery var: %d",
7697 attnum);
7698 Assert(netlevelsup == 0);
7699 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7700
7701 result = get_name_for_var_field((Var *) tle->expr, fieldno,
7702 levelsup, context);
7703
7704 pop_child_plan(dpns, &save_dpns);
7705 return result;
7706 }
7707 }
7708 break;
7709 }
7710
7711 /*
7712 * We now have an expression we can't expand any more, so see if
7713 * get_expr_result_tupdesc() can do anything with it.
7714 */
7715 tupleDesc = get_expr_result_tupdesc(expr, false);
7716 /* Got the tupdesc, so we can extract the field name */
7717 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7718 return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7719 }
7720
7721 /*
7722 * Try to find the referenced expression for a PARAM_EXEC Param that might
7723 * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
7724 *
7725 * If successful, return the expression and set *dpns_p and *ancestor_cell_p
7726 * appropriately for calling push_ancestor_plan(). If no referent can be
7727 * found, return NULL.
7728 */
7729 static Node *
find_param_referent(Param * param,deparse_context * context,deparse_namespace ** dpns_p,ListCell ** ancestor_cell_p)7730 find_param_referent(Param *param, deparse_context *context,
7731 deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
7732 {
7733 /* Initialize output parameters to prevent compiler warnings */
7734 *dpns_p = NULL;
7735 *ancestor_cell_p = NULL;
7736
7737 /*
7738 * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
7739 * SubPlan argument. This will necessarily be in some ancestor of the
7740 * current expression's Plan node.
7741 */
7742 if (param->paramkind == PARAM_EXEC)
7743 {
7744 deparse_namespace *dpns;
7745 Plan *child_plan;
7746 bool in_same_plan_level;
7747 ListCell *lc;
7748
7749 dpns = (deparse_namespace *) linitial(context->namespaces);
7750 child_plan = dpns->plan;
7751 in_same_plan_level = true;
7752
7753 foreach(lc, dpns->ancestors)
7754 {
7755 Node *ancestor = (Node *) lfirst(lc);
7756 ListCell *lc2;
7757
7758 /*
7759 * NestLoops transmit params to their inner child only; also, once
7760 * we've crawled up out of a subplan, this couldn't possibly be
7761 * the right match.
7762 */
7763 if (IsA(ancestor, NestLoop) &&
7764 child_plan == innerPlan(ancestor) &&
7765 in_same_plan_level)
7766 {
7767 NestLoop *nl = (NestLoop *) ancestor;
7768
7769 foreach(lc2, nl->nestParams)
7770 {
7771 NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
7772
7773 if (nlp->paramno == param->paramid)
7774 {
7775 /* Found a match, so return it */
7776 *dpns_p = dpns;
7777 *ancestor_cell_p = lc;
7778 return (Node *) nlp->paramval;
7779 }
7780 }
7781 }
7782
7783 /*
7784 * If ancestor is a SubPlan, check the arguments it provides.
7785 */
7786 if (IsA(ancestor, SubPlan))
7787 {
7788 SubPlan *subplan = (SubPlan *) ancestor;
7789 ListCell *lc3;
7790 ListCell *lc4;
7791
7792 forboth(lc3, subplan->parParam, lc4, subplan->args)
7793 {
7794 int paramid = lfirst_int(lc3);
7795 Node *arg = (Node *) lfirst(lc4);
7796
7797 if (paramid == param->paramid)
7798 {
7799 /*
7800 * Found a match, so return it. But, since Vars in
7801 * the arg are to be evaluated in the surrounding
7802 * context, we have to point to the next ancestor item
7803 * that is *not* a SubPlan.
7804 */
7805 ListCell *rest;
7806
7807 for_each_cell(rest, dpns->ancestors,
7808 lnext(dpns->ancestors, lc))
7809 {
7810 Node *ancestor2 = (Node *) lfirst(rest);
7811
7812 if (!IsA(ancestor2, SubPlan))
7813 {
7814 *dpns_p = dpns;
7815 *ancestor_cell_p = rest;
7816 return arg;
7817 }
7818 }
7819 elog(ERROR, "SubPlan cannot be outermost ancestor");
7820 }
7821 }
7822
7823 /* We have emerged from a subplan. */
7824 in_same_plan_level = false;
7825
7826 /* SubPlan isn't a kind of Plan, so skip the rest */
7827 continue;
7828 }
7829
7830 /*
7831 * Check to see if we're emerging from an initplan of the current
7832 * ancestor plan. Initplans never have any parParams, so no need
7833 * to search that list, but we need to know if we should reset
7834 * in_same_plan_level.
7835 */
7836 foreach(lc2, ((Plan *) ancestor)->initPlan)
7837 {
7838 SubPlan *subplan = castNode(SubPlan, lfirst(lc2));
7839
7840 if (child_plan != (Plan *) list_nth(dpns->subplans,
7841 subplan->plan_id - 1))
7842 continue;
7843
7844 /* No parameters to be had here. */
7845 Assert(subplan->parParam == NIL);
7846
7847 /* We have emerged from an initplan. */
7848 in_same_plan_level = false;
7849 break;
7850 }
7851
7852 /* No luck, crawl up to next ancestor */
7853 child_plan = (Plan *) ancestor;
7854 }
7855 }
7856
7857 /* No referent found */
7858 return NULL;
7859 }
7860
7861 /*
7862 * Display a Param appropriately.
7863 */
7864 static void
get_parameter(Param * param,deparse_context * context)7865 get_parameter(Param *param, deparse_context *context)
7866 {
7867 Node *expr;
7868 deparse_namespace *dpns;
7869 ListCell *ancestor_cell;
7870
7871 /*
7872 * If it's a PARAM_EXEC parameter, try to locate the expression from which
7873 * the parameter was computed. Note that failing to find a referent isn't
7874 * an error, since the Param might well be a subplan output rather than an
7875 * input.
7876 */
7877 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7878 if (expr)
7879 {
7880 /* Found a match, so print it */
7881 deparse_namespace save_dpns;
7882 bool save_varprefix;
7883 bool need_paren;
7884
7885 /* Switch attention to the ancestor plan node */
7886 push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7887
7888 /*
7889 * Force prefixing of Vars, since they won't belong to the relation
7890 * being scanned in the original plan node.
7891 */
7892 save_varprefix = context->varprefix;
7893 context->varprefix = true;
7894
7895 /*
7896 * A Param's expansion is typically a Var, Aggref, or upper-level
7897 * Param, which wouldn't need extra parentheses. Otherwise, insert
7898 * parens to ensure the expression looks atomic.
7899 */
7900 need_paren = !(IsA(expr, Var) ||
7901 IsA(expr, Aggref) ||
7902 IsA(expr, Param));
7903 if (need_paren)
7904 appendStringInfoChar(context->buf, '(');
7905
7906 get_rule_expr(expr, context, false);
7907
7908 if (need_paren)
7909 appendStringInfoChar(context->buf, ')');
7910
7911 context->varprefix = save_varprefix;
7912
7913 pop_ancestor_plan(dpns, &save_dpns);
7914
7915 return;
7916 }
7917
7918 /*
7919 * If it's an external parameter, see if the outermost namespace provides
7920 * function argument names.
7921 */
7922 if (param->paramkind == PARAM_EXTERN)
7923 {
7924 dpns = lfirst(list_tail(context->namespaces));
7925 if (dpns->argnames)
7926 {
7927 char *argname = dpns->argnames[param->paramid - 1];
7928
7929 if (argname)
7930 {
7931 bool should_qualify = false;
7932 ListCell *lc;
7933
7934 /*
7935 * Qualify the parameter name if there are any other deparse
7936 * namespaces with range tables. This avoids qualifying in
7937 * trivial cases like "RETURN a + b", but makes it safe in all
7938 * other cases.
7939 */
7940 foreach(lc, context->namespaces)
7941 {
7942 deparse_namespace *dpns = lfirst(lc);
7943
7944 if (list_length(dpns->rtable_names) > 0)
7945 {
7946 should_qualify = true;
7947 break;
7948 }
7949 }
7950 if (should_qualify)
7951 {
7952 appendStringInfoString(context->buf, quote_identifier(dpns->funcname));
7953 appendStringInfoChar(context->buf, '.');
7954 }
7955
7956 appendStringInfoString(context->buf, quote_identifier(argname));
7957 return;
7958 }
7959 }
7960 }
7961
7962 /*
7963 * Not PARAM_EXEC, or couldn't find referent: just print $N.
7964 */
7965 appendStringInfo(context->buf, "$%d", param->paramid);
7966 }
7967
7968 /*
7969 * get_simple_binary_op_name
7970 *
7971 * helper function for isSimpleNode
7972 * will return single char binary operator name, or NULL if it's not
7973 */
7974 static const char *
get_simple_binary_op_name(OpExpr * expr)7975 get_simple_binary_op_name(OpExpr *expr)
7976 {
7977 List *args = expr->args;
7978
7979 if (list_length(args) == 2)
7980 {
7981 /* binary operator */
7982 Node *arg1 = (Node *) linitial(args);
7983 Node *arg2 = (Node *) lsecond(args);
7984 const char *op;
7985
7986 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
7987 if (strlen(op) == 1)
7988 return op;
7989 }
7990 return NULL;
7991 }
7992
7993
7994 /*
7995 * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
7996 *
7997 * true : simple in the context of parent node's type
7998 * false : not simple
7999 */
8000 static bool
isSimpleNode(Node * node,Node * parentNode,int prettyFlags)8001 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
8002 {
8003 if (!node)
8004 return false;
8005
8006 switch (nodeTag(node))
8007 {
8008 case T_Var:
8009 case T_Const:
8010 case T_Param:
8011 case T_CoerceToDomainValue:
8012 case T_SetToDefault:
8013 case T_CurrentOfExpr:
8014 /* single words: always simple */
8015 return true;
8016
8017 case T_SubscriptingRef:
8018 case T_ArrayExpr:
8019 case T_RowExpr:
8020 case T_CoalesceExpr:
8021 case T_MinMaxExpr:
8022 case T_SQLValueFunction:
8023 case T_XmlExpr:
8024 case T_NextValueExpr:
8025 case T_NullIfExpr:
8026 case T_Aggref:
8027 case T_WindowFunc:
8028 case T_FuncExpr:
8029 /* function-like: name(..) or name[..] */
8030 return true;
8031
8032 /* CASE keywords act as parentheses */
8033 case T_CaseExpr:
8034 return true;
8035
8036 case T_FieldSelect:
8037
8038 /*
8039 * appears simple since . has top precedence, unless parent is
8040 * T_FieldSelect itself!
8041 */
8042 return (IsA(parentNode, FieldSelect) ? false : true);
8043
8044 case T_FieldStore:
8045
8046 /*
8047 * treat like FieldSelect (probably doesn't matter)
8048 */
8049 return (IsA(parentNode, FieldStore) ? false : true);
8050
8051 case T_CoerceToDomain:
8052 /* maybe simple, check args */
8053 return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8054 node, prettyFlags);
8055 case T_RelabelType:
8056 return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8057 node, prettyFlags);
8058 case T_CoerceViaIO:
8059 return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
8060 node, prettyFlags);
8061 case T_ArrayCoerceExpr:
8062 return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8063 node, prettyFlags);
8064 case T_ConvertRowtypeExpr:
8065 return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8066 node, prettyFlags);
8067
8068 case T_OpExpr:
8069 {
8070 /* depends on parent node type; needs further checking */
8071 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8072 {
8073 const char *op;
8074 const char *parentOp;
8075 bool is_lopriop;
8076 bool is_hipriop;
8077 bool is_lopriparent;
8078 bool is_hipriparent;
8079
8080 op = get_simple_binary_op_name((OpExpr *) node);
8081 if (!op)
8082 return false;
8083
8084 /* We know only the basic operators + - and * / % */
8085 is_lopriop = (strchr("+-", *op) != NULL);
8086 is_hipriop = (strchr("*/%", *op) != NULL);
8087 if (!(is_lopriop || is_hipriop))
8088 return false;
8089
8090 parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8091 if (!parentOp)
8092 return false;
8093
8094 is_lopriparent = (strchr("+-", *parentOp) != NULL);
8095 is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8096 if (!(is_lopriparent || is_hipriparent))
8097 return false;
8098
8099 if (is_hipriop && is_lopriparent)
8100 return true; /* op binds tighter than parent */
8101
8102 if (is_lopriop && is_hipriparent)
8103 return false;
8104
8105 /*
8106 * Operators are same priority --- can skip parens only if
8107 * we have (a - b) - c, not a - (b - c).
8108 */
8109 if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
8110 return true;
8111
8112 return false;
8113 }
8114 /* else do the same stuff as for T_SubLink et al. */
8115 }
8116 /* FALLTHROUGH */
8117
8118 case T_SubLink:
8119 case T_NullTest:
8120 case T_BooleanTest:
8121 case T_DistinctExpr:
8122 switch (nodeTag(parentNode))
8123 {
8124 case T_FuncExpr:
8125 {
8126 /* special handling for casts */
8127 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8128
8129 if (type == COERCE_EXPLICIT_CAST ||
8130 type == COERCE_IMPLICIT_CAST)
8131 return false;
8132 return true; /* own parentheses */
8133 }
8134 case T_BoolExpr: /* lower precedence */
8135 case T_SubscriptingRef: /* other separators */
8136 case T_ArrayExpr: /* other separators */
8137 case T_RowExpr: /* other separators */
8138 case T_CoalesceExpr: /* own parentheses */
8139 case T_MinMaxExpr: /* own parentheses */
8140 case T_XmlExpr: /* own parentheses */
8141 case T_NullIfExpr: /* other separators */
8142 case T_Aggref: /* own parentheses */
8143 case T_WindowFunc: /* own parentheses */
8144 case T_CaseExpr: /* other separators */
8145 return true;
8146 default:
8147 return false;
8148 }
8149
8150 case T_BoolExpr:
8151 switch (nodeTag(parentNode))
8152 {
8153 case T_BoolExpr:
8154 if (prettyFlags & PRETTYFLAG_PAREN)
8155 {
8156 BoolExprType type;
8157 BoolExprType parentType;
8158
8159 type = ((BoolExpr *) node)->boolop;
8160 parentType = ((BoolExpr *) parentNode)->boolop;
8161 switch (type)
8162 {
8163 case NOT_EXPR:
8164 case AND_EXPR:
8165 if (parentType == AND_EXPR || parentType == OR_EXPR)
8166 return true;
8167 break;
8168 case OR_EXPR:
8169 if (parentType == OR_EXPR)
8170 return true;
8171 break;
8172 }
8173 }
8174 return false;
8175 case T_FuncExpr:
8176 {
8177 /* special handling for casts */
8178 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8179
8180 if (type == COERCE_EXPLICIT_CAST ||
8181 type == COERCE_IMPLICIT_CAST)
8182 return false;
8183 return true; /* own parentheses */
8184 }
8185 case T_SubscriptingRef: /* other separators */
8186 case T_ArrayExpr: /* other separators */
8187 case T_RowExpr: /* other separators */
8188 case T_CoalesceExpr: /* own parentheses */
8189 case T_MinMaxExpr: /* own parentheses */
8190 case T_XmlExpr: /* own parentheses */
8191 case T_NullIfExpr: /* other separators */
8192 case T_Aggref: /* own parentheses */
8193 case T_WindowFunc: /* own parentheses */
8194 case T_CaseExpr: /* other separators */
8195 return true;
8196 default:
8197 return false;
8198 }
8199
8200 default:
8201 break;
8202 }
8203 /* those we don't know: in dubio complexo */
8204 return false;
8205 }
8206
8207
8208 /*
8209 * appendContextKeyword - append a keyword to buffer
8210 *
8211 * If prettyPrint is enabled, perform a line break, and adjust indentation.
8212 * Otherwise, just append the keyword.
8213 */
8214 static void
appendContextKeyword(deparse_context * context,const char * str,int indentBefore,int indentAfter,int indentPlus)8215 appendContextKeyword(deparse_context *context, const char *str,
8216 int indentBefore, int indentAfter, int indentPlus)
8217 {
8218 StringInfo buf = context->buf;
8219
8220 if (PRETTY_INDENT(context))
8221 {
8222 int indentAmount;
8223
8224 context->indentLevel += indentBefore;
8225
8226 /* remove any trailing spaces currently in the buffer ... */
8227 removeStringInfoSpaces(buf);
8228 /* ... then add a newline and some spaces */
8229 appendStringInfoChar(buf, '\n');
8230
8231 if (context->indentLevel < PRETTYINDENT_LIMIT)
8232 indentAmount = Max(context->indentLevel, 0) + indentPlus;
8233 else
8234 {
8235 /*
8236 * If we're indented more than PRETTYINDENT_LIMIT characters, try
8237 * to conserve horizontal space by reducing the per-level
8238 * indentation. For best results the scale factor here should
8239 * divide all the indent amounts that get added to indentLevel
8240 * (PRETTYINDENT_STD, etc). It's important that the indentation
8241 * not grow unboundedly, else deeply-nested trees use O(N^2)
8242 * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8243 */
8244 indentAmount = PRETTYINDENT_LIMIT +
8245 (context->indentLevel - PRETTYINDENT_LIMIT) /
8246 (PRETTYINDENT_STD / 2);
8247 indentAmount %= PRETTYINDENT_LIMIT;
8248 /* scale/wrap logic affects indentLevel, but not indentPlus */
8249 indentAmount += indentPlus;
8250 }
8251 appendStringInfoSpaces(buf, indentAmount);
8252
8253 appendStringInfoString(buf, str);
8254
8255 context->indentLevel += indentAfter;
8256 if (context->indentLevel < 0)
8257 context->indentLevel = 0;
8258 }
8259 else
8260 appendStringInfoString(buf, str);
8261 }
8262
8263 /*
8264 * removeStringInfoSpaces - delete trailing spaces from a buffer.
8265 *
8266 * Possibly this should move to stringinfo.c at some point.
8267 */
8268 static void
removeStringInfoSpaces(StringInfo str)8269 removeStringInfoSpaces(StringInfo str)
8270 {
8271 while (str->len > 0 && str->data[str->len - 1] == ' ')
8272 str->data[--(str->len)] = '\0';
8273 }
8274
8275
8276 /*
8277 * get_rule_expr_paren - deparse expr using get_rule_expr,
8278 * embracing the string with parentheses if necessary for prettyPrint.
8279 *
8280 * Never embrace if prettyFlags=0, because it's done in the calling node.
8281 *
8282 * Any node that does *not* embrace its argument node by sql syntax (with
8283 * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
8284 * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
8285 * added.
8286 */
8287 static void
get_rule_expr_paren(Node * node,deparse_context * context,bool showimplicit,Node * parentNode)8288 get_rule_expr_paren(Node *node, deparse_context *context,
8289 bool showimplicit, Node *parentNode)
8290 {
8291 bool need_paren;
8292
8293 need_paren = PRETTY_PAREN(context) &&
8294 !isSimpleNode(node, parentNode, context->prettyFlags);
8295
8296 if (need_paren)
8297 appendStringInfoChar(context->buf, '(');
8298
8299 get_rule_expr(node, context, showimplicit);
8300
8301 if (need_paren)
8302 appendStringInfoChar(context->buf, ')');
8303 }
8304
8305
8306 /* ----------
8307 * get_rule_expr - Parse back an expression
8308 *
8309 * Note: showimplicit determines whether we display any implicit cast that
8310 * is present at the top of the expression tree. It is a passed argument,
8311 * not a field of the context struct, because we change the value as we
8312 * recurse down into the expression. In general we suppress implicit casts
8313 * when the result type is known with certainty (eg, the arguments of an
8314 * OR must be boolean). We display implicit casts for arguments of functions
8315 * and operators, since this is needed to be certain that the same function
8316 * or operator will be chosen when the expression is re-parsed.
8317 * ----------
8318 */
8319 static void
get_rule_expr(Node * node,deparse_context * context,bool showimplicit)8320 get_rule_expr(Node *node, deparse_context *context,
8321 bool showimplicit)
8322 {
8323 StringInfo buf = context->buf;
8324
8325 if (node == NULL)
8326 return;
8327
8328 /* Guard against excessively long or deeply-nested queries */
8329 CHECK_FOR_INTERRUPTS();
8330 check_stack_depth();
8331
8332 /*
8333 * Each level of get_rule_expr must emit an indivisible term
8334 * (parenthesized if necessary) to ensure result is reparsed into the same
8335 * expression tree. The only exception is that when the input is a List,
8336 * we emit the component items comma-separated with no surrounding
8337 * decoration; this is convenient for most callers.
8338 */
8339 switch (nodeTag(node))
8340 {
8341 case T_Var:
8342 (void) get_variable((Var *) node, 0, false, context);
8343 break;
8344
8345 case T_Const:
8346 get_const_expr((Const *) node, context, 0);
8347 break;
8348
8349 case T_Param:
8350 get_parameter((Param *) node, context);
8351 break;
8352
8353 case T_Aggref:
8354 get_agg_expr((Aggref *) node, context, (Aggref *) node);
8355 break;
8356
8357 case T_GroupingFunc:
8358 {
8359 GroupingFunc *gexpr = (GroupingFunc *) node;
8360
8361 appendStringInfoString(buf, "GROUPING(");
8362 get_rule_expr((Node *) gexpr->args, context, true);
8363 appendStringInfoChar(buf, ')');
8364 }
8365 break;
8366
8367 case T_WindowFunc:
8368 get_windowfunc_expr((WindowFunc *) node, context);
8369 break;
8370
8371 case T_SubscriptingRef:
8372 {
8373 SubscriptingRef *sbsref = (SubscriptingRef *) node;
8374 bool need_parens;
8375
8376 /*
8377 * If the argument is a CaseTestExpr, we must be inside a
8378 * FieldStore, ie, we are assigning to an element of an array
8379 * within a composite column. Since we already punted on
8380 * displaying the FieldStore's target information, just punt
8381 * here too, and display only the assignment source
8382 * expression.
8383 */
8384 if (IsA(sbsref->refexpr, CaseTestExpr))
8385 {
8386 Assert(sbsref->refassgnexpr);
8387 get_rule_expr((Node *) sbsref->refassgnexpr,
8388 context, showimplicit);
8389 break;
8390 }
8391
8392 /*
8393 * Parenthesize the argument unless it's a simple Var or a
8394 * FieldSelect. (In particular, if it's another
8395 * SubscriptingRef, we *must* parenthesize to avoid
8396 * confusion.)
8397 */
8398 need_parens = !IsA(sbsref->refexpr, Var) &&
8399 !IsA(sbsref->refexpr, FieldSelect);
8400 if (need_parens)
8401 appendStringInfoChar(buf, '(');
8402 get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
8403 if (need_parens)
8404 appendStringInfoChar(buf, ')');
8405
8406 /*
8407 * If there's a refassgnexpr, we want to print the node in the
8408 * format "container[subscripts] := refassgnexpr". This is
8409 * not legal SQL, so decompilation of INSERT or UPDATE
8410 * statements should always use processIndirection as part of
8411 * the statement-level syntax. We should only see this when
8412 * EXPLAIN tries to print the targetlist of a plan resulting
8413 * from such a statement.
8414 */
8415 if (sbsref->refassgnexpr)
8416 {
8417 Node *refassgnexpr;
8418
8419 /*
8420 * Use processIndirection to print this node's subscripts
8421 * as well as any additional field selections or
8422 * subscripting in immediate descendants. It returns the
8423 * RHS expr that is actually being "assigned".
8424 */
8425 refassgnexpr = processIndirection(node, context);
8426 appendStringInfoString(buf, " := ");
8427 get_rule_expr(refassgnexpr, context, showimplicit);
8428 }
8429 else
8430 {
8431 /* Just an ordinary container fetch, so print subscripts */
8432 printSubscripts(sbsref, context);
8433 }
8434 }
8435 break;
8436
8437 case T_FuncExpr:
8438 get_func_expr((FuncExpr *) node, context, showimplicit);
8439 break;
8440
8441 case T_NamedArgExpr:
8442 {
8443 NamedArgExpr *na = (NamedArgExpr *) node;
8444
8445 appendStringInfo(buf, "%s => ", quote_identifier(na->name));
8446 get_rule_expr((Node *) na->arg, context, showimplicit);
8447 }
8448 break;
8449
8450 case T_OpExpr:
8451 get_oper_expr((OpExpr *) node, context);
8452 break;
8453
8454 case T_DistinctExpr:
8455 {
8456 DistinctExpr *expr = (DistinctExpr *) node;
8457 List *args = expr->args;
8458 Node *arg1 = (Node *) linitial(args);
8459 Node *arg2 = (Node *) lsecond(args);
8460
8461 if (!PRETTY_PAREN(context))
8462 appendStringInfoChar(buf, '(');
8463 get_rule_expr_paren(arg1, context, true, node);
8464 appendStringInfoString(buf, " IS DISTINCT FROM ");
8465 get_rule_expr_paren(arg2, context, true, node);
8466 if (!PRETTY_PAREN(context))
8467 appendStringInfoChar(buf, ')');
8468 }
8469 break;
8470
8471 case T_NullIfExpr:
8472 {
8473 NullIfExpr *nullifexpr = (NullIfExpr *) node;
8474
8475 appendStringInfoString(buf, "NULLIF(");
8476 get_rule_expr((Node *) nullifexpr->args, context, true);
8477 appendStringInfoChar(buf, ')');
8478 }
8479 break;
8480
8481 case T_ScalarArrayOpExpr:
8482 {
8483 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
8484 List *args = expr->args;
8485 Node *arg1 = (Node *) linitial(args);
8486 Node *arg2 = (Node *) lsecond(args);
8487
8488 if (!PRETTY_PAREN(context))
8489 appendStringInfoChar(buf, '(');
8490 get_rule_expr_paren(arg1, context, true, node);
8491 appendStringInfo(buf, " %s %s (",
8492 generate_operator_name(expr->opno,
8493 exprType(arg1),
8494 get_base_element_type(exprType(arg2))),
8495 expr->useOr ? "ANY" : "ALL");
8496 get_rule_expr_paren(arg2, context, true, node);
8497
8498 /*
8499 * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
8500 * a bare sub-SELECT. Since we're here, the sub-SELECT must
8501 * be meant as a scalar sub-SELECT yielding an array value to
8502 * be used in ScalarArrayOpExpr; but the grammar will
8503 * preferentially interpret such a construct as an ANY/ALL
8504 * SubLink. To prevent misparsing the output that way, insert
8505 * a dummy coercion (which will be stripped by parse analysis,
8506 * so no inefficiency is added in dump and reload). This is
8507 * indeed most likely what the user wrote to get the construct
8508 * accepted in the first place.
8509 */
8510 if (IsA(arg2, SubLink) &&
8511 ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
8512 appendStringInfo(buf, "::%s",
8513 format_type_with_typemod(exprType(arg2),
8514 exprTypmod(arg2)));
8515 appendStringInfoChar(buf, ')');
8516 if (!PRETTY_PAREN(context))
8517 appendStringInfoChar(buf, ')');
8518 }
8519 break;
8520
8521 case T_BoolExpr:
8522 {
8523 BoolExpr *expr = (BoolExpr *) node;
8524 Node *first_arg = linitial(expr->args);
8525 ListCell *arg;
8526
8527 switch (expr->boolop)
8528 {
8529 case AND_EXPR:
8530 if (!PRETTY_PAREN(context))
8531 appendStringInfoChar(buf, '(');
8532 get_rule_expr_paren(first_arg, context,
8533 false, node);
8534 for_each_from(arg, expr->args, 1)
8535 {
8536 appendStringInfoString(buf, " AND ");
8537 get_rule_expr_paren((Node *) lfirst(arg), context,
8538 false, node);
8539 }
8540 if (!PRETTY_PAREN(context))
8541 appendStringInfoChar(buf, ')');
8542 break;
8543
8544 case OR_EXPR:
8545 if (!PRETTY_PAREN(context))
8546 appendStringInfoChar(buf, '(');
8547 get_rule_expr_paren(first_arg, context,
8548 false, node);
8549 for_each_from(arg, expr->args, 1)
8550 {
8551 appendStringInfoString(buf, " OR ");
8552 get_rule_expr_paren((Node *) lfirst(arg), context,
8553 false, node);
8554 }
8555 if (!PRETTY_PAREN(context))
8556 appendStringInfoChar(buf, ')');
8557 break;
8558
8559 case NOT_EXPR:
8560 if (!PRETTY_PAREN(context))
8561 appendStringInfoChar(buf, '(');
8562 appendStringInfoString(buf, "NOT ");
8563 get_rule_expr_paren(first_arg, context,
8564 false, node);
8565 if (!PRETTY_PAREN(context))
8566 appendStringInfoChar(buf, ')');
8567 break;
8568
8569 default:
8570 elog(ERROR, "unrecognized boolop: %d",
8571 (int) expr->boolop);
8572 }
8573 }
8574 break;
8575
8576 case T_SubLink:
8577 get_sublink_expr((SubLink *) node, context);
8578 break;
8579
8580 case T_SubPlan:
8581 {
8582 SubPlan *subplan = (SubPlan *) node;
8583
8584 /*
8585 * We cannot see an already-planned subplan in rule deparsing,
8586 * only while EXPLAINing a query plan. We don't try to
8587 * reconstruct the original SQL, just reference the subplan
8588 * that appears elsewhere in EXPLAIN's result.
8589 */
8590 if (subplan->useHashTable)
8591 appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
8592 else
8593 appendStringInfo(buf, "(%s)", subplan->plan_name);
8594 }
8595 break;
8596
8597 case T_AlternativeSubPlan:
8598 {
8599 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
8600 ListCell *lc;
8601
8602 /*
8603 * This case cannot be reached in normal usage, since no
8604 * AlternativeSubPlan can appear either in parsetrees or
8605 * finished plan trees. We keep it just in case somebody
8606 * wants to use this code to print planner data structures.
8607 */
8608 appendStringInfoString(buf, "(alternatives: ");
8609 foreach(lc, asplan->subplans)
8610 {
8611 SubPlan *splan = lfirst_node(SubPlan, lc);
8612
8613 if (splan->useHashTable)
8614 appendStringInfo(buf, "hashed %s", splan->plan_name);
8615 else
8616 appendStringInfoString(buf, splan->plan_name);
8617 if (lnext(asplan->subplans, lc))
8618 appendStringInfoString(buf, " or ");
8619 }
8620 appendStringInfoChar(buf, ')');
8621 }
8622 break;
8623
8624 case T_FieldSelect:
8625 {
8626 FieldSelect *fselect = (FieldSelect *) node;
8627 Node *arg = (Node *) fselect->arg;
8628 int fno = fselect->fieldnum;
8629 const char *fieldname;
8630 bool need_parens;
8631
8632 /*
8633 * Parenthesize the argument unless it's an SubscriptingRef or
8634 * another FieldSelect. Note in particular that it would be
8635 * WRONG to not parenthesize a Var argument; simplicity is not
8636 * the issue here, having the right number of names is.
8637 */
8638 need_parens = !IsA(arg, SubscriptingRef) &&
8639 !IsA(arg, FieldSelect);
8640 if (need_parens)
8641 appendStringInfoChar(buf, '(');
8642 get_rule_expr(arg, context, true);
8643 if (need_parens)
8644 appendStringInfoChar(buf, ')');
8645
8646 /*
8647 * Get and print the field name.
8648 */
8649 fieldname = get_name_for_var_field((Var *) arg, fno,
8650 0, context);
8651 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
8652 }
8653 break;
8654
8655 case T_FieldStore:
8656 {
8657 FieldStore *fstore = (FieldStore *) node;
8658 bool need_parens;
8659
8660 /*
8661 * There is no good way to represent a FieldStore as real SQL,
8662 * so decompilation of INSERT or UPDATE statements should
8663 * always use processIndirection as part of the
8664 * statement-level syntax. We should only get here when
8665 * EXPLAIN tries to print the targetlist of a plan resulting
8666 * from such a statement. The plan case is even harder than
8667 * ordinary rules would be, because the planner tries to
8668 * collapse multiple assignments to the same field or subfield
8669 * into one FieldStore; so we can see a list of target fields
8670 * not just one, and the arguments could be FieldStores
8671 * themselves. We don't bother to try to print the target
8672 * field names; we just print the source arguments, with a
8673 * ROW() around them if there's more than one. This isn't
8674 * terribly complete, but it's probably good enough for
8675 * EXPLAIN's purposes; especially since anything more would be
8676 * either hopelessly confusing or an even poorer
8677 * representation of what the plan is actually doing.
8678 */
8679 need_parens = (list_length(fstore->newvals) != 1);
8680 if (need_parens)
8681 appendStringInfoString(buf, "ROW(");
8682 get_rule_expr((Node *) fstore->newvals, context, showimplicit);
8683 if (need_parens)
8684 appendStringInfoChar(buf, ')');
8685 }
8686 break;
8687
8688 case T_RelabelType:
8689 {
8690 RelabelType *relabel = (RelabelType *) node;
8691 Node *arg = (Node *) relabel->arg;
8692
8693 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
8694 !showimplicit)
8695 {
8696 /* don't show the implicit cast */
8697 get_rule_expr_paren(arg, context, false, node);
8698 }
8699 else
8700 {
8701 get_coercion_expr(arg, context,
8702 relabel->resulttype,
8703 relabel->resulttypmod,
8704 node);
8705 }
8706 }
8707 break;
8708
8709 case T_CoerceViaIO:
8710 {
8711 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
8712 Node *arg = (Node *) iocoerce->arg;
8713
8714 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
8715 !showimplicit)
8716 {
8717 /* don't show the implicit cast */
8718 get_rule_expr_paren(arg, context, false, node);
8719 }
8720 else
8721 {
8722 get_coercion_expr(arg, context,
8723 iocoerce->resulttype,
8724 -1,
8725 node);
8726 }
8727 }
8728 break;
8729
8730 case T_ArrayCoerceExpr:
8731 {
8732 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
8733 Node *arg = (Node *) acoerce->arg;
8734
8735 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
8736 !showimplicit)
8737 {
8738 /* don't show the implicit cast */
8739 get_rule_expr_paren(arg, context, false, node);
8740 }
8741 else
8742 {
8743 get_coercion_expr(arg, context,
8744 acoerce->resulttype,
8745 acoerce->resulttypmod,
8746 node);
8747 }
8748 }
8749 break;
8750
8751 case T_ConvertRowtypeExpr:
8752 {
8753 ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
8754 Node *arg = (Node *) convert->arg;
8755
8756 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
8757 !showimplicit)
8758 {
8759 /* don't show the implicit cast */
8760 get_rule_expr_paren(arg, context, false, node);
8761 }
8762 else
8763 {
8764 get_coercion_expr(arg, context,
8765 convert->resulttype, -1,
8766 node);
8767 }
8768 }
8769 break;
8770
8771 case T_CollateExpr:
8772 {
8773 CollateExpr *collate = (CollateExpr *) node;
8774 Node *arg = (Node *) collate->arg;
8775
8776 if (!PRETTY_PAREN(context))
8777 appendStringInfoChar(buf, '(');
8778 get_rule_expr_paren(arg, context, showimplicit, node);
8779 appendStringInfo(buf, " COLLATE %s",
8780 generate_collation_name(collate->collOid));
8781 if (!PRETTY_PAREN(context))
8782 appendStringInfoChar(buf, ')');
8783 }
8784 break;
8785
8786 case T_CaseExpr:
8787 {
8788 CaseExpr *caseexpr = (CaseExpr *) node;
8789 ListCell *temp;
8790
8791 appendContextKeyword(context, "CASE",
8792 0, PRETTYINDENT_VAR, 0);
8793 if (caseexpr->arg)
8794 {
8795 appendStringInfoChar(buf, ' ');
8796 get_rule_expr((Node *) caseexpr->arg, context, true);
8797 }
8798 foreach(temp, caseexpr->args)
8799 {
8800 CaseWhen *when = (CaseWhen *) lfirst(temp);
8801 Node *w = (Node *) when->expr;
8802
8803 if (caseexpr->arg)
8804 {
8805 /*
8806 * The parser should have produced WHEN clauses of the
8807 * form "CaseTestExpr = RHS", possibly with an
8808 * implicit coercion inserted above the CaseTestExpr.
8809 * For accurate decompilation of rules it's essential
8810 * that we show just the RHS. However in an
8811 * expression that's been through the optimizer, the
8812 * WHEN clause could be almost anything (since the
8813 * equality operator could have been expanded into an
8814 * inline function). If we don't recognize the form
8815 * of the WHEN clause, just punt and display it as-is.
8816 */
8817 if (IsA(w, OpExpr))
8818 {
8819 List *args = ((OpExpr *) w)->args;
8820
8821 if (list_length(args) == 2 &&
8822 IsA(strip_implicit_coercions(linitial(args)),
8823 CaseTestExpr))
8824 w = (Node *) lsecond(args);
8825 }
8826 }
8827
8828 if (!PRETTY_INDENT(context))
8829 appendStringInfoChar(buf, ' ');
8830 appendContextKeyword(context, "WHEN ",
8831 0, 0, 0);
8832 get_rule_expr(w, context, false);
8833 appendStringInfoString(buf, " THEN ");
8834 get_rule_expr((Node *) when->result, context, true);
8835 }
8836 if (!PRETTY_INDENT(context))
8837 appendStringInfoChar(buf, ' ');
8838 appendContextKeyword(context, "ELSE ",
8839 0, 0, 0);
8840 get_rule_expr((Node *) caseexpr->defresult, context, true);
8841 if (!PRETTY_INDENT(context))
8842 appendStringInfoChar(buf, ' ');
8843 appendContextKeyword(context, "END",
8844 -PRETTYINDENT_VAR, 0, 0);
8845 }
8846 break;
8847
8848 case T_CaseTestExpr:
8849 {
8850 /*
8851 * Normally we should never get here, since for expressions
8852 * that can contain this node type we attempt to avoid
8853 * recursing to it. But in an optimized expression we might
8854 * be unable to avoid that (see comments for CaseExpr). If we
8855 * do see one, print it as CASE_TEST_EXPR.
8856 */
8857 appendStringInfoString(buf, "CASE_TEST_EXPR");
8858 }
8859 break;
8860
8861 case T_ArrayExpr:
8862 {
8863 ArrayExpr *arrayexpr = (ArrayExpr *) node;
8864
8865 appendStringInfoString(buf, "ARRAY[");
8866 get_rule_expr((Node *) arrayexpr->elements, context, true);
8867 appendStringInfoChar(buf, ']');
8868
8869 /*
8870 * If the array isn't empty, we assume its elements are
8871 * coerced to the desired type. If it's empty, though, we
8872 * need an explicit coercion to the array type.
8873 */
8874 if (arrayexpr->elements == NIL)
8875 appendStringInfo(buf, "::%s",
8876 format_type_with_typemod(arrayexpr->array_typeid, -1));
8877 }
8878 break;
8879
8880 case T_RowExpr:
8881 {
8882 RowExpr *rowexpr = (RowExpr *) node;
8883 TupleDesc tupdesc = NULL;
8884 ListCell *arg;
8885 int i;
8886 char *sep;
8887
8888 /*
8889 * If it's a named type and not RECORD, we may have to skip
8890 * dropped columns and/or claim there are NULLs for added
8891 * columns.
8892 */
8893 if (rowexpr->row_typeid != RECORDOID)
8894 {
8895 tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
8896 Assert(list_length(rowexpr->args) <= tupdesc->natts);
8897 }
8898
8899 /*
8900 * SQL99 allows "ROW" to be omitted when there is more than
8901 * one column, but for simplicity we always print it.
8902 */
8903 appendStringInfoString(buf, "ROW(");
8904 sep = "";
8905 i = 0;
8906 foreach(arg, rowexpr->args)
8907 {
8908 Node *e = (Node *) lfirst(arg);
8909
8910 if (tupdesc == NULL ||
8911 !TupleDescAttr(tupdesc, i)->attisdropped)
8912 {
8913 appendStringInfoString(buf, sep);
8914 /* Whole-row Vars need special treatment here */
8915 get_rule_expr_toplevel(e, context, true);
8916 sep = ", ";
8917 }
8918 i++;
8919 }
8920 if (tupdesc != NULL)
8921 {
8922 while (i < tupdesc->natts)
8923 {
8924 if (!TupleDescAttr(tupdesc, i)->attisdropped)
8925 {
8926 appendStringInfoString(buf, sep);
8927 appendStringInfoString(buf, "NULL");
8928 sep = ", ";
8929 }
8930 i++;
8931 }
8932
8933 ReleaseTupleDesc(tupdesc);
8934 }
8935 appendStringInfoChar(buf, ')');
8936 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
8937 appendStringInfo(buf, "::%s",
8938 format_type_with_typemod(rowexpr->row_typeid, -1));
8939 }
8940 break;
8941
8942 case T_RowCompareExpr:
8943 {
8944 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
8945 ListCell *arg;
8946 char *sep;
8947
8948 /*
8949 * SQL99 allows "ROW" to be omitted when there is more than
8950 * one column, but for simplicity we always print it.
8951 */
8952 appendStringInfoString(buf, "(ROW(");
8953 sep = "";
8954 foreach(arg, rcexpr->largs)
8955 {
8956 Node *e = (Node *) lfirst(arg);
8957
8958 appendStringInfoString(buf, sep);
8959 get_rule_expr(e, context, true);
8960 sep = ", ";
8961 }
8962
8963 /*
8964 * We assume that the name of the first-column operator will
8965 * do for all the rest too. This is definitely open to
8966 * failure, eg if some but not all operators were renamed
8967 * since the construct was parsed, but there seems no way to
8968 * be perfect.
8969 */
8970 appendStringInfo(buf, ") %s ROW(",
8971 generate_operator_name(linitial_oid(rcexpr->opnos),
8972 exprType(linitial(rcexpr->largs)),
8973 exprType(linitial(rcexpr->rargs))));
8974 sep = "";
8975 foreach(arg, rcexpr->rargs)
8976 {
8977 Node *e = (Node *) lfirst(arg);
8978
8979 appendStringInfoString(buf, sep);
8980 get_rule_expr(e, context, true);
8981 sep = ", ";
8982 }
8983 appendStringInfoString(buf, "))");
8984 }
8985 break;
8986
8987 case T_CoalesceExpr:
8988 {
8989 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
8990
8991 appendStringInfoString(buf, "COALESCE(");
8992 get_rule_expr((Node *) coalesceexpr->args, context, true);
8993 appendStringInfoChar(buf, ')');
8994 }
8995 break;
8996
8997 case T_MinMaxExpr:
8998 {
8999 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
9000
9001 switch (minmaxexpr->op)
9002 {
9003 case IS_GREATEST:
9004 appendStringInfoString(buf, "GREATEST(");
9005 break;
9006 case IS_LEAST:
9007 appendStringInfoString(buf, "LEAST(");
9008 break;
9009 }
9010 get_rule_expr((Node *) minmaxexpr->args, context, true);
9011 appendStringInfoChar(buf, ')');
9012 }
9013 break;
9014
9015 case T_SQLValueFunction:
9016 {
9017 SQLValueFunction *svf = (SQLValueFunction *) node;
9018
9019 /*
9020 * Note: this code knows that typmod for time, timestamp, and
9021 * timestamptz just prints as integer.
9022 */
9023 switch (svf->op)
9024 {
9025 case SVFOP_CURRENT_DATE:
9026 appendStringInfoString(buf, "CURRENT_DATE");
9027 break;
9028 case SVFOP_CURRENT_TIME:
9029 appendStringInfoString(buf, "CURRENT_TIME");
9030 break;
9031 case SVFOP_CURRENT_TIME_N:
9032 appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
9033 break;
9034 case SVFOP_CURRENT_TIMESTAMP:
9035 appendStringInfoString(buf, "CURRENT_TIMESTAMP");
9036 break;
9037 case SVFOP_CURRENT_TIMESTAMP_N:
9038 appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
9039 svf->typmod);
9040 break;
9041 case SVFOP_LOCALTIME:
9042 appendStringInfoString(buf, "LOCALTIME");
9043 break;
9044 case SVFOP_LOCALTIME_N:
9045 appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
9046 break;
9047 case SVFOP_LOCALTIMESTAMP:
9048 appendStringInfoString(buf, "LOCALTIMESTAMP");
9049 break;
9050 case SVFOP_LOCALTIMESTAMP_N:
9051 appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
9052 svf->typmod);
9053 break;
9054 case SVFOP_CURRENT_ROLE:
9055 appendStringInfoString(buf, "CURRENT_ROLE");
9056 break;
9057 case SVFOP_CURRENT_USER:
9058 appendStringInfoString(buf, "CURRENT_USER");
9059 break;
9060 case SVFOP_USER:
9061 appendStringInfoString(buf, "USER");
9062 break;
9063 case SVFOP_SESSION_USER:
9064 appendStringInfoString(buf, "SESSION_USER");
9065 break;
9066 case SVFOP_CURRENT_CATALOG:
9067 appendStringInfoString(buf, "CURRENT_CATALOG");
9068 break;
9069 case SVFOP_CURRENT_SCHEMA:
9070 appendStringInfoString(buf, "CURRENT_SCHEMA");
9071 break;
9072 }
9073 }
9074 break;
9075
9076 case T_XmlExpr:
9077 {
9078 XmlExpr *xexpr = (XmlExpr *) node;
9079 bool needcomma = false;
9080 ListCell *arg;
9081 ListCell *narg;
9082 Const *con;
9083
9084 switch (xexpr->op)
9085 {
9086 case IS_XMLCONCAT:
9087 appendStringInfoString(buf, "XMLCONCAT(");
9088 break;
9089 case IS_XMLELEMENT:
9090 appendStringInfoString(buf, "XMLELEMENT(");
9091 break;
9092 case IS_XMLFOREST:
9093 appendStringInfoString(buf, "XMLFOREST(");
9094 break;
9095 case IS_XMLPARSE:
9096 appendStringInfoString(buf, "XMLPARSE(");
9097 break;
9098 case IS_XMLPI:
9099 appendStringInfoString(buf, "XMLPI(");
9100 break;
9101 case IS_XMLROOT:
9102 appendStringInfoString(buf, "XMLROOT(");
9103 break;
9104 case IS_XMLSERIALIZE:
9105 appendStringInfoString(buf, "XMLSERIALIZE(");
9106 break;
9107 case IS_DOCUMENT:
9108 break;
9109 }
9110 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
9111 {
9112 if (xexpr->xmloption == XMLOPTION_DOCUMENT)
9113 appendStringInfoString(buf, "DOCUMENT ");
9114 else
9115 appendStringInfoString(buf, "CONTENT ");
9116 }
9117 if (xexpr->name)
9118 {
9119 appendStringInfo(buf, "NAME %s",
9120 quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
9121 needcomma = true;
9122 }
9123 if (xexpr->named_args)
9124 {
9125 if (xexpr->op != IS_XMLFOREST)
9126 {
9127 if (needcomma)
9128 appendStringInfoString(buf, ", ");
9129 appendStringInfoString(buf, "XMLATTRIBUTES(");
9130 needcomma = false;
9131 }
9132 forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
9133 {
9134 Node *e = (Node *) lfirst(arg);
9135 char *argname = strVal(lfirst(narg));
9136
9137 if (needcomma)
9138 appendStringInfoString(buf, ", ");
9139 get_rule_expr((Node *) e, context, true);
9140 appendStringInfo(buf, " AS %s",
9141 quote_identifier(map_xml_name_to_sql_identifier(argname)));
9142 needcomma = true;
9143 }
9144 if (xexpr->op != IS_XMLFOREST)
9145 appendStringInfoChar(buf, ')');
9146 }
9147 if (xexpr->args)
9148 {
9149 if (needcomma)
9150 appendStringInfoString(buf, ", ");
9151 switch (xexpr->op)
9152 {
9153 case IS_XMLCONCAT:
9154 case IS_XMLELEMENT:
9155 case IS_XMLFOREST:
9156 case IS_XMLPI:
9157 case IS_XMLSERIALIZE:
9158 /* no extra decoration needed */
9159 get_rule_expr((Node *) xexpr->args, context, true);
9160 break;
9161 case IS_XMLPARSE:
9162 Assert(list_length(xexpr->args) == 2);
9163
9164 get_rule_expr((Node *) linitial(xexpr->args),
9165 context, true);
9166
9167 con = lsecond_node(Const, xexpr->args);
9168 Assert(!con->constisnull);
9169 if (DatumGetBool(con->constvalue))
9170 appendStringInfoString(buf,
9171 " PRESERVE WHITESPACE");
9172 else
9173 appendStringInfoString(buf,
9174 " STRIP WHITESPACE");
9175 break;
9176 case IS_XMLROOT:
9177 Assert(list_length(xexpr->args) == 3);
9178
9179 get_rule_expr((Node *) linitial(xexpr->args),
9180 context, true);
9181
9182 appendStringInfoString(buf, ", VERSION ");
9183 con = (Const *) lsecond(xexpr->args);
9184 if (IsA(con, Const) &&
9185 con->constisnull)
9186 appendStringInfoString(buf, "NO VALUE");
9187 else
9188 get_rule_expr((Node *) con, context, false);
9189
9190 con = lthird_node(Const, xexpr->args);
9191 if (con->constisnull)
9192 /* suppress STANDALONE NO VALUE */ ;
9193 else
9194 {
9195 switch (DatumGetInt32(con->constvalue))
9196 {
9197 case XML_STANDALONE_YES:
9198 appendStringInfoString(buf,
9199 ", STANDALONE YES");
9200 break;
9201 case XML_STANDALONE_NO:
9202 appendStringInfoString(buf,
9203 ", STANDALONE NO");
9204 break;
9205 case XML_STANDALONE_NO_VALUE:
9206 appendStringInfoString(buf,
9207 ", STANDALONE NO VALUE");
9208 break;
9209 default:
9210 break;
9211 }
9212 }
9213 break;
9214 case IS_DOCUMENT:
9215 get_rule_expr_paren((Node *) xexpr->args, context, false, node);
9216 break;
9217 }
9218
9219 }
9220 if (xexpr->op == IS_XMLSERIALIZE)
9221 appendStringInfo(buf, " AS %s",
9222 format_type_with_typemod(xexpr->type,
9223 xexpr->typmod));
9224 if (xexpr->op == IS_DOCUMENT)
9225 appendStringInfoString(buf, " IS DOCUMENT");
9226 else
9227 appendStringInfoChar(buf, ')');
9228 }
9229 break;
9230
9231 case T_NullTest:
9232 {
9233 NullTest *ntest = (NullTest *) node;
9234
9235 if (!PRETTY_PAREN(context))
9236 appendStringInfoChar(buf, '(');
9237 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
9238
9239 /*
9240 * For scalar inputs, we prefer to print as IS [NOT] NULL,
9241 * which is shorter and traditional. If it's a rowtype input
9242 * but we're applying a scalar test, must print IS [NOT]
9243 * DISTINCT FROM NULL to be semantically correct.
9244 */
9245 if (ntest->argisrow ||
9246 !type_is_rowtype(exprType((Node *) ntest->arg)))
9247 {
9248 switch (ntest->nulltesttype)
9249 {
9250 case IS_NULL:
9251 appendStringInfoString(buf, " IS NULL");
9252 break;
9253 case IS_NOT_NULL:
9254 appendStringInfoString(buf, " IS NOT NULL");
9255 break;
9256 default:
9257 elog(ERROR, "unrecognized nulltesttype: %d",
9258 (int) ntest->nulltesttype);
9259 }
9260 }
9261 else
9262 {
9263 switch (ntest->nulltesttype)
9264 {
9265 case IS_NULL:
9266 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
9267 break;
9268 case IS_NOT_NULL:
9269 appendStringInfoString(buf, " IS DISTINCT FROM NULL");
9270 break;
9271 default:
9272 elog(ERROR, "unrecognized nulltesttype: %d",
9273 (int) ntest->nulltesttype);
9274 }
9275 }
9276 if (!PRETTY_PAREN(context))
9277 appendStringInfoChar(buf, ')');
9278 }
9279 break;
9280
9281 case T_BooleanTest:
9282 {
9283 BooleanTest *btest = (BooleanTest *) node;
9284
9285 if (!PRETTY_PAREN(context))
9286 appendStringInfoChar(buf, '(');
9287 get_rule_expr_paren((Node *) btest->arg, context, false, node);
9288 switch (btest->booltesttype)
9289 {
9290 case IS_TRUE:
9291 appendStringInfoString(buf, " IS TRUE");
9292 break;
9293 case IS_NOT_TRUE:
9294 appendStringInfoString(buf, " IS NOT TRUE");
9295 break;
9296 case IS_FALSE:
9297 appendStringInfoString(buf, " IS FALSE");
9298 break;
9299 case IS_NOT_FALSE:
9300 appendStringInfoString(buf, " IS NOT FALSE");
9301 break;
9302 case IS_UNKNOWN:
9303 appendStringInfoString(buf, " IS UNKNOWN");
9304 break;
9305 case IS_NOT_UNKNOWN:
9306 appendStringInfoString(buf, " IS NOT UNKNOWN");
9307 break;
9308 default:
9309 elog(ERROR, "unrecognized booltesttype: %d",
9310 (int) btest->booltesttype);
9311 }
9312 if (!PRETTY_PAREN(context))
9313 appendStringInfoChar(buf, ')');
9314 }
9315 break;
9316
9317 case T_CoerceToDomain:
9318 {
9319 CoerceToDomain *ctest = (CoerceToDomain *) node;
9320 Node *arg = (Node *) ctest->arg;
9321
9322 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
9323 !showimplicit)
9324 {
9325 /* don't show the implicit cast */
9326 get_rule_expr(arg, context, false);
9327 }
9328 else
9329 {
9330 get_coercion_expr(arg, context,
9331 ctest->resulttype,
9332 ctest->resulttypmod,
9333 node);
9334 }
9335 }
9336 break;
9337
9338 case T_CoerceToDomainValue:
9339 appendStringInfoString(buf, "VALUE");
9340 break;
9341
9342 case T_SetToDefault:
9343 appendStringInfoString(buf, "DEFAULT");
9344 break;
9345
9346 case T_CurrentOfExpr:
9347 {
9348 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
9349
9350 if (cexpr->cursor_name)
9351 appendStringInfo(buf, "CURRENT OF %s",
9352 quote_identifier(cexpr->cursor_name));
9353 else
9354 appendStringInfo(buf, "CURRENT OF $%d",
9355 cexpr->cursor_param);
9356 }
9357 break;
9358
9359 case T_NextValueExpr:
9360 {
9361 NextValueExpr *nvexpr = (NextValueExpr *) node;
9362
9363 /*
9364 * This isn't exactly nextval(), but that seems close enough
9365 * for EXPLAIN's purposes.
9366 */
9367 appendStringInfoString(buf, "nextval(");
9368 simple_quote_literal(buf,
9369 generate_relation_name(nvexpr->seqid,
9370 NIL));
9371 appendStringInfoChar(buf, ')');
9372 }
9373 break;
9374
9375 case T_InferenceElem:
9376 {
9377 InferenceElem *iexpr = (InferenceElem *) node;
9378 bool save_varprefix;
9379 bool need_parens;
9380
9381 /*
9382 * InferenceElem can only refer to target relation, so a
9383 * prefix is not useful, and indeed would cause parse errors.
9384 */
9385 save_varprefix = context->varprefix;
9386 context->varprefix = false;
9387
9388 /*
9389 * Parenthesize the element unless it's a simple Var or a bare
9390 * function call. Follows pg_get_indexdef_worker().
9391 */
9392 need_parens = !IsA(iexpr->expr, Var);
9393 if (IsA(iexpr->expr, FuncExpr) &&
9394 ((FuncExpr *) iexpr->expr)->funcformat ==
9395 COERCE_EXPLICIT_CALL)
9396 need_parens = false;
9397
9398 if (need_parens)
9399 appendStringInfoChar(buf, '(');
9400 get_rule_expr((Node *) iexpr->expr,
9401 context, false);
9402 if (need_parens)
9403 appendStringInfoChar(buf, ')');
9404
9405 context->varprefix = save_varprefix;
9406
9407 if (iexpr->infercollid)
9408 appendStringInfo(buf, " COLLATE %s",
9409 generate_collation_name(iexpr->infercollid));
9410
9411 /* Add the operator class name, if not default */
9412 if (iexpr->inferopclass)
9413 {
9414 Oid inferopclass = iexpr->inferopclass;
9415 Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
9416
9417 get_opclass_name(inferopclass, inferopcinputtype, buf);
9418 }
9419 }
9420 break;
9421
9422 case T_PartitionBoundSpec:
9423 {
9424 PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
9425 ListCell *cell;
9426 char *sep;
9427
9428 if (spec->is_default)
9429 {
9430 appendStringInfoString(buf, "DEFAULT");
9431 break;
9432 }
9433
9434 switch (spec->strategy)
9435 {
9436 case PARTITION_STRATEGY_HASH:
9437 Assert(spec->modulus > 0 && spec->remainder >= 0);
9438 Assert(spec->modulus > spec->remainder);
9439
9440 appendStringInfoString(buf, "FOR VALUES");
9441 appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
9442 spec->modulus, spec->remainder);
9443 break;
9444
9445 case PARTITION_STRATEGY_LIST:
9446 Assert(spec->listdatums != NIL);
9447
9448 appendStringInfoString(buf, "FOR VALUES IN (");
9449 sep = "";
9450 foreach(cell, spec->listdatums)
9451 {
9452 Const *val = castNode(Const, lfirst(cell));
9453
9454 appendStringInfoString(buf, sep);
9455 get_const_expr(val, context, -1);
9456 sep = ", ";
9457 }
9458
9459 appendStringInfoChar(buf, ')');
9460 break;
9461
9462 case PARTITION_STRATEGY_RANGE:
9463 Assert(spec->lowerdatums != NIL &&
9464 spec->upperdatums != NIL &&
9465 list_length(spec->lowerdatums) ==
9466 list_length(spec->upperdatums));
9467
9468 appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
9469 get_range_partbound_string(spec->lowerdatums),
9470 get_range_partbound_string(spec->upperdatums));
9471 break;
9472
9473 default:
9474 elog(ERROR, "unrecognized partition strategy: %d",
9475 (int) spec->strategy);
9476 break;
9477 }
9478 }
9479 break;
9480
9481 case T_List:
9482 {
9483 char *sep;
9484 ListCell *l;
9485
9486 sep = "";
9487 foreach(l, (List *) node)
9488 {
9489 appendStringInfoString(buf, sep);
9490 get_rule_expr((Node *) lfirst(l), context, showimplicit);
9491 sep = ", ";
9492 }
9493 }
9494 break;
9495
9496 case T_TableFunc:
9497 get_tablefunc((TableFunc *) node, context, showimplicit);
9498 break;
9499
9500 default:
9501 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
9502 break;
9503 }
9504 }
9505
9506 /*
9507 * get_rule_expr_toplevel - Parse back a toplevel expression
9508 *
9509 * Same as get_rule_expr(), except that if the expr is just a Var, we pass
9510 * istoplevel = true not false to get_variable(). This causes whole-row Vars
9511 * to get printed with decoration that will prevent expansion of "*".
9512 * We need to use this in contexts such as ROW() and VALUES(), where the
9513 * parser would expand "foo.*" appearing at top level. (In principle we'd
9514 * use this in get_target_list() too, but that has additional worries about
9515 * whether to print AS, so it needs to invoke get_variable() directly anyway.)
9516 */
9517 static void
get_rule_expr_toplevel(Node * node,deparse_context * context,bool showimplicit)9518 get_rule_expr_toplevel(Node *node, deparse_context *context,
9519 bool showimplicit)
9520 {
9521 if (node && IsA(node, Var))
9522 (void) get_variable((Var *) node, 0, true, context);
9523 else
9524 get_rule_expr(node, context, showimplicit);
9525 }
9526
9527 /*
9528 * get_rule_expr_funccall - Parse back a function-call expression
9529 *
9530 * Same as get_rule_expr(), except that we guarantee that the output will
9531 * look like a function call, or like one of the things the grammar treats as
9532 * equivalent to a function call (see the func_expr_windowless production).
9533 * This is needed in places where the grammar uses func_expr_windowless and
9534 * you can't substitute a parenthesized a_expr. If what we have isn't going
9535 * to look like a function call, wrap it in a dummy CAST() expression, which
9536 * will satisfy the grammar --- and, indeed, is likely what the user wrote to
9537 * produce such a thing.
9538 */
9539 static void
get_rule_expr_funccall(Node * node,deparse_context * context,bool showimplicit)9540 get_rule_expr_funccall(Node *node, deparse_context *context,
9541 bool showimplicit)
9542 {
9543 if (looks_like_function(node))
9544 get_rule_expr(node, context, showimplicit);
9545 else
9546 {
9547 StringInfo buf = context->buf;
9548
9549 appendStringInfoString(buf, "CAST(");
9550 /* no point in showing any top-level implicit cast */
9551 get_rule_expr(node, context, false);
9552 appendStringInfo(buf, " AS %s)",
9553 format_type_with_typemod(exprType(node),
9554 exprTypmod(node)));
9555 }
9556 }
9557
9558 /*
9559 * Helper function to identify node types that satisfy func_expr_windowless.
9560 * If in doubt, "false" is always a safe answer.
9561 */
9562 static bool
looks_like_function(Node * node)9563 looks_like_function(Node *node)
9564 {
9565 if (node == NULL)
9566 return false; /* probably shouldn't happen */
9567 switch (nodeTag(node))
9568 {
9569 case T_FuncExpr:
9570 /* OK, unless it's going to deparse as a cast */
9571 return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
9572 ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
9573 case T_NullIfExpr:
9574 case T_CoalesceExpr:
9575 case T_MinMaxExpr:
9576 case T_SQLValueFunction:
9577 case T_XmlExpr:
9578 /* these are all accepted by func_expr_common_subexpr */
9579 return true;
9580 default:
9581 break;
9582 }
9583 return false;
9584 }
9585
9586
9587 /*
9588 * get_oper_expr - Parse back an OpExpr node
9589 */
9590 static void
get_oper_expr(OpExpr * expr,deparse_context * context)9591 get_oper_expr(OpExpr *expr, deparse_context *context)
9592 {
9593 StringInfo buf = context->buf;
9594 Oid opno = expr->opno;
9595 List *args = expr->args;
9596
9597 if (!PRETTY_PAREN(context))
9598 appendStringInfoChar(buf, '(');
9599 if (list_length(args) == 2)
9600 {
9601 /* binary operator */
9602 Node *arg1 = (Node *) linitial(args);
9603 Node *arg2 = (Node *) lsecond(args);
9604
9605 get_rule_expr_paren(arg1, context, true, (Node *) expr);
9606 appendStringInfo(buf, " %s ",
9607 generate_operator_name(opno,
9608 exprType(arg1),
9609 exprType(arg2)));
9610 get_rule_expr_paren(arg2, context, true, (Node *) expr);
9611 }
9612 else
9613 {
9614 /* prefix operator */
9615 Node *arg = (Node *) linitial(args);
9616
9617 appendStringInfo(buf, "%s ",
9618 generate_operator_name(opno,
9619 InvalidOid,
9620 exprType(arg)));
9621 get_rule_expr_paren(arg, context, true, (Node *) expr);
9622 }
9623 if (!PRETTY_PAREN(context))
9624 appendStringInfoChar(buf, ')');
9625 }
9626
9627 /*
9628 * get_func_expr - Parse back a FuncExpr node
9629 */
9630 static void
get_func_expr(FuncExpr * expr,deparse_context * context,bool showimplicit)9631 get_func_expr(FuncExpr *expr, deparse_context *context,
9632 bool showimplicit)
9633 {
9634 StringInfo buf = context->buf;
9635 Oid funcoid = expr->funcid;
9636 Oid argtypes[FUNC_MAX_ARGS];
9637 int nargs;
9638 List *argnames;
9639 bool use_variadic;
9640 ListCell *l;
9641
9642 /*
9643 * If the function call came from an implicit coercion, then just show the
9644 * first argument --- unless caller wants to see implicit coercions.
9645 */
9646 if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
9647 {
9648 get_rule_expr_paren((Node *) linitial(expr->args), context,
9649 false, (Node *) expr);
9650 return;
9651 }
9652
9653 /*
9654 * If the function call came from a cast, then show the first argument
9655 * plus an explicit cast operation.
9656 */
9657 if (expr->funcformat == COERCE_EXPLICIT_CAST ||
9658 expr->funcformat == COERCE_IMPLICIT_CAST)
9659 {
9660 Node *arg = linitial(expr->args);
9661 Oid rettype = expr->funcresulttype;
9662 int32 coercedTypmod;
9663
9664 /* Get the typmod if this is a length-coercion function */
9665 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
9666
9667 get_coercion_expr(arg, context,
9668 rettype, coercedTypmod,
9669 (Node *) expr);
9670
9671 return;
9672 }
9673
9674 /*
9675 * If the function was called using one of the SQL spec's random special
9676 * syntaxes, try to reproduce that. If we don't recognize the function,
9677 * fall through.
9678 */
9679 if (expr->funcformat == COERCE_SQL_SYNTAX)
9680 {
9681 if (get_func_sql_syntax(expr, context))
9682 return;
9683 }
9684
9685 /*
9686 * Normal function: display as proname(args). First we need to extract
9687 * the argument datatypes.
9688 */
9689 if (list_length(expr->args) > FUNC_MAX_ARGS)
9690 ereport(ERROR,
9691 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
9692 errmsg("too many arguments")));
9693 nargs = 0;
9694 argnames = NIL;
9695 foreach(l, expr->args)
9696 {
9697 Node *arg = (Node *) lfirst(l);
9698
9699 if (IsA(arg, NamedArgExpr))
9700 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
9701 argtypes[nargs] = exprType(arg);
9702 nargs++;
9703 }
9704
9705 appendStringInfo(buf, "%s(",
9706 generate_function_name(funcoid, nargs,
9707 argnames, argtypes,
9708 expr->funcvariadic,
9709 &use_variadic,
9710 context->special_exprkind));
9711 nargs = 0;
9712 foreach(l, expr->args)
9713 {
9714 if (nargs++ > 0)
9715 appendStringInfoString(buf, ", ");
9716 if (use_variadic && lnext(expr->args, l) == NULL)
9717 appendStringInfoString(buf, "VARIADIC ");
9718 get_rule_expr((Node *) lfirst(l), context, true);
9719 }
9720 appendStringInfoChar(buf, ')');
9721 }
9722
9723 /*
9724 * get_agg_expr - Parse back an Aggref node
9725 */
9726 static void
get_agg_expr(Aggref * aggref,deparse_context * context,Aggref * original_aggref)9727 get_agg_expr(Aggref *aggref, deparse_context *context,
9728 Aggref *original_aggref)
9729 {
9730 StringInfo buf = context->buf;
9731 Oid argtypes[FUNC_MAX_ARGS];
9732 int nargs;
9733 bool use_variadic;
9734
9735 /*
9736 * For a combining aggregate, we look up and deparse the corresponding
9737 * partial aggregate instead. This is necessary because our input
9738 * argument list has been replaced; the new argument list always has just
9739 * one element, which will point to a partial Aggref that supplies us with
9740 * transition states to combine.
9741 */
9742 if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
9743 {
9744 TargetEntry *tle;
9745
9746 Assert(list_length(aggref->args) == 1);
9747 tle = linitial_node(TargetEntry, aggref->args);
9748 resolve_special_varno((Node *) tle->expr, context,
9749 get_agg_combine_expr, original_aggref);
9750 return;
9751 }
9752
9753 /*
9754 * Mark as PARTIAL, if appropriate. We look to the original aggref so as
9755 * to avoid printing this when recursing from the code just above.
9756 */
9757 if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
9758 appendStringInfoString(buf, "PARTIAL ");
9759
9760 /* Extract the argument types as seen by the parser */
9761 nargs = get_aggregate_argtypes(aggref, argtypes);
9762
9763 /* Print the aggregate name, schema-qualified if needed */
9764 appendStringInfo(buf, "%s(%s",
9765 generate_function_name(aggref->aggfnoid, nargs,
9766 NIL, argtypes,
9767 aggref->aggvariadic,
9768 &use_variadic,
9769 context->special_exprkind),
9770 (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
9771
9772 if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
9773 {
9774 /*
9775 * Ordered-set aggregates do not use "*" syntax. Also, we needn't
9776 * worry about inserting VARIADIC. So we can just dump the direct
9777 * args as-is.
9778 */
9779 Assert(!aggref->aggvariadic);
9780 get_rule_expr((Node *) aggref->aggdirectargs, context, true);
9781 Assert(aggref->aggorder != NIL);
9782 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
9783 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
9784 }
9785 else
9786 {
9787 /* aggstar can be set only in zero-argument aggregates */
9788 if (aggref->aggstar)
9789 appendStringInfoChar(buf, '*');
9790 else
9791 {
9792 ListCell *l;
9793 int i;
9794
9795 i = 0;
9796 foreach(l, aggref->args)
9797 {
9798 TargetEntry *tle = (TargetEntry *) lfirst(l);
9799 Node *arg = (Node *) tle->expr;
9800
9801 Assert(!IsA(arg, NamedArgExpr));
9802 if (tle->resjunk)
9803 continue;
9804 if (i++ > 0)
9805 appendStringInfoString(buf, ", ");
9806 if (use_variadic && i == nargs)
9807 appendStringInfoString(buf, "VARIADIC ");
9808 get_rule_expr(arg, context, true);
9809 }
9810 }
9811
9812 if (aggref->aggorder != NIL)
9813 {
9814 appendStringInfoString(buf, " ORDER BY ");
9815 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
9816 }
9817 }
9818
9819 if (aggref->aggfilter != NULL)
9820 {
9821 appendStringInfoString(buf, ") FILTER (WHERE ");
9822 get_rule_expr((Node *) aggref->aggfilter, context, false);
9823 }
9824
9825 appendStringInfoChar(buf, ')');
9826 }
9827
9828 /*
9829 * This is a helper function for get_agg_expr(). It's used when we deparse
9830 * a combining Aggref; resolve_special_varno locates the corresponding partial
9831 * Aggref and then calls this.
9832 */
9833 static void
get_agg_combine_expr(Node * node,deparse_context * context,void * callback_arg)9834 get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
9835 {
9836 Aggref *aggref;
9837 Aggref *original_aggref = callback_arg;
9838
9839 if (!IsA(node, Aggref))
9840 elog(ERROR, "combining Aggref does not point to an Aggref");
9841
9842 aggref = (Aggref *) node;
9843 get_agg_expr(aggref, context, original_aggref);
9844 }
9845
9846 /*
9847 * get_windowfunc_expr - Parse back a WindowFunc node
9848 */
9849 static void
get_windowfunc_expr(WindowFunc * wfunc,deparse_context * context)9850 get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
9851 {
9852 StringInfo buf = context->buf;
9853 Oid argtypes[FUNC_MAX_ARGS];
9854 int nargs;
9855 List *argnames;
9856 ListCell *l;
9857
9858 if (list_length(wfunc->args) > FUNC_MAX_ARGS)
9859 ereport(ERROR,
9860 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
9861 errmsg("too many arguments")));
9862 nargs = 0;
9863 argnames = NIL;
9864 foreach(l, wfunc->args)
9865 {
9866 Node *arg = (Node *) lfirst(l);
9867
9868 if (IsA(arg, NamedArgExpr))
9869 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
9870 argtypes[nargs] = exprType(arg);
9871 nargs++;
9872 }
9873
9874 appendStringInfo(buf, "%s(",
9875 generate_function_name(wfunc->winfnoid, nargs,
9876 argnames, argtypes,
9877 false, NULL,
9878 context->special_exprkind));
9879 /* winstar can be set only in zero-argument aggregates */
9880 if (wfunc->winstar)
9881 appendStringInfoChar(buf, '*');
9882 else
9883 get_rule_expr((Node *) wfunc->args, context, true);
9884
9885 if (wfunc->aggfilter != NULL)
9886 {
9887 appendStringInfoString(buf, ") FILTER (WHERE ");
9888 get_rule_expr((Node *) wfunc->aggfilter, context, false);
9889 }
9890
9891 appendStringInfoString(buf, ") OVER ");
9892
9893 foreach(l, context->windowClause)
9894 {
9895 WindowClause *wc = (WindowClause *) lfirst(l);
9896
9897 if (wc->winref == wfunc->winref)
9898 {
9899 if (wc->name)
9900 appendStringInfoString(buf, quote_identifier(wc->name));
9901 else
9902 get_rule_windowspec(wc, context->windowTList, context);
9903 break;
9904 }
9905 }
9906 if (l == NULL)
9907 {
9908 if (context->windowClause)
9909 elog(ERROR, "could not find window clause for winref %u",
9910 wfunc->winref);
9911
9912 /*
9913 * In EXPLAIN, we don't have window context information available, so
9914 * we have to settle for this:
9915 */
9916 appendStringInfoString(buf, "(?)");
9917 }
9918 }
9919
9920 /*
9921 * get_func_sql_syntax - Parse back a SQL-syntax function call
9922 *
9923 * Returns true if we successfully deparsed, false if we did not
9924 * recognize the function.
9925 */
9926 static bool
get_func_sql_syntax(FuncExpr * expr,deparse_context * context)9927 get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
9928 {
9929 StringInfo buf = context->buf;
9930 Oid funcoid = expr->funcid;
9931
9932 switch (funcoid)
9933 {
9934 case F_TIMEZONE_INTERVAL_TIMESTAMP:
9935 case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
9936 case F_TIMEZONE_INTERVAL_TIMETZ:
9937 case F_TIMEZONE_TEXT_TIMESTAMP:
9938 case F_TIMEZONE_TEXT_TIMESTAMPTZ:
9939 case F_TIMEZONE_TEXT_TIMETZ:
9940 /* AT TIME ZONE ... note reversed argument order */
9941 appendStringInfoChar(buf, '(');
9942 get_rule_expr((Node *) lsecond(expr->args), context, false);
9943 appendStringInfoString(buf, " AT TIME ZONE ");
9944 get_rule_expr((Node *) linitial(expr->args), context, false);
9945 appendStringInfoChar(buf, ')');
9946 return true;
9947
9948 case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
9949 case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
9950 case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
9951 case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
9952 case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
9953 case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
9954 case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
9955 case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
9956 case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
9957 case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
9958 case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
9959 case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
9960 case F_OVERLAPS_TIME_TIME_TIME_TIME:
9961 /* (x1, x2) OVERLAPS (y1, y2) */
9962 appendStringInfoString(buf, "((");
9963 get_rule_expr((Node *) linitial(expr->args), context, false);
9964 appendStringInfoString(buf, ", ");
9965 get_rule_expr((Node *) lsecond(expr->args), context, false);
9966 appendStringInfoString(buf, ") OVERLAPS (");
9967 get_rule_expr((Node *) lthird(expr->args), context, false);
9968 appendStringInfoString(buf, ", ");
9969 get_rule_expr((Node *) lfourth(expr->args), context, false);
9970 appendStringInfoString(buf, "))");
9971 return true;
9972
9973 case F_EXTRACT_TEXT_DATE:
9974 case F_EXTRACT_TEXT_TIME:
9975 case F_EXTRACT_TEXT_TIMETZ:
9976 case F_EXTRACT_TEXT_TIMESTAMP:
9977 case F_EXTRACT_TEXT_TIMESTAMPTZ:
9978 case F_EXTRACT_TEXT_INTERVAL:
9979 /* EXTRACT (x FROM y) */
9980 appendStringInfoString(buf, "EXTRACT(");
9981 {
9982 Const *con = (Const *) linitial(expr->args);
9983
9984 Assert(IsA(con, Const) &&
9985 con->consttype == TEXTOID &&
9986 !con->constisnull);
9987 appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
9988 }
9989 appendStringInfoString(buf, " FROM ");
9990 get_rule_expr((Node *) lsecond(expr->args), context, false);
9991 appendStringInfoChar(buf, ')');
9992 return true;
9993
9994 case F_IS_NORMALIZED:
9995 /* IS xxx NORMALIZED */
9996 appendStringInfoString(buf, "((");
9997 get_rule_expr((Node *) linitial(expr->args), context, false);
9998 appendStringInfoString(buf, ") IS");
9999 if (list_length(expr->args) == 2)
10000 {
10001 Const *con = (Const *) lsecond(expr->args);
10002
10003 Assert(IsA(con, Const) &&
10004 con->consttype == TEXTOID &&
10005 !con->constisnull);
10006 appendStringInfo(buf, " %s",
10007 TextDatumGetCString(con->constvalue));
10008 }
10009 appendStringInfoString(buf, " NORMALIZED)");
10010 return true;
10011
10012 case F_PG_COLLATION_FOR:
10013 /* COLLATION FOR */
10014 appendStringInfoString(buf, "COLLATION FOR (");
10015 get_rule_expr((Node *) linitial(expr->args), context, false);
10016 appendStringInfoChar(buf, ')');
10017 return true;
10018
10019 /*
10020 * XXX EXTRACT, a/k/a date_part(), is intentionally not covered
10021 * yet. Add it after we change the return type to numeric.
10022 */
10023
10024 case F_NORMALIZE:
10025 /* NORMALIZE() */
10026 appendStringInfoString(buf, "NORMALIZE(");
10027 get_rule_expr((Node *) linitial(expr->args), context, false);
10028 if (list_length(expr->args) == 2)
10029 {
10030 Const *con = (Const *) lsecond(expr->args);
10031
10032 Assert(IsA(con, Const) &&
10033 con->consttype == TEXTOID &&
10034 !con->constisnull);
10035 appendStringInfo(buf, ", %s",
10036 TextDatumGetCString(con->constvalue));
10037 }
10038 appendStringInfoChar(buf, ')');
10039 return true;
10040
10041 case F_OVERLAY_BIT_BIT_INT4:
10042 case F_OVERLAY_BIT_BIT_INT4_INT4:
10043 case F_OVERLAY_BYTEA_BYTEA_INT4:
10044 case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
10045 case F_OVERLAY_TEXT_TEXT_INT4:
10046 case F_OVERLAY_TEXT_TEXT_INT4_INT4:
10047 /* OVERLAY() */
10048 appendStringInfoString(buf, "OVERLAY(");
10049 get_rule_expr((Node *) linitial(expr->args), context, false);
10050 appendStringInfoString(buf, " PLACING ");
10051 get_rule_expr((Node *) lsecond(expr->args), context, false);
10052 appendStringInfoString(buf, " FROM ");
10053 get_rule_expr((Node *) lthird(expr->args), context, false);
10054 if (list_length(expr->args) == 4)
10055 {
10056 appendStringInfoString(buf, " FOR ");
10057 get_rule_expr((Node *) lfourth(expr->args), context, false);
10058 }
10059 appendStringInfoChar(buf, ')');
10060 return true;
10061
10062 case F_POSITION_BIT_BIT:
10063 case F_POSITION_BYTEA_BYTEA:
10064 case F_POSITION_TEXT_TEXT:
10065 /* POSITION() ... extra parens since args are b_expr not a_expr */
10066 appendStringInfoString(buf, "POSITION((");
10067 get_rule_expr((Node *) lsecond(expr->args), context, false);
10068 appendStringInfoString(buf, ") IN (");
10069 get_rule_expr((Node *) linitial(expr->args), context, false);
10070 appendStringInfoString(buf, "))");
10071 return true;
10072
10073 case F_SUBSTRING_BIT_INT4:
10074 case F_SUBSTRING_BIT_INT4_INT4:
10075 case F_SUBSTRING_BYTEA_INT4:
10076 case F_SUBSTRING_BYTEA_INT4_INT4:
10077 case F_SUBSTRING_TEXT_INT4:
10078 case F_SUBSTRING_TEXT_INT4_INT4:
10079 /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
10080 appendStringInfoString(buf, "SUBSTRING(");
10081 get_rule_expr((Node *) linitial(expr->args), context, false);
10082 appendStringInfoString(buf, " FROM ");
10083 get_rule_expr((Node *) lsecond(expr->args), context, false);
10084 if (list_length(expr->args) == 3)
10085 {
10086 appendStringInfoString(buf, " FOR ");
10087 get_rule_expr((Node *) lthird(expr->args), context, false);
10088 }
10089 appendStringInfoChar(buf, ')');
10090 return true;
10091
10092 case F_SUBSTRING_TEXT_TEXT_TEXT:
10093 /* SUBSTRING SIMILAR/ESCAPE */
10094 appendStringInfoString(buf, "SUBSTRING(");
10095 get_rule_expr((Node *) linitial(expr->args), context, false);
10096 appendStringInfoString(buf, " SIMILAR ");
10097 get_rule_expr((Node *) lsecond(expr->args), context, false);
10098 appendStringInfoString(buf, " ESCAPE ");
10099 get_rule_expr((Node *) lthird(expr->args), context, false);
10100 appendStringInfoChar(buf, ')');
10101 return true;
10102
10103 case F_BTRIM_BYTEA_BYTEA:
10104 case F_BTRIM_TEXT:
10105 case F_BTRIM_TEXT_TEXT:
10106 /* TRIM() */
10107 appendStringInfoString(buf, "TRIM(BOTH");
10108 if (list_length(expr->args) == 2)
10109 {
10110 appendStringInfoChar(buf, ' ');
10111 get_rule_expr((Node *) lsecond(expr->args), context, false);
10112 }
10113 appendStringInfoString(buf, " FROM ");
10114 get_rule_expr((Node *) linitial(expr->args), context, false);
10115 appendStringInfoChar(buf, ')');
10116 return true;
10117
10118 case F_LTRIM_BYTEA_BYTEA:
10119 case F_LTRIM_TEXT:
10120 case F_LTRIM_TEXT_TEXT:
10121 /* TRIM() */
10122 appendStringInfoString(buf, "TRIM(LEADING");
10123 if (list_length(expr->args) == 2)
10124 {
10125 appendStringInfoChar(buf, ' ');
10126 get_rule_expr((Node *) lsecond(expr->args), context, false);
10127 }
10128 appendStringInfoString(buf, " FROM ");
10129 get_rule_expr((Node *) linitial(expr->args), context, false);
10130 appendStringInfoChar(buf, ')');
10131 return true;
10132
10133 case F_RTRIM_BYTEA_BYTEA:
10134 case F_RTRIM_TEXT:
10135 case F_RTRIM_TEXT_TEXT:
10136 /* TRIM() */
10137 appendStringInfoString(buf, "TRIM(TRAILING");
10138 if (list_length(expr->args) == 2)
10139 {
10140 appendStringInfoChar(buf, ' ');
10141 get_rule_expr((Node *) lsecond(expr->args), context, false);
10142 }
10143 appendStringInfoString(buf, " FROM ");
10144 get_rule_expr((Node *) linitial(expr->args), context, false);
10145 appendStringInfoChar(buf, ')');
10146 return true;
10147
10148 case F_XMLEXISTS:
10149 /* XMLEXISTS ... extra parens because args are c_expr */
10150 appendStringInfoString(buf, "XMLEXISTS((");
10151 get_rule_expr((Node *) linitial(expr->args), context, false);
10152 appendStringInfoString(buf, ") PASSING (");
10153 get_rule_expr((Node *) lsecond(expr->args), context, false);
10154 appendStringInfoString(buf, "))");
10155 return true;
10156 }
10157 return false;
10158 }
10159
10160 /* ----------
10161 * get_coercion_expr
10162 *
10163 * Make a string representation of a value coerced to a specific type
10164 * ----------
10165 */
10166 static void
get_coercion_expr(Node * arg,deparse_context * context,Oid resulttype,int32 resulttypmod,Node * parentNode)10167 get_coercion_expr(Node *arg, deparse_context *context,
10168 Oid resulttype, int32 resulttypmod,
10169 Node *parentNode)
10170 {
10171 StringInfo buf = context->buf;
10172
10173 /*
10174 * Since parse_coerce.c doesn't immediately collapse application of
10175 * length-coercion functions to constants, what we'll typically see in
10176 * such cases is a Const with typmod -1 and a length-coercion function
10177 * right above it. Avoid generating redundant output. However, beware of
10178 * suppressing casts when the user actually wrote something like
10179 * 'foo'::text::char(3).
10180 *
10181 * Note: it might seem that we are missing the possibility of needing to
10182 * print a COLLATE clause for such a Const. However, a Const could only
10183 * have nondefault collation in a post-constant-folding tree, in which the
10184 * length coercion would have been folded too. See also the special
10185 * handling of CollateExpr in coerce_to_target_type(): any collation
10186 * marking will be above the coercion node, not below it.
10187 */
10188 if (arg && IsA(arg, Const) &&
10189 ((Const *) arg)->consttype == resulttype &&
10190 ((Const *) arg)->consttypmod == -1)
10191 {
10192 /* Show the constant without normal ::typename decoration */
10193 get_const_expr((Const *) arg, context, -1);
10194 }
10195 else
10196 {
10197 if (!PRETTY_PAREN(context))
10198 appendStringInfoChar(buf, '(');
10199 get_rule_expr_paren(arg, context, false, parentNode);
10200 if (!PRETTY_PAREN(context))
10201 appendStringInfoChar(buf, ')');
10202 }
10203
10204 /*
10205 * Never emit resulttype(arg) functional notation. A pg_proc entry could
10206 * take precedence, and a resulttype in pg_temp would require schema
10207 * qualification that format_type_with_typemod() would usually omit. We've
10208 * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
10209 * would work fine.
10210 */
10211 appendStringInfo(buf, "::%s",
10212 format_type_with_typemod(resulttype, resulttypmod));
10213 }
10214
10215 /* ----------
10216 * get_const_expr
10217 *
10218 * Make a string representation of a Const
10219 *
10220 * showtype can be -1 to never show "::typename" decoration, or +1 to always
10221 * show it, or 0 to show it only if the constant wouldn't be assumed to be
10222 * the right type by default.
10223 *
10224 * If the Const's collation isn't default for its type, show that too.
10225 * We mustn't do this when showtype is -1 (since that means the caller will
10226 * print "::typename", and we can't put a COLLATE clause in between). It's
10227 * caller's responsibility that collation isn't missed in such cases.
10228 * ----------
10229 */
10230 static void
get_const_expr(Const * constval,deparse_context * context,int showtype)10231 get_const_expr(Const *constval, deparse_context *context, int showtype)
10232 {
10233 StringInfo buf = context->buf;
10234 Oid typoutput;
10235 bool typIsVarlena;
10236 char *extval;
10237 bool needlabel = false;
10238
10239 if (constval->constisnull)
10240 {
10241 /*
10242 * Always label the type of a NULL constant to prevent misdecisions
10243 * about type when reparsing.
10244 */
10245 appendStringInfoString(buf, "NULL");
10246 if (showtype >= 0)
10247 {
10248 appendStringInfo(buf, "::%s",
10249 format_type_with_typemod(constval->consttype,
10250 constval->consttypmod));
10251 get_const_collation(constval, context);
10252 }
10253 return;
10254 }
10255
10256 getTypeOutputInfo(constval->consttype,
10257 &typoutput, &typIsVarlena);
10258
10259 extval = OidOutputFunctionCall(typoutput, constval->constvalue);
10260
10261 switch (constval->consttype)
10262 {
10263 case INT4OID:
10264
10265 /*
10266 * INT4 can be printed without any decoration, unless it is
10267 * negative; in that case print it as '-nnn'::integer to ensure
10268 * that the output will re-parse as a constant, not as a constant
10269 * plus operator. In most cases we could get away with printing
10270 * (-nnn) instead, because of the way that gram.y handles negative
10271 * literals; but that doesn't work for INT_MIN, and it doesn't
10272 * seem that much prettier anyway.
10273 */
10274 if (extval[0] != '-')
10275 appendStringInfoString(buf, extval);
10276 else
10277 {
10278 appendStringInfo(buf, "'%s'", extval);
10279 needlabel = true; /* we must attach a cast */
10280 }
10281 break;
10282
10283 case NUMERICOID:
10284
10285 /*
10286 * NUMERIC can be printed without quotes if it looks like a float
10287 * constant (not an integer, and not Infinity or NaN) and doesn't
10288 * have a leading sign (for the same reason as for INT4).
10289 */
10290 if (isdigit((unsigned char) extval[0]) &&
10291 strcspn(extval, "eE.") != strlen(extval))
10292 {
10293 appendStringInfoString(buf, extval);
10294 }
10295 else
10296 {
10297 appendStringInfo(buf, "'%s'", extval);
10298 needlabel = true; /* we must attach a cast */
10299 }
10300 break;
10301
10302 case BOOLOID:
10303 if (strcmp(extval, "t") == 0)
10304 appendStringInfoString(buf, "true");
10305 else
10306 appendStringInfoString(buf, "false");
10307 break;
10308
10309 default:
10310 simple_quote_literal(buf, extval);
10311 break;
10312 }
10313
10314 pfree(extval);
10315
10316 if (showtype < 0)
10317 return;
10318
10319 /*
10320 * For showtype == 0, append ::typename unless the constant will be
10321 * implicitly typed as the right type when it is read in.
10322 *
10323 * XXX this code has to be kept in sync with the behavior of the parser,
10324 * especially make_const.
10325 */
10326 switch (constval->consttype)
10327 {
10328 case BOOLOID:
10329 case UNKNOWNOID:
10330 /* These types can be left unlabeled */
10331 needlabel = false;
10332 break;
10333 case INT4OID:
10334 /* We determined above whether a label is needed */
10335 break;
10336 case NUMERICOID:
10337
10338 /*
10339 * Float-looking constants will be typed as numeric, which we
10340 * checked above; but if there's a nondefault typmod we need to
10341 * show it.
10342 */
10343 needlabel |= (constval->consttypmod >= 0);
10344 break;
10345 default:
10346 needlabel = true;
10347 break;
10348 }
10349 if (needlabel || showtype > 0)
10350 appendStringInfo(buf, "::%s",
10351 format_type_with_typemod(constval->consttype,
10352 constval->consttypmod));
10353
10354 get_const_collation(constval, context);
10355 }
10356
10357 /*
10358 * helper for get_const_expr: append COLLATE if needed
10359 */
10360 static void
get_const_collation(Const * constval,deparse_context * context)10361 get_const_collation(Const *constval, deparse_context *context)
10362 {
10363 StringInfo buf = context->buf;
10364
10365 if (OidIsValid(constval->constcollid))
10366 {
10367 Oid typcollation = get_typcollation(constval->consttype);
10368
10369 if (constval->constcollid != typcollation)
10370 {
10371 appendStringInfo(buf, " COLLATE %s",
10372 generate_collation_name(constval->constcollid));
10373 }
10374 }
10375 }
10376
10377 /*
10378 * simple_quote_literal - Format a string as a SQL literal, append to buf
10379 */
10380 static void
simple_quote_literal(StringInfo buf,const char * val)10381 simple_quote_literal(StringInfo buf, const char *val)
10382 {
10383 const char *valptr;
10384
10385 /*
10386 * We form the string literal according to the prevailing setting of
10387 * standard_conforming_strings; we never use E''. User is responsible for
10388 * making sure result is used correctly.
10389 */
10390 appendStringInfoChar(buf, '\'');
10391 for (valptr = val; *valptr; valptr++)
10392 {
10393 char ch = *valptr;
10394
10395 if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
10396 appendStringInfoChar(buf, ch);
10397 appendStringInfoChar(buf, ch);
10398 }
10399 appendStringInfoChar(buf, '\'');
10400 }
10401
10402
10403 /* ----------
10404 * get_sublink_expr - Parse back a sublink
10405 * ----------
10406 */
10407 static void
get_sublink_expr(SubLink * sublink,deparse_context * context)10408 get_sublink_expr(SubLink *sublink, deparse_context *context)
10409 {
10410 StringInfo buf = context->buf;
10411 Query *query = (Query *) (sublink->subselect);
10412 char *opname = NULL;
10413 bool need_paren;
10414
10415 if (sublink->subLinkType == ARRAY_SUBLINK)
10416 appendStringInfoString(buf, "ARRAY(");
10417 else
10418 appendStringInfoChar(buf, '(');
10419
10420 /*
10421 * Note that we print the name of only the first operator, when there are
10422 * multiple combining operators. This is an approximation that could go
10423 * wrong in various scenarios (operators in different schemas, renamed
10424 * operators, etc) but there is not a whole lot we can do about it, since
10425 * the syntax allows only one operator to be shown.
10426 */
10427 if (sublink->testexpr)
10428 {
10429 if (IsA(sublink->testexpr, OpExpr))
10430 {
10431 /* single combining operator */
10432 OpExpr *opexpr = (OpExpr *) sublink->testexpr;
10433
10434 get_rule_expr(linitial(opexpr->args), context, true);
10435 opname = generate_operator_name(opexpr->opno,
10436 exprType(linitial(opexpr->args)),
10437 exprType(lsecond(opexpr->args)));
10438 }
10439 else if (IsA(sublink->testexpr, BoolExpr))
10440 {
10441 /* multiple combining operators, = or <> cases */
10442 char *sep;
10443 ListCell *l;
10444
10445 appendStringInfoChar(buf, '(');
10446 sep = "";
10447 foreach(l, ((BoolExpr *) sublink->testexpr)->args)
10448 {
10449 OpExpr *opexpr = lfirst_node(OpExpr, l);
10450
10451 appendStringInfoString(buf, sep);
10452 get_rule_expr(linitial(opexpr->args), context, true);
10453 if (!opname)
10454 opname = generate_operator_name(opexpr->opno,
10455 exprType(linitial(opexpr->args)),
10456 exprType(lsecond(opexpr->args)));
10457 sep = ", ";
10458 }
10459 appendStringInfoChar(buf, ')');
10460 }
10461 else if (IsA(sublink->testexpr, RowCompareExpr))
10462 {
10463 /* multiple combining operators, < <= > >= cases */
10464 RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
10465
10466 appendStringInfoChar(buf, '(');
10467 get_rule_expr((Node *) rcexpr->largs, context, true);
10468 opname = generate_operator_name(linitial_oid(rcexpr->opnos),
10469 exprType(linitial(rcexpr->largs)),
10470 exprType(linitial(rcexpr->rargs)));
10471 appendStringInfoChar(buf, ')');
10472 }
10473 else
10474 elog(ERROR, "unrecognized testexpr type: %d",
10475 (int) nodeTag(sublink->testexpr));
10476 }
10477
10478 need_paren = true;
10479
10480 switch (sublink->subLinkType)
10481 {
10482 case EXISTS_SUBLINK:
10483 appendStringInfoString(buf, "EXISTS ");
10484 break;
10485
10486 case ANY_SUBLINK:
10487 if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
10488 appendStringInfoString(buf, " IN ");
10489 else
10490 appendStringInfo(buf, " %s ANY ", opname);
10491 break;
10492
10493 case ALL_SUBLINK:
10494 appendStringInfo(buf, " %s ALL ", opname);
10495 break;
10496
10497 case ROWCOMPARE_SUBLINK:
10498 appendStringInfo(buf, " %s ", opname);
10499 break;
10500
10501 case EXPR_SUBLINK:
10502 case MULTIEXPR_SUBLINK:
10503 case ARRAY_SUBLINK:
10504 need_paren = false;
10505 break;
10506
10507 case CTE_SUBLINK: /* shouldn't occur in a SubLink */
10508 default:
10509 elog(ERROR, "unrecognized sublink type: %d",
10510 (int) sublink->subLinkType);
10511 break;
10512 }
10513
10514 if (need_paren)
10515 appendStringInfoChar(buf, '(');
10516
10517 get_query_def(query, buf, context->namespaces, NULL,
10518 context->prettyFlags, context->wrapColumn,
10519 context->indentLevel);
10520
10521 if (need_paren)
10522 appendStringInfoString(buf, "))");
10523 else
10524 appendStringInfoChar(buf, ')');
10525 }
10526
10527
10528 /* ----------
10529 * get_tablefunc - Parse back a table function
10530 * ----------
10531 */
10532 static void
get_tablefunc(TableFunc * tf,deparse_context * context,bool showimplicit)10533 get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
10534 {
10535 StringInfo buf = context->buf;
10536
10537 /* XMLTABLE is the only existing implementation. */
10538
10539 appendStringInfoString(buf, "XMLTABLE(");
10540
10541 if (tf->ns_uris != NIL)
10542 {
10543 ListCell *lc1,
10544 *lc2;
10545 bool first = true;
10546
10547 appendStringInfoString(buf, "XMLNAMESPACES (");
10548 forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
10549 {
10550 Node *expr = (Node *) lfirst(lc1);
10551 Value *ns_node = (Value *) lfirst(lc2);
10552
10553 if (!first)
10554 appendStringInfoString(buf, ", ");
10555 else
10556 first = false;
10557
10558 if (ns_node != NULL)
10559 {
10560 get_rule_expr(expr, context, showimplicit);
10561 appendStringInfo(buf, " AS %s", strVal(ns_node));
10562 }
10563 else
10564 {
10565 appendStringInfoString(buf, "DEFAULT ");
10566 get_rule_expr(expr, context, showimplicit);
10567 }
10568 }
10569 appendStringInfoString(buf, "), ");
10570 }
10571
10572 appendStringInfoChar(buf, '(');
10573 get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
10574 appendStringInfoString(buf, ") PASSING (");
10575 get_rule_expr((Node *) tf->docexpr, context, showimplicit);
10576 appendStringInfoChar(buf, ')');
10577
10578 if (tf->colexprs != NIL)
10579 {
10580 ListCell *l1;
10581 ListCell *l2;
10582 ListCell *l3;
10583 ListCell *l4;
10584 ListCell *l5;
10585 int colnum = 0;
10586
10587 appendStringInfoString(buf, " COLUMNS ");
10588 forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
10589 l4, tf->colexprs, l5, tf->coldefexprs)
10590 {
10591 char *colname = strVal(lfirst(l1));
10592 Oid typid = lfirst_oid(l2);
10593 int32 typmod = lfirst_int(l3);
10594 Node *colexpr = (Node *) lfirst(l4);
10595 Node *coldefexpr = (Node *) lfirst(l5);
10596 bool ordinality = (tf->ordinalitycol == colnum);
10597 bool notnull = bms_is_member(colnum, tf->notnulls);
10598
10599 if (colnum > 0)
10600 appendStringInfoString(buf, ", ");
10601 colnum++;
10602
10603 appendStringInfo(buf, "%s %s", quote_identifier(colname),
10604 ordinality ? "FOR ORDINALITY" :
10605 format_type_with_typemod(typid, typmod));
10606 if (ordinality)
10607 continue;
10608
10609 if (coldefexpr != NULL)
10610 {
10611 appendStringInfoString(buf, " DEFAULT (");
10612 get_rule_expr((Node *) coldefexpr, context, showimplicit);
10613 appendStringInfoChar(buf, ')');
10614 }
10615 if (colexpr != NULL)
10616 {
10617 appendStringInfoString(buf, " PATH (");
10618 get_rule_expr((Node *) colexpr, context, showimplicit);
10619 appendStringInfoChar(buf, ')');
10620 }
10621 if (notnull)
10622 appendStringInfoString(buf, " NOT NULL");
10623 }
10624 }
10625
10626 appendStringInfoChar(buf, ')');
10627 }
10628
10629 /* ----------
10630 * get_from_clause - Parse back a FROM clause
10631 *
10632 * "prefix" is the keyword that denotes the start of the list of FROM
10633 * elements. It is FROM when used to parse back SELECT and UPDATE, but
10634 * is USING when parsing back DELETE.
10635 * ----------
10636 */
10637 static void
get_from_clause(Query * query,const char * prefix,deparse_context * context)10638 get_from_clause(Query *query, const char *prefix, deparse_context *context)
10639 {
10640 StringInfo buf = context->buf;
10641 bool first = true;
10642 ListCell *l;
10643
10644 /*
10645 * We use the query's jointree as a guide to what to print. However, we
10646 * must ignore auto-added RTEs that are marked not inFromCl. (These can
10647 * only appear at the top level of the jointree, so it's sufficient to
10648 * check here.) This check also ensures we ignore the rule pseudo-RTEs
10649 * for NEW and OLD.
10650 */
10651 foreach(l, query->jointree->fromlist)
10652 {
10653 Node *jtnode = (Node *) lfirst(l);
10654
10655 if (IsA(jtnode, RangeTblRef))
10656 {
10657 int varno = ((RangeTblRef *) jtnode)->rtindex;
10658 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
10659
10660 if (!rte->inFromCl)
10661 continue;
10662 }
10663
10664 if (first)
10665 {
10666 appendContextKeyword(context, prefix,
10667 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
10668 first = false;
10669
10670 get_from_clause_item(jtnode, query, context);
10671 }
10672 else
10673 {
10674 StringInfoData itembuf;
10675
10676 appendStringInfoString(buf, ", ");
10677
10678 /*
10679 * Put the new FROM item's text into itembuf so we can decide
10680 * after we've got it whether or not it needs to go on a new line.
10681 */
10682 initStringInfo(&itembuf);
10683 context->buf = &itembuf;
10684
10685 get_from_clause_item(jtnode, query, context);
10686
10687 /* Restore context's output buffer */
10688 context->buf = buf;
10689
10690 /* Consider line-wrapping if enabled */
10691 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
10692 {
10693 /* Does the new item start with a new line? */
10694 if (itembuf.len > 0 && itembuf.data[0] == '\n')
10695 {
10696 /* If so, we shouldn't add anything */
10697 /* instead, remove any trailing spaces currently in buf */
10698 removeStringInfoSpaces(buf);
10699 }
10700 else
10701 {
10702 char *trailing_nl;
10703
10704 /* Locate the start of the current line in the buffer */
10705 trailing_nl = strrchr(buf->data, '\n');
10706 if (trailing_nl == NULL)
10707 trailing_nl = buf->data;
10708 else
10709 trailing_nl++;
10710
10711 /*
10712 * Add a newline, plus some indentation, if the new item
10713 * would cause an overflow.
10714 */
10715 if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
10716 appendContextKeyword(context, "", -PRETTYINDENT_STD,
10717 PRETTYINDENT_STD,
10718 PRETTYINDENT_VAR);
10719 }
10720 }
10721
10722 /* Add the new item */
10723 appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
10724
10725 /* clean up */
10726 pfree(itembuf.data);
10727 }
10728 }
10729 }
10730
10731 static void
get_from_clause_item(Node * jtnode,Query * query,deparse_context * context)10732 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
10733 {
10734 StringInfo buf = context->buf;
10735 deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
10736
10737 if (IsA(jtnode, RangeTblRef))
10738 {
10739 int varno = ((RangeTblRef *) jtnode)->rtindex;
10740 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
10741 char *refname = get_rtable_name(varno, context);
10742 deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
10743 RangeTblFunction *rtfunc1 = NULL;
10744 bool printalias;
10745
10746 if (rte->lateral)
10747 appendStringInfoString(buf, "LATERAL ");
10748
10749 /* Print the FROM item proper */
10750 switch (rte->rtekind)
10751 {
10752 case RTE_RELATION:
10753 /* Normal relation RTE */
10754 appendStringInfo(buf, "%s%s",
10755 only_marker(rte),
10756 generate_relation_name(rte->relid,
10757 context->namespaces));
10758 break;
10759 case RTE_SUBQUERY:
10760 /* Subquery RTE */
10761 appendStringInfoChar(buf, '(');
10762 get_query_def(rte->subquery, buf, context->namespaces, NULL,
10763 context->prettyFlags, context->wrapColumn,
10764 context->indentLevel);
10765 appendStringInfoChar(buf, ')');
10766 break;
10767 case RTE_FUNCTION:
10768 /* Function RTE */
10769 rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
10770
10771 /*
10772 * Omit ROWS FROM() syntax for just one function, unless it
10773 * has both a coldeflist and WITH ORDINALITY. If it has both,
10774 * we must use ROWS FROM() syntax to avoid ambiguity about
10775 * whether the coldeflist includes the ordinality column.
10776 */
10777 if (list_length(rte->functions) == 1 &&
10778 (rtfunc1->funccolnames == NIL || !rte->funcordinality))
10779 {
10780 get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
10781 /* we'll print the coldeflist below, if it has one */
10782 }
10783 else
10784 {
10785 bool all_unnest;
10786 ListCell *lc;
10787
10788 /*
10789 * If all the function calls in the list are to unnest,
10790 * and none need a coldeflist, then collapse the list back
10791 * down to UNNEST(args). (If we had more than one
10792 * built-in unnest function, this would get more
10793 * difficult.)
10794 *
10795 * XXX This is pretty ugly, since it makes not-terribly-
10796 * future-proof assumptions about what the parser would do
10797 * with the output; but the alternative is to emit our
10798 * nonstandard ROWS FROM() notation for what might have
10799 * been a perfectly spec-compliant multi-argument
10800 * UNNEST().
10801 */
10802 all_unnest = true;
10803 foreach(lc, rte->functions)
10804 {
10805 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
10806
10807 if (!IsA(rtfunc->funcexpr, FuncExpr) ||
10808 ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
10809 rtfunc->funccolnames != NIL)
10810 {
10811 all_unnest = false;
10812 break;
10813 }
10814 }
10815
10816 if (all_unnest)
10817 {
10818 List *allargs = NIL;
10819
10820 foreach(lc, rte->functions)
10821 {
10822 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
10823 List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
10824
10825 allargs = list_concat(allargs, args);
10826 }
10827
10828 appendStringInfoString(buf, "UNNEST(");
10829 get_rule_expr((Node *) allargs, context, true);
10830 appendStringInfoChar(buf, ')');
10831 }
10832 else
10833 {
10834 int funcno = 0;
10835
10836 appendStringInfoString(buf, "ROWS FROM(");
10837 foreach(lc, rte->functions)
10838 {
10839 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
10840
10841 if (funcno > 0)
10842 appendStringInfoString(buf, ", ");
10843 get_rule_expr_funccall(rtfunc->funcexpr, context, true);
10844 if (rtfunc->funccolnames != NIL)
10845 {
10846 /* Reconstruct the column definition list */
10847 appendStringInfoString(buf, " AS ");
10848 get_from_clause_coldeflist(rtfunc,
10849 NULL,
10850 context);
10851 }
10852 funcno++;
10853 }
10854 appendStringInfoChar(buf, ')');
10855 }
10856 /* prevent printing duplicate coldeflist below */
10857 rtfunc1 = NULL;
10858 }
10859 if (rte->funcordinality)
10860 appendStringInfoString(buf, " WITH ORDINALITY");
10861 break;
10862 case RTE_TABLEFUNC:
10863 get_tablefunc(rte->tablefunc, context, true);
10864 break;
10865 case RTE_VALUES:
10866 /* Values list RTE */
10867 appendStringInfoChar(buf, '(');
10868 get_values_def(rte->values_lists, context);
10869 appendStringInfoChar(buf, ')');
10870 break;
10871 case RTE_CTE:
10872 appendStringInfoString(buf, quote_identifier(rte->ctename));
10873 break;
10874 default:
10875 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
10876 break;
10877 }
10878
10879 /* Print the relation alias, if needed */
10880 printalias = false;
10881 if (rte->alias != NULL)
10882 {
10883 /* Always print alias if user provided one */
10884 printalias = true;
10885 }
10886 else if (colinfo->printaliases)
10887 {
10888 /* Always print alias if we need to print column aliases */
10889 printalias = true;
10890 }
10891 else if (rte->rtekind == RTE_RELATION)
10892 {
10893 /*
10894 * No need to print alias if it's same as relation name (this
10895 * would normally be the case, but not if set_rtable_names had to
10896 * resolve a conflict).
10897 */
10898 if (strcmp(refname, get_relation_name(rte->relid)) != 0)
10899 printalias = true;
10900 }
10901 else if (rte->rtekind == RTE_FUNCTION)
10902 {
10903 /*
10904 * For a function RTE, always print alias. This covers possible
10905 * renaming of the function and/or instability of the
10906 * FigureColname rules for things that aren't simple functions.
10907 * Note we'd need to force it anyway for the columndef list case.
10908 */
10909 printalias = true;
10910 }
10911 else if (rte->rtekind == RTE_VALUES)
10912 {
10913 /* Alias is syntactically required for VALUES */
10914 printalias = true;
10915 }
10916 else if (rte->rtekind == RTE_CTE)
10917 {
10918 /*
10919 * No need to print alias if it's same as CTE name (this would
10920 * normally be the case, but not if set_rtable_names had to
10921 * resolve a conflict).
10922 */
10923 if (strcmp(refname, rte->ctename) != 0)
10924 printalias = true;
10925 }
10926 if (printalias)
10927 appendStringInfo(buf, " %s", quote_identifier(refname));
10928
10929 /* Print the column definitions or aliases, if needed */
10930 if (rtfunc1 && rtfunc1->funccolnames != NIL)
10931 {
10932 /* Reconstruct the columndef list, which is also the aliases */
10933 get_from_clause_coldeflist(rtfunc1, colinfo, context);
10934 }
10935 else
10936 {
10937 /* Else print column aliases as needed */
10938 get_column_alias_list(colinfo, context);
10939 }
10940
10941 /* Tablesample clause must go after any alias */
10942 if (rte->rtekind == RTE_RELATION && rte->tablesample)
10943 get_tablesample_def(rte->tablesample, context);
10944 }
10945 else if (IsA(jtnode, JoinExpr))
10946 {
10947 JoinExpr *j = (JoinExpr *) jtnode;
10948 deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
10949 bool need_paren_on_right;
10950
10951 need_paren_on_right = PRETTY_PAREN(context) &&
10952 !IsA(j->rarg, RangeTblRef) &&
10953 !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
10954
10955 if (!PRETTY_PAREN(context) || j->alias != NULL)
10956 appendStringInfoChar(buf, '(');
10957
10958 get_from_clause_item(j->larg, query, context);
10959
10960 switch (j->jointype)
10961 {
10962 case JOIN_INNER:
10963 if (j->quals)
10964 appendContextKeyword(context, " JOIN ",
10965 -PRETTYINDENT_STD,
10966 PRETTYINDENT_STD,
10967 PRETTYINDENT_JOIN);
10968 else
10969 appendContextKeyword(context, " CROSS JOIN ",
10970 -PRETTYINDENT_STD,
10971 PRETTYINDENT_STD,
10972 PRETTYINDENT_JOIN);
10973 break;
10974 case JOIN_LEFT:
10975 appendContextKeyword(context, " LEFT JOIN ",
10976 -PRETTYINDENT_STD,
10977 PRETTYINDENT_STD,
10978 PRETTYINDENT_JOIN);
10979 break;
10980 case JOIN_FULL:
10981 appendContextKeyword(context, " FULL JOIN ",
10982 -PRETTYINDENT_STD,
10983 PRETTYINDENT_STD,
10984 PRETTYINDENT_JOIN);
10985 break;
10986 case JOIN_RIGHT:
10987 appendContextKeyword(context, " RIGHT JOIN ",
10988 -PRETTYINDENT_STD,
10989 PRETTYINDENT_STD,
10990 PRETTYINDENT_JOIN);
10991 break;
10992 default:
10993 elog(ERROR, "unrecognized join type: %d",
10994 (int) j->jointype);
10995 }
10996
10997 if (need_paren_on_right)
10998 appendStringInfoChar(buf, '(');
10999 get_from_clause_item(j->rarg, query, context);
11000 if (need_paren_on_right)
11001 appendStringInfoChar(buf, ')');
11002
11003 if (j->usingClause)
11004 {
11005 ListCell *lc;
11006 bool first = true;
11007
11008 appendStringInfoString(buf, " USING (");
11009 /* Use the assigned names, not what's in usingClause */
11010 foreach(lc, colinfo->usingNames)
11011 {
11012 char *colname = (char *) lfirst(lc);
11013
11014 if (first)
11015 first = false;
11016 else
11017 appendStringInfoString(buf, ", ");
11018 appendStringInfoString(buf, quote_identifier(colname));
11019 }
11020 appendStringInfoChar(buf, ')');
11021
11022 if (j->join_using_alias)
11023 appendStringInfo(buf, " AS %s",
11024 quote_identifier(j->join_using_alias->aliasname));
11025 }
11026 else if (j->quals)
11027 {
11028 appendStringInfoString(buf, " ON ");
11029 if (!PRETTY_PAREN(context))
11030 appendStringInfoChar(buf, '(');
11031 get_rule_expr(j->quals, context, false);
11032 if (!PRETTY_PAREN(context))
11033 appendStringInfoChar(buf, ')');
11034 }
11035 else if (j->jointype != JOIN_INNER)
11036 {
11037 /* If we didn't say CROSS JOIN above, we must provide an ON */
11038 appendStringInfoString(buf, " ON TRUE");
11039 }
11040
11041 if (!PRETTY_PAREN(context) || j->alias != NULL)
11042 appendStringInfoChar(buf, ')');
11043
11044 /* Yes, it's correct to put alias after the right paren ... */
11045 if (j->alias != NULL)
11046 {
11047 /*
11048 * Note that it's correct to emit an alias clause if and only if
11049 * there was one originally. Otherwise we'd be converting a named
11050 * join to unnamed or vice versa, which creates semantic
11051 * subtleties we don't want. However, we might print a different
11052 * alias name than was there originally.
11053 */
11054 appendStringInfo(buf, " %s",
11055 quote_identifier(get_rtable_name(j->rtindex,
11056 context)));
11057 get_column_alias_list(colinfo, context);
11058 }
11059 }
11060 else
11061 elog(ERROR, "unrecognized node type: %d",
11062 (int) nodeTag(jtnode));
11063 }
11064
11065 /*
11066 * get_column_alias_list - print column alias list for an RTE
11067 *
11068 * Caller must already have printed the relation's alias name.
11069 */
11070 static void
get_column_alias_list(deparse_columns * colinfo,deparse_context * context)11071 get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
11072 {
11073 StringInfo buf = context->buf;
11074 int i;
11075 bool first = true;
11076
11077 /* Don't print aliases if not needed */
11078 if (!colinfo->printaliases)
11079 return;
11080
11081 for (i = 0; i < colinfo->num_new_cols; i++)
11082 {
11083 char *colname = colinfo->new_colnames[i];
11084
11085 if (first)
11086 {
11087 appendStringInfoChar(buf, '(');
11088 first = false;
11089 }
11090 else
11091 appendStringInfoString(buf, ", ");
11092 appendStringInfoString(buf, quote_identifier(colname));
11093 }
11094 if (!first)
11095 appendStringInfoChar(buf, ')');
11096 }
11097
11098 /*
11099 * get_from_clause_coldeflist - reproduce FROM clause coldeflist
11100 *
11101 * When printing a top-level coldeflist (which is syntactically also the
11102 * relation's column alias list), use column names from colinfo. But when
11103 * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
11104 * original coldeflist's names, which are available in rtfunc->funccolnames.
11105 * Pass NULL for colinfo to select the latter behavior.
11106 *
11107 * The coldeflist is appended immediately (no space) to buf. Caller is
11108 * responsible for ensuring that an alias or AS is present before it.
11109 */
11110 static void
get_from_clause_coldeflist(RangeTblFunction * rtfunc,deparse_columns * colinfo,deparse_context * context)11111 get_from_clause_coldeflist(RangeTblFunction *rtfunc,
11112 deparse_columns *colinfo,
11113 deparse_context *context)
11114 {
11115 StringInfo buf = context->buf;
11116 ListCell *l1;
11117 ListCell *l2;
11118 ListCell *l3;
11119 ListCell *l4;
11120 int i;
11121
11122 appendStringInfoChar(buf, '(');
11123
11124 i = 0;
11125 forfour(l1, rtfunc->funccoltypes,
11126 l2, rtfunc->funccoltypmods,
11127 l3, rtfunc->funccolcollations,
11128 l4, rtfunc->funccolnames)
11129 {
11130 Oid atttypid = lfirst_oid(l1);
11131 int32 atttypmod = lfirst_int(l2);
11132 Oid attcollation = lfirst_oid(l3);
11133 char *attname;
11134
11135 if (colinfo)
11136 attname = colinfo->colnames[i];
11137 else
11138 attname = strVal(lfirst(l4));
11139
11140 Assert(attname); /* shouldn't be any dropped columns here */
11141
11142 if (i > 0)
11143 appendStringInfoString(buf, ", ");
11144 appendStringInfo(buf, "%s %s",
11145 quote_identifier(attname),
11146 format_type_with_typemod(atttypid, atttypmod));
11147 if (OidIsValid(attcollation) &&
11148 attcollation != get_typcollation(atttypid))
11149 appendStringInfo(buf, " COLLATE %s",
11150 generate_collation_name(attcollation));
11151
11152 i++;
11153 }
11154
11155 appendStringInfoChar(buf, ')');
11156 }
11157
11158 /*
11159 * get_tablesample_def - print a TableSampleClause
11160 */
11161 static void
get_tablesample_def(TableSampleClause * tablesample,deparse_context * context)11162 get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
11163 {
11164 StringInfo buf = context->buf;
11165 Oid argtypes[1];
11166 int nargs;
11167 ListCell *l;
11168
11169 /*
11170 * We should qualify the handler's function name if it wouldn't be
11171 * resolved by lookup in the current search path.
11172 */
11173 argtypes[0] = INTERNALOID;
11174 appendStringInfo(buf, " TABLESAMPLE %s (",
11175 generate_function_name(tablesample->tsmhandler, 1,
11176 NIL, argtypes,
11177 false, NULL, EXPR_KIND_NONE));
11178
11179 nargs = 0;
11180 foreach(l, tablesample->args)
11181 {
11182 if (nargs++ > 0)
11183 appendStringInfoString(buf, ", ");
11184 get_rule_expr((Node *) lfirst(l), context, false);
11185 }
11186 appendStringInfoChar(buf, ')');
11187
11188 if (tablesample->repeatable != NULL)
11189 {
11190 appendStringInfoString(buf, " REPEATABLE (");
11191 get_rule_expr((Node *) tablesample->repeatable, context, false);
11192 appendStringInfoChar(buf, ')');
11193 }
11194 }
11195
11196 /*
11197 * get_opclass_name - fetch name of an index operator class
11198 *
11199 * The opclass name is appended (after a space) to buf.
11200 *
11201 * Output is suppressed if the opclass is the default for the given
11202 * actual_datatype. (If you don't want this behavior, just pass
11203 * InvalidOid for actual_datatype.)
11204 */
11205 static void
get_opclass_name(Oid opclass,Oid actual_datatype,StringInfo buf)11206 get_opclass_name(Oid opclass, Oid actual_datatype,
11207 StringInfo buf)
11208 {
11209 HeapTuple ht_opc;
11210 Form_pg_opclass opcrec;
11211 char *opcname;
11212 char *nspname;
11213
11214 ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
11215 if (!HeapTupleIsValid(ht_opc))
11216 elog(ERROR, "cache lookup failed for opclass %u", opclass);
11217 opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
11218
11219 if (!OidIsValid(actual_datatype) ||
11220 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
11221 {
11222 /* Okay, we need the opclass name. Do we need to qualify it? */
11223 opcname = NameStr(opcrec->opcname);
11224 if (OpclassIsVisible(opclass))
11225 appendStringInfo(buf, " %s", quote_identifier(opcname));
11226 else
11227 {
11228 nspname = get_namespace_name(opcrec->opcnamespace);
11229 appendStringInfo(buf, " %s.%s",
11230 quote_identifier(nspname),
11231 quote_identifier(opcname));
11232 }
11233 }
11234 ReleaseSysCache(ht_opc);
11235 }
11236
11237 /*
11238 * generate_opclass_name
11239 * Compute the name to display for a opclass specified by OID
11240 *
11241 * The result includes all necessary quoting and schema-prefixing.
11242 */
11243 char *
generate_opclass_name(Oid opclass)11244 generate_opclass_name(Oid opclass)
11245 {
11246 StringInfoData buf;
11247
11248 initStringInfo(&buf);
11249 get_opclass_name(opclass, InvalidOid, &buf);
11250
11251 return &buf.data[1]; /* get_opclass_name() prepends space */
11252 }
11253
11254 /*
11255 * processIndirection - take care of array and subfield assignment
11256 *
11257 * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
11258 * appear in the input, printing them as decoration for the base column
11259 * name (which we assume the caller just printed). We might also need to
11260 * strip CoerceToDomain nodes, but only ones that appear above assignment
11261 * nodes.
11262 *
11263 * Returns the subexpression that's to be assigned.
11264 */
11265 static Node *
processIndirection(Node * node,deparse_context * context)11266 processIndirection(Node *node, deparse_context *context)
11267 {
11268 StringInfo buf = context->buf;
11269 CoerceToDomain *cdomain = NULL;
11270
11271 for (;;)
11272 {
11273 if (node == NULL)
11274 break;
11275 if (IsA(node, FieldStore))
11276 {
11277 FieldStore *fstore = (FieldStore *) node;
11278 Oid typrelid;
11279 char *fieldname;
11280
11281 /* lookup tuple type */
11282 typrelid = get_typ_typrelid(fstore->resulttype);
11283 if (!OidIsValid(typrelid))
11284 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
11285 format_type_be(fstore->resulttype));
11286
11287 /*
11288 * Print the field name. There should only be one target field in
11289 * stored rules. There could be more than that in executable
11290 * target lists, but this function cannot be used for that case.
11291 */
11292 Assert(list_length(fstore->fieldnums) == 1);
11293 fieldname = get_attname(typrelid,
11294 linitial_int(fstore->fieldnums), false);
11295 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
11296
11297 /*
11298 * We ignore arg since it should be an uninteresting reference to
11299 * the target column or subcolumn.
11300 */
11301 node = (Node *) linitial(fstore->newvals);
11302 }
11303 else if (IsA(node, SubscriptingRef))
11304 {
11305 SubscriptingRef *sbsref = (SubscriptingRef *) node;
11306
11307 if (sbsref->refassgnexpr == NULL)
11308 break;
11309
11310 printSubscripts(sbsref, context);
11311
11312 /*
11313 * We ignore refexpr since it should be an uninteresting reference
11314 * to the target column or subcolumn.
11315 */
11316 node = (Node *) sbsref->refassgnexpr;
11317 }
11318 else if (IsA(node, CoerceToDomain))
11319 {
11320 cdomain = (CoerceToDomain *) node;
11321 /* If it's an explicit domain coercion, we're done */
11322 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
11323 break;
11324 /* Tentatively descend past the CoerceToDomain */
11325 node = (Node *) cdomain->arg;
11326 }
11327 else
11328 break;
11329 }
11330
11331 /*
11332 * If we descended past a CoerceToDomain whose argument turned out not to
11333 * be a FieldStore or array assignment, back up to the CoerceToDomain.
11334 * (This is not enough to be fully correct if there are nested implicit
11335 * CoerceToDomains, but such cases shouldn't ever occur.)
11336 */
11337 if (cdomain && node == (Node *) cdomain->arg)
11338 node = (Node *) cdomain;
11339
11340 return node;
11341 }
11342
11343 static void
printSubscripts(SubscriptingRef * sbsref,deparse_context * context)11344 printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
11345 {
11346 StringInfo buf = context->buf;
11347 ListCell *lowlist_item;
11348 ListCell *uplist_item;
11349
11350 lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
11351 foreach(uplist_item, sbsref->refupperindexpr)
11352 {
11353 appendStringInfoChar(buf, '[');
11354 if (lowlist_item)
11355 {
11356 /* If subexpression is NULL, get_rule_expr prints nothing */
11357 get_rule_expr((Node *) lfirst(lowlist_item), context, false);
11358 appendStringInfoChar(buf, ':');
11359 lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
11360 }
11361 /* If subexpression is NULL, get_rule_expr prints nothing */
11362 get_rule_expr((Node *) lfirst(uplist_item), context, false);
11363 appendStringInfoChar(buf, ']');
11364 }
11365 }
11366
11367 /*
11368 * quote_identifier - Quote an identifier only if needed
11369 *
11370 * When quotes are needed, we palloc the required space; slightly
11371 * space-wasteful but well worth it for notational simplicity.
11372 */
11373 const char *
quote_identifier(const char * ident)11374 quote_identifier(const char *ident)
11375 {
11376 /*
11377 * Can avoid quoting if ident starts with a lowercase letter or underscore
11378 * and contains only lowercase letters, digits, and underscores, *and* is
11379 * not any SQL keyword. Otherwise, supply quotes.
11380 */
11381 int nquotes = 0;
11382 bool safe;
11383 const char *ptr;
11384 char *result;
11385 char *optr;
11386
11387 /*
11388 * would like to use <ctype.h> macros here, but they might yield unwanted
11389 * locale-specific results...
11390 */
11391 safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
11392
11393 for (ptr = ident; *ptr; ptr++)
11394 {
11395 char ch = *ptr;
11396
11397 if ((ch >= 'a' && ch <= 'z') ||
11398 (ch >= '0' && ch <= '9') ||
11399 (ch == '_'))
11400 {
11401 /* okay */
11402 }
11403 else
11404 {
11405 safe = false;
11406 if (ch == '"')
11407 nquotes++;
11408 }
11409 }
11410
11411 if (quote_all_identifiers)
11412 safe = false;
11413
11414 if (safe)
11415 {
11416 /*
11417 * Check for keyword. We quote keywords except for unreserved ones.
11418 * (In some cases we could avoid quoting a col_name or type_func_name
11419 * keyword, but it seems much harder than it's worth to tell that.)
11420 *
11421 * Note: ScanKeywordLookup() does case-insensitive comparison, but
11422 * that's fine, since we already know we have all-lower-case.
11423 */
11424 int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
11425
11426 if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
11427 safe = false;
11428 }
11429
11430 if (safe)
11431 return ident; /* no change needed */
11432
11433 result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
11434
11435 optr = result;
11436 *optr++ = '"';
11437 for (ptr = ident; *ptr; ptr++)
11438 {
11439 char ch = *ptr;
11440
11441 if (ch == '"')
11442 *optr++ = '"';
11443 *optr++ = ch;
11444 }
11445 *optr++ = '"';
11446 *optr = '\0';
11447
11448 return result;
11449 }
11450
11451 /*
11452 * quote_qualified_identifier - Quote a possibly-qualified identifier
11453 *
11454 * Return a name of the form qualifier.ident, or just ident if qualifier
11455 * is NULL, quoting each component if necessary. The result is palloc'd.
11456 */
11457 char *
quote_qualified_identifier(const char * qualifier,const char * ident)11458 quote_qualified_identifier(const char *qualifier,
11459 const char *ident)
11460 {
11461 StringInfoData buf;
11462
11463 initStringInfo(&buf);
11464 if (qualifier)
11465 appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
11466 appendStringInfoString(&buf, quote_identifier(ident));
11467 return buf.data;
11468 }
11469
11470 /*
11471 * get_relation_name
11472 * Get the unqualified name of a relation specified by OID
11473 *
11474 * This differs from the underlying get_rel_name() function in that it will
11475 * throw error instead of silently returning NULL if the OID is bad.
11476 */
11477 static char *
get_relation_name(Oid relid)11478 get_relation_name(Oid relid)
11479 {
11480 char *relname = get_rel_name(relid);
11481
11482 if (!relname)
11483 elog(ERROR, "cache lookup failed for relation %u", relid);
11484 return relname;
11485 }
11486
11487 /*
11488 * generate_relation_name
11489 * Compute the name to display for a relation specified by OID
11490 *
11491 * The result includes all necessary quoting and schema-prefixing.
11492 *
11493 * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
11494 * We will forcibly qualify the relation name if it equals any CTE name
11495 * visible in the namespace list.
11496 */
11497 static char *
generate_relation_name(Oid relid,List * namespaces)11498 generate_relation_name(Oid relid, List *namespaces)
11499 {
11500 HeapTuple tp;
11501 Form_pg_class reltup;
11502 bool need_qual;
11503 ListCell *nslist;
11504 char *relname;
11505 char *nspname;
11506 char *result;
11507
11508 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11509 if (!HeapTupleIsValid(tp))
11510 elog(ERROR, "cache lookup failed for relation %u", relid);
11511 reltup = (Form_pg_class) GETSTRUCT(tp);
11512 relname = NameStr(reltup->relname);
11513
11514 /* Check for conflicting CTE name */
11515 need_qual = false;
11516 foreach(nslist, namespaces)
11517 {
11518 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
11519 ListCell *ctlist;
11520
11521 foreach(ctlist, dpns->ctes)
11522 {
11523 CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
11524
11525 if (strcmp(cte->ctename, relname) == 0)
11526 {
11527 need_qual = true;
11528 break;
11529 }
11530 }
11531 if (need_qual)
11532 break;
11533 }
11534
11535 /* Otherwise, qualify the name if not visible in search path */
11536 if (!need_qual)
11537 need_qual = !RelationIsVisible(relid);
11538
11539 if (need_qual)
11540 nspname = get_namespace_name(reltup->relnamespace);
11541 else
11542 nspname = NULL;
11543
11544 result = quote_qualified_identifier(nspname, relname);
11545
11546 ReleaseSysCache(tp);
11547
11548 return result;
11549 }
11550
11551 /*
11552 * generate_qualified_relation_name
11553 * Compute the name to display for a relation specified by OID
11554 *
11555 * As above, but unconditionally schema-qualify the name.
11556 */
11557 static char *
generate_qualified_relation_name(Oid relid)11558 generate_qualified_relation_name(Oid relid)
11559 {
11560 HeapTuple tp;
11561 Form_pg_class reltup;
11562 char *relname;
11563 char *nspname;
11564 char *result;
11565
11566 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11567 if (!HeapTupleIsValid(tp))
11568 elog(ERROR, "cache lookup failed for relation %u", relid);
11569 reltup = (Form_pg_class) GETSTRUCT(tp);
11570 relname = NameStr(reltup->relname);
11571
11572 nspname = get_namespace_name(reltup->relnamespace);
11573 if (!nspname)
11574 elog(ERROR, "cache lookup failed for namespace %u",
11575 reltup->relnamespace);
11576
11577 result = quote_qualified_identifier(nspname, relname);
11578
11579 ReleaseSysCache(tp);
11580
11581 return result;
11582 }
11583
11584 /*
11585 * generate_function_name
11586 * Compute the name to display for a function specified by OID,
11587 * given that it is being called with the specified actual arg names and
11588 * types. (Those matter because of ambiguous-function resolution rules.)
11589 *
11590 * If we're dealing with a potentially variadic function (in practice, this
11591 * means a FuncExpr or Aggref, not some other way of calling a function), then
11592 * has_variadic must specify whether variadic arguments have been merged,
11593 * and *use_variadic_p will be set to indicate whether to print VARIADIC in
11594 * the output. For non-FuncExpr cases, has_variadic should be false and
11595 * use_variadic_p can be NULL.
11596 *
11597 * The result includes all necessary quoting and schema-prefixing.
11598 */
11599 static char *
generate_function_name(Oid funcid,int nargs,List * argnames,Oid * argtypes,bool has_variadic,bool * use_variadic_p,ParseExprKind special_exprkind)11600 generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
11601 bool has_variadic, bool *use_variadic_p,
11602 ParseExprKind special_exprkind)
11603 {
11604 char *result;
11605 HeapTuple proctup;
11606 Form_pg_proc procform;
11607 char *proname;
11608 bool use_variadic;
11609 char *nspname;
11610 FuncDetailCode p_result;
11611 Oid p_funcid;
11612 Oid p_rettype;
11613 bool p_retset;
11614 int p_nvargs;
11615 Oid p_vatype;
11616 Oid *p_true_typeids;
11617 bool force_qualify = false;
11618
11619 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
11620 if (!HeapTupleIsValid(proctup))
11621 elog(ERROR, "cache lookup failed for function %u", funcid);
11622 procform = (Form_pg_proc) GETSTRUCT(proctup);
11623 proname = NameStr(procform->proname);
11624
11625 /*
11626 * Due to parser hacks to avoid needing to reserve CUBE, we need to force
11627 * qualification in some special cases.
11628 */
11629 if (special_exprkind == EXPR_KIND_GROUP_BY)
11630 {
11631 if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
11632 force_qualify = true;
11633 }
11634
11635 /*
11636 * Determine whether VARIADIC should be printed. We must do this first
11637 * since it affects the lookup rules in func_get_detail().
11638 *
11639 * We always print VARIADIC if the function has a merged variadic-array
11640 * argument. Note that this is always the case for functions taking a
11641 * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
11642 * and printed the array elements as separate arguments, the call could
11643 * match a newer non-VARIADIC function.
11644 */
11645 if (use_variadic_p)
11646 {
11647 /* Parser should not have set funcvariadic unless fn is variadic */
11648 Assert(!has_variadic || OidIsValid(procform->provariadic));
11649 use_variadic = has_variadic;
11650 *use_variadic_p = use_variadic;
11651 }
11652 else
11653 {
11654 Assert(!has_variadic);
11655 use_variadic = false;
11656 }
11657
11658 /*
11659 * The idea here is to schema-qualify only if the parser would fail to
11660 * resolve the correct function given the unqualified func name with the
11661 * specified argtypes and VARIADIC flag. But if we already decided to
11662 * force qualification, then we can skip the lookup and pretend we didn't
11663 * find it.
11664 */
11665 if (!force_qualify)
11666 p_result = func_get_detail(list_make1(makeString(proname)),
11667 NIL, argnames, nargs, argtypes,
11668 !use_variadic, true, false,
11669 &p_funcid, &p_rettype,
11670 &p_retset, &p_nvargs, &p_vatype,
11671 &p_true_typeids, NULL);
11672 else
11673 {
11674 p_result = FUNCDETAIL_NOTFOUND;
11675 p_funcid = InvalidOid;
11676 }
11677
11678 if ((p_result == FUNCDETAIL_NORMAL ||
11679 p_result == FUNCDETAIL_AGGREGATE ||
11680 p_result == FUNCDETAIL_WINDOWFUNC) &&
11681 p_funcid == funcid)
11682 nspname = NULL;
11683 else
11684 nspname = get_namespace_name(procform->pronamespace);
11685
11686 result = quote_qualified_identifier(nspname, proname);
11687
11688 ReleaseSysCache(proctup);
11689
11690 return result;
11691 }
11692
11693 /*
11694 * generate_operator_name
11695 * Compute the name to display for an operator specified by OID,
11696 * given that it is being called with the specified actual arg types.
11697 * (Arg types matter because of ambiguous-operator resolution rules.
11698 * Pass InvalidOid for unused arg of a unary operator.)
11699 *
11700 * The result includes all necessary quoting and schema-prefixing,
11701 * plus the OPERATOR() decoration needed to use a qualified operator name
11702 * in an expression.
11703 */
11704 static char *
generate_operator_name(Oid operid,Oid arg1,Oid arg2)11705 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
11706 {
11707 StringInfoData buf;
11708 HeapTuple opertup;
11709 Form_pg_operator operform;
11710 char *oprname;
11711 char *nspname;
11712 Operator p_result;
11713
11714 initStringInfo(&buf);
11715
11716 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
11717 if (!HeapTupleIsValid(opertup))
11718 elog(ERROR, "cache lookup failed for operator %u", operid);
11719 operform = (Form_pg_operator) GETSTRUCT(opertup);
11720 oprname = NameStr(operform->oprname);
11721
11722 /*
11723 * The idea here is to schema-qualify only if the parser would fail to
11724 * resolve the correct operator given the unqualified op name with the
11725 * specified argtypes.
11726 */
11727 switch (operform->oprkind)
11728 {
11729 case 'b':
11730 p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
11731 true, -1);
11732 break;
11733 case 'l':
11734 p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
11735 true, -1);
11736 break;
11737 default:
11738 elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
11739 p_result = NULL; /* keep compiler quiet */
11740 break;
11741 }
11742
11743 if (p_result != NULL && oprid(p_result) == operid)
11744 nspname = NULL;
11745 else
11746 {
11747 nspname = get_namespace_name(operform->oprnamespace);
11748 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
11749 }
11750
11751 appendStringInfoString(&buf, oprname);
11752
11753 if (nspname)
11754 appendStringInfoChar(&buf, ')');
11755
11756 if (p_result != NULL)
11757 ReleaseSysCache(p_result);
11758
11759 ReleaseSysCache(opertup);
11760
11761 return buf.data;
11762 }
11763
11764 /*
11765 * generate_operator_clause --- generate a binary-operator WHERE clause
11766 *
11767 * This is used for internally-generated-and-executed SQL queries, where
11768 * precision is essential and readability is secondary. The basic
11769 * requirement is to append "leftop op rightop" to buf, where leftop and
11770 * rightop are given as strings and are assumed to yield types leftoptype
11771 * and rightoptype; the operator is identified by OID. The complexity
11772 * comes from needing to be sure that the parser will select the desired
11773 * operator when the query is parsed. We always name the operator using
11774 * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
11775 * We have to emit casts too, if either input isn't already the input type
11776 * of the operator; else we are at the mercy of the parser's heuristics for
11777 * ambiguous-operator resolution. The caller must ensure that leftop and
11778 * rightop are suitable arguments for a cast operation; it's best to insert
11779 * parentheses if they aren't just variables or parameters.
11780 */
11781 void
generate_operator_clause(StringInfo buf,const char * leftop,Oid leftoptype,Oid opoid,const char * rightop,Oid rightoptype)11782 generate_operator_clause(StringInfo buf,
11783 const char *leftop, Oid leftoptype,
11784 Oid opoid,
11785 const char *rightop, Oid rightoptype)
11786 {
11787 HeapTuple opertup;
11788 Form_pg_operator operform;
11789 char *oprname;
11790 char *nspname;
11791
11792 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
11793 if (!HeapTupleIsValid(opertup))
11794 elog(ERROR, "cache lookup failed for operator %u", opoid);
11795 operform = (Form_pg_operator) GETSTRUCT(opertup);
11796 Assert(operform->oprkind == 'b');
11797 oprname = NameStr(operform->oprname);
11798
11799 nspname = get_namespace_name(operform->oprnamespace);
11800
11801 appendStringInfoString(buf, leftop);
11802 if (leftoptype != operform->oprleft)
11803 add_cast_to(buf, operform->oprleft);
11804 appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
11805 appendStringInfoString(buf, oprname);
11806 appendStringInfo(buf, ") %s", rightop);
11807 if (rightoptype != operform->oprright)
11808 add_cast_to(buf, operform->oprright);
11809
11810 ReleaseSysCache(opertup);
11811 }
11812
11813 /*
11814 * Add a cast specification to buf. We spell out the type name the hard way,
11815 * intentionally not using format_type_be(). This is to avoid corner cases
11816 * for CHARACTER, BIT, and perhaps other types, where specifying the type
11817 * using SQL-standard syntax results in undesirable data truncation. By
11818 * doing it this way we can be certain that the cast will have default (-1)
11819 * target typmod.
11820 */
11821 static void
add_cast_to(StringInfo buf,Oid typid)11822 add_cast_to(StringInfo buf, Oid typid)
11823 {
11824 HeapTuple typetup;
11825 Form_pg_type typform;
11826 char *typname;
11827 char *nspname;
11828
11829 typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
11830 if (!HeapTupleIsValid(typetup))
11831 elog(ERROR, "cache lookup failed for type %u", typid);
11832 typform = (Form_pg_type) GETSTRUCT(typetup);
11833
11834 typname = NameStr(typform->typname);
11835 nspname = get_namespace_name(typform->typnamespace);
11836
11837 appendStringInfo(buf, "::%s.%s",
11838 quote_identifier(nspname), quote_identifier(typname));
11839
11840 ReleaseSysCache(typetup);
11841 }
11842
11843 /*
11844 * generate_qualified_type_name
11845 * Compute the name to display for a type specified by OID
11846 *
11847 * This is different from format_type_be() in that we unconditionally
11848 * schema-qualify the name. That also means no special syntax for
11849 * SQL-standard type names ... although in current usage, this should
11850 * only get used for domains, so such cases wouldn't occur anyway.
11851 */
11852 static char *
generate_qualified_type_name(Oid typid)11853 generate_qualified_type_name(Oid typid)
11854 {
11855 HeapTuple tp;
11856 Form_pg_type typtup;
11857 char *typname;
11858 char *nspname;
11859 char *result;
11860
11861 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
11862 if (!HeapTupleIsValid(tp))
11863 elog(ERROR, "cache lookup failed for type %u", typid);
11864 typtup = (Form_pg_type) GETSTRUCT(tp);
11865 typname = NameStr(typtup->typname);
11866
11867 nspname = get_namespace_name(typtup->typnamespace);
11868 if (!nspname)
11869 elog(ERROR, "cache lookup failed for namespace %u",
11870 typtup->typnamespace);
11871
11872 result = quote_qualified_identifier(nspname, typname);
11873
11874 ReleaseSysCache(tp);
11875
11876 return result;
11877 }
11878
11879 /*
11880 * generate_collation_name
11881 * Compute the name to display for a collation specified by OID
11882 *
11883 * The result includes all necessary quoting and schema-prefixing.
11884 */
11885 char *
generate_collation_name(Oid collid)11886 generate_collation_name(Oid collid)
11887 {
11888 HeapTuple tp;
11889 Form_pg_collation colltup;
11890 char *collname;
11891 char *nspname;
11892 char *result;
11893
11894 tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
11895 if (!HeapTupleIsValid(tp))
11896 elog(ERROR, "cache lookup failed for collation %u", collid);
11897 colltup = (Form_pg_collation) GETSTRUCT(tp);
11898 collname = NameStr(colltup->collname);
11899
11900 if (!CollationIsVisible(collid))
11901 nspname = get_namespace_name(colltup->collnamespace);
11902 else
11903 nspname = NULL;
11904
11905 result = quote_qualified_identifier(nspname, collname);
11906
11907 ReleaseSysCache(tp);
11908
11909 return result;
11910 }
11911
11912 /*
11913 * Given a C string, produce a TEXT datum.
11914 *
11915 * We assume that the input was palloc'd and may be freed.
11916 */
11917 static text *
string_to_text(char * str)11918 string_to_text(char *str)
11919 {
11920 text *result;
11921
11922 result = cstring_to_text(str);
11923 pfree(str);
11924 return result;
11925 }
11926
11927 /*
11928 * Generate a C string representing a relation options from text[] datum.
11929 */
11930 static void
get_reloptions(StringInfo buf,Datum reloptions)11931 get_reloptions(StringInfo buf, Datum reloptions)
11932 {
11933 Datum *options;
11934 int noptions;
11935 int i;
11936
11937 deconstruct_array(DatumGetArrayTypeP(reloptions),
11938 TEXTOID, -1, false, TYPALIGN_INT,
11939 &options, NULL, &noptions);
11940
11941 for (i = 0; i < noptions; i++)
11942 {
11943 char *option = TextDatumGetCString(options[i]);
11944 char *name;
11945 char *separator;
11946 char *value;
11947
11948 /*
11949 * Each array element should have the form name=value. If the "=" is
11950 * missing for some reason, treat it like an empty value.
11951 */
11952 name = option;
11953 separator = strchr(option, '=');
11954 if (separator)
11955 {
11956 *separator = '\0';
11957 value = separator + 1;
11958 }
11959 else
11960 value = "";
11961
11962 if (i > 0)
11963 appendStringInfoString(buf, ", ");
11964 appendStringInfo(buf, "%s=", quote_identifier(name));
11965
11966 /*
11967 * In general we need to quote the value; but to avoid unnecessary
11968 * clutter, do not quote if it is an identifier that would not need
11969 * quoting. (We could also allow numbers, but that is a bit trickier
11970 * than it looks --- for example, are leading zeroes significant? We
11971 * don't want to assume very much here about what custom reloptions
11972 * might mean.)
11973 */
11974 if (quote_identifier(value) == value)
11975 appendStringInfoString(buf, value);
11976 else
11977 simple_quote_literal(buf, value);
11978
11979 pfree(option);
11980 }
11981 }
11982
11983 /*
11984 * Generate a C string representing a relation's reloptions, or NULL if none.
11985 */
11986 static char *
flatten_reloptions(Oid relid)11987 flatten_reloptions(Oid relid)
11988 {
11989 char *result = NULL;
11990 HeapTuple tuple;
11991 Datum reloptions;
11992 bool isnull;
11993
11994 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11995 if (!HeapTupleIsValid(tuple))
11996 elog(ERROR, "cache lookup failed for relation %u", relid);
11997
11998 reloptions = SysCacheGetAttr(RELOID, tuple,
11999 Anum_pg_class_reloptions, &isnull);
12000 if (!isnull)
12001 {
12002 StringInfoData buf;
12003
12004 initStringInfo(&buf);
12005 get_reloptions(&buf, reloptions);
12006
12007 result = buf.data;
12008 }
12009
12010 ReleaseSysCache(tuple);
12011
12012 return result;
12013 }
12014
12015 /*
12016 * get_range_partbound_string
12017 * A C string representation of one range partition bound
12018 */
12019 char *
get_range_partbound_string(List * bound_datums)12020 get_range_partbound_string(List *bound_datums)
12021 {
12022 deparse_context context;
12023 StringInfo buf = makeStringInfo();
12024 ListCell *cell;
12025 char *sep;
12026
12027 memset(&context, 0, sizeof(deparse_context));
12028 context.buf = buf;
12029
12030 appendStringInfoChar(buf, '(');
12031 sep = "";
12032 foreach(cell, bound_datums)
12033 {
12034 PartitionRangeDatum *datum =
12035 castNode(PartitionRangeDatum, lfirst(cell));
12036
12037 appendStringInfoString(buf, sep);
12038 if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
12039 appendStringInfoString(buf, "MINVALUE");
12040 else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
12041 appendStringInfoString(buf, "MAXVALUE");
12042 else
12043 {
12044 Const *val = castNode(Const, datum->value);
12045
12046 get_const_expr(val, &context, -1);
12047 }
12048 sep = ", ";
12049 }
12050 appendStringInfoChar(buf, ')');
12051
12052 return buf->data;
12053 }
12054