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