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