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