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