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