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