Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * ruleutils.c
4 : * Functions to convert stored expressions/querytrees back to
5 : * source text
6 : *
7 : * Portions Copyright (c) 1996-2023, 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/parse_relation.h"
57 : #include "parser/parser.h"
58 : #include "parser/parsetree.h"
59 : #include "rewrite/rewriteHandler.h"
60 : #include "rewrite/rewriteManip.h"
61 : #include "rewrite/rewriteSupport.h"
62 : #include "utils/array.h"
63 : #include "utils/builtins.h"
64 : #include "utils/fmgroids.h"
65 : #include "utils/guc.h"
66 : #include "utils/hsearch.h"
67 : #include "utils/lsyscache.h"
68 : #include "utils/partcache.h"
69 : #include "utils/rel.h"
70 : #include "utils/ruleutils.h"
71 : #include "utils/snapmgr.h"
72 : #include "utils/syscache.h"
73 : #include "utils/typcache.h"
74 : #include "utils/varlena.h"
75 : #include "utils/xml.h"
76 :
77 : /* ----------
78 : * Pretty formatting constants
79 : * ----------
80 : */
81 :
82 : /* Indent counts */
83 : #define PRETTYINDENT_STD 8
84 : #define PRETTYINDENT_JOIN 4
85 : #define PRETTYINDENT_VAR 4
86 :
87 : #define PRETTYINDENT_LIMIT 40 /* wrap limit */
88 :
89 : /* Pretty flags */
90 : #define PRETTYFLAG_PAREN 0x0001
91 : #define PRETTYFLAG_INDENT 0x0002
92 : #define PRETTYFLAG_SCHEMA 0x0004
93 :
94 : /* Standard conversion of a "bool pretty" option to detailed flags */
95 : #define GET_PRETTY_FLAGS(pretty) \
96 : ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
97 : : PRETTYFLAG_INDENT)
98 :
99 : /* Default line length for pretty-print wrapping: 0 means wrap always */
100 : #define WRAP_COLUMN_DEFAULT 0
101 :
102 : /* macros to test if pretty action needed */
103 : #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
104 : #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
105 : #define PRETTY_SCHEMA(context) ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
106 :
107 :
108 : /* ----------
109 : * Local data types
110 : * ----------
111 : */
112 :
113 : /* Context info needed for invoking a recursive querytree display routine */
114 : typedef struct
115 : {
116 : StringInfo buf; /* output buffer to append to */
117 : List *namespaces; /* List of deparse_namespace nodes */
118 : List *windowClause; /* Current query level's WINDOW clause */
119 : List *windowTList; /* targetlist for resolving WINDOW clause */
120 : int prettyFlags; /* enabling of pretty-print functions */
121 : int wrapColumn; /* max line length, or -1 for no limit */
122 : int indentLevel; /* current indent level for pretty-print */
123 : bool varprefix; /* true to print prefixes on Vars */
124 : ParseExprKind special_exprkind; /* set only for exprkinds needing special
125 : * handling */
126 : Bitmapset *appendparents; /* if not null, map child Vars of these relids
127 : * back to the parent rel */
128 : } deparse_context;
129 :
130 : /*
131 : * Each level of query context around a subtree needs a level of Var namespace.
132 : * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
133 : * the current context's namespaces list.
134 : *
135 : * rtable is the list of actual RTEs from the Query or PlannedStmt.
136 : * rtable_names holds the alias name to be used for each RTE (either a C
137 : * string, or NULL for nameless RTEs such as unnamed joins).
138 : * rtable_columns holds the column alias names to be used for each RTE.
139 : *
140 : * subplans is a list of Plan trees for SubPlans and CTEs (it's only used
141 : * in the PlannedStmt case).
142 : * ctes is a list of CommonTableExpr nodes (only used in the Query case).
143 : * appendrels, if not null (it's only used in the PlannedStmt case), is an
144 : * array of AppendRelInfo nodes, indexed by child relid. We use that to map
145 : * child-table Vars to their inheritance parents.
146 : *
147 : * In some cases we need to make names of merged JOIN USING columns unique
148 : * across the whole query, not only per-RTE. If so, unique_using is true
149 : * and using_names is a list of C strings representing names already assigned
150 : * to USING columns.
151 : *
152 : * When deparsing plan trees, there is always just a single item in the
153 : * deparse_namespace list (since a plan tree never contains Vars with
154 : * varlevelsup > 0). We store the Plan node that is the immediate
155 : * parent of the expression to be deparsed, as well as a list of that
156 : * Plan's ancestors. In addition, we store its outer and inner subplan nodes,
157 : * as well as their targetlists, and the index tlist if the current plan node
158 : * might contain INDEX_VAR Vars. (These fields could be derived on-the-fly
159 : * from the current Plan node, but it seems notationally clearer to set them
160 : * up as separate fields.)
161 : */
162 : typedef struct
163 : {
164 : List *rtable; /* List of RangeTblEntry nodes */
165 : List *rtable_names; /* Parallel list of names for RTEs */
166 : List *rtable_columns; /* Parallel list of deparse_columns structs */
167 : List *subplans; /* List of Plan trees for SubPlans */
168 : List *ctes; /* List of CommonTableExpr nodes */
169 : AppendRelInfo **appendrels; /* Array of AppendRelInfo nodes, or NULL */
170 : /* Workspace for column alias assignment: */
171 : bool unique_using; /* Are we making USING names globally unique */
172 : List *using_names; /* List of assigned names for USING columns */
173 : /* Remaining fields are used only when deparsing a Plan tree: */
174 : Plan *plan; /* immediate parent of current expression */
175 : List *ancestors; /* ancestors of plan */
176 : Plan *outer_plan; /* outer subnode, or NULL if none */
177 : Plan *inner_plan; /* inner subnode, or NULL if none */
178 : List *outer_tlist; /* referent for OUTER_VAR Vars */
179 : List *inner_tlist; /* referent for INNER_VAR Vars */
180 : List *index_tlist; /* referent for INDEX_VAR Vars */
181 : /* Special namespace representing a function signature: */
182 : char *funcname;
183 : int numargs;
184 : char **argnames;
185 : } deparse_namespace;
186 :
187 : /*
188 : * Per-relation data about column alias names.
189 : *
190 : * Selecting aliases is unreasonably complicated because of the need to dump
191 : * rules/views whose underlying tables may have had columns added, deleted, or
192 : * renamed since the query was parsed. We must nonetheless print the rule/view
193 : * in a form that can be reloaded and will produce the same results as before.
194 : *
195 : * For each RTE used in the query, we must assign column aliases that are
196 : * unique within that RTE. SQL does not require this of the original query,
197 : * but due to factors such as *-expansion we need to be able to uniquely
198 : * reference every column in a decompiled query. As long as we qualify all
199 : * column references, per-RTE uniqueness is sufficient for that.
200 : *
201 : * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
202 : * since they just inherit column names from their input RTEs, and we can't
203 : * rename the columns at the join level. Most of the time this isn't an issue
204 : * because we don't need to reference the join's output columns as such; we
205 : * can reference the input columns instead. That approach can fail for merged
206 : * JOIN USING columns, however, so when we have one of those in an unnamed
207 : * join, we have to make that column's alias globally unique across the whole
208 : * query to ensure it can be referenced unambiguously.
209 : *
210 : * Another problem is that a JOIN USING clause requires the columns to be
211 : * merged to have the same aliases in both input RTEs, and that no other
212 : * columns in those RTEs or their children conflict with the USING names.
213 : * To handle that, we do USING-column alias assignment in a recursive
214 : * traversal of the query's jointree. When descending through a JOIN with
215 : * USING, we preassign the USING column names to the child columns, overriding
216 : * other rules for column alias assignment. We also mark each RTE with a list
217 : * of all USING column names selected for joins containing that RTE, so that
218 : * when we assign other columns' aliases later, we can avoid conflicts.
219 : *
220 : * Another problem is that if a JOIN's input tables have had columns added or
221 : * deleted since the query was parsed, we must generate a column alias list
222 : * for the join that matches the current set of input columns --- otherwise, a
223 : * change in the number of columns in the left input would throw off matching
224 : * of aliases to columns of the right input. Thus, positions in the printable
225 : * column alias list are not necessarily one-for-one with varattnos of the
226 : * JOIN, so we need a separate new_colnames[] array for printing purposes.
227 : */
228 : typedef struct
229 : {
230 : /*
231 : * colnames is an array containing column aliases to use for columns that
232 : * existed when the query was parsed. Dropped columns have NULL entries.
233 : * This array can be directly indexed by varattno to get a Var's name.
234 : *
235 : * Non-NULL entries are guaranteed unique within the RTE, *except* when
236 : * this is for an unnamed JOIN RTE. In that case we merely copy up names
237 : * from the two input RTEs.
238 : *
239 : * During the recursive descent in set_using_names(), forcible assignment
240 : * of a child RTE's column name is represented by pre-setting that element
241 : * of the child's colnames array. So at that stage, NULL entries in this
242 : * array just mean that no name has been preassigned, not necessarily that
243 : * the column is dropped.
244 : */
245 : int num_cols; /* length of colnames[] array */
246 : char **colnames; /* array of C strings and NULLs */
247 :
248 : /*
249 : * new_colnames is an array containing column aliases to use for columns
250 : * that would exist if the query was re-parsed against the current
251 : * definitions of its base tables. This is what to print as the column
252 : * alias list for the RTE. This array does not include dropped columns,
253 : * but it will include columns added since original parsing. Indexes in
254 : * it therefore have little to do with current varattno values. As above,
255 : * entries are unique unless this is for an unnamed JOIN RTE. (In such an
256 : * RTE, we never actually print this array, but we must compute it anyway
257 : * for possible use in computing column names of upper joins.) The
258 : * parallel array is_new_col marks which of these columns are new since
259 : * original parsing. Entries with is_new_col false must match the
260 : * non-NULL colnames entries one-for-one.
261 : */
262 : int num_new_cols; /* length of new_colnames[] array */
263 : char **new_colnames; /* array of C strings */
264 : bool *is_new_col; /* array of bool flags */
265 :
266 : /* This flag tells whether we should actually print a column alias list */
267 : bool printaliases;
268 :
269 : /* This list has all names used as USING names in joins above this RTE */
270 : List *parentUsing; /* names assigned to parent merged columns */
271 :
272 : /*
273 : * If this struct is for a JOIN RTE, we fill these fields during the
274 : * set_using_names() pass to describe its relationship to its child RTEs.
275 : *
276 : * leftattnos and rightattnos are arrays with one entry per existing
277 : * output column of the join (hence, indexable by join varattno). For a
278 : * simple reference to a column of the left child, leftattnos[i] is the
279 : * child RTE's attno and rightattnos[i] is zero; and conversely for a
280 : * column of the right child. But for merged columns produced by JOIN
281 : * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
282 : * Note that a simple reference might be to a child RTE column that's been
283 : * dropped; but that's OK since the column could not be used in the query.
284 : *
285 : * If it's a JOIN USING, usingNames holds the alias names selected for the
286 : * merged columns (these might be different from the original USING list,
287 : * if we had to modify names to achieve uniqueness).
288 : */
289 : int leftrti; /* rangetable index of left child */
290 : int rightrti; /* rangetable index of right child */
291 : int *leftattnos; /* left-child varattnos of join cols, or 0 */
292 : int *rightattnos; /* right-child varattnos of join cols, or 0 */
293 : List *usingNames; /* names assigned to merged columns */
294 : } deparse_columns;
295 :
296 : /* This macro is analogous to rt_fetch(), but for deparse_columns structs */
297 : #define deparse_columns_fetch(rangetable_index, dpns) \
298 : ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
299 :
300 : /*
301 : * Entry in set_rtable_names' hash table
302 : */
303 : typedef struct
304 : {
305 : char name[NAMEDATALEN]; /* Hash key --- must be first */
306 : int counter; /* Largest addition used so far for name */
307 : } NameHashEntry;
308 :
309 : /* Callback signature for resolve_special_varno() */
310 : typedef void (*rsv_callback) (Node *node, deparse_context *context,
311 : void *callback_arg);
312 :
313 :
314 : /* ----------
315 : * Global data
316 : * ----------
317 : */
318 : static SPIPlanPtr plan_getrulebyoid = NULL;
319 : static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
320 : static SPIPlanPtr plan_getviewrule = NULL;
321 : static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
322 :
323 : /* GUC parameters */
324 : bool quote_all_identifiers = false;
325 :
326 :
327 : /* ----------
328 : * Local functions
329 : *
330 : * Most of these functions used to use fixed-size buffers to build their
331 : * results. Now, they take an (already initialized) StringInfo object
332 : * as a parameter, and append their text output to its contents.
333 : * ----------
334 : */
335 : static char *deparse_expression_pretty(Node *expr, List *dpcontext,
336 : bool forceprefix, bool showimplicit,
337 : int prettyFlags, int startIndent);
338 : static char *pg_get_viewdef_worker(Oid viewoid,
339 : int prettyFlags, int wrapColumn);
340 : static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
341 : static int decompile_column_index_array(Datum column_index_array, Oid relId,
342 : StringInfo buf);
343 : static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
344 : static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
345 : const Oid *excludeOps,
346 : bool attrsOnly, bool keysOnly,
347 : bool showTblSpc, bool inherits,
348 : int prettyFlags, bool missing_ok);
349 : static char *pg_get_statisticsobj_worker(Oid statextid, bool columns_only,
350 : bool missing_ok);
351 : static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
352 : bool attrsOnly, bool missing_ok);
353 : static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
354 : int prettyFlags, bool missing_ok);
355 : static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
356 : int prettyFlags);
357 : static int print_function_arguments(StringInfo buf, HeapTuple proctup,
358 : bool print_table_args, bool print_defaults);
359 : static void print_function_rettype(StringInfo buf, HeapTuple proctup);
360 : static void print_function_trftypes(StringInfo buf, HeapTuple proctup);
361 : static void print_function_sqlbody(StringInfo buf, HeapTuple proctup);
362 : static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
363 : Bitmapset *rels_used);
364 : static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
365 : List *parent_namespaces);
366 : static void set_simple_column_names(deparse_namespace *dpns);
367 : static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode);
368 : static void set_using_names(deparse_namespace *dpns, Node *jtnode,
369 : List *parentUsing);
370 : static void set_relation_column_names(deparse_namespace *dpns,
371 : RangeTblEntry *rte,
372 : deparse_columns *colinfo);
373 : static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
374 : deparse_columns *colinfo);
375 : static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
376 : deparse_columns *colinfo);
377 : static char *make_colname_unique(char *colname, deparse_namespace *dpns,
378 : deparse_columns *colinfo);
379 : static void expand_colnames_array_to(deparse_columns *colinfo, int n);
380 : static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
381 : deparse_columns *colinfo);
382 : static char *get_rtable_name(int rtindex, deparse_context *context);
383 : static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
384 : static Plan *find_recursive_union(deparse_namespace *dpns,
385 : WorkTableScan *wtscan);
386 : static void push_child_plan(deparse_namespace *dpns, Plan *plan,
387 : deparse_namespace *save_dpns);
388 : static void pop_child_plan(deparse_namespace *dpns,
389 : deparse_namespace *save_dpns);
390 : static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
391 : deparse_namespace *save_dpns);
392 : static void pop_ancestor_plan(deparse_namespace *dpns,
393 : deparse_namespace *save_dpns);
394 : static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
395 : int prettyFlags);
396 : static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
397 : int prettyFlags, int wrapColumn);
398 : static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
399 : TupleDesc resultDesc, bool colNamesVisible,
400 : int prettyFlags, int wrapColumn, int startIndent);
401 : static void get_values_def(List *values_lists, deparse_context *context);
402 : static void get_with_clause(Query *query, deparse_context *context);
403 : static void get_select_query_def(Query *query, deparse_context *context,
404 : TupleDesc resultDesc, bool colNamesVisible);
405 : static void get_insert_query_def(Query *query, deparse_context *context,
406 : bool colNamesVisible);
407 : static void get_update_query_def(Query *query, deparse_context *context,
408 : bool colNamesVisible);
409 : static void get_update_query_targetlist_def(Query *query, List *targetList,
410 : deparse_context *context,
411 : RangeTblEntry *rte);
412 : static void get_delete_query_def(Query *query, deparse_context *context,
413 : bool colNamesVisible);
414 : static void get_utility_query_def(Query *query, deparse_context *context);
415 : static void get_basic_select_query(Query *query, deparse_context *context,
416 : TupleDesc resultDesc, bool colNamesVisible);
417 : static void get_target_list(List *targetList, deparse_context *context,
418 : TupleDesc resultDesc, bool colNamesVisible);
419 : static void get_setop_query(Node *setOp, Query *query,
420 : deparse_context *context,
421 : TupleDesc resultDesc, bool colNamesVisible);
422 : static Node *get_rule_sortgroupclause(Index ref, List *tlist,
423 : bool force_colno,
424 : deparse_context *context);
425 : static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
426 : bool omit_parens, deparse_context *context);
427 : static void get_rule_orderby(List *orderList, List *targetList,
428 : bool force_colno, deparse_context *context);
429 : static void get_rule_windowclause(Query *query, deparse_context *context);
430 : static void get_rule_windowspec(WindowClause *wc, List *targetList,
431 : deparse_context *context);
432 : static char *get_variable(Var *var, int levelsup, bool istoplevel,
433 : deparse_context *context);
434 : static void get_special_variable(Node *node, deparse_context *context,
435 : void *callback_arg);
436 : static void resolve_special_varno(Node *node, deparse_context *context,
437 : rsv_callback callback, void *callback_arg);
438 : static Node *find_param_referent(Param *param, deparse_context *context,
439 : deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
440 : static void get_parameter(Param *param, deparse_context *context);
441 : static const char *get_simple_binary_op_name(OpExpr *expr);
442 : static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
443 : static void appendContextKeyword(deparse_context *context, const char *str,
444 : int indentBefore, int indentAfter, int indentPlus);
445 : static void removeStringInfoSpaces(StringInfo str);
446 : static void get_rule_expr(Node *node, deparse_context *context,
447 : bool showimplicit);
448 : static void get_rule_expr_toplevel(Node *node, deparse_context *context,
449 : bool showimplicit);
450 : static void get_rule_list_toplevel(List *lst, deparse_context *context,
451 : bool showimplicit);
452 : static void get_rule_expr_funccall(Node *node, deparse_context *context,
453 : bool showimplicit);
454 : static bool looks_like_function(Node *node);
455 : static void get_oper_expr(OpExpr *expr, deparse_context *context);
456 : static void get_func_expr(FuncExpr *expr, deparse_context *context,
457 : bool showimplicit);
458 : static void get_agg_expr(Aggref *aggref, deparse_context *context,
459 : Aggref *original_aggref);
460 : static void get_agg_expr_helper(Aggref *aggref, deparse_context *context,
461 : Aggref *original_aggref, const char *funcname,
462 : const char *options, bool is_json_objectagg);
463 : static void get_agg_combine_expr(Node *node, deparse_context *context,
464 : void *callback_arg);
465 : static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
466 : static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
467 : const char *funcname, const char *options,
468 : bool is_json_objectagg);
469 : static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context);
470 : static void get_coercion_expr(Node *arg, deparse_context *context,
471 : Oid resulttype, int32 resulttypmod,
472 : Node *parentNode);
473 : static void get_const_expr(Const *constval, deparse_context *context,
474 : int showtype);
475 : static void get_const_collation(Const *constval, deparse_context *context);
476 : static void get_json_format(JsonFormat *format, StringInfo buf);
477 : static void get_json_constructor(JsonConstructorExpr *ctor,
478 : deparse_context *context, bool showimplicit);
479 : static void get_json_constructor_options(JsonConstructorExpr *ctor,
480 : StringInfo buf);
481 : static void get_json_agg_constructor(JsonConstructorExpr *ctor,
482 : deparse_context *context,
483 : const char *funcname,
484 : bool is_json_objectagg);
485 : static void simple_quote_literal(StringInfo buf, const char *val);
486 : static void get_sublink_expr(SubLink *sublink, deparse_context *context);
487 : static void get_tablefunc(TableFunc *tf, deparse_context *context,
488 : bool showimplicit);
489 : static void get_from_clause(Query *query, const char *prefix,
490 : deparse_context *context);
491 : static void get_from_clause_item(Node *jtnode, Query *query,
492 : deparse_context *context);
493 : static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
494 : deparse_context *context);
495 : static void get_column_alias_list(deparse_columns *colinfo,
496 : deparse_context *context);
497 : static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
498 : deparse_columns *colinfo,
499 : deparse_context *context);
500 : static void get_tablesample_def(TableSampleClause *tablesample,
501 : deparse_context *context);
502 : static void get_opclass_name(Oid opclass, Oid actual_datatype,
503 : StringInfo buf);
504 : static Node *processIndirection(Node *node, deparse_context *context);
505 : static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
506 : static char *get_relation_name(Oid relid);
507 : static char *generate_relation_name(Oid relid, List *namespaces);
508 : static char *generate_qualified_relation_name(Oid relid);
509 : static char *generate_function_name(Oid funcid, int nargs,
510 : List *argnames, Oid *argtypes,
511 : bool has_variadic, bool *use_variadic_p,
512 : ParseExprKind special_exprkind);
513 : static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
514 : static void add_cast_to(StringInfo buf, Oid typid);
515 : static char *generate_qualified_type_name(Oid typid);
516 : static text *string_to_text(char *str);
517 : static char *flatten_reloptions(Oid relid);
518 : static void get_reloptions(StringInfo buf, Datum reloptions);
519 :
520 : #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
521 :
522 :
523 : /* ----------
524 : * pg_get_ruledef - Do it all and return a text
525 : * that could be used as a statement
526 : * to recreate the rule
527 : * ----------
528 : */
529 : Datum
8312 tgl 530 GIC 219 : pg_get_ruledef(PG_FUNCTION_ARGS)
531 : {
7661 532 219 : Oid ruleoid = PG_GETARG_OID(0);
533 : int prettyFlags;
534 : char *res;
535 :
3717 536 219 : prettyFlags = PRETTYFLAG_INDENT;
537 :
2448 rhaas 538 219 : res = pg_get_ruledef_worker(ruleoid, prettyFlags);
539 :
540 219 : if (res == NULL)
541 3 : PG_RETURN_NULL();
542 :
543 216 : PG_RETURN_TEXT_P(string_to_text(res));
544 : }
7193 tgl 545 ECB :
546 :
547 : Datum
7193 tgl 548 GIC 48 : pg_get_ruledef_ext(PG_FUNCTION_ARGS)
549 : {
550 48 : Oid ruleoid = PG_GETARG_OID(0);
7193 tgl 551 CBC 48 : bool pretty = PG_GETARG_BOOL(1);
552 : int prettyFlags;
2448 rhaas 553 ECB : char *res;
554 :
377 tgl 555 CBC 48 : prettyFlags = GET_PRETTY_FLAGS(pretty);
2448 rhaas 556 ECB :
2448 rhaas 557 GIC 48 : res = pg_get_ruledef_worker(ruleoid, prettyFlags);
2448 rhaas 558 ECB :
2448 rhaas 559 GIC 48 : if (res == NULL)
2448 rhaas 560 UIC 0 : PG_RETURN_NULL();
561 :
2448 rhaas 562 GIC 48 : PG_RETURN_TEXT_P(string_to_text(res));
7193 tgl 563 ECB : }
564 :
565 :
6913 566 : static char *
7193 tgl 567 GIC 267 : pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
568 : {
569 : Datum args[1];
7661 tgl 570 ECB : char nulls[1];
571 : int spirc;
8986 bruce 572 : HeapTuple ruletup;
573 : TupleDesc rulettc;
8397 574 : StringInfoData buf;
6913 tgl 575 EUB :
576 : /*
6913 tgl 577 ECB : * Do this first so that string is alloc'd in outer context not SPI's.
578 : */
6913 tgl 579 GIC 267 : initStringInfo(&buf);
580 :
581 : /*
8986 bruce 582 ECB : * Connect to SPI manager
583 : */
8986 bruce 584 GIC 267 : if (SPI_connect() != SPI_OK_CONNECT)
7196 tgl 585 UIC 0 : elog(ERROR, "SPI_connect failed");
586 :
587 : /*
588 : * On the first call prepare the plan to lookup pg_rewrite. We read
589 : * pg_rewrite over the SPI manager instead of using the syscache to be
590 : * checked for read access on pg_rewrite.
591 : */
7661 tgl 592 GIC 267 : if (plan_getrulebyoid == NULL)
593 : {
8986 bruce 594 ECB : Oid argtypes[1];
595 : SPIPlanPtr plan;
596 :
7661 tgl 597 GIC 17 : argtypes[0] = OIDOID;
598 17 : plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
8986 bruce 599 CBC 17 : if (plan == NULL)
7196 tgl 600 UBC 0 : elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
4223 tgl 601 GIC 17 : SPI_keepplan(plan);
602 17 : plan_getrulebyoid = plan;
603 : }
604 :
605 : /*
606 : * Get the pg_rewrite tuple for this rule
8986 bruce 607 ECB : */
7661 tgl 608 GIC 267 : args[0] = ObjectIdGetDatum(ruleoid);
609 267 : nulls[0] = ' ';
3424 peter_e 610 267 : spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
8986 bruce 611 267 : if (spirc != SPI_OK_SELECT)
7196 tgl 612 LBC 0 : elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
8986 bruce 613 CBC 267 : if (SPI_processed != 1)
2448 rhaas 614 ECB : {
2448 rhaas 615 EUB : /*
2448 rhaas 616 ECB : * There is no tuple data available here, just keep the output buffer
617 : * empty.
618 : */
619 : }
620 : else
621 : {
622 : /*
6123 neilc 623 : * Get the rule's definition and put it into executor's memory
6913 tgl 624 : */
6913 tgl 625 CBC 264 : ruletup = SPI_tuptable->vals[0];
626 264 : rulettc = SPI_tuptable->tupdesc;
6913 tgl 627 GBC 264 : make_ruledef(&buf, ruletup, rulettc, prettyFlags);
8986 bruce 628 ECB : }
629 :
630 : /*
631 : * Disconnect from SPI manager
632 : */
8986 bruce 633 GIC 267 : if (SPI_finish() != SPI_OK_FINISH)
7196 tgl 634 UIC 0 : elog(ERROR, "SPI_finish failed");
635 :
2448 rhaas 636 GIC 267 : if (buf.len == 0)
637 3 : return NULL;
638 :
6913 tgl 639 264 : return buf.data;
8994 bruce 640 ECB : }
641 :
642 :
643 : /* ----------
644 : * pg_get_viewdef - Mainly the same thing, but we
645 : * only return the SELECT part of a view
646 : * ----------
647 : */
8312 tgl 648 : Datum
8312 tgl 649 GBC 947 : pg_get_viewdef(PG_FUNCTION_ARGS)
650 : {
7661 tgl 651 ECB : /* By OID */
7661 tgl 652 CBC 947 : Oid viewoid = PG_GETARG_OID(0);
653 : int prettyFlags;
2448 rhaas 654 ECB : char *res;
655 :
3717 tgl 656 GIC 947 : prettyFlags = PRETTYFLAG_INDENT;
657 :
2448 rhaas 658 947 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
659 :
660 947 : if (res == NULL)
661 3 : PG_RETURN_NULL();
662 :
663 944 : PG_RETURN_TEXT_P(string_to_text(res));
7193 tgl 664 ECB : }
665 :
666 :
667 : Datum
7193 tgl 668 GIC 233 : pg_get_viewdef_ext(PG_FUNCTION_ARGS)
669 : {
670 : /* By OID */
7193 tgl 671 CBC 233 : Oid viewoid = PG_GETARG_OID(0);
7193 tgl 672 GIC 233 : bool pretty = PG_GETARG_BOOL(1);
7193 tgl 673 ECB : int prettyFlags;
674 : char *res;
675 :
377 tgl 676 CBC 233 : prettyFlags = GET_PRETTY_FLAGS(pretty);
677 :
2448 rhaas 678 233 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
679 :
2448 rhaas 680 GIC 233 : if (res == NULL)
2448 rhaas 681 UIC 0 : PG_RETURN_NULL();
682 :
2448 rhaas 683 CBC 233 : PG_RETURN_TEXT_P(string_to_text(res));
684 : }
685 :
4067 andrew 686 ECB : Datum
4067 andrew 687 CBC 3 : pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
688 : {
689 : /* By OID */
4067 andrew 690 GIC 3 : Oid viewoid = PG_GETARG_OID(0);
3955 bruce 691 CBC 3 : int wrap = PG_GETARG_INT32(1);
692 : int prettyFlags;
2448 rhaas 693 ECB : char *res;
694 :
4067 andrew 695 : /* calling this implies we want pretty printing */
377 tgl 696 GBC 3 : prettyFlags = GET_PRETTY_FLAGS(true);
697 :
2448 rhaas 698 CBC 3 : res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
699 :
2448 rhaas 700 GIC 3 : if (res == NULL)
2448 rhaas 701 UIC 0 : PG_RETURN_NULL();
2448 rhaas 702 ECB :
2448 rhaas 703 GIC 3 : PG_RETURN_TEXT_P(string_to_text(res));
704 : }
4067 andrew 705 ECB :
7661 tgl 706 : Datum
7661 tgl 707 GIC 36 : pg_get_viewdef_name(PG_FUNCTION_ARGS)
708 : {
709 : /* By qualified name */
2219 noah 710 36 : text *viewname = PG_GETARG_TEXT_PP(0);
3717 tgl 711 ECB : int prettyFlags;
712 : RangeVar *viewrel;
7661 713 : Oid viewoid;
714 : char *res;
715 :
3717 tgl 716 GBC 36 : prettyFlags = PRETTYFLAG_INDENT;
717 :
4293 rhaas 718 ECB : /* Look up view name. Can't lock it - we might not have privileges. */
6526 neilc 719 GIC 36 : viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
4148 rhaas 720 36 : viewoid = RangeVarGetRelid(viewrel, NoLock, false);
721 :
2448 rhaas 722 CBC 36 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
723 :
2448 rhaas 724 GIC 36 : if (res == NULL)
2448 rhaas 725 LBC 0 : PG_RETURN_NULL();
726 :
2448 rhaas 727 GIC 36 : PG_RETURN_TEXT_P(string_to_text(res));
728 : }
729 :
730 :
7193 tgl 731 ECB : Datum
7193 tgl 732 GIC 192 : pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
733 : {
7193 tgl 734 ECB : /* By qualified name */
2219 noah 735 CBC 192 : text *viewname = PG_GETARG_TEXT_PP(0);
7193 tgl 736 GIC 192 : bool pretty = PG_GETARG_BOOL(1);
7193 tgl 737 ECB : int prettyFlags;
738 : RangeVar *viewrel;
739 : Oid viewoid;
2436 tgl 740 EUB : char *res;
741 :
377 tgl 742 CBC 192 : prettyFlags = GET_PRETTY_FLAGS(pretty);
743 :
744 : /* Look up view name. Can't lock it - we might not have privileges. */
6526 neilc 745 GIC 192 : viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
4148 rhaas 746 192 : viewoid = RangeVarGetRelid(viewrel, NoLock, false);
7193 tgl 747 ECB :
2436 tgl 748 GIC 192 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
749 :
2436 tgl 750 CBC 192 : if (res == NULL)
2436 tgl 751 LBC 0 : PG_RETURN_NULL();
752 :
2436 tgl 753 GIC 192 : PG_RETURN_TEXT_P(string_to_text(res));
754 : }
755 :
756 : /*
7661 tgl 757 ECB : * Common code for by-OID and by-name variants of pg_get_viewdef
758 : */
759 : static char *
3758 tgl 760 CBC 1411 : pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
7661 tgl 761 ECB : {
762 : Datum args[2];
763 : char nulls[2];
764 : int spirc;
8986 bruce 765 : HeapTuple ruletup;
8986 bruce 766 EUB : TupleDesc rulettc;
767 : StringInfoData buf;
6913 tgl 768 ECB :
769 : /*
770 : * Do this first so that string is alloc'd in outer context not SPI's.
771 : */
6913 tgl 772 GIC 1411 : initStringInfo(&buf);
773 :
774 : /*
8986 bruce 775 ECB : * Connect to SPI manager
776 : */
8986 bruce 777 GIC 1411 : if (SPI_connect() != SPI_OK_CONNECT)
7196 tgl 778 UIC 0 : elog(ERROR, "SPI_connect failed");
779 :
780 : /*
781 : * On the first call prepare the plan to lookup pg_rewrite. We read
782 : * pg_rewrite over the SPI manager instead of using the syscache to be
783 : * checked for read access on pg_rewrite.
784 : */
7661 tgl 785 GIC 1411 : if (plan_getviewrule == NULL)
786 : {
7661 tgl 787 ECB : Oid argtypes[2];
788 : SPIPlanPtr plan;
789 :
7661 tgl 790 GIC 108 : argtypes[0] = OIDOID;
791 108 : argtypes[1] = NAMEOID;
7661 tgl 792 CBC 108 : plan = SPI_prepare(query_getviewrule, 2, argtypes);
8986 bruce 793 GBC 108 : if (plan == NULL)
7196 tgl 794 UIC 0 : elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
4223 tgl 795 GIC 108 : SPI_keepplan(plan);
796 108 : plan_getviewrule = plan;
797 : }
798 :
799 : /*
7661 tgl 800 ECB : * Get the pg_rewrite tuple for the view's SELECT rule
801 : */
7661 tgl 802 GIC 1411 : args[0] = ObjectIdGetDatum(viewoid);
3424 peter_e 803 1411 : args[1] = DirectFunctionCall1(namein, CStringGetDatum(ViewSelectRuleName));
8986 bruce 804 1411 : nulls[0] = ' ';
7661 tgl 805 CBC 1411 : nulls[1] = ' ';
3424 peter_e 806 1411 : spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
8986 bruce 807 1411 : if (spirc != SPI_OK_SELECT)
7646 tgl 808 LBC 0 : elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
8986 bruce 809 GBC 1411 : if (SPI_processed != 1)
2448 rhaas 810 ECB : {
811 : /*
812 : * There is no tuple data available here, just keep the output buffer
813 : * empty.
814 : */
815 : }
816 : else
8986 bruce 817 : {
8053 818 : /*
6123 neilc 819 : * Get the rule's definition and put it into executor's memory
8986 bruce 820 : */
8986 bruce 821 CBC 1408 : ruletup = SPI_tuptable->vals[0];
822 1408 : rulettc = SPI_tuptable->tupdesc;
3758 tgl 823 GBC 1408 : make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
8986 bruce 824 ECB : }
825 :
826 : /*
827 : * Disconnect from SPI manager
828 : */
8986 bruce 829 GIC 1411 : if (SPI_finish() != SPI_OK_FINISH)
7196 tgl 830 UIC 0 : elog(ERROR, "SPI_finish failed");
831 :
2448 rhaas 832 GIC 1411 : if (buf.len == 0)
833 3 : return NULL;
834 :
6913 tgl 835 1408 : return buf.data;
8994 bruce 836 ECB : }
837 :
7325 838 : /* ----------
839 : * pg_get_triggerdef - Get the definition of a trigger
840 : * ----------
841 : */
842 : Datum
7325 bruce 843 GIC 102 : pg_get_triggerdef(PG_FUNCTION_ARGS)
7325 bruce 844 ECB : {
7325 bruce 845 GBC 102 : Oid trigid = PG_GETARG_OID(0);
846 : char *res;
2448 rhaas 847 ECB :
2448 rhaas 848 CBC 102 : res = pg_get_triggerdef_worker(trigid, false);
849 :
850 102 : if (res == NULL)
2448 rhaas 851 GIC 3 : PG_RETURN_NULL();
852 :
853 99 : PG_RETURN_TEXT_P(string_to_text(res));
854 : }
855 :
856 : Datum
4930 peter_e 857 576 : pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
4930 peter_e 858 ECB : {
4930 peter_e 859 GIC 576 : Oid trigid = PG_GETARG_OID(0);
4930 peter_e 860 CBC 576 : bool pretty = PG_GETARG_BOOL(1);
861 : char *res;
862 :
2448 rhaas 863 576 : res = pg_get_triggerdef_worker(trigid, pretty);
864 :
865 576 : if (res == NULL)
2448 rhaas 866 LBC 0 : PG_RETURN_NULL();
867 :
2448 rhaas 868 CBC 576 : PG_RETURN_TEXT_P(string_to_text(res));
869 : }
870 :
871 : static char *
4930 peter_e 872 678 : pg_get_triggerdef_worker(Oid trigid, bool pretty)
873 : {
7325 bruce 874 ECB : HeapTuple ht_trig;
875 : Form_pg_trigger trigrec;
876 : StringInfoData buf;
877 : Relation tgrel;
7264 tgl 878 : ScanKeyData skey[1];
879 : SysScanDesc tgscan;
7264 tgl 880 CBC 678 : int findx = 0;
7188 bruce 881 EUB : char *tgname;
882 : char *tgoldtable;
2347 kgrittn 883 ECB : char *tgnewtable;
884 : Datum value;
885 : bool isnull;
886 :
7325 bruce 887 : /*
888 : * Fetch the pg_trigger tuple by the Oid of the trigger
889 : */
1539 andres 890 GIC 678 : tgrel = table_open(TriggerRelationId, AccessShareLock);
891 :
7088 tgl 892 678 : ScanKeyInit(&skey[0],
893 : Anum_pg_trigger_oid,
894 : BTEqualStrategyNumber, F_OIDEQ,
7088 tgl 895 ECB : ObjectIdGetDatum(trigid));
896 :
6569 tgl 897 GIC 678 : tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
898 : NULL, 1, skey);
899 :
7264 900 678 : ht_trig = systable_getnext(tgscan);
901 :
902 678 : if (!HeapTupleIsValid(ht_trig))
903 : {
2448 rhaas 904 3 : systable_endscan(tgscan);
1539 andres 905 CBC 3 : table_close(tgrel, AccessShareLock);
2448 rhaas 906 GIC 3 : return NULL;
2448 rhaas 907 ECB : }
908 :
7325 bruce 909 GIC 675 : trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
910 :
911 : /*
6385 bruce 912 ECB : * Start the trigger definition. Note that the trigger's name should never
913 : * be schema-qualified, but the trigger rel's name may be.
914 : */
7325 bruce 915 CBC 675 : initStringInfo(&buf);
916 :
917 675 : tgname = NameStr(trigrec->tgname);
4826 itagaki.takahiro 918 GIC 1350 : appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
4830 tgl 919 CBC 675 : OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
7325 bruce 920 ECB : quote_identifier(tgname));
921 :
7325 bruce 922 GIC 675 : if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
3447 rhaas 923 259 : appendStringInfoString(&buf, "BEFORE");
4564 tgl 924 CBC 416 : else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
3447 rhaas 925 GIC 404 : appendStringInfoString(&buf, "AFTER");
4564 tgl 926 12 : else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
3447 rhaas 927 12 : appendStringInfoString(&buf, "INSTEAD OF");
928 : else
4564 tgl 929 UIC 0 : elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
4564 tgl 930 ECB :
7325 bruce 931 GIC 675 : if (TRIGGER_FOR_INSERT(trigrec->tgtype))
7325 bruce 932 ECB : {
3447 rhaas 933 CBC 443 : appendStringInfoString(&buf, " INSERT");
7325 bruce 934 443 : findx++;
935 : }
7325 bruce 936 GIC 675 : if (TRIGGER_FOR_DELETE(trigrec->tgtype))
7325 bruce 937 ECB : {
7325 bruce 938 CBC 113 : if (findx > 0)
3447 rhaas 939 45 : appendStringInfoString(&buf, " OR DELETE");
7325 bruce 940 ECB : else
3447 rhaas 941 CBC 68 : appendStringInfoString(&buf, " DELETE");
7325 bruce 942 113 : findx++;
943 : }
7325 bruce 944 GBC 675 : if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
945 : {
7325 bruce 946 CBC 324 : if (findx > 0)
3447 rhaas 947 GIC 160 : appendStringInfoString(&buf, " OR UPDATE");
7325 bruce 948 ECB : else
3447 rhaas 949 CBC 164 : appendStringInfoString(&buf, " UPDATE");
4888 tgl 950 GIC 324 : findx++;
4925 tgl 951 ECB : /* tgattr is first var-width field, so OK to access directly */
4925 tgl 952 GIC 324 : if (trigrec->tgattr.dim1 > 0)
4925 tgl 953 ECB : {
4790 bruce 954 : int i;
955 :
4925 tgl 956 CBC 38 : appendStringInfoString(&buf, " OF ");
957 84 : for (i = 0; i < trigrec->tgattr.dim1; i++)
958 : {
4790 bruce 959 ECB : char *attname;
960 :
4925 tgl 961 CBC 46 : if (i > 0)
962 8 : appendStringInfoString(&buf, ", ");
1882 alvherre 963 GIC 46 : attname = get_attname(trigrec->tgrelid,
1882 alvherre 964 CBC 46 : trigrec->tgattr.values[i], false);
4925 tgl 965 46 : appendStringInfoString(&buf, quote_identifier(attname));
966 : }
4925 tgl 967 ECB : }
968 : }
5490 tgl 969 GIC 675 : if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
970 : {
5490 tgl 971 LBC 0 : if (findx > 0)
3447 rhaas 972 0 : appendStringInfoString(&buf, " OR TRUNCATE");
973 : else
3447 rhaas 974 UIC 0 : appendStringInfoString(&buf, " TRUNCATE");
4888 tgl 975 0 : findx++;
5490 tgl 976 ECB : }
1868 977 :
978 : /*
979 : * In non-pretty mode, always schema-qualify the target table name for
980 : * safety. In pretty mode, schema-qualify only if not visible.
981 : */
4826 itagaki.takahiro 982 GIC 1350 : appendStringInfo(&buf, " ON %s ",
983 : pretty ?
1868 tgl 984 CBC 69 : generate_relation_name(trigrec->tgrelid, NIL) :
1868 tgl 985 GIC 606 : generate_qualified_relation_name(trigrec->tgrelid));
7325 bruce 986 EUB :
4830 tgl 987 GBC 675 : if (OidIsValid(trigrec->tgconstraint))
988 : {
4888 tgl 989 UBC 0 : if (OidIsValid(trigrec->tgconstrrelid))
4826 itagaki.takahiro 990 0 : appendStringInfo(&buf, "FROM %s ",
991 : generate_relation_name(trigrec->tgconstrrelid, NIL));
7325 bruce 992 UIC 0 : if (!trigrec->tgdeferrable)
3447 rhaas 993 0 : appendStringInfoString(&buf, "NOT ");
994 0 : appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
7325 bruce 995 0 : if (trigrec->tginitdeferred)
3447 rhaas 996 0 : appendStringInfoString(&buf, "DEFERRED ");
7325 bruce 997 ECB : else
3447 rhaas 998 UIC 0 : appendStringInfoString(&buf, "IMMEDIATE ");
7325 bruce 999 ECB : }
1000 :
2347 kgrittn 1001 GIC 675 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
2347 kgrittn 1002 ECB : tgrel->rd_att, &isnull);
2347 kgrittn 1003 GIC 675 : if (!isnull)
1633 tgl 1004 GBC 49 : tgoldtable = NameStr(*DatumGetName(value));
2347 kgrittn 1005 EUB : else
2347 kgrittn 1006 GIC 626 : tgoldtable = NULL;
2347 kgrittn 1007 GBC 675 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
2347 kgrittn 1008 EUB : tgrel->rd_att, &isnull);
2347 kgrittn 1009 GBC 675 : if (!isnull)
1633 tgl 1010 54 : tgnewtable = NameStr(*DatumGetName(value));
2347 kgrittn 1011 EUB : else
2347 kgrittn 1012 GIC 621 : tgnewtable = NULL;
2347 kgrittn 1013 GBC 675 : if (tgoldtable != NULL || tgnewtable != NULL)
1014 : {
2347 kgrittn 1015 GIC 76 : appendStringInfoString(&buf, "REFERENCING ");
2347 kgrittn 1016 CBC 76 : if (tgoldtable != NULL)
1633 tgl 1017 GIC 49 : appendStringInfo(&buf, "OLD TABLE AS %s ",
1633 tgl 1018 ECB : quote_identifier(tgoldtable));
2347 kgrittn 1019 CBC 76 : if (tgnewtable != NULL)
1633 tgl 1020 GIC 54 : appendStringInfo(&buf, "NEW TABLE AS %s ",
1633 tgl 1021 ECB : quote_identifier(tgnewtable));
2347 kgrittn 1022 : }
1023 :
7325 bruce 1024 CBC 675 : if (TRIGGER_FOR_ROW(trigrec->tgtype))
3447 rhaas 1025 520 : appendStringInfoString(&buf, "FOR EACH ROW ");
1026 : else
1027 155 : appendStringInfoString(&buf, "FOR EACH STATEMENT ");
7325 bruce 1028 ECB :
1029 : /* If the trigger has a WHEN qualification, add that */
4888 tgl 1030 CBC 675 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
4888 tgl 1031 ECB : tgrel->rd_att, &isnull);
4888 tgl 1032 CBC 675 : if (!isnull)
1033 : {
4790 bruce 1034 ECB : Node *qual;
4429 tgl 1035 : char relkind;
1036 : deparse_context context;
1037 : deparse_namespace dpns;
1038 : RangeTblEntry *oldrte;
4790 bruce 1039 : RangeTblEntry *newrte;
4888 tgl 1040 :
4888 tgl 1041 GIC 72 : appendStringInfoString(&buf, "WHEN (");
4888 tgl 1042 ECB :
4888 tgl 1043 GIC 72 : qual = stringToNode(TextDatumGetCString(value));
1044 :
4429 tgl 1045 CBC 72 : relkind = get_rel_relkind(trigrec->tgrelid);
1046 :
4888 tgl 1047 ECB : /* Build minimal OLD and NEW RTEs for the rel */
4888 tgl 1048 GIC 72 : oldrte = makeNode(RangeTblEntry);
1049 72 : oldrte->rtekind = RTE_RELATION;
1050 72 : oldrte->relid = trigrec->tgrelid;
4429 1051 72 : oldrte->relkind = relkind;
1652 1052 72 : oldrte->rellockmode = AccessShareLock;
3852 1053 72 : oldrte->alias = makeAlias("old", NIL);
1054 72 : oldrte->eref = oldrte->alias;
3897 1055 72 : oldrte->lateral = false;
4888 tgl 1056 CBC 72 : oldrte->inh = false;
4888 tgl 1057 GIC 72 : oldrte->inFromCl = true;
4888 tgl 1058 ECB :
4888 tgl 1059 GIC 72 : newrte = makeNode(RangeTblEntry);
4888 tgl 1060 CBC 72 : newrte->rtekind = RTE_RELATION;
4888 tgl 1061 GIC 72 : newrte->relid = trigrec->tgrelid;
4429 1062 72 : newrte->relkind = relkind;
1652 tgl 1063 CBC 72 : newrte->rellockmode = AccessShareLock;
3852 1064 72 : newrte->alias = makeAlias("new", NIL);
1065 72 : newrte->eref = newrte->alias;
3897 1066 72 : newrte->lateral = false;
4888 1067 72 : newrte->inh = false;
1068 72 : newrte->inFromCl = true;
4888 tgl 1069 ECB :
1070 : /* Build two-element rtable */
4653 tgl 1071 CBC 72 : memset(&dpns, 0, sizeof(dpns));
4888 1072 72 : dpns.rtable = list_make2(oldrte, newrte);
1215 tgl 1073 GIC 72 : dpns.subplans = NIL;
4888 tgl 1074 CBC 72 : dpns.ctes = NIL;
1215 1075 72 : dpns.appendrels = NULL;
3852 1076 72 : set_rtable_names(&dpns, NIL, NULL);
3751 1077 72 : set_simple_column_names(&dpns);
4888 tgl 1078 ECB :
1079 : /* Set up context with one-deep namespace stack */
4888 tgl 1080 CBC 72 : context.buf = &buf;
1081 72 : context.namespaces = list_make1(&dpns);
1082 72 : context.windowClause = NIL;
1083 72 : context.windowTList = NIL;
4888 tgl 1084 GIC 72 : context.varprefix = true;
377 1085 72 : context.prettyFlags = GET_PRETTY_FLAGS(pretty);
3758 tgl 1086 CBC 72 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
4888 1087 72 : context.indentLevel = PRETTYINDENT_STD;
2885 andres 1088 72 : context.special_exprkind = EXPR_KIND_NONE;
1215 tgl 1089 72 : context.appendparents = NULL;
4888 tgl 1090 ECB :
4888 tgl 1091 CBC 72 : get_rule_expr(qual, &context, false);
4888 tgl 1092 ECB :
3447 rhaas 1093 GIC 72 : appendStringInfoString(&buf, ") ");
1094 : }
4888 tgl 1095 ECB :
1522 peter 1096 CBC 675 : appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
4931 tgl 1097 ECB : generate_function_name(trigrec->tgfoid, 0,
1244 1098 : NIL, NULL,
2885 andres 1099 : false, NULL, EXPR_KIND_NONE));
7325 bruce 1100 :
7264 tgl 1101 CBC 675 : if (trigrec->tgnargs > 0)
7325 bruce 1102 ECB : {
7264 tgl 1103 : char *p;
1104 : int i;
1105 :
4888 tgl 1106 CBC 225 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
1107 : tgrel->rd_att, &isnull);
7264 1108 225 : if (isnull)
7264 tgl 1109 UIC 0 : elog(ERROR, "tgargs is null for trigger %u", trigid);
2219 noah 1110 GIC 225 : p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
7264 tgl 1111 CBC 598 : for (i = 0; i < trigrec->tgnargs; i++)
1112 : {
7264 tgl 1113 GIC 373 : if (i > 0)
3447 rhaas 1114 148 : appendStringInfoString(&buf, ", ");
5328 tgl 1115 373 : simple_quote_literal(&buf, p);
6160 tgl 1116 ECB : /* advance p to next string embedded in tgargs */
5328 tgl 1117 GIC 3378 : while (*p)
1118 3005 : p++;
6160 1119 373 : p++;
1120 : }
7325 bruce 1121 ECB : }
1122 :
7264 tgl 1123 : /* We deliberately do not put semi-colon at end */
3447 rhaas 1124 GBC 675 : appendStringInfoChar(&buf, ')');
7325 bruce 1125 ECB :
6913 tgl 1126 : /* Clean up */
7264 tgl 1127 GIC 675 : systable_endscan(tgscan);
7264 tgl 1128 ECB :
1539 andres 1129 CBC 675 : table_close(tgrel, AccessShareLock);
7325 bruce 1130 ECB :
4930 peter_e 1131 GIC 675 : return buf.data;
7325 bruce 1132 ECB : }
8994 1133 :
8955 1134 : /* ----------
1135 : * pg_get_indexdef - Get the definition of an index
1136 : *
1137 : * In the extended version, there is a colno argument as well as pretty bool.
1138 : * if colno == 0, we want a complete index definition.
7193 tgl 1139 : * if colno > 0, we only want the Nth index key's variable or expression.
1140 : *
1141 : * Note that the SQL-function versions of this omit any info about the
5657 1142 : * index tablespace; this is intentional because pg_dump wants it that way.
1143 : * However pg_get_indexdef_string() includes the index tablespace.
8955 bruce 1144 : * ----------
1145 : */
8339 tgl 1146 : Datum
8339 tgl 1147 GIC 2088 : pg_get_indexdef(PG_FUNCTION_ARGS)
1148 : {
1149 2088 : Oid indexrelid = PG_GETARG_OID(0);
1150 : int prettyFlags;
1151 : char *res;
1152 :
3717 1153 2088 : prettyFlags = PRETTYFLAG_INDENT;
1154 :
1725 1155 2088 : res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1156 : false, false,
1157 : false, false,
1158 : prettyFlags, true);
1159 :
2448 rhaas 1160 2088 : if (res == NULL)
1161 3 : PG_RETURN_NULL();
2448 rhaas 1162 ECB :
2448 rhaas 1163 GIC 2085 : PG_RETURN_TEXT_P(string_to_text(res));
7193 tgl 1164 ECB : }
1165 :
1166 : Datum
7193 tgl 1167 GIC 850 : pg_get_indexdef_ext(PG_FUNCTION_ARGS)
7193 tgl 1168 ECB : {
7193 tgl 1169 GIC 850 : Oid indexrelid = PG_GETARG_OID(0);
7188 bruce 1170 CBC 850 : int32 colno = PG_GETARG_INT32(1);
7193 tgl 1171 GIC 850 : bool pretty = PG_GETARG_BOOL(2);
1172 : int prettyFlags;
1173 : char *res;
1174 :
377 tgl 1175 CBC 850 : prettyFlags = GET_PRETTY_FLAGS(pretty);
2448 rhaas 1176 ECB :
1725 tgl 1177 GIC 850 : res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1725 tgl 1178 ECB : colno != 0, false,
1179 : false, false,
1180 : prettyFlags, true);
1181 :
2448 rhaas 1182 CBC 850 : if (res == NULL)
2448 rhaas 1183 UIC 0 : PG_RETURN_NULL();
2448 rhaas 1184 ECB :
2448 rhaas 1185 CBC 850 : PG_RETURN_TEXT_P(string_to_text(res));
6913 tgl 1186 ECB : }
1187 :
1188 : /*
1189 : * Internal version for use by ALTER TABLE.
2328 1190 : * Includes a tablespace clause in the result.
1191 : * Returns a palloc'd C string; no pretty-printing.
1192 : */
1193 : char *
6913 tgl 1194 GIC 97 : pg_get_indexdef_string(Oid indexrelid)
1195 : {
1725 1196 97 : return pg_get_indexdef_worker(indexrelid, 0, NULL,
1725 tgl 1197 ECB : false, false,
1725 tgl 1198 EUB : true, true,
1199 : 0, false);
4999 tgl 1200 ECB : }
1201 :
1202 : /* Internal version that just reports the key-column definitions */
1203 : char *
4999 tgl 1204 GIC 550 : pg_get_indexdef_columns(Oid indexrelid, bool pretty)
1205 : {
1206 : int prettyFlags;
1207 :
377 1208 550 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1868 tgl 1209 ECB :
1725 tgl 1210 GIC 550 : return pg_get_indexdef_worker(indexrelid, 0, NULL,
1725 tgl 1211 ECB : true, true,
1212 : false, false,
1213 : prettyFlags, false);
1214 : }
1215 :
1216 : /*
1217 : * Internal workhorse to decompile an index definition.
1218 : *
4871 1219 : * This is now used for exclusion constraints as well: if excludeOps is not
1220 : * NULL then it points to an array of exclusion operator OIDs.
1221 : */
1222 : static char *
4999 tgl 1223 CBC 3637 : pg_get_indexdef_worker(Oid indexrelid, int colno,
1224 : const Oid *excludeOps,
1725 tgl 1225 ECB : bool attrsOnly, bool keysOnly,
1226 : bool showTblSpc, bool inherits,
1227 : int prettyFlags, bool missing_ok)
1228 : {
1229 : /* might want a separate isConstraint parameter later */
4871 tgl 1230 GIC 3637 : bool isConstraint = (excludeOps != NULL);
1231 : HeapTuple ht_idx;
1232 : HeapTuple ht_idxrel;
1233 : HeapTuple ht_am;
1234 : Form_pg_index idxrec;
1235 : Form_pg_class idxrelrec;
1236 : Form_pg_am amrec;
1237 : IndexAmRoutine *amroutine;
7256 tgl 1238 ECB : List *indexprs;
1239 : ListCell *indexpr_item;
1240 : List *context;
1241 : Oid indrelid;
1242 : int keyno;
1243 : Datum indcollDatum;
1244 : Datum indclassDatum;
5934 1245 : Datum indoptionDatum;
1246 : oidvector *indcollation;
1247 : oidvector *indclass;
1248 : int2vector *indoption;
1249 : StringInfoData buf;
1250 : char *str;
1251 : char *sep;
1252 :
1253 : /*
1254 : * Fetch the pg_index tuple by the Oid of the index
1255 : */
4802 rhaas 1256 GIC 3637 : ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
8955 bruce 1257 3637 : if (!HeapTupleIsValid(ht_idx))
1258 : {
2448 rhaas 1259 3 : if (missing_ok)
1260 3 : return NULL;
7196 tgl 1261 UIC 0 : elog(ERROR, "cache lookup failed for index %u", indexrelid);
1262 : }
8720 bruce 1263 GIC 3634 : idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1264 :
7646 tgl 1265 3634 : indrelid = idxrec->indrelid;
1266 3634 : Assert(indexrelid == idxrec->indexrelid);
1267 :
1268 : /* Must get indcollation, indclass, and indoption the hard way */
15 dgustafsson 1269 GNC 3634 : indcollDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1270 : Anum_pg_index_indcollation);
4443 peter_e 1271 GIC 3634 : indcollation = (oidvector *) DatumGetPointer(indcollDatum);
4443 peter_e 1272 ECB :
15 dgustafsson 1273 GNC 3634 : indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1274 : Anum_pg_index_indclass);
6585 tgl 1275 CBC 3634 : indclass = (oidvector *) DatumGetPointer(indclassDatum);
1276 :
15 dgustafsson 1277 GNC 3634 : indoptionDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1278 : Anum_pg_index_indoption);
5934 tgl 1279 GIC 3634 : indoption = (int2vector *) DatumGetPointer(indoptionDatum);
6585 tgl 1280 ECB :
1281 : /*
8955 bruce 1282 : * Fetch the pg_class tuple of the index relation
1283 : */
4802 rhaas 1284 CBC 3634 : ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
8955 bruce 1285 GIC 3634 : if (!HeapTupleIsValid(ht_idxrel))
7196 tgl 1286 LBC 0 : elog(ERROR, "cache lookup failed for relation %u", indexrelid);
8720 bruce 1287 GIC 3634 : idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
8955 bruce 1288 ECB :
1289 : /*
7860 tgl 1290 : * Fetch the pg_am tuple of the index' access method
1291 : */
4802 rhaas 1292 GIC 3634 : ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
7719 tgl 1293 3634 : if (!HeapTupleIsValid(ht_am))
7196 tgl 1294 UIC 0 : elog(ERROR, "cache lookup failed for access method %u",
7196 tgl 1295 ECB : idxrelrec->relam);
7719 tgl 1296 CBC 3634 : amrec = (Form_pg_am) GETSTRUCT(ht_am);
8955 bruce 1297 EUB :
2639 tgl 1298 ECB : /* Fetch the index AM's API struct */
2639 tgl 1299 GIC 3634 : amroutine = GetIndexAmRoutine(amrec->amhandler);
1300 :
1301 : /*
1302 : * Get the index expressions, if any. (NOTE: we do not use the relcache
6385 bruce 1303 ECB : * versions of the expressions and predicate, because we want to display
1304 : * non-const-folded expressions.)
7256 tgl 1305 EUB : */
1838 andrew 1306 GIC 3634 : if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
7256 tgl 1307 ECB : {
1308 : Datum exprsDatum;
1309 : char *exprsString;
1310 :
15 dgustafsson 1311 GNC 276 : exprsDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1312 : Anum_pg_index_indexprs);
5493 tgl 1313 GIC 276 : exprsString = TextDatumGetCString(exprsDatum);
7256 1314 276 : indexprs = (List *) stringToNode(exprsString);
7256 tgl 1315 CBC 276 : pfree(exprsString);
1316 : }
1317 : else
7256 tgl 1318 GIC 3358 : indexprs = NIL;
1319 :
6892 neilc 1320 CBC 3634 : indexpr_item = list_head(indexprs);
1321 :
4541 tgl 1322 3634 : context = deparse_context_for(get_relation_name(indrelid), indrelid);
7256 tgl 1323 ECB :
8053 bruce 1324 : /*
1325 : * Start the index definition. Note that the index's name should never be
1326 : * schema-qualified, but the indexed rel's name may be.
8955 1327 : */
8590 tgl 1328 GIC 3634 : initStringInfo(&buf);
7193 tgl 1329 ECB :
4999 tgl 1330 GIC 3634 : if (!attrsOnly)
4871 tgl 1331 ECB : {
4871 tgl 1332 GIC 2859 : if (!isConstraint)
1906 alvherre 1333 5614 : appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
4871 tgl 1334 2807 : idxrec->indisunique ? "UNIQUE " : "",
1335 2807 : quote_identifier(NameStr(idxrelrec->relname)),
1906 alvherre 1336 2807 : idxrelrec->relkind == RELKIND_PARTITIONED_INDEX
1906 alvherre 1337 CBC 318 : && !inherits ? "ONLY " : "",
1868 tgl 1338 GIC 2807 : (prettyFlags & PRETTYFLAG_SCHEMA) ?
1868 tgl 1339 CBC 625 : generate_relation_name(indrelid, NIL) :
1868 tgl 1340 GIC 2182 : generate_qualified_relation_name(indrelid),
4871 tgl 1341 CBC 2807 : quote_identifier(NameStr(amrec->amname)));
2118 tgl 1342 ECB : else /* currently, must be EXCLUDE constraint */
4871 tgl 1343 CBC 52 : appendStringInfo(&buf, "EXCLUDE USING %s (",
1344 52 : quote_identifier(NameStr(amrec->amname)));
4871 tgl 1345 ECB : }
8720 bruce 1346 :
8053 1347 : /*
7256 tgl 1348 : * Report the indexed attributes
8955 bruce 1349 : */
8955 bruce 1350 CBC 3634 : sep = "";
7256 tgl 1351 GIC 8973 : for (keyno = 0; keyno < idxrec->indnatts; keyno++)
8955 bruce 1352 ECB : {
6585 tgl 1353 CBC 5387 : AttrNumber attnum = idxrec->indkey.values[keyno];
1354 : Oid keycoltype;
1355 : Oid keycolcollation;
1356 :
1357 : /*
1358 : * Ignore non-key attributes if told to.
1828 teodor 1359 ECB : */
1725 tgl 1360 CBC 5387 : if (keysOnly && keyno >= idxrec->indnkeyatts)
1828 teodor 1361 GIC 48 : break;
1828 teodor 1362 ECB :
1363 : /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1725 tgl 1364 GIC 5339 : if (!colno && keyno == idxrec->indnkeyatts)
1365 : {
1828 teodor 1366 124 : appendStringInfoString(&buf, ") INCLUDE (");
1367 124 : sep = "";
1368 : }
1828 teodor 1369 ECB :
7193 tgl 1370 CBC 5339 : if (!colno)
6553 neilc 1371 GIC 5024 : appendStringInfoString(&buf, sep);
8955 bruce 1372 5339 : sep = ", ";
8955 bruce 1373 ECB :
7256 tgl 1374 GIC 5339 : if (attnum != 0)
7256 tgl 1375 ECB : {
1376 : /* Simple index column */
1377 : char *attname;
1378 : int32 keycoltypmod;
8955 bruce 1379 :
1882 alvherre 1380 CBC 4984 : attname = get_attname(indrelid, attnum, false);
7188 bruce 1381 4984 : if (!colno || colno == keyno + 1)
7008 neilc 1382 GIC 4900 : appendStringInfoString(&buf, quote_identifier(attname));
4397 tgl 1383 CBC 4984 : get_atttypetypmodcoll(indrelid, attnum,
1384 : &keycoltype, &keycoltypmod,
1385 : &keycolcollation);
1386 : }
1387 : else
1388 : {
7256 tgl 1389 ECB : /* expressional index */
1390 : Node *indexkey;
1391 :
6892 neilc 1392 CBC 355 : if (indexpr_item == NULL)
7256 tgl 1393 UIC 0 : elog(ERROR, "too few entries in indexprs list");
6892 neilc 1394 GIC 355 : indexkey = (Node *) lfirst(indexpr_item);
1364 tgl 1395 355 : indexpr_item = lnext(indexprs, indexpr_item);
1396 : /* Deparse */
7193 1397 355 : str = deparse_expression_pretty(indexkey, context, false, false,
1398 : prettyFlags, 0);
7188 bruce 1399 355 : if (!colno || colno == keyno + 1)
1400 : {
7188 bruce 1401 ECB : /* Need parens if it's not a bare function call */
2096 tgl 1402 GBC 349 : if (looks_like_function(indexkey))
7008 neilc 1403 CBC 26 : appendStringInfoString(&buf, str);
7188 bruce 1404 ECB : else
7193 tgl 1405 GIC 323 : appendStringInfo(&buf, "(%s)", str);
7193 tgl 1406 ECB : }
7256 tgl 1407 GIC 355 : keycoltype = exprType(indexkey);
4399 tgl 1408 CBC 355 : keycolcollation = exprCollation(indexkey);
1409 : }
1410 :
1725 tgl 1411 ECB : /* Print additional decoration for (selected) key columns */
1725 tgl 1412 CBC 5339 : if (!attrsOnly && keyno < idxrec->indnkeyatts &&
1725 tgl 1413 UIC 0 : (!colno || colno == keyno + 1))
5589 tgl 1414 ECB : {
1463 tgl 1415 GIC 4169 : int16 opt = indoption->values[keyno];
1463 tgl 1416 CBC 4169 : Oid indcoll = indcollation->values[keyno];
1105 akorotkov 1417 4169 : Datum attoptions = get_attoptions(indexrelid, keyno + 1);
1105 akorotkov 1418 GIC 4169 : bool has_options = attoptions != (Datum) 0;
1419 :
1420 : /* Add collation, if not default for column */
4399 tgl 1421 CBC 4169 : if (OidIsValid(indcoll) && indcoll != keycolcollation)
4399 tgl 1422 GBC 54 : appendStringInfo(&buf, " COLLATE %s",
1423 : generate_collation_name((indcoll)));
4443 peter_e 1424 ECB :
5589 tgl 1425 : /* Add the operator class name, if not default */
1105 akorotkov 1426 CBC 4169 : get_opclass_name(indclass->values[keyno],
1105 akorotkov 1427 ECB : has_options ? InvalidOid : keycoltype, &buf);
1428 :
1105 akorotkov 1429 GIC 4169 : if (has_options)
1105 akorotkov 1430 ECB : {
1105 akorotkov 1431 CBC 15 : appendStringInfoString(&buf, " (");
1105 akorotkov 1432 GIC 15 : get_reloptions(&buf, attoptions);
1433 15 : appendStringInfoChar(&buf, ')');
1434 : }
5934 tgl 1435 ECB :
1436 : /* Add options if relevant */
2639 tgl 1437 GIC 4169 : if (amroutine->amcanorder)
5934 tgl 1438 ECB : {
1439 : /* if it supports sort ordering, report DESC and NULLS opts */
5589 tgl 1440 CBC 3520 : if (opt & INDOPTION_DESC)
5589 tgl 1441 ECB : {
3447 rhaas 1442 LBC 0 : appendStringInfoString(&buf, " DESC");
1443 : /* NULLS FIRST is the default in this case */
5589 tgl 1444 UIC 0 : if (!(opt & INDOPTION_NULLS_FIRST))
3447 rhaas 1445 0 : appendStringInfoString(&buf, " NULLS LAST");
5589 tgl 1446 ECB : }
1447 : else
1448 : {
5589 tgl 1449 CBC 3520 : if (opt & INDOPTION_NULLS_FIRST)
3447 rhaas 1450 UIC 0 : appendStringInfoString(&buf, " NULLS FIRST");
5589 tgl 1451 EUB : }
1452 : }
4871 1453 :
1454 : /* Add the exclusion operator if relevant */
4871 tgl 1455 GIC 4169 : if (excludeOps != NULL)
1456 62 : appendStringInfo(&buf, " WITH %s",
1457 62 : generate_operator_name(excludeOps[keyno],
4871 tgl 1458 ECB : keycoltype,
4871 tgl 1459 EUB : keycoltype));
1460 : }
1461 : }
1462 :
4999 tgl 1463 GIC 3634 : if (!attrsOnly)
6124 tgl 1464 ECB : {
7188 bruce 1465 CBC 2859 : appendStringInfoChar(&buf, ')');
7860 tgl 1466 ECB :
430 peter 1467 GIC 2859 : if (idxrec->indnullsnotdistinct)
215 drowley 1468 GNC 6 : appendStringInfoString(&buf, " NULLS NOT DISTINCT");
1469 :
1470 : /*
1471 : * If it has options, append "WITH (options)"
6124 tgl 1472 ECB : */
6124 tgl 1473 GIC 2859 : str = flatten_reloptions(indexrelid);
6124 tgl 1474 CBC 2859 : if (str)
1475 : {
1476 105 : appendStringInfo(&buf, " WITH (%s)", str);
1477 105 : pfree(str);
1478 : }
1479 :
1480 : /*
1481 : * Print tablespace, but only if requested
6124 tgl 1482 ECB : */
5657 tgl 1483 CBC 2859 : if (showTblSpc)
1484 : {
5657 tgl 1485 ECB : Oid tblspc;
1486 :
5657 tgl 1487 GIC 97 : tblspc = get_rel_tablespace(indexrelid);
1445 alvherre 1488 97 : if (OidIsValid(tblspc))
1489 : {
1490 27 : if (isConstraint)
1445 alvherre 1491 UIC 0 : appendStringInfoString(&buf, " USING INDEX");
1445 alvherre 1492 CBC 27 : appendStringInfo(&buf, " TABLESPACE %s",
1445 alvherre 1493 GIC 27 : quote_identifier(get_tablespace_name(tblspc)));
1494 : }
1495 : }
6125 bruce 1496 ECB :
7188 1497 : /*
1498 : * If it's a partial index, decompile and append the predicate
1499 : */
1838 andrew 1500 GBC 2859 : if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
7188 bruce 1501 ECB : {
7193 tgl 1502 : Node *node;
1503 : Datum predDatum;
1504 : char *predString;
1505 :
1506 : /* Convert text string to node tree */
15 dgustafsson 1507 GNC 154 : predDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1508 : Anum_pg_index_indpred);
5493 tgl 1509 GIC 154 : predString = TextDatumGetCString(predDatum);
7193 1510 154 : node = (Node *) stringToNode(predString);
1511 154 : pfree(predString);
1512 :
1513 : /* Deparse */
7193 tgl 1514 CBC 154 : str = deparse_expression_pretty(node, context, false, false,
1515 : prettyFlags, 0);
4871 1516 154 : if (isConstraint)
1517 21 : appendStringInfo(&buf, " WHERE (%s)", str);
4871 tgl 1518 ECB : else
4871 tgl 1519 GIC 133 : appendStringInfo(&buf, " WHERE %s", str);
1520 : }
7860 tgl 1521 ECB : }
1522 :
6913 1523 : /* Clean up */
8179 tgl 1524 CBC 3634 : ReleaseSysCache(ht_idx);
8179 tgl 1525 GIC 3634 : ReleaseSysCache(ht_idxrel);
7719 tgl 1526 CBC 3634 : ReleaseSysCache(ht_am);
1527 :
6913 tgl 1528 GIC 3634 : return buf.data;
1529 : }
1530 :
377 tgl 1531 ECB : /* ----------
1532 : * pg_get_querydef
1533 : *
1534 : * Public entry point to deparse one query parsetree.
1535 : * The pretty flags are determined by GET_PRETTY_FLAGS(pretty).
1536 : *
1537 : * The result is a palloc'd C string.
1538 : * ----------
1539 : */
1540 : char *
377 tgl 1541 UIC 0 : pg_get_querydef(Query *query, bool pretty)
1542 : {
1543 : StringInfoData buf;
1544 : int prettyFlags;
1545 :
1546 0 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1547 :
377 tgl 1548 UBC 0 : initStringInfo(&buf);
1549 :
323 tgl 1550 UIC 0 : get_query_def(query, &buf, NIL, NULL, true,
1551 : prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1552 :
377 tgl 1553 UBC 0 : return buf.data;
1554 : }
377 tgl 1555 EUB :
1556 : /*
2156 1557 : * pg_get_statisticsobjdef
1558 : * Get the definition of an extended statistics object
1559 : */
2207 alvherre 1560 : Datum
2156 tgl 1561 GIC 134 : pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
1562 : {
2207 alvherre 1563 134 : Oid statextid = PG_GETARG_OID(0);
1564 : char *res;
1565 :
744 tomas.vondra 1566 134 : res = pg_get_statisticsobj_worker(statextid, false, true);
1567 :
744 tomas.vondra 1568 CBC 134 : if (res == NULL)
744 tomas.vondra 1569 GIC 3 : PG_RETURN_NULL();
744 tomas.vondra 1570 ECB :
744 tomas.vondra 1571 GIC 131 : PG_RETURN_TEXT_P(string_to_text(res));
1572 : }
744 tomas.vondra 1573 ECB :
1574 : /*
1575 : * Internal version for use by ALTER TABLE.
1576 : * Includes a tablespace clause in the result.
1577 : * Returns a palloc'd C string; no pretty-printing.
1578 : */
1579 : char *
744 tomas.vondra 1580 GIC 7 : pg_get_statisticsobjdef_string(Oid statextid)
1581 : {
1582 7 : return pg_get_statisticsobj_worker(statextid, false, false);
1583 : }
1584 :
1585 : /*
1586 : * pg_get_statisticsobjdef_columns
744 tomas.vondra 1587 ECB : * Get columns and expressions for an extended statistics object
1588 : */
1589 : Datum
744 tomas.vondra 1590 GIC 198 : pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)
1591 : {
1592 198 : Oid statextid = PG_GETARG_OID(0);
1593 : char *res;
1594 :
1595 198 : res = pg_get_statisticsobj_worker(statextid, true, true);
1596 :
2207 alvherre 1597 CBC 198 : if (res == NULL)
2207 alvherre 1598 UIC 0 : PG_RETURN_NULL();
2207 alvherre 1599 ECB :
2207 alvherre 1600 GIC 198 : PG_RETURN_TEXT_P(string_to_text(res));
1601 : }
2207 alvherre 1602 ECB :
1603 : /*
1604 : * Internal workhorse to decompile an extended statistics object.
2207 alvherre 1605 EUB : */
1606 : static char *
744 tomas.vondra 1607 CBC 339 : pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
1608 : {
1609 : Form_pg_statistic_ext statextrec;
1610 : HeapTuple statexttup;
1611 : StringInfoData buf;
1612 : int colno;
1613 : char *nsp;
2195 simon 1614 ECB : ArrayType *arr;
1615 : char *enabled;
1616 : Datum datum;
1617 : bool ndistinct_enabled;
1618 : bool dependencies_enabled;
1619 : bool mcv_enabled;
1620 : int i;
1621 : List *context;
1622 : ListCell *lc;
744 tomas.vondra 1623 GIC 339 : List *exprs = NIL;
1624 : bool has_exprs;
1625 : int ncolumns;
1626 :
2207 alvherre 1627 339 : statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1628 :
2207 alvherre 1629 CBC 339 : if (!HeapTupleIsValid(statexttup))
1630 : {
2207 alvherre 1631 GIC 3 : if (missing_ok)
1632 3 : return NULL;
2156 tgl 1633 LBC 0 : elog(ERROR, "cache lookup failed for statistics object %u", statextid);
1634 : }
2207 alvherre 1635 ECB :
1636 : /* has the statistics expressions? */
744 tomas.vondra 1637 CBC 336 : has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
2207 alvherre 1638 ECB :
744 tomas.vondra 1639 GBC 336 : statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1640 :
1641 : /*
1642 : * Get the statistics expressions, if any. (NOTE: we do not use the
744 tomas.vondra 1643 ECB : * relcache versions of the expressions, because we want to display
1644 : * non-const-folded expressions.)
2195 simon 1645 : */
744 tomas.vondra 1646 GIC 336 : if (has_exprs)
1647 : {
1648 : Datum exprsDatum;
1649 : char *exprsString;
1650 :
15 dgustafsson 1651 GNC 71 : exprsDatum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1652 : Anum_pg_statistic_ext_stxexprs);
744 tomas.vondra 1653 GIC 71 : exprsString = TextDatumGetCString(exprsDatum);
1654 71 : exprs = (List *) stringToNode(exprsString);
744 tomas.vondra 1655 CBC 71 : pfree(exprsString);
1656 : }
744 tomas.vondra 1657 ECB : else
744 tomas.vondra 1658 CBC 265 : exprs = NIL;
2195 simon 1659 ECB :
1660 : /* count the number of columns (attributes and expressions) */
744 tomas.vondra 1661 GIC 336 : ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
1474 tomas.vondra 1662 ECB :
744 tomas.vondra 1663 GIC 336 : initStringInfo(&buf);
1664 :
744 tomas.vondra 1665 CBC 336 : if (!columns_only)
1666 : {
621 tgl 1667 138 : nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
744 tomas.vondra 1668 GIC 138 : appendStringInfo(&buf, "CREATE STATISTICS %s",
744 tomas.vondra 1669 ECB : quote_qualified_identifier(nsp,
744 tomas.vondra 1670 GIC 138 : NameStr(statextrec->stxname)));
1474 tomas.vondra 1671 ECB :
744 1672 : /*
1673 : * Decode the stxkind column so that we know which stats types to
1674 : * print.
1675 : */
15 dgustafsson 1676 GNC 138 : datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1677 : Anum_pg_statistic_ext_stxkind);
744 tomas.vondra 1678 GIC 138 : arr = DatumGetArrayTypeP(datum);
744 tomas.vondra 1679 CBC 138 : if (ARR_NDIM(arr) != 1 ||
744 tomas.vondra 1680 GIC 138 : ARR_HASNULL(arr) ||
744 tomas.vondra 1681 CBC 138 : ARR_ELEMTYPE(arr) != CHAROID)
744 tomas.vondra 1682 LBC 0 : elog(ERROR, "stxkind is not a 1-D char array");
744 tomas.vondra 1683 CBC 138 : enabled = (char *) ARR_DATA_PTR(arr);
744 tomas.vondra 1684 ECB :
744 tomas.vondra 1685 GBC 138 : ndistinct_enabled = false;
744 tomas.vondra 1686 CBC 138 : dependencies_enabled = false;
744 tomas.vondra 1687 GIC 138 : mcv_enabled = false;
744 tomas.vondra 1688 ECB :
744 tomas.vondra 1689 CBC 359 : for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1474 tomas.vondra 1690 ECB : {
744 tomas.vondra 1691 GIC 221 : if (enabled[i] == STATS_EXT_NDISTINCT)
744 tomas.vondra 1692 CBC 75 : ndistinct_enabled = true;
744 tomas.vondra 1693 GIC 146 : else if (enabled[i] == STATS_EXT_DEPENDENCIES)
744 tomas.vondra 1694 CBC 48 : dependencies_enabled = true;
1695 98 : else if (enabled[i] == STATS_EXT_MCV)
1696 57 : mcv_enabled = true;
744 tomas.vondra 1697 ECB :
1698 : /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
1474 1699 : }
1700 :
1701 : /*
1702 : * If any option is disabled, then we'll need to append the types
1703 : * clause to show which options are enabled. We omit the types clause
1704 : * on purpose when all options are enabled, so a pg_dump/pg_restore
1705 : * will create all statistics types on a newer postgres version, if
1706 : * the statistics had all options enabled on the original version.
1707 : *
1708 : * But if the statistics is defined on just a single column, it has to
1709 : * be an expression statistics. In that case we don't need to specify
1710 : * kinds.
1711 : */
744 tomas.vondra 1712 GIC 138 : if ((!ndistinct_enabled || !dependencies_enabled || !mcv_enabled) &&
1713 : (ncolumns > 1))
1714 : {
744 tomas.vondra 1715 CBC 63 : bool gotone = false;
1716 :
744 tomas.vondra 1717 GIC 63 : appendStringInfoString(&buf, " (");
1474 tomas.vondra 1718 ECB :
744 tomas.vondra 1719 GIC 63 : if (ndistinct_enabled)
744 tomas.vondra 1720 ECB : {
744 tomas.vondra 1721 GIC 36 : appendStringInfoString(&buf, "ndistinct");
744 tomas.vondra 1722 CBC 36 : gotone = true;
1723 : }
2195 simon 1724 ECB :
744 tomas.vondra 1725 CBC 63 : if (dependencies_enabled)
1726 : {
744 tomas.vondra 1727 GIC 9 : appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
744 tomas.vondra 1728 CBC 9 : gotone = true;
1729 : }
744 tomas.vondra 1730 ECB :
744 tomas.vondra 1731 CBC 63 : if (mcv_enabled)
744 tomas.vondra 1732 GIC 18 : appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
1733 :
744 tomas.vondra 1734 CBC 63 : appendStringInfoChar(&buf, ')');
744 tomas.vondra 1735 ECB : }
1736 :
744 tomas.vondra 1737 CBC 138 : appendStringInfoString(&buf, " ON ");
1738 : }
1739 :
744 tomas.vondra 1740 ECB : /* decode simple column references */
2183 alvherre 1741 GIC 956 : for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
1742 : {
1743 620 : AttrNumber attnum = statextrec->stxkeys.values[colno];
2207 alvherre 1744 ECB : char *attname;
1745 :
2207 alvherre 1746 CBC 620 : if (colno > 0)
2207 alvherre 1747 GIC 349 : appendStringInfoString(&buf, ", ");
1748 :
1882 alvherre 1749 CBC 620 : attname = get_attname(statextrec->stxrelid, attnum, false);
2207 alvherre 1750 ECB :
2207 alvherre 1751 GIC 620 : appendStringInfoString(&buf, quote_identifier(attname));
2207 alvherre 1752 ECB : }
1753 :
744 tomas.vondra 1754 CBC 336 : context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1755 : statextrec->stxrelid);
1756 :
1757 450 : foreach(lc, exprs)
1758 : {
744 tomas.vondra 1759 GIC 114 : Node *expr = (Node *) lfirst(lc);
744 tomas.vondra 1760 ECB : char *str;
585 tomas.vondra 1761 GIC 114 : int prettyFlags = PRETTYFLAG_PAREN;
744 tomas.vondra 1762 ECB :
744 tomas.vondra 1763 GIC 114 : str = deparse_expression_pretty(expr, context, false, false,
744 tomas.vondra 1764 ECB : prettyFlags, 0);
1765 :
744 tomas.vondra 1766 CBC 114 : if (colno > 0)
744 tomas.vondra 1767 GIC 49 : appendStringInfoString(&buf, ", ");
1768 :
744 tomas.vondra 1769 ECB : /* Need parens if it's not a bare function call */
744 tomas.vondra 1770 CBC 114 : if (looks_like_function(expr))
744 tomas.vondra 1771 GIC 17 : appendStringInfoString(&buf, str);
1772 : else
744 tomas.vondra 1773 CBC 97 : appendStringInfo(&buf, "(%s)", str);
744 tomas.vondra 1774 ECB :
744 tomas.vondra 1775 GIC 114 : colno++;
744 tomas.vondra 1776 ECB : }
1777 :
744 tomas.vondra 1778 CBC 336 : if (!columns_only)
744 tomas.vondra 1779 GIC 138 : appendStringInfo(&buf, " FROM %s",
1780 : generate_relation_name(statextrec->stxrelid, NIL));
2207 alvherre 1781 ECB :
2207 alvherre 1782 CBC 336 : ReleaseSysCache(statexttup);
1783 :
2207 alvherre 1784 GIC 336 : return buf.data;
2207 alvherre 1785 ECB : }
1786 :
744 tomas.vondra 1787 : /*
1788 : * Generate text array of expressions for statistics object.
1789 : */
1790 : Datum
744 tomas.vondra 1791 UIC 0 : pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
1792 : {
1793 0 : Oid statextid = PG_GETARG_OID(0);
744 tomas.vondra 1794 EUB : Form_pg_statistic_ext statextrec;
1795 : HeapTuple statexttup;
1796 : Datum datum;
1797 : List *context;
1798 : ListCell *lc;
744 tomas.vondra 1799 UIC 0 : List *exprs = NIL;
1800 : bool has_exprs;
744 tomas.vondra 1801 EUB : char *tmp;
744 tomas.vondra 1802 UIC 0 : ArrayBuildState *astate = NULL;
1803 :
744 tomas.vondra 1804 UBC 0 : statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1805 :
1806 0 : if (!HeapTupleIsValid(statexttup))
702 tomas.vondra 1807 UIC 0 : PG_RETURN_NULL();
744 tomas.vondra 1808 EUB :
702 1809 : /* Does the stats object have expressions? */
744 tomas.vondra 1810 UIC 0 : has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1811 :
744 tomas.vondra 1812 EUB : /* no expressions? we're done */
744 tomas.vondra 1813 UIC 0 : if (!has_exprs)
1814 : {
744 tomas.vondra 1815 UBC 0 : ReleaseSysCache(statexttup);
744 tomas.vondra 1816 UIC 0 : PG_RETURN_NULL();
744 tomas.vondra 1817 EUB : }
1818 :
744 tomas.vondra 1819 UIC 0 : statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1820 :
744 tomas.vondra 1821 EUB : /*
1822 : * Get the statistics expressions, and deparse them into text values.
1823 : */
15 dgustafsson 1824 UNC 0 : datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1825 : Anum_pg_statistic_ext_stxexprs);
744 tomas.vondra 1826 UBC 0 : tmp = TextDatumGetCString(datum);
1827 0 : exprs = (List *) stringToNode(tmp);
1828 0 : pfree(tmp);
1829 :
1830 0 : context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1831 : statextrec->stxrelid);
1832 :
1833 0 : foreach(lc, exprs)
1834 : {
1835 0 : Node *expr = (Node *) lfirst(lc);
1836 : char *str;
1837 0 : int prettyFlags = PRETTYFLAG_INDENT;
1838 :
1839 0 : str = deparse_expression_pretty(expr, context, false, false,
1840 : prettyFlags, 0);
1841 :
1842 0 : astate = accumArrayResult(astate,
1843 0 : PointerGetDatum(cstring_to_text(str)),
1844 : false,
1845 : TEXTOID,
1846 : CurrentMemoryContext);
1847 : }
1848 :
1849 0 : ReleaseSysCache(statexttup);
1850 :
1851 0 : PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
1852 : }
1853 :
1854 : /*
1855 : * pg_get_partkeydef
1856 : *
1857 : * Returns the partition key specification, ie, the following:
1858 : *
1859 : * { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
1860 : */
1861 : Datum
2314 rhaas 1862 CBC 586 : pg_get_partkeydef(PG_FUNCTION_ARGS)
1863 : {
1864 586 : Oid relid = PG_GETARG_OID(0);
1865 : char *res;
1866 :
2174 sfrost 1867 586 : res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1868 :
1869 586 : if (res == NULL)
1870 3 : PG_RETURN_NULL();
1871 :
1872 583 : PG_RETURN_TEXT_P(string_to_text(res));
1873 : }
1874 :
1875 : /* Internal version that just reports the column definitions */
1876 : char *
2228 rhaas 1877 68 : pg_get_partkeydef_columns(Oid relid, bool pretty)
1878 : {
1879 : int prettyFlags;
1880 :
377 tgl 1881 68 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1882 :
2174 sfrost 1883 68 : return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1884 : }
1885 :
1886 : /*
1887 : * Internal workhorse to decompile a partition key definition.
1888 : */
1889 : static char *
2228 rhaas 1890 654 : pg_get_partkeydef_worker(Oid relid, int prettyFlags,
1891 : bool attrsOnly, bool missing_ok)
1892 : {
1893 : Form_pg_partitioned_table form;
1894 : HeapTuple tuple;
1895 : oidvector *partclass;
1896 : oidvector *partcollation;
1897 : List *partexprs;
1898 : ListCell *partexpr_item;
1899 : List *context;
1900 : Datum datum;
1901 : StringInfoData buf;
1902 : int keyno;
1903 : char *str;
1904 : char *sep;
2314 rhaas 1905 ECB :
2314 rhaas 1906 CBC 654 : tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
2314 rhaas 1907 GIC 654 : if (!HeapTupleIsValid(tuple))
2174 sfrost 1908 ECB : {
2174 sfrost 1909 CBC 3 : if (missing_ok)
2174 sfrost 1910 GBC 3 : return NULL;
2314 rhaas 1911 UIC 0 : elog(ERROR, "cache lookup failed for partition key of %u", relid);
1912 : }
2314 rhaas 1913 ECB :
2314 rhaas 1914 GIC 651 : form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
2314 rhaas 1915 ECB :
2314 rhaas 1916 GIC 651 : Assert(form->partrelid == relid);
1917 :
2314 rhaas 1918 ECB : /* Must get partclass and partcollation the hard way */
15 dgustafsson 1919 GNC 651 : datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1920 : Anum_pg_partitioned_table_partclass);
2314 rhaas 1921 CBC 651 : partclass = (oidvector *) DatumGetPointer(datum);
1922 :
15 dgustafsson 1923 GNC 651 : datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1924 : Anum_pg_partitioned_table_partcollation);
2314 rhaas 1925 GIC 651 : partcollation = (oidvector *) DatumGetPointer(datum);
1926 :
1927 :
1928 : /*
1929 : * Get the expressions, if any. (NOTE: we do not use the relcache
2266 rhaas 1930 ECB : * versions of the expressions, because we want to display
1931 : * non-const-folded expressions.)
1932 : */
1838 andrew 1933 GIC 651 : if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
1934 : {
2314 rhaas 1935 ECB : Datum exprsDatum;
1936 : char *exprsString;
1937 :
15 dgustafsson 1938 GNC 73 : exprsDatum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1939 : Anum_pg_partitioned_table_partexprs);
2314 rhaas 1940 GIC 73 : exprsString = TextDatumGetCString(exprsDatum);
1941 73 : partexprs = (List *) stringToNode(exprsString);
2314 rhaas 1942 ECB :
2314 rhaas 1943 GIC 73 : if (!IsA(partexprs, List))
2314 rhaas 1944 UIC 0 : elog(ERROR, "unexpected node type found in partexprs: %d",
2266 rhaas 1945 ECB : (int) nodeTag(partexprs));
1946 :
2314 rhaas 1947 CBC 73 : pfree(exprsString);
2314 rhaas 1948 ECB : }
1949 : else
2314 rhaas 1950 CBC 578 : partexprs = NIL;
1951 :
1952 651 : partexpr_item = list_head(partexprs);
2314 rhaas 1953 GIC 651 : context = deparse_context_for(get_relation_name(relid), relid);
2314 rhaas 1954 ECB :
2314 rhaas 1955 CBC 651 : initStringInfo(&buf);
2314 rhaas 1956 ECB :
2314 rhaas 1957 CBC 651 : switch (form->partstrat)
2314 rhaas 1958 ECB : {
1977 rhaas 1959 CBC 27 : case PARTITION_STRATEGY_HASH:
1960 27 : if (!attrsOnly)
1375 drowley 1961 27 : appendStringInfoString(&buf, "HASH");
1977 rhaas 1962 27 : break;
2314 1963 220 : case PARTITION_STRATEGY_LIST:
2228 1964 220 : if (!attrsOnly)
2063 peter_e 1965 200 : appendStringInfoString(&buf, "LIST");
2314 rhaas 1966 GBC 220 : break;
1967 404 : case PARTITION_STRATEGY_RANGE:
2228 rhaas 1968 GIC 404 : if (!attrsOnly)
2063 peter_e 1969 356 : appendStringInfoString(&buf, "RANGE");
2314 rhaas 1970 404 : break;
2314 rhaas 1971 LBC 0 : default:
1972 0 : elog(ERROR, "unexpected partition strategy: %d",
2266 rhaas 1973 ECB : (int) form->partstrat);
2314 1974 : }
1975 :
2228 rhaas 1976 CBC 651 : if (!attrsOnly)
2063 peter_e 1977 GIC 583 : appendStringInfoString(&buf, " (");
2314 rhaas 1978 651 : sep = "";
1979 1378 : for (keyno = 0; keyno < form->partnatts; keyno++)
1980 : {
2314 rhaas 1981 CBC 727 : AttrNumber attnum = form->partattrs.values[keyno];
2314 rhaas 1982 ECB : Oid keycoltype;
1983 : Oid keycolcollation;
1984 : Oid partcoll;
1985 :
2314 rhaas 1986 GIC 727 : appendStringInfoString(&buf, sep);
1987 727 : sep = ", ";
1988 727 : if (attnum != 0)
2314 rhaas 1989 ECB : {
1990 : /* Simple attribute reference */
1991 : char *attname;
1992 : int32 keycoltypmod;
1993 :
1882 alvherre 1994 GIC 648 : attname = get_attname(relid, attnum, false);
2314 rhaas 1995 648 : appendStringInfoString(&buf, quote_identifier(attname));
1996 648 : get_atttypetypmodcoll(relid, attnum,
1997 : &keycoltype, &keycoltypmod,
1998 : &keycolcollation);
1999 : }
2314 rhaas 2000 ECB : else
2314 rhaas 2001 EUB : {
2314 rhaas 2002 ECB : /* Expression */
2003 : Node *partkey;
2004 :
2314 rhaas 2005 GIC 79 : if (partexpr_item == NULL)
2314 rhaas 2006 LBC 0 : elog(ERROR, "too few entries in partexprs list");
2314 rhaas 2007 GIC 79 : partkey = (Node *) lfirst(partexpr_item);
1364 tgl 2008 79 : partexpr_item = lnext(partexprs, partexpr_item);
2096 tgl 2009 ECB :
2314 rhaas 2010 : /* Deparse */
2314 rhaas 2011 GIC 79 : str = deparse_expression_pretty(partkey, context, false, false,
2096 tgl 2012 ECB : prettyFlags, 0);
2013 : /* Need parens if it's not a bare function call */
2096 tgl 2014 CBC 79 : if (looks_like_function(partkey))
2015 28 : appendStringInfoString(&buf, str);
2016 : else
2096 tgl 2017 GIC 51 : appendStringInfo(&buf, "(%s)", str);
2018 :
2314 rhaas 2019 CBC 79 : keycoltype = exprType(partkey);
2020 79 : keycolcollation = exprCollation(partkey);
2314 rhaas 2021 ECB : }
2022 :
2023 : /* Add collation, if not default for column */
2314 rhaas 2024 GIC 727 : partcoll = partcollation->values[keyno];
2228 rhaas 2025 CBC 727 : if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
2314 2026 3 : appendStringInfo(&buf, " COLLATE %s",
2027 : generate_collation_name((partcoll)));
2028 :
2314 rhaas 2029 ECB : /* Add the operator class name, if not default */
2228 rhaas 2030 CBC 727 : if (!attrsOnly)
2228 rhaas 2031 GIC 632 : get_opclass_name(partclass->values[keyno], keycoltype, &buf);
2032 : }
2228 rhaas 2033 ECB :
2228 rhaas 2034 GIC 651 : if (!attrsOnly)
2228 rhaas 2035 CBC 583 : appendStringInfoChar(&buf, ')');
2036 :
2037 : /* Clean up */
2314 rhaas 2038 GIC 651 : ReleaseSysCache(tuple);
2039 :
2040 651 : return buf.data;
2041 : }
2042 :
2043 : /*
2157 rhaas 2044 ECB : * pg_get_partition_constraintdef
2045 : *
2046 : * Returns partition constraint expression as a string for the input relation
2047 : */
2048 : Datum
2157 rhaas 2049 GIC 78 : pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
2050 : {
2153 bruce 2051 78 : Oid relationId = PG_GETARG_OID(0);
2153 bruce 2052 ECB : Expr *constr_expr;
2053 : int prettyFlags;
2054 : List *context;
2055 : char *consrc;
2157 rhaas 2056 :
2157 rhaas 2057 GIC 78 : constr_expr = get_partition_qual_relid(relationId);
2058 :
2059 : /* Quick exit if no partition constraint */
2060 78 : if (constr_expr == NULL)
2157 rhaas 2061 CBC 9 : PG_RETURN_NULL();
2157 rhaas 2062 ECB :
2063 : /*
2064 : * Deparse and return the constraint expression.
2065 : */
2157 rhaas 2066 CBC 69 : prettyFlags = PRETTYFLAG_INDENT;
2157 rhaas 2067 GIC 69 : context = deparse_context_for(get_relation_name(relationId), relationId);
2068 69 : consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2069 : false, prettyFlags, 0);
2070 :
2071 69 : PG_RETURN_TEXT_P(string_to_text(consrc));
2072 : }
2073 :
2074 : /*
2075 : * pg_get_partconstrdef_string
1467 alvherre 2076 ECB : *
2077 : * Returns the partition constraint as a C-string for the input relation, with
2078 : * the given alias. No pretty-printing.
2079 : */
2080 : char *
1467 alvherre 2081 CBC 43 : pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
1467 alvherre 2082 ECB : {
2083 : Expr *constr_expr;
2084 : List *context;
2085 :
1467 alvherre 2086 GIC 43 : constr_expr = get_partition_qual_relid(partitionId);
2087 43 : context = deparse_context_for(aliasname, partitionId);
2088 :
2089 43 : return deparse_expression((Node *) constr_expr, context, true, false);
2090 : }
2091 :
2092 : /*
2093 : * pg_get_constraintdef
7541 tgl 2094 ECB : *
2095 : * Returns the definition for the constraint, ie, everything that needs to
2096 : * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
2097 : */
2098 : Datum
7541 tgl 2099 GIC 843 : pg_get_constraintdef(PG_FUNCTION_ARGS)
7541 tgl 2100 ECB : {
7522 bruce 2101 GIC 843 : Oid constraintId = PG_GETARG_OID(0);
3717 tgl 2102 ECB : int prettyFlags;
2103 : char *res;
7193 2104 :
3717 tgl 2105 CBC 843 : prettyFlags = PRETTYFLAG_INDENT;
2106 :
2448 rhaas 2107 843 : res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2108 :
2448 rhaas 2109 GIC 843 : if (res == NULL)
2110 3 : PG_RETURN_NULL();
2448 rhaas 2111 ECB :
2448 rhaas 2112 GIC 840 : PG_RETURN_TEXT_P(string_to_text(res));
7193 tgl 2113 ECB : }
2114 :
2115 : Datum
7193 tgl 2116 GIC 1521 : pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
2117 : {
7193 tgl 2118 CBC 1521 : Oid constraintId = PG_GETARG_OID(0);
7193 tgl 2119 GIC 1521 : bool pretty = PG_GETARG_BOOL(1);
7193 tgl 2120 ECB : int prettyFlags;
2121 : char *res;
2122 :
377 tgl 2123 GBC 1521 : prettyFlags = GET_PRETTY_FLAGS(pretty);
2124 :
2448 rhaas 2125 CBC 1521 : res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2126 :
2448 rhaas 2127 GIC 1521 : if (res == NULL)
2448 rhaas 2128 UIC 0 : PG_RETURN_NULL();
2129 :
2448 rhaas 2130 GIC 1521 : PG_RETURN_TEXT_P(string_to_text(res));
2131 : }
7193 tgl 2132 ECB :
2133 : /*
2697 2134 : * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
2135 : */
2136 : char *
2697 tgl 2137 GIC 202 : pg_get_constraintdef_command(Oid constraintId)
2138 : {
2448 rhaas 2139 202 : return pg_get_constraintdef_worker(constraintId, true, 0, false);
2140 : }
7193 tgl 2141 ECB :
2142 : /*
2143 : * As of 9.4, we now use an MVCC snapshot for this.
2144 : */
2145 : static char *
6913 tgl 2146 GIC 2566 : pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
2147 : int prettyFlags, bool missing_ok)
2148 : {
7522 bruce 2149 ECB : HeapTuple tup;
2150 : Form_pg_constraint conForm;
2151 : StringInfoData buf;
3260 2152 : SysScanDesc scandesc;
2153 : ScanKeyData scankey[1];
3260 bruce 2154 GIC 2566 : Snapshot snapshot = RegisterSnapshot(GetTransactionSnapshot());
1539 andres 2155 2566 : Relation relation = table_open(ConstraintRelationId, AccessShareLock);
2156 :
3290 simon 2157 CBC 2566 : ScanKeyInit(&scankey[0],
2158 : Anum_pg_constraint_oid,
2159 : BTEqualStrategyNumber, F_OIDEQ,
2160 : ObjectIdGetDatum(constraintId));
2161 :
3290 simon 2162 GIC 2566 : scandesc = systable_beginscan(relation,
2163 : ConstraintOidIndexId,
2164 : true,
2165 : snapshot,
2166 : 1,
2167 : scankey);
3290 simon 2168 ECB :
2169 : /*
3260 bruce 2170 : * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2171 : * via SearchSysCache, which works fine.
3290 simon 2172 : */
3290 simon 2173 GIC 2566 : tup = systable_getnext(scandesc);
3290 simon 2174 ECB :
3290 simon 2175 GIC 2566 : UnregisterSnapshot(snapshot);
7541 tgl 2176 ECB :
2448 rhaas 2177 CBC 2566 : if (!HeapTupleIsValid(tup))
2448 rhaas 2178 ECB : {
2448 rhaas 2179 GIC 3 : if (missing_ok)
2448 rhaas 2180 EUB : {
2448 rhaas 2181 GIC 3 : systable_endscan(scandesc);
1539 andres 2182 3 : table_close(relation, AccessShareLock);
2448 rhaas 2183 CBC 3 : return NULL;
2184 : }
2135 tgl 2185 LBC 0 : elog(ERROR, "could not find tuple for constraint %u", constraintId);
2186 : }
3290 simon 2187 ECB :
7541 tgl 2188 GIC 2563 : conForm = (Form_pg_constraint) GETSTRUCT(tup);
7541 tgl 2189 ECB :
7541 tgl 2190 GIC 2563 : initStringInfo(&buf);
2191 :
2697 2192 2563 : if (fullCommand)
2193 : {
1985 2194 202 : if (OidIsValid(conForm->conrelid))
2195 : {
2196 : /*
2197 : * Currently, callers want ALTER TABLE (without ONLY) for CHECK
1985 tgl 2198 ECB : * constraints, and other types of constraints don't inherit
2199 : * anyway so it doesn't matter whether we say ONLY or not. Someday
2200 : * we might need to let callers specify whether to put ONLY in the
2201 : * command.
2202 : */
1985 tgl 2203 GIC 195 : appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2204 : generate_qualified_relation_name(conForm->conrelid),
1985 tgl 2205 CBC 195 : quote_identifier(NameStr(conForm->conname)));
1985 tgl 2206 ECB : }
2207 : else
2208 : {
2209 : /* Must be a domain constraint */
1985 tgl 2210 GIC 7 : Assert(OidIsValid(conForm->contypid));
2211 7 : appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
1985 tgl 2212 ECB : generate_qualified_type_name(conForm->contypid),
1985 tgl 2213 GIC 7 : quote_identifier(NameStr(conForm->conname)));
1985 tgl 2214 ECB : }
2215 : }
2216 :
7541 tgl 2217 GIC 2563 : switch (conForm->contype)
2218 : {
2219 314 : case CONSTRAINT_FOREIGN:
2220 : {
7522 bruce 2221 ECB : Datum val;
2222 : bool isnull;
2223 : const char *string;
7541 tgl 2224 :
2225 : /* Start off the constraint definition */
3447 rhaas 2226 GIC 314 : appendStringInfoString(&buf, "FOREIGN KEY (");
7541 tgl 2227 ECB :
2228 : /* Fetch and build referencing-column list */
15 dgustafsson 2229 GNC 314 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2230 : Anum_pg_constraint_conkey);
2231 :
7522 bruce 2232 CBC 314 : decompile_column_index_array(val, conForm->conrelid, &buf);
2233 :
2234 : /* add foreign relation name */
2235 314 : appendStringInfo(&buf, ") REFERENCES %s(",
2236 : generate_relation_name(conForm->confrelid,
5298 tgl 2237 ECB : NIL));
2238 :
2239 : /* Fetch and build referenced-column list */
15 dgustafsson 2240 GNC 314 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2241 : Anum_pg_constraint_confkey);
7541 tgl 2242 EUB :
7522 bruce 2243 GBC 314 : decompile_column_index_array(val, conForm->confrelid, &buf);
7541 tgl 2244 EUB :
3447 rhaas 2245 CBC 314 : appendStringInfoChar(&buf, ')');
7541 tgl 2246 ECB :
7522 bruce 2247 : /* Add match type */
7522 bruce 2248 GBC 314 : switch (conForm->confmatchtype)
7522 bruce 2249 EUB : {
7522 bruce 2250 GIC 17 : case FKCONSTR_MATCH_FULL:
2251 17 : string = " MATCH FULL";
2252 17 : break;
7522 bruce 2253 UIC 0 : case FKCONSTR_MATCH_PARTIAL:
7522 bruce 2254 LBC 0 : string = " MATCH PARTIAL";
7522 bruce 2255 UIC 0 : break;
3948 tgl 2256 GIC 297 : case FKCONSTR_MATCH_SIMPLE:
7522 bruce 2257 CBC 297 : string = "";
7522 bruce 2258 GIC 297 : break;
7522 bruce 2259 LBC 0 : default:
7196 tgl 2260 0 : elog(ERROR, "unrecognized confmatchtype: %d",
7196 tgl 2261 ECB : conForm->confmatchtype);
7522 bruce 2262 EUB : string = ""; /* keep compiler quiet */
2263 : break;
2264 : }
7008 neilc 2265 CBC 314 : appendStringInfoString(&buf, string);
7541 tgl 2266 ECB :
7370 2267 : /* Add ON UPDATE and ON DELETE clauses, if needed */
7522 bruce 2268 CBC 314 : switch (conForm->confupdtype)
7522 bruce 2269 ECB : {
7522 bruce 2270 CBC 252 : case FKCONSTR_ACTION_NOACTION:
7188 bruce 2271 GBC 252 : string = NULL; /* suppress default */
7522 2272 252 : break;
7522 bruce 2273 UBC 0 : case FKCONSTR_ACTION_RESTRICT:
2274 0 : string = "RESTRICT";
2275 0 : break;
7522 bruce 2276 GIC 48 : case FKCONSTR_ACTION_CASCADE:
2277 48 : string = "CASCADE";
2278 48 : break;
2279 14 : case FKCONSTR_ACTION_SETNULL:
7522 bruce 2280 CBC 14 : string = "SET NULL";
2281 14 : break;
7522 bruce 2282 UIC 0 : case FKCONSTR_ACTION_SETDEFAULT:
7522 bruce 2283 LBC 0 : string = "SET DEFAULT";
7522 bruce 2284 UIC 0 : break;
7522 bruce 2285 LBC 0 : default:
7196 tgl 2286 0 : elog(ERROR, "unrecognized confupdtype: %d",
7196 tgl 2287 ECB : conForm->confupdtype);
7370 tgl 2288 EUB : string = NULL; /* keep compiler quiet */
7522 bruce 2289 : break;
2290 : }
7370 tgl 2291 CBC 314 : if (string)
bruce 2292 62 : appendStringInfo(&buf, " ON UPDATE %s", string);
7541 tgl 2293 ECB :
7522 bruce 2294 CBC 314 : switch (conForm->confdeltype)
7522 bruce 2295 ECB : {
7522 bruce 2296 CBC 254 : case FKCONSTR_ACTION_NOACTION:
7188 2297 254 : string = NULL; /* suppress default */
7522 2298 254 : break;
7522 bruce 2299 LBC 0 : case FKCONSTR_ACTION_RESTRICT:
7522 bruce 2300 UBC 0 : string = "RESTRICT";
2301 0 : break;
7522 bruce 2302 GIC 48 : case FKCONSTR_ACTION_CASCADE:
2303 48 : string = "CASCADE";
2304 48 : break;
2305 9 : case FKCONSTR_ACTION_SETNULL:
7522 bruce 2306 CBC 9 : string = "SET NULL";
2307 9 : break;
7522 bruce 2308 GIC 3 : case FKCONSTR_ACTION_SETDEFAULT:
2309 3 : string = "SET DEFAULT";
2310 3 : break;
7522 bruce 2311 UIC 0 : default:
7196 tgl 2312 0 : elog(ERROR, "unrecognized confdeltype: %d",
7196 tgl 2313 ECB : conForm->confdeltype);
2314 : string = NULL; /* keep compiler quiet */
7522 bruce 2315 : break;
2316 : }
7370 tgl 2317 CBC 314 : if (string)
bruce 2318 60 : appendStringInfo(&buf, " ON DELETE %s", string);
7541 tgl 2319 ECB :
2320 : /*
2321 : * Add columns specified to SET NULL or SET DEFAULT if
332 2322 : * provided.
2323 : */
487 peter 2324 CBC 314 : val = SysCacheGetAttr(CONSTROID, tup,
2325 : Anum_pg_constraint_confdelsetcols, &isnull);
487 peter 2326 GIC 314 : if (!isnull)
2327 : {
215 drowley 2328 GNC 6 : appendStringInfoString(&buf, " (");
487 peter 2329 GIC 6 : decompile_column_index_array(val, conForm->conrelid, &buf);
215 drowley 2330 GNC 6 : appendStringInfoChar(&buf, ')');
2331 : }
2332 :
7522 bruce 2333 CBC 314 : break;
7522 bruce 2334 ECB : }
7360 bruce 2335 GIC 1199 : case CONSTRAINT_PRIMARY:
7360 bruce 2336 ECB : case CONSTRAINT_UNIQUE:
2337 : {
2338 : Datum val;
5657 tgl 2339 : Oid indexId;
1679 alvherre 2340 : int keyatts;
1679 alvherre 2341 EUB : HeapTuple indtup;
7360 bruce 2342 ECB :
2343 : /* Start off the constraint definition */
7360 bruce 2344 GBC 1199 : if (conForm->contype == CONSTRAINT_PRIMARY)
430 peter 2345 GIC 1047 : appendStringInfoString(&buf, "PRIMARY KEY ");
7360 bruce 2346 ECB : else
430 peter 2347 GIC 152 : appendStringInfoString(&buf, "UNIQUE ");
2348 :
430 peter 2349 CBC 1199 : indexId = conForm->conindid;
2350 :
430 peter 2351 GIC 1199 : indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
430 peter 2352 CBC 1199 : if (!HeapTupleIsValid(indtup))
430 peter 2353 UIC 0 : elog(ERROR, "cache lookup failed for index %u", indexId);
430 peter 2354 CBC 1199 : if (conForm->contype == CONSTRAINT_UNIQUE &&
430 peter 2355 GIC 152 : ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
430 peter 2356 UIC 0 : appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
430 peter 2357 ECB :
215 drowley 2358 GNC 1199 : appendStringInfoChar(&buf, '(');
7360 bruce 2359 ECB :
2360 : /* Fetch and build target column list */
15 dgustafsson 2361 GNC 1199 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2362 : Anum_pg_constraint_conkey);
7360 bruce 2363 ECB :
1679 alvherre 2364 GIC 1199 : keyatts = decompile_column_index_array(val, conForm->conrelid, &buf);
7360 bruce 2365 ECB :
3447 rhaas 2366 GIC 1199 : appendStringInfoChar(&buf, ')');
2367 :
1679 alvherre 2368 ECB : /* Build including column list (from pg_index.indkeys) */
15 dgustafsson 2369 GNC 1199 : val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2370 : Anum_pg_index_indnatts);
1679 alvherre 2371 GIC 1199 : if (DatumGetInt32(val) > keyatts)
2372 : {
1679 alvherre 2373 ECB : Datum cols;
2374 : Datum *keys;
2375 : int nKeys;
2376 : int j;
2377 :
1828 teodor 2378 GIC 41 : appendStringInfoString(&buf, " INCLUDE (");
2379 :
15 dgustafsson 2380 GNC 41 : cols = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2381 : Anum_pg_index_indkey);
2382 :
282 peter 2383 41 : deconstruct_array_builtin(DatumGetArrayTypeP(cols), INT2OID,
2384 : &keys, NULL, &nKeys);
2385 :
1679 alvherre 2386 GIC 123 : for (j = keyatts; j < nKeys; j++)
1679 alvherre 2387 ECB : {
2388 : char *colName;
1679 alvherre 2389 EUB :
1679 alvherre 2390 GBC 82 : colName = get_attname(conForm->conrelid,
1679 alvherre 2391 GIC 82 : DatumGetInt16(keys[j]), false);
2392 82 : if (j > keyatts)
2393 41 : appendStringInfoString(&buf, ", ");
2394 82 : appendStringInfoString(&buf, quote_identifier(colName));
2395 : }
2396 :
1828 teodor 2397 41 : appendStringInfoChar(&buf, ')');
2398 : }
1679 alvherre 2399 CBC 1199 : ReleaseSysCache(indtup);
5657 tgl 2400 ECB :
2401 : /* XXX why do we only print these bits if fullCommand? */
5657 tgl 2402 CBC 1199 : if (fullCommand && OidIsValid(indexId))
2403 : {
5657 tgl 2404 GIC 90 : char *options = flatten_reloptions(indexId);
5657 tgl 2405 ECB : Oid tblspc;
2406 :
6125 bruce 2407 CBC 90 : if (options)
2408 : {
6125 bruce 2409 UIC 0 : appendStringInfo(&buf, " WITH (%s)", options);
2410 0 : pfree(options);
2411 : }
2412 :
2413 : /*
2414 : * Print the tablespace, unless it's the database default.
2415 : * This is to help ALTER TABLE usage of this facility,
1445 alvherre 2416 ECB : * which needs this behavior to recreate exact catalog
2417 : * state.
2418 : */
5657 tgl 2419 CBC 90 : tblspc = get_rel_tablespace(indexId);
2420 90 : if (OidIsValid(tblspc))
5657 tgl 2421 GIC 12 : appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2118 2422 12 : quote_identifier(get_tablespace_name(tblspc)));
6125 bruce 2423 ECB : }
2424 :
7360 bruce 2425 GIC 1199 : break;
7360 bruce 2426 ECB : }
7360 bruce 2427 GIC 971 : case CONSTRAINT_CHECK:
2428 : {
2429 : Datum val;
2430 : char *conbin;
7228 bruce 2431 ECB : char *consrc;
2432 : Node *expr;
2433 : List *context;
7360 2434 :
2435 : /* Fetch constraint expression in parsetree form */
15 dgustafsson 2436 GNC 971 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2437 : Anum_pg_constraint_conbin);
2438 :
5493 tgl 2439 GIC 971 : conbin = TextDatumGetCString(val);
7228 bruce 2440 971 : expr = stringToNode(conbin);
2441 :
2442 : /* Set up deparsing context for Var nodes in constraint */
2443 971 : if (conForm->conrelid != InvalidOid)
2444 : {
2445 : /* relation constraint */
4541 tgl 2446 CBC 880 : context = deparse_context_for(get_relation_name(conForm->conrelid),
2447 : conForm->conrelid);
7127 tgl 2448 ECB : }
7228 bruce 2449 : else
2450 : {
7127 tgl 2451 : /* domain constraint --- can't have Vars */
7127 tgl 2452 GIC 91 : context = NIL;
2453 : }
2454 :
7193 tgl 2455 CBC 971 : consrc = deparse_expression_pretty(expr, context, false, false,
2456 : prettyFlags, 0);
7228 bruce 2457 ECB :
7127 tgl 2458 : /*
2459 : * Now emit the constraint definition, adding NO INHERIT if
4006 alvherre 2460 : * necessary.
4006 alvherre 2461 EUB : *
3955 bruce 2462 ECB : * There are cases where the constraint expression will be
2463 : * fully parenthesized and we don't need the outer parens ...
2464 : * but there are other cases where we do need 'em. Be
3955 bruce 2465 EUB : * conservative for now.
2466 : *
2467 : * Note that simply checking for leading '(' and trailing ')'
2468 : * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2469 : */
3911 alvherre 2470 GIC 971 : appendStringInfo(&buf, "CHECK (%s)%s",
2471 : consrc,
2472 971 : conForm->connoinherit ? " NO INHERIT" : "");
7360 bruce 2473 GBC 971 : break;
7360 bruce 2474 EUB : }
2 alvherre 2475 GNC 27 : case CONSTRAINT_NOTNULL:
2476 : {
2477 : AttrNumber attnum;
2478 :
2479 27 : attnum = extractNotNullColumn(tup);
2480 :
2481 27 : appendStringInfo(&buf, "NOT NULL %s",
2482 27 : quote_identifier(get_attname(conForm->conrelid,
2483 : attnum, false)));
2484 27 : if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
2 alvherre 2485 UNC 0 : appendStringInfoString(&buf, " NO INHERIT");
2 alvherre 2486 GNC 27 : break;
2487 : }
2488 :
4830 tgl 2489 LBC 0 : case CONSTRAINT_TRIGGER:
2490 :
4830 tgl 2491 ECB : /*
2492 : * There isn't an ALTER TABLE syntax for creating a user-defined
2493 : * constraint trigger, but it seems better to print something than
2494 : * throw an error; if we throw error then this function couldn't
2495 : * safely be applied to all rows of pg_constraint.
2496 : */
3447 rhaas 2497 UIC 0 : appendStringInfoString(&buf, "TRIGGER");
4830 tgl 2498 0 : break;
4871 tgl 2499 CBC 52 : case CONSTRAINT_EXCLUSION:
2500 : {
4790 bruce 2501 GIC 52 : Oid indexOid = conForm->conindid;
4790 bruce 2502 ECB : Datum val;
2503 : Datum *elems;
2504 : int nElems;
2505 : int i;
2506 : Oid *operators;
2507 :
2508 : /* Extract operator OIDs from the pg_constraint tuple */
15 dgustafsson 2509 GNC 52 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2510 : Anum_pg_constraint_conexclop);
2511 :
282 peter 2512 52 : deconstruct_array_builtin(DatumGetArrayTypeP(val), OIDOID,
2513 : &elems, NULL, &nElems);
2514 :
4871 tgl 2515 CBC 52 : operators = (Oid *) palloc(nElems * sizeof(Oid));
4871 tgl 2516 GIC 114 : for (i = 0; i < nElems; i++)
4871 tgl 2517 GBC 62 : operators[i] = DatumGetObjectId(elems[i]);
4871 tgl 2518 EUB :
2519 : /* pg_get_indexdef_worker does the rest */
2520 : /* suppress tablespace because pg_dump wants it that way */
4871 tgl 2521 GIC 52 : appendStringInfoString(&buf,
4871 tgl 2522 CBC 52 : pg_get_indexdef_worker(indexOid,
4871 tgl 2523 ECB : 0,
2524 : operators,
4871 tgl 2525 EUB : false,
4871 tgl 2526 ECB : false,
1906 alvherre 2527 : false,
2528 : false,
2529 : prettyFlags,
2448 rhaas 2530 : false));
4871 tgl 2531 CBC 52 : break;
2532 : }
7541 tgl 2533 LBC 0 : default:
7146 peter_e 2534 UIC 0 : elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2535 : break;
2536 : }
2537 :
5002 tgl 2538 GIC 2563 : if (conForm->condeferrable)
3447 rhaas 2539 20 : appendStringInfoString(&buf, " DEFERRABLE");
5002 tgl 2540 2563 : if (conForm->condeferred)
3447 rhaas 2541 UIC 0 : appendStringInfoString(&buf, " INITIALLY DEFERRED");
4329 alvherre 2542 GIC 2563 : if (!conForm->convalidated)
4329 alvherre 2543 CBC 47 : appendStringInfoString(&buf, " NOT VALID");
2544 :
2545 : /* Cleanup */
3290 simon 2546 GIC 2563 : systable_endscan(scandesc);
1539 andres 2547 2563 : table_close(relation, AccessShareLock);
2548 :
6913 tgl 2549 2563 : return buf.data;
2550 : }
7541 tgl 2551 ECB :
2552 :
2553 : /*
2554 : * Convert an int16[] Datum into a comma-separated list of column names
2555 : * for the indicated relation; append the list to buf. Returns the number
2556 : * of keys.
2557 : */
1679 alvherre 2558 : static int
7541 tgl 2559 GIC 1833 : decompile_column_index_array(Datum column_index_array, Oid relId,
7541 tgl 2560 ECB : StringInfo buf)
2561 : {
2562 : Datum *keys;
2563 : int nKeys;
2564 : int j;
2565 :
2566 : /* Extract data from array of int16 */
282 peter 2567 GNC 1833 : deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2568 : &keys, NULL, &nKeys);
2569 :
7541 tgl 2570 GIC 4229 : for (j = 0; j < nKeys; j++)
2571 : {
2572 : char *colName;
2573 :
1882 alvherre 2574 2396 : colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2575 :
7541 tgl 2576 2396 : if (j == 0)
7008 neilc 2577 1833 : appendStringInfoString(buf, quote_identifier(colName));
2578 : else
2579 563 : appendStringInfo(buf, ", %s", quote_identifier(colName));
2580 : }
2581 :
1679 alvherre 2582 1833 : return nKeys;
2583 : }
2584 :
2585 :
2586 : /* ----------
2587 : * pg_get_expr - Decompile an expression tree
2588 : *
7937 tgl 2589 ECB : * Input: an expression tree in nodeToString form, and a relation OID
2590 : *
2591 : * Output: reverse-listed expression
2592 : *
2593 : * Currently, the expression can only refer to a single relation, namely
2594 : * the one specified by the second parameter. This is sufficient for
2595 : * partial indexes, column default expressions, etc. We also support
5066 2596 : * Var-free expressions, for which the OID can be InvalidOid.
2597 : *
455 2598 : * We expect this function to work, or throw a reasonably clean error,
2599 : * for any node tree that can appear in a catalog pg_node_tree column.
2600 : * Query trees, such as those appearing in pg_rewrite.ev_action, are
2601 : * not supported. Nor are expressions in more than one relation, which
2602 : * can appear in places like pg_rewrite.ev_qual.
2603 : * ----------
2604 : */
2605 : Datum
7937 tgl 2606 GIC 3353 : pg_get_expr(PG_FUNCTION_ARGS)
2607 : {
2219 noah 2608 3353 : text *expr = PG_GETARG_TEXT_PP(0);
7188 bruce 2609 CBC 3353 : Oid relid = PG_GETARG_OID(1);
3717 tgl 2610 EUB : int prettyFlags;
2611 : char *relname;
2612 :
3717 tgl 2613 GBC 3353 : prettyFlags = PRETTYFLAG_INDENT;
2614 :
5066 tgl 2615 CBC 3353 : if (OidIsValid(relid))
2616 : {
2617 : /* Get the name for the relation */
5066 tgl 2618 GIC 3353 : relname = get_rel_name(relid);
5066 tgl 2619 ECB :
2620 : /*
2621 : * If the OID isn't actually valid, don't throw an error, just return
2622 : * NULL. This is a bit questionable, but it's what we've done
2623 : * historically, and it can help avoid unwanted failures when
2624 : * examining catalog entries for just-deleted relations.
2625 : */
5066 tgl 2626 GIC 3353 : if (relname == NULL)
5066 tgl 2627 LBC 0 : PG_RETURN_NULL();
2628 : }
5066 tgl 2629 ECB : else
5066 tgl 2630 UIC 0 : relname = NULL;
2631 :
3717 tgl 2632 CBC 3353 : PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
2633 : }
7193 tgl 2634 ECB :
7193 tgl 2635 EUB : Datum
7193 tgl 2636 GIC 203 : pg_get_expr_ext(PG_FUNCTION_ARGS)
2637 : {
2219 noah 2638 GBC 203 : text *expr = PG_GETARG_TEXT_PP(0);
7188 bruce 2639 GIC 203 : Oid relid = PG_GETARG_OID(1);
7193 tgl 2640 CBC 203 : bool pretty = PG_GETARG_BOOL(2);
2641 : int prettyFlags;
2642 : char *relname;
2643 :
377 2644 203 : prettyFlags = GET_PRETTY_FLAGS(pretty);
2645 :
5066 tgl 2646 GIC 203 : if (OidIsValid(relid))
2647 : {
2648 : /* Get the name for the relation */
2649 203 : relname = get_rel_name(relid);
2650 : /* See notes above */
2651 203 : if (relname == NULL)
5066 tgl 2652 UIC 0 : PG_RETURN_NULL();
2653 : }
5066 tgl 2654 ECB : else
5066 tgl 2655 UIC 0 : relname = NULL;
2656 :
5066 tgl 2657 CBC 203 : PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
2658 : }
7193 tgl 2659 ECB :
2660 : static text *
5066 tgl 2661 GIC 3556 : pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
2662 : {
2663 : Node *node;
2664 : Node *tst;
2665 : Relids relids;
2666 : List *context;
7193 tgl 2667 ECB : char *exprstr;
2668 : char *str;
7193 tgl 2669 EUB :
455 tgl 2670 ECB : /* Convert input pg_node_tree (really TEXT) object to C string */
5493 tgl 2671 GBC 3556 : exprstr = text_to_cstring(expr);
2672 :
2673 : /* Convert expression to node tree */
7937 tgl 2674 GIC 3556 : node = (Node *) stringToNode(exprstr);
2675 :
5066 2676 3556 : pfree(exprstr);
2677 :
2678 : /*
455 tgl 2679 ECB : * Throw error if the input is a querytree rather than an expression tree.
2680 : * While we could support queries here, there seems no very good reason
2681 : * to. In most such catalog columns, we'll see a List of Query nodes, or
2682 : * even nested Lists, so drill down to a non-List node before checking.
455 tgl 2683 EUB : */
455 tgl 2684 GIC 3556 : tst = node;
2685 3556 : while (tst && IsA(tst, List))
455 tgl 2686 UIC 0 : tst = linitial((List *) tst);
455 tgl 2687 GIC 3556 : if (tst && IsA(tst, Query))
455 tgl 2688 UIC 0 : ereport(ERROR,
455 tgl 2689 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2690 : errmsg("input is a query, not an expression")));
2691 :
2692 : /*
2693 : * Throw error if the expression contains Vars we won't be able to
2694 : * deparse.
2695 : */
455 tgl 2696 CBC 3556 : relids = pull_varnos(NULL, node);
2697 3556 : if (OidIsValid(relid))
2698 : {
455 tgl 2699 GBC 3556 : if (!bms_is_subset(relids, bms_make_singleton(1)))
455 tgl 2700 UIC 0 : ereport(ERROR,
2701 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
455 tgl 2702 ECB : errmsg("expression contains variables of more than one relation")));
2703 : }
2704 : else
2705 : {
455 tgl 2706 UIC 0 : if (!bms_is_empty(relids))
2707 0 : ereport(ERROR,
2708 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2709 : errmsg("expression contains variables")));
2710 : }
2711 :
2712 : /* Prepare deparse context if needed */
5066 tgl 2713 GIC 3556 : if (OidIsValid(relid))
2714 3556 : context = deparse_context_for(relname, relid);
5066 tgl 2715 ECB : else
5066 tgl 2716 UIC 0 : context = NIL;
5066 tgl 2717 ECB :
2718 : /* Deparse */
7193 tgl 2719 GIC 3556 : str = deparse_expression_pretty(node, context, false, false,
2720 : prettyFlags, 0);
2721 :
5066 2722 3556 : return string_to_text(str);
2723 : }
2724 :
7937 tgl 2725 ECB :
8955 bruce 2726 : /* ----------
2727 : * pg_get_userbyid - Get a user name by roleid and
2728 : * fallback to 'unknown (OID=n)'
2729 : * ----------
2730 : */
8335 tgl 2731 : Datum
8335 tgl 2732 CBC 774 : pg_get_userbyid(PG_FUNCTION_ARGS)
2733 : {
6494 2734 774 : Oid roleid = PG_GETARG_OID(0);
8335 tgl 2735 ECB : Name result;
6494 2736 : HeapTuple roletup;
2737 : Form_pg_authid role_rec;
2738 :
8053 bruce 2739 EUB : /*
2740 : * Allocate space for the result
8955 bruce 2741 ECB : */
8335 tgl 2742 GIC 774 : result = (Name) palloc(NAMEDATALEN);
8554 bruce 2743 774 : memset(NameStr(*result), 0, NAMEDATALEN);
2744 :
2745 : /*
2746 : * Get the pg_authid entry and print the result
2747 : */
4802 rhaas 2748 774 : roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
6494 tgl 2749 774 : if (HeapTupleIsValid(roletup))
2750 : {
2751 774 : role_rec = (Form_pg_authid) GETSTRUCT(roletup);
972 peter 2752 774 : *result = role_rec->rolname;
6494 tgl 2753 CBC 774 : ReleaseSysCache(roletup);
2754 : }
8955 bruce 2755 ECB : else
6494 tgl 2756 LBC 0 : sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2757 :
8335 tgl 2758 GIC 774 : PG_RETURN_NAME(result);
2759 : }
2760 :
6862 tgl 2761 ECB :
2762 : /*
2763 : * pg_get_serial_sequence
2764 : * Get the name of the sequence used by an identity or serial column,
2765 : * formatted suitably for passing to setval, nextval or currval.
2766 : * First parameter is not treated as double-quoted, second parameter
2767 : * is --- see documentation for reason.
2768 : */
2769 : Datum
6862 tgl 2770 GIC 6 : pg_get_serial_sequence(PG_FUNCTION_ARGS)
2771 : {
2219 noah 2772 CBC 6 : text *tablename = PG_GETARG_TEXT_PP(0);
5493 tgl 2773 GIC 6 : text *columnname = PG_GETARG_TEXT_PP(1);
6862 tgl 2774 ECB : RangeVar *tablerv;
2775 : Oid tableOid;
6797 bruce 2776 EUB : char *column;
2777 : AttrNumber attnum;
6797 bruce 2778 GIC 6 : Oid sequenceId = InvalidOid;
2779 : Relation depRel;
2780 : ScanKeyData key[3];
2781 : SysScanDesc scan;
6862 tgl 2782 ECB : HeapTuple tup;
2783 :
3260 bruce 2784 : /* Look up table name. Can't lock it - we might not have privileges. */
6526 neilc 2785 GIC 6 : tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
4148 rhaas 2786 6 : tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2787 :
6862 tgl 2788 ECB : /* Get the number of the column */
5493 tgl 2789 GIC 6 : column = text_to_cstring(columnname);
2790 :
6862 2791 6 : attnum = get_attnum(tableOid, column);
6862 tgl 2792 CBC 6 : if (attnum == InvalidAttrNumber)
6862 tgl 2793 UIC 0 : ereport(ERROR,
2794 : (errcode(ERRCODE_UNDEFINED_COLUMN),
2795 : errmsg("column \"%s\" of relation \"%s\" does not exist",
2796 : column, tablerv->relname)));
6862 tgl 2797 ECB :
2798 : /* Search the dependency table for the dependent sequence */
1539 andres 2799 GIC 6 : depRel = table_open(DependRelationId, AccessShareLock);
6862 tgl 2800 ECB :
6862 tgl 2801 GIC 6 : ScanKeyInit(&key[0],
6862 tgl 2802 ECB : Anum_pg_depend_refclassid,
2803 : BTEqualStrategyNumber, F_OIDEQ,
2804 : ObjectIdGetDatum(RelationRelationId));
6862 tgl 2805 GIC 6 : ScanKeyInit(&key[1],
2806 : Anum_pg_depend_refobjid,
2807 : BTEqualStrategyNumber, F_OIDEQ,
2808 : ObjectIdGetDatum(tableOid));
6862 tgl 2809 CBC 6 : ScanKeyInit(&key[2],
6862 tgl 2810 ECB : Anum_pg_depend_refobjsubid,
2811 : BTEqualStrategyNumber, F_INT4EQ,
2812 : Int32GetDatum(attnum));
2813 :
6569 tgl 2814 GIC 6 : scan = systable_beginscan(depRel, DependReferenceIndexId, true,
3568 rhaas 2815 ECB : NULL, 3, key);
6862 tgl 2816 :
6862 tgl 2817 GIC 15 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
2818 : {
6797 bruce 2819 15 : Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
6862 tgl 2820 ECB :
2821 : /*
2822 : * Look for an auto dependency (serial column) or internal dependency
2032 peter_e 2823 : * (identity column) of a sequence on a column. (We need the relkind
2824 : * test because indexes can also have auto dependencies on columns.)
2825 : */
6569 tgl 2826 GIC 15 : if (deprec->classid == RelationRelationId &&
6862 tgl 2827 CBC 6 : deprec->objsubid == 0 &&
2032 peter_e 2828 GIC 6 : (deprec->deptype == DEPENDENCY_AUTO ||
2032 peter_e 2829 CBC 9 : deprec->deptype == DEPENDENCY_INTERNAL) &&
5994 tgl 2830 GIC 6 : get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2831 : {
6862 tgl 2832 GBC 6 : sequenceId = deprec->objid;
6862 tgl 2833 GIC 6 : break;
2834 : }
2835 : }
2836 :
2837 6 : systable_endscan(scan);
1539 andres 2838 6 : table_close(depRel, AccessShareLock);
2839 :
6862 tgl 2840 6 : if (OidIsValid(sequenceId))
2841 : {
2842 : char *result;
2843 :
2697 2844 6 : result = generate_qualified_relation_name(sequenceId);
2845 :
6862 2846 6 : PG_RETURN_TEXT_P(string_to_text(result));
6862 tgl 2847 ECB : }
2848 :
6862 tgl 2849 LBC 0 : PG_RETURN_NULL();
2850 : }
2851 :
2852 :
2853 : /*
2854 : * pg_get_functiondef
2855 : * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
2856 : * the specified function.
2857 : *
2858 : * Note: if you change the output format of this function, be careful not
2859 : * to break psql's rules (in \ef and \sf) for identifying the start of the
2860 : * function body. To wit: the function body starts on a line that begins with
2861 : * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
2862 : */
5328 tgl 2863 ECB : Datum
5328 tgl 2864 GIC 73 : pg_get_functiondef(PG_FUNCTION_ARGS)
2865 : {
5328 tgl 2866 CBC 73 : Oid funcid = PG_GETARG_OID(0);
5328 tgl 2867 ECB : StringInfoData buf;
2868 : StringInfoData dq;
2869 : HeapTuple proctup;
2870 : Form_pg_proc proc;
1881 peter_e 2871 : bool isfunction;
2872 : Datum tmp;
5328 tgl 2873 : bool isnull;
5328 tgl 2874 EUB : const char *prosrc;
2875 : const char *name;
2876 : const char *nsp;
2877 : float4 procost;
5328 tgl 2878 ECB : int oldlen;
2879 :
5328 tgl 2880 GIC 73 : initStringInfo(&buf);
2881 :
2882 : /* Look up the function */
4802 rhaas 2883 73 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
5328 tgl 2884 CBC 73 : if (!HeapTupleIsValid(proctup))
2448 rhaas 2885 3 : PG_RETURN_NULL();
2886 :
5328 tgl 2887 GIC 70 : proc = (Form_pg_proc) GETSTRUCT(proctup);
5328 tgl 2888 CBC 70 : name = NameStr(proc->proname);
5328 tgl 2889 ECB :
1864 peter_e 2890 CBC 70 : if (proc->prokind == PROKIND_AGGREGATE)
5328 tgl 2891 UIC 0 : ereport(ERROR,
5328 tgl 2892 ECB : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2893 : errmsg("\"%s\" is an aggregate function", name)));
2894 :
1864 peter_e 2895 GIC 70 : isfunction = (proc->prokind != PROKIND_PROCEDURE);
2896 :
5328 tgl 2897 ECB : /*
2898 : * We always qualify the function name, to ensure the right function gets
5050 bruce 2899 : * replaced.
5328 tgl 2900 : */
621 tgl 2901 GIC 70 : nsp = get_namespace_name_or_temp(proc->pronamespace);
1881 peter_e 2902 70 : appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
1881 peter_e 2903 ECB : isfunction ? "FUNCTION" : "PROCEDURE",
2904 : quote_qualified_identifier(nsp, name));
5239 peter_e 2905 CBC 70 : (void) print_function_arguments(&buf, proctup, false, true);
1881 peter_e 2906 GBC 70 : appendStringInfoString(&buf, ")\n");
1881 peter_e 2907 CBC 70 : if (isfunction)
2908 : {
2909 61 : appendStringInfoString(&buf, " RETURNS ");
2910 61 : print_function_rettype(&buf, proctup);
2911 61 : appendStringInfoChar(&buf, '\n');
1881 peter_e 2912 ECB : }
2905 2913 :
2905 peter_e 2914 CBC 70 : print_function_trftypes(&buf, proctup);
2905 peter_e 2915 ECB :
1881 peter_e 2916 CBC 70 : appendStringInfo(&buf, " LANGUAGE %s\n",
2118 tgl 2917 GIC 70 : quote_identifier(get_language_name(proc->prolang, false)));
2918 :
5328 tgl 2919 ECB : /* Emit some miscellaneous options on one line */
5328 tgl 2920 GIC 70 : oldlen = buf.len;
5328 tgl 2921 ECB :
1864 peter_e 2922 CBC 70 : if (proc->prokind == PROKIND_WINDOW)
5212 tgl 2923 LBC 0 : appendStringInfoString(&buf, " WINDOW");
5328 tgl 2924 GBC 70 : switch (proc->provolatile)
5328 tgl 2925 EUB : {
5328 tgl 2926 GBC 12 : case PROVOLATILE_IMMUTABLE:
5328 tgl 2927 CBC 12 : appendStringInfoString(&buf, " IMMUTABLE");
2928 12 : break;
5328 tgl 2929 GIC 9 : case PROVOLATILE_STABLE:
2930 9 : appendStringInfoString(&buf, " STABLE");
5328 tgl 2931 CBC 9 : break;
2932 49 : case PROVOLATILE_VOLATILE:
2933 49 : break;
5328 tgl 2934 ECB : }
2539 rhaas 2935 :
2539 rhaas 2936 GBC 70 : switch (proc->proparallel)
2937 : {
2539 rhaas 2938 GIC 19 : case PROPARALLEL_SAFE:
2539 rhaas 2939 CBC 19 : appendStringInfoString(&buf, " PARALLEL SAFE");
2940 19 : break;
2539 rhaas 2941 LBC 0 : case PROPARALLEL_RESTRICTED:
2539 rhaas 2942 UIC 0 : appendStringInfoString(&buf, " PARALLEL RESTRICTED");
2539 rhaas 2943 LBC 0 : break;
2539 rhaas 2944 CBC 51 : case PROPARALLEL_UNSAFE:
2945 51 : break;
2946 : }
2539 rhaas 2947 ECB :
5328 tgl 2948 GBC 70 : if (proc->proisstrict)
5328 tgl 2949 GIC 24 : appendStringInfoString(&buf, " STRICT");
5328 tgl 2950 CBC 70 : if (proc->prosecdef)
5328 tgl 2951 GIC 3 : appendStringInfoString(&buf, " SECURITY DEFINER");
2873 2952 70 : if (proc->proleakproof)
2873 tgl 2953 UIC 0 : appendStringInfoString(&buf, " LEAKPROOF");
2954 :
2955 : /* This code for the default cost and rows should match functioncmds.c */
5328 tgl 2956 GIC 70 : if (proc->prolang == INTERNALlanguageId ||
2957 70 : proc->prolang == ClanguageId)
5328 tgl 2958 GBC 4 : procost = 1;
5328 tgl 2959 EUB : else
5328 tgl 2960 GIC 66 : procost = 100;
2961 70 : if (proc->procost != procost)
2962 3 : appendStringInfo(&buf, " COST %g", proc->procost);
2963 :
2964 70 : if (proc->prorows > 0 && proc->prorows != 1000)
5328 tgl 2965 LBC 0 : appendStringInfo(&buf, " ROWS %g", proc->prorows);
5328 tgl 2966 ECB :
1520 tgl 2967 GIC 70 : if (proc->prosupport)
2968 : {
1520 tgl 2969 ECB : Oid argtypes[1];
2970 :
2971 : /*
2972 : * We should qualify the support function's name if it wouldn't be
2973 : * resolved by lookup in the current search path.
2974 : */
1520 tgl 2975 LBC 0 : argtypes[0] = INTERNALOID;
2976 0 : appendStringInfo(&buf, " SUPPORT %s",
1520 tgl 2977 ECB : generate_function_name(proc->prosupport, 1,
2978 : NIL, argtypes,
2979 : false, NULL, EXPR_KIND_NONE));
2980 : }
2981 :
5328 tgl 2982 GIC 70 : if (oldlen != buf.len)
5328 tgl 2983 CBC 31 : appendStringInfoChar(&buf, '\n');
2984 :
2985 : /* Emit any proconfig options, one per line */
5328 tgl 2986 GIC 70 : tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
2987 70 : if (!isnull)
2988 : {
5050 bruce 2989 CBC 3 : ArrayType *a = DatumGetArrayTypeP(tmp);
2990 : int i;
5328 tgl 2991 ECB :
5328 tgl 2992 GIC 3 : Assert(ARR_ELEMTYPE(a) == TEXTOID);
2993 3 : Assert(ARR_NDIM(a) == 1);
5328 tgl 2994 CBC 3 : Assert(ARR_LBOUND(a)[0] == 1);
5328 tgl 2995 ECB :
5328 tgl 2996 GBC 18 : for (i = 1; i <= ARR_DIMS(a)[0]; i++)
5328 tgl 2997 ECB : {
2998 : Datum d;
2999 :
5328 tgl 3000 GIC 15 : d = array_ref(a, 1, &i,
3001 : -1 /* varlenarray */ ,
3002 : -1 /* TEXT's typlen */ ,
3003 : false /* TEXT's typbyval */ ,
3004 : TYPALIGN_INT /* TEXT's typalign */ ,
3005 : &isnull);
3006 15 : if (!isnull)
3007 : {
3008 15 : char *configitem = TextDatumGetCString(d);
3009 : char *pos;
3010 :
3011 15 : pos = strchr(configitem, '=');
3012 15 : if (pos == NULL)
5328 tgl 3013 UIC 0 : continue;
5328 tgl 3014 GIC 15 : *pos++ = '\0';
3015 :
3016 15 : appendStringInfo(&buf, " SET %s TO ",
3017 : quote_identifier(configitem));
5328 tgl 3018 ECB :
3019 : /*
3020 : * Variables that are marked GUC_LIST_QUOTE were already fully
3021 : * quoted by flatten_set_variable_args() before they were put
3022 : * into the proconfig array. However, because the quoting
3023 : * rules used there aren't exactly like SQL's, we have to
1713 3024 : * break the list value apart and then quote the elements as
3025 : * string literals. (The elements may be double-quoted as-is,
3026 : * but we can't just feed them to the SQL parser; it would do
1713 tgl 3027 EUB : * the wrong thing with elements that are zero-length or
3028 : * longer than NAMEDATALEN.)
1713 tgl 3029 ECB : *
3030 : * Variables that are not so marked should just be emitted as
3031 : * simple string literals. If the variable is not known to
3032 : * guc.c, we'll do that; this makes it unsafe to use
3033 : * GUC_LIST_QUOTE for extension variables.
5328 3034 : */
1845 tgl 3035 CBC 15 : if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
3036 : {
3037 : List *namelist;
3038 : ListCell *lc;
1713 tgl 3039 ECB :
3040 : /* Parse string into list of identifiers */
1713 tgl 3041 GIC 6 : if (!SplitGUCList(pos, ',', &namelist))
3042 : {
3043 : /* this shouldn't fail really */
1713 tgl 3044 UIC 0 : elog(ERROR, "invalid list syntax in proconfig item");
3045 : }
1713 tgl 3046 CBC 21 : foreach(lc, namelist)
1713 tgl 3047 ECB : {
1713 tgl 3048 GIC 15 : char *curname = (char *) lfirst(lc);
1713 tgl 3049 ECB :
1713 tgl 3050 GIC 15 : simple_quote_literal(&buf, curname);
1364 3051 15 : if (lnext(namelist, lc))
1713 3052 9 : appendStringInfoString(&buf, ", ");
1713 tgl 3053 ECB : }
3054 : }
5328 3055 : else
5328 tgl 3056 CBC 9 : simple_quote_literal(&buf, pos);
5328 tgl 3057 GIC 15 : appendStringInfoChar(&buf, '\n');
5328 tgl 3058 ECB : }
3059 : }
3060 : }
3061 :
3062 : /* And finally the function definition ... */
586 tgl 3063 CBC 70 : (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
732 peter 3064 GIC 70 : if (proc->prolang == SQLlanguageId && !isnull)
3065 : {
3066 39 : print_function_sqlbody(&buf, proctup);
3067 : }
3068 : else
3069 : {
697 tgl 3070 31 : appendStringInfoString(&buf, "AS ");
3071 :
3072 31 : tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
697 tgl 3073 CBC 31 : if (!isnull)
697 tgl 3074 ECB : {
697 tgl 3075 CBC 4 : simple_quote_literal(&buf, TextDatumGetCString(tmp));
3076 4 : appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
697 tgl 3077 EUB : }
5328 tgl 3078 ECB :
15 dgustafsson 3079 GNC 31 : tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosrc);
697 tgl 3080 CBC 31 : prosrc = TextDatumGetCString(tmp);
3081 :
3082 : /*
697 tgl 3083 ECB : * We always use dollar quoting. Figure out a suitable delimiter.
3084 : *
3085 : * Since the user is likely to be editing the function body string, we
3086 : * shouldn't use a short delimiter that he might easily create a
3087 : * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3088 : * if needed.
3089 : */
697 tgl 3090 GIC 31 : initStringInfo(&dq);
3091 31 : appendStringInfoChar(&dq, '$');
3092 31 : appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3093 31 : while (strstr(prosrc, dq.data) != NULL)
697 tgl 3094 UIC 0 : appendStringInfoChar(&dq, 'x');
697 tgl 3095 GIC 31 : appendStringInfoChar(&dq, '$');
3096 :
697 tgl 3097 CBC 31 : appendBinaryStringInfo(&buf, dq.data, dq.len);
697 tgl 3098 GIC 31 : appendStringInfoString(&buf, prosrc);
697 tgl 3099 CBC 31 : appendBinaryStringInfo(&buf, dq.data, dq.len);
3100 : }
3101 :
3447 rhaas 3102 GIC 70 : appendStringInfoChar(&buf, '\n');
5328 tgl 3103 ECB :
5328 tgl 3104 CBC 70 : ReleaseSysCache(proctup);
5328 tgl 3105 ECB :
5328 tgl 3106 GIC 70 : PG_RETURN_TEXT_P(string_to_text(buf.data));
5328 tgl 3107 ECB : }
3108 :
5378 3109 : /*
3110 : * pg_get_function_arguments
3111 : * Get a nicely-formatted list of arguments for a function.
3112 : * This is everything that would go between the parentheses in
3113 : * CREATE FUNCTION.
3114 : */
3115 : Datum
5378 tgl 3116 GIC 2234 : pg_get_function_arguments(PG_FUNCTION_ARGS)
3117 : {
3118 2234 : Oid funcid = PG_GETARG_OID(0);
3119 : StringInfoData buf;
3120 : HeapTuple proctup;
3121 :
4802 rhaas 3122 2234 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
5378 tgl 3123 CBC 2234 : if (!HeapTupleIsValid(proctup))
2445 rhaas 3124 GIC 3 : PG_RETURN_NULL();
2445 rhaas 3125 ECB :
2445 rhaas 3126 GIC 2231 : initStringInfo(&buf);
3127 :
5239 peter_e 3128 2231 : (void) print_function_arguments(&buf, proctup, false, true);
5378 tgl 3129 ECB :
5378 tgl 3130 CBC 2231 : ReleaseSysCache(proctup);
5378 tgl 3131 ECB :
5378 tgl 3132 GIC 2231 : PG_RETURN_TEXT_P(string_to_text(buf.data));
5378 tgl 3133 ECB : }
3134 :
5239 peter_e 3135 : /*
3136 : * pg_get_function_identity_arguments
3137 : * Get a formatted list of arguments for a function.
3138 : * This is everything that would go between the parentheses in
5225 tgl 3139 : * ALTER FUNCTION, etc. In particular, don't print defaults.
3140 : */
3141 : Datum
5239 peter_e 3142 GIC 1977 : pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
3143 : {
3144 1977 : Oid funcid = PG_GETARG_OID(0);
3145 : StringInfoData buf;
3146 : HeapTuple proctup;
3147 :
4802 rhaas 3148 CBC 1977 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
5239 peter_e 3149 GIC 1977 : if (!HeapTupleIsValid(proctup))
2445 rhaas 3150 CBC 3 : PG_RETURN_NULL();
3151 :
2445 rhaas 3152 GIC 1974 : initStringInfo(&buf);
3153 :
5239 peter_e 3154 CBC 1974 : (void) print_function_arguments(&buf, proctup, false, false);
5239 peter_e 3155 ECB :
5239 peter_e 3156 CBC 1974 : ReleaseSysCache(proctup);
3157 :
3158 1974 : PG_RETURN_TEXT_P(string_to_text(buf.data));
3159 : }
5239 peter_e 3160 ECB :
5378 tgl 3161 : /*
3162 : * pg_get_function_result
3163 : * Get a nicely-formatted version of the result type of a function.
3164 : * This is what would appear after RETURNS in CREATE FUNCTION.
3165 : */
3166 : Datum
5378 tgl 3167 GIC 1939 : pg_get_function_result(PG_FUNCTION_ARGS)
5378 tgl 3168 ECB : {
5378 tgl 3169 GIC 1939 : Oid funcid = PG_GETARG_OID(0);
5378 tgl 3170 ECB : StringInfoData buf;
3171 : HeapTuple proctup;
3172 :
4802 rhaas 3173 GIC 1939 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
5378 tgl 3174 1939 : if (!HeapTupleIsValid(proctup))
2445 rhaas 3175 3 : PG_RETURN_NULL();
3176 :
1864 peter_e 3177 1936 : if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
1956 peter_e 3178 ECB : {
1956 peter_e 3179 GIC 105 : ReleaseSysCache(proctup);
1956 peter_e 3180 CBC 105 : PG_RETURN_NULL();
1956 peter_e 3181 ECB : }
3182 :
2445 rhaas 3183 GIC 1831 : initStringInfo(&buf);
5378 tgl 3184 ECB :
5328 tgl 3185 GIC 1831 : print_function_rettype(&buf, proctup);
5328 tgl 3186 ECB :
5328 tgl 3187 GIC 1831 : ReleaseSysCache(proctup);
3188 :
5328 tgl 3189 CBC 1831 : PG_RETURN_TEXT_P(string_to_text(buf.data));
5328 tgl 3190 ECB : }
3191 :
3192 : /*
3193 : * Guts of pg_get_function_result: append the function's return type
3194 : * to the specified buffer.
3195 : */
3196 : static void
5328 tgl 3197 CBC 1892 : print_function_rettype(StringInfo buf, HeapTuple proctup)
3198 : {
5328 tgl 3199 GIC 1892 : Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
5328 tgl 3200 CBC 1892 : int ntabargs = 0;
5328 tgl 3201 ECB : StringInfoData rbuf;
3202 :
5328 tgl 3203 GIC 1892 : initStringInfo(&rbuf);
3204 :
5328 tgl 3205 CBC 1892 : if (proc->proretset)
5378 tgl 3206 ECB : {
3207 : /* It might be a table function; try to print the arguments */
5328 tgl 3208 GIC 173 : appendStringInfoString(&rbuf, "TABLE(");
5225 3209 173 : ntabargs = print_function_arguments(&rbuf, proctup, true, false);
5378 3210 173 : if (ntabargs > 0)
2890 peter_e 3211 35 : appendStringInfoChar(&rbuf, ')');
3212 : else
5328 tgl 3213 138 : resetStringInfo(&rbuf);
3214 : }
3215 :
5378 tgl 3216 CBC 1892 : if (ntabargs == 0)
3217 : {
3218 : /* Not a table function, so do the normal thing */
5328 3219 1857 : if (proc->proretset)
5328 tgl 3220 GIC 138 : appendStringInfoString(&rbuf, "SETOF ");
3221 1857 : appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3222 : }
3223 :
1356 drowley 3224 CBC 1892 : appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
5378 tgl 3225 GIC 1892 : }
3226 :
3227 : /*
5378 tgl 3228 ECB : * Common code for pg_get_function_arguments and pg_get_function_result:
3229 : * append the desired subset of arguments to buf. We print only TABLE
3230 : * arguments when print_table_args is true, and all the others when it's false.
3231 : * We print argument defaults only if print_defaults is true.
3232 : * Function return value is the number of arguments printed.
3233 : */
3234 : static int
5378 tgl 3235 CBC 4448 : print_function_arguments(StringInfo buf, HeapTuple proctup,
5225 tgl 3236 ECB : bool print_table_args, bool print_defaults)
3237 : {
5225 tgl 3238 GIC 4448 : Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3239 : int numargs;
3240 : Oid *argtypes;
5378 tgl 3241 ECB : char **argnames;
3242 : char *argmodes;
3394 tgl 3243 GIC 4448 : int insertorderbyat = -1;
5378 tgl 3244 ECB : int argsprinted;
3245 : int inputargno;
3246 : int nlackdefaults;
1364 tgl 3247 GIC 4448 : List *argdefaults = NIL;
5225 tgl 3248 CBC 4448 : ListCell *nextargdefault = NULL;
5378 tgl 3249 ECB : int i;
3250 :
5378 tgl 3251 CBC 4448 : numargs = get_func_arg_info(proctup,
3252 : &argtypes, &argnames, &argmodes);
5378 tgl 3253 ECB :
5225 tgl 3254 GIC 4448 : nlackdefaults = numargs;
3255 4448 : if (print_defaults && proc->pronargdefaults > 0)
3256 : {
3257 : Datum proargdefaults;
5225 tgl 3258 ECB : bool isnull;
3259 :
5225 tgl 3260 GIC 18 : proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3261 : Anum_pg_proc_proargdefaults,
3262 : &isnull);
5225 tgl 3263 CBC 18 : if (!isnull)
5225 tgl 3264 ECB : {
5050 bruce 3265 EUB : char *str;
3266 :
5225 tgl 3267 CBC 18 : str = TextDatumGetCString(proargdefaults);
2238 peter_e 3268 18 : argdefaults = castNode(List, stringToNode(str));
5225 tgl 3269 18 : pfree(str);
3270 18 : nextargdefault = list_head(argdefaults);
3271 : /* nlackdefaults counts only *input* arguments lacking defaults */
5225 tgl 3272 GIC 18 : nlackdefaults = proc->pronargs - list_length(argdefaults);
5225 tgl 3273 ECB : }
5239 peter_e 3274 : }
3275 :
3276 : /* Check for special treatment of ordered-set aggregates */
1864 peter_e 3277 CBC 4448 : if (proc->prokind == PROKIND_AGGREGATE)
3394 tgl 3278 ECB : {
3279 : HeapTuple aggtup;
3280 : Form_pg_aggregate agg;
3281 :
1601 andres 3282 GIC 591 : aggtup = SearchSysCache1(AGGFNOID, proc->oid);
3394 tgl 3283 CBC 591 : if (!HeapTupleIsValid(aggtup))
3394 tgl 3284 UIC 0 : elog(ERROR, "cache lookup failed for aggregate %u",
1601 andres 3285 ECB : proc->oid);
3394 tgl 3286 GIC 591 : agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
3287 591 : if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3288 26 : insertorderbyat = agg->aggnumdirectargs;
3289 591 : ReleaseSysCache(aggtup);
3290 : }
3394 tgl 3291 ECB :
5378 tgl 3292 CBC 4448 : argsprinted = 0;
5225 tgl 3293 GIC 4448 : inputargno = 0;
5378 tgl 3294 CBC 9039 : for (i = 0; i < numargs; i++)
5378 tgl 3295 ECB : {
5050 bruce 3296 CBC 4591 : Oid argtype = argtypes[i];
3297 4591 : char *argname = argnames ? argnames[i] : NULL;
3298 4591 : char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
5378 tgl 3299 ECB : const char *modename;
5050 bruce 3300 : bool isinput;
5378 tgl 3301 :
5378 tgl 3302 CBC 4591 : switch (argmode)
5378 tgl 3303 ECB : {
5378 tgl 3304 CBC 3860 : case PROARGMODE_IN:
668 tgl 3305 ECB :
3306 : /*
3307 : * For procedures, explicitly mark all argument modes, so as
3308 : * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3309 : */
668 tgl 3310 CBC 3860 : if (proc->prokind == PROKIND_PROCEDURE)
3311 263 : modename = "IN ";
668 tgl 3312 ECB : else
668 tgl 3313 GBC 3597 : modename = "";
5225 3314 3860 : isinput = true;
5378 tgl 3315 GIC 3860 : break;
3316 20 : case PROARGMODE_INOUT:
3317 20 : modename = "INOUT ";
5225 3318 20 : isinput = true;
5378 tgl 3319 CBC 20 : break;
3320 472 : case PROARGMODE_OUT:
5378 tgl 3321 GIC 472 : modename = "OUT ";
5225 tgl 3322 CBC 472 : isinput = false;
5378 3323 472 : break;
5378 tgl 3324 GIC 89 : case PROARGMODE_VARIADIC:
5378 tgl 3325 CBC 89 : modename = "VARIADIC ";
5225 tgl 3326 GIC 89 : isinput = true;
5378 tgl 3327 CBC 89 : break;
3328 150 : case PROARGMODE_TABLE:
3329 150 : modename = "";
5225 tgl 3330 GIC 150 : isinput = false;
5378 tgl 3331 CBC 150 : break;
5378 tgl 3332 LBC 0 : default:
5378 tgl 3333 UIC 0 : elog(ERROR, "invalid parameter mode '%c'", argmode);
5050 bruce 3334 ECB : modename = NULL; /* keep compiler quiet */
5225 tgl 3335 : isinput = false;
5378 3336 : break;
3337 : }
5225 tgl 3338 CBC 4591 : if (isinput)
5225 tgl 3339 GIC 3969 : inputargno++; /* this is a 1-based counter */
3340 :
3341 4591 : if (print_table_args != (argmode == PROARGMODE_TABLE))
5225 tgl 3342 CBC 364 : continue;
5225 tgl 3343 ECB :
3394 tgl 3344 CBC 4227 : if (argsprinted == insertorderbyat)
3345 : {
3346 26 : if (argsprinted)
3394 tgl 3347 GIC 26 : appendStringInfoChar(buf, ' ');
3348 26 : appendStringInfoString(buf, "ORDER BY ");
3394 tgl 3349 ECB : }
3394 tgl 3350 GIC 4201 : else if (argsprinted)
5378 3351 1314 : appendStringInfoString(buf, ", ");
3394 tgl 3352 ECB :
5378 tgl 3353 GIC 4227 : appendStringInfoString(buf, modename);
5225 tgl 3354 CBC 4227 : if (argname && argname[0])
5052 tgl 3355 GIC 1446 : appendStringInfo(buf, "%s ", quote_identifier(argname));
5378 tgl 3356 CBC 4227 : appendStringInfoString(buf, format_type_be(argtype));
5225 tgl 3357 GIC 4227 : if (print_defaults && isinput && inputargno > nlackdefaults)
3358 : {
3359 : Node *expr;
5239 peter_e 3360 ECB :
5225 tgl 3361 GIC 25 : Assert(nextargdefault != NULL);
3362 25 : expr = (Node *) lfirst(nextargdefault);
1364 3363 25 : nextargdefault = lnext(argdefaults, nextargdefault);
5239 peter_e 3364 ECB :
5225 tgl 3365 GIC 25 : appendStringInfo(buf, " DEFAULT %s",
3366 : deparse_expression(expr, NIL, false, false));
5225 tgl 3367 ECB : }
5378 tgl 3368 CBC 4227 : argsprinted++;
3394 tgl 3369 ECB :
3370 : /* nasty hack: print the last arg twice for variadic ordered-set agg */
3394 tgl 3371 GIC 4227 : if (argsprinted == insertorderbyat && i == numargs - 1)
3372 : {
3373 13 : i--;
3374 : /* aggs shouldn't have defaults anyway, but just to be sure ... */
3375 13 : print_defaults = false;
3394 tgl 3376 ECB : }
3377 : }
3378 :
5378 tgl 3379 GIC 4448 : return argsprinted;
3380 : }
5378 tgl 3381 ECB :
3421 peter_e 3382 : static bool
3421 peter_e 3383 GIC 48 : is_input_argument(int nth, const char *argmodes)
3384 : {
3385 : return (!argmodes
3421 peter_e 3386 CBC 21 : || argmodes[nth] == PROARGMODE_IN
3387 9 : || argmodes[nth] == PROARGMODE_INOUT
3421 peter_e 3388 GIC 69 : || argmodes[nth] == PROARGMODE_VARIADIC);
3421 peter_e 3389 ECB : }
3390 :
2905 3391 : /*
3392 : * Append used transformed types to specified buffer
3393 : */
3394 : static void
2905 peter_e 3395 CBC 70 : print_function_trftypes(StringInfo buf, HeapTuple proctup)
3396 : {
3397 : Oid *trftypes;
3398 : int ntypes;
3399 :
2905 peter_e 3400 GIC 70 : ntypes = get_func_trftypes(proctup, &trftypes);
3401 70 : if (ntypes > 0)
3402 : {
3403 : int i;
2905 peter_e 3404 ECB :
804 tgl 3405 GIC 3 : appendStringInfoString(buf, " TRANSFORM ");
2905 peter_e 3406 CBC 8 : for (i = 0; i < ntypes; i++)
2905 peter_e 3407 ECB : {
2905 peter_e 3408 GIC 5 : if (i != 0)
3409 2 : appendStringInfoString(buf, ", ");
2894 magnus 3410 5 : appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3411 : }
804 tgl 3412 3 : appendStringInfoChar(buf, '\n');
3413 : }
2905 peter_e 3414 70 : }
3415 :
3416 : /*
3417 : * Get textual representation of a function argument's default value. The
3418 : * second argument of this function is the argument number among all arguments
3419 : * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3420 : * how information_schema.sql uses it.
3421 : */
3422 : Datum
3421 peter_e 3423 CBC 27 : pg_get_function_arg_default(PG_FUNCTION_ARGS)
3421 peter_e 3424 ECB : {
3421 peter_e 3425 CBC 27 : Oid funcid = PG_GETARG_OID(0);
3421 peter_e 3426 GIC 27 : int32 nth_arg = PG_GETARG_INT32(1);
3421 peter_e 3427 ECB : HeapTuple proctup;
3428 : Form_pg_proc proc;
3429 : int numargs;
3430 : Oid *argtypes;
3431 : char **argnames;
3432 : char *argmodes;
3433 : int i;
3434 : List *argdefaults;
3435 : Node *node;
3436 : char *str;
3437 : int nth_inputarg;
3438 : Datum proargdefaults;
3439 : bool isnull;
3440 : int nth_default;
3441 :
3421 peter_e 3442 CBC 27 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3421 peter_e 3443 GIC 27 : if (!HeapTupleIsValid(proctup))
2445 rhaas 3444 GBC 6 : PG_RETURN_NULL();
3421 peter_e 3445 EUB :
3421 peter_e 3446 GIC 21 : numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3447 21 : if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3421 peter_e 3448 ECB : {
3421 peter_e 3449 CBC 6 : ReleaseSysCache(proctup);
3450 6 : PG_RETURN_NULL();
3451 : }
3421 peter_e 3452 ECB :
3421 peter_e 3453 GIC 15 : nth_inputarg = 0;
3454 42 : for (i = 0; i < nth_arg; i++)
3455 27 : if (is_input_argument(i, argmodes))
3456 24 : nth_inputarg++;
3457 :
3421 peter_e 3458 CBC 15 : proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3459 : Anum_pg_proc_proargdefaults,
3421 peter_e 3460 ECB : &isnull);
3421 peter_e 3461 GIC 15 : if (isnull)
3421 peter_e 3462 ECB : {
3421 peter_e 3463 LBC 0 : ReleaseSysCache(proctup);
3421 peter_e 3464 UIC 0 : PG_RETURN_NULL();
3421 peter_e 3465 ECB : }
3466 :
3421 peter_e 3467 GIC 15 : str = TextDatumGetCString(proargdefaults);
2238 peter_e 3468 CBC 15 : argdefaults = castNode(List, stringToNode(str));
3421 peter_e 3469 GIC 15 : pfree(str);
3421 peter_e 3470 ECB :
3421 peter_e 3471 GIC 15 : proc = (Form_pg_proc) GETSTRUCT(proctup);
3472 :
3473 : /*
3260 bruce 3474 ECB : * Calculate index into proargdefaults: proargdefaults corresponds to the
3475 : * last N input arguments, where N = pronargdefaults.
3476 : */
3421 peter_e 3477 GIC 15 : nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3478 :
3479 15 : if (nth_default < 0 || nth_default >= list_length(argdefaults))
3421 peter_e 3480 ECB : {
3421 peter_e 3481 GIC 3 : ReleaseSysCache(proctup);
3482 3 : PG_RETURN_NULL();
3483 : }
3421 peter_e 3484 CBC 12 : node = list_nth(argdefaults, nth_default);
3485 12 : str = deparse_expression(node, NIL, false, false);
3486 :
3487 12 : ReleaseSysCache(proctup);
3421 peter_e 3488 ECB :
3421 peter_e 3489 GIC 12 : PG_RETURN_TEXT_P(string_to_text(str));
3421 peter_e 3490 ECB : }
3491 :
3492 : static void
732 peter 3493 CBC 54 : print_function_sqlbody(StringInfo buf, HeapTuple proctup)
3494 : {
3495 : int numargs;
3496 : Oid *argtypes;
3497 : char **argnames;
732 peter 3498 ECB : char *argmodes;
732 peter 3499 GIC 54 : deparse_namespace dpns = {0};
732 peter 3500 ECB : Datum tmp;
3501 : Node *n;
3502 :
732 peter 3503 CBC 54 : dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
732 peter 3504 GIC 54 : numargs = get_func_arg_info(proctup,
3505 : &argtypes, &argnames, &argmodes);
732 peter 3506 CBC 54 : dpns.numargs = numargs;
3507 54 : dpns.argnames = argnames;
3508 :
15 dgustafsson 3509 GNC 54 : tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
732 peter 3510 GIC 54 : n = stringToNode(TextDatumGetCString(tmp));
3511 :
732 peter 3512 CBC 54 : if (IsA(n, List))
3513 : {
3514 : List *stmts;
3515 : ListCell *lc;
732 peter 3516 ECB :
732 peter 3517 GIC 32 : stmts = linitial(castNode(List, n));
3518 :
732 peter 3519 CBC 32 : appendStringInfoString(buf, "BEGIN ATOMIC\n");
732 peter 3520 ECB :
732 peter 3521 GIC 59 : foreach(lc, stmts)
3522 : {
732 peter 3523 CBC 27 : Query *query = lfirst_node(Query, lc);
3524 :
3525 : /* It seems advisable to get at least AccessShareLock on rels */
586 tgl 3526 27 : AcquireRewriteLocks(query, false, false);
323 tgl 3527 GIC 27 : get_query_def(query, buf, list_make1(&dpns), NULL, false,
586 tgl 3528 ECB : PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 1);
732 peter 3529 GIC 27 : appendStringInfoChar(buf, ';');
3530 27 : appendStringInfoChar(buf, '\n');
3531 : }
3532 :
732 peter 3533 CBC 32 : appendStringInfoString(buf, "END");
3534 : }
3535 : else
732 peter 3536 ECB : {
586 tgl 3537 CBC 22 : Query *query = castNode(Query, n);
586 tgl 3538 EUB :
3539 : /* It seems advisable to get at least AccessShareLock on rels */
586 tgl 3540 CBC 22 : AcquireRewriteLocks(query, false, false);
323 3541 22 : get_query_def(query, buf, list_make1(&dpns), NULL, false,
3542 : 0, WRAP_COLUMN_DEFAULT, 0);
732 peter 3543 ECB : }
732 peter 3544 CBC 54 : }
3545 :
3546 : Datum
3547 1686 : pg_get_function_sqlbody(PG_FUNCTION_ARGS)
3548 : {
3549 1686 : Oid funcid = PG_GETARG_OID(0);
3550 : StringInfoData buf;
732 peter 3551 ECB : HeapTuple proctup;
3552 : bool isnull;
3553 :
732 peter 3554 GIC 1686 : initStringInfo(&buf);
3555 :
3556 : /* Look up the function */
3557 1686 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3558 1686 : if (!HeapTupleIsValid(proctup))
732 peter 3559 UIC 0 : PG_RETURN_NULL();
3560 :
586 tgl 3561 CBC 1686 : (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
732 peter 3562 GIC 1686 : if (isnull)
3563 : {
732 peter 3564 CBC 1671 : ReleaseSysCache(proctup);
732 peter 3565 GIC 1671 : PG_RETURN_NULL();
3566 : }
3567 :
3568 15 : print_function_sqlbody(&buf, proctup);
3569 :
3570 15 : ReleaseSysCache(proctup);
3571 :
215 drowley 3572 GNC 15 : PG_RETURN_TEXT_P(cstring_to_text_with_len(buf.data, buf.len));
3573 : }
3574 :
3575 :
3576 : /*
3577 : * deparse_expression - General utility for deparsing expressions
3578 : *
3579 : * calls deparse_expression_pretty with all prettyPrinting disabled
3580 : */
3581 : char *
7193 tgl 3582 GIC 28781 : deparse_expression(Node *expr, List *dpcontext,
3583 : bool forceprefix, bool showimplicit)
3584 : {
7188 bruce 3585 28781 : return deparse_expression_pretty(expr, dpcontext, forceprefix,
3586 : showimplicit, 0, 0);
3587 : }
7193 tgl 3588 ECB :
3589 : /* ----------
3590 : * deparse_expression_pretty - General utility for deparsing expressions
3591 : *
3592 : * expr is the node tree to be deparsed. It must be a transformed expression
3593 : * tree (ie, not the raw output of gram.y).
3594 : *
8089 3595 : * dpcontext is a list of deparse_namespace nodes representing the context
3260 bruce 3596 : * for interpreting Vars in the node tree. It can be NIL if no Vars are
3751 tgl 3597 : * expected.
8589 3598 : *
2062 peter_e 3599 : * forceprefix is true to force all Vars to be prefixed with their table names.
8589 tgl 3600 : *
2062 peter_e 3601 : * showimplicit is true to force all implicit casts to be shown explicitly.
7188 bruce 3602 : *
3751 tgl 3603 : * Tries to pretty up the output according to prettyFlags and startIndent.
7507 3604 : *
8589 3605 : * The result is a palloc'd string.
3606 : * ----------
3607 : */
3608 : static char *
7193 tgl 3609 CBC 34079 : deparse_expression_pretty(Node *expr, List *dpcontext,
3610 : bool forceprefix, bool showimplicit,
3611 : int prettyFlags, int startIndent)
3612 : {
3613 : StringInfoData buf;
3614 : deparse_context context;
3615 :
8589 tgl 3616 GIC 34079 : initStringInfo(&buf);
3617 34079 : context.buf = &buf;
8089 3618 34079 : context.namespaces = dpcontext;
5215 3619 34079 : context.windowClause = NIL;
3620 34079 : context.windowTList = NIL;
8089 tgl 3621 CBC 34079 : context.varprefix = forceprefix;
7193 tgl 3622 GIC 34079 : context.prettyFlags = prettyFlags;
3758 3623 34079 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
7193 3624 34079 : context.indentLevel = startIndent;
2885 andres 3625 34079 : context.special_exprkind = EXPR_KIND_NONE;
1215 tgl 3626 CBC 34079 : context.appendparents = NULL;
3627 :
7507 tgl 3628 GIC 34079 : get_rule_expr(expr, &context, showimplicit);
8589 tgl 3629 ECB :
8589 tgl 3630 CBC 34079 : return buf.data;
8589 tgl 3631 ECB : }
8955 bruce 3632 :
8089 tgl 3633 : /* ----------
3634 : * deparse_context_for - Build deparse context for a single relation
3635 : *
7688 3636 : * Given the reference name (alias) and OID of a relation, build deparsing
3637 : * context for an expression referencing only that relation (as varno 1,
3260 bruce 3638 : * varlevelsup 0). This is sufficient for many uses of deparse_expression.
3639 : * ----------
3640 : */
8089 tgl 3641 : List *
7688 tgl 3642 CBC 9629 : deparse_context_for(const char *aliasname, Oid relid)
8089 tgl 3643 ECB : {
3644 : deparse_namespace *dpns;
3645 : RangeTblEntry *rte;
3646 :
4653 tgl 3647 GIC 9629 : dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3648 :
8089 tgl 3649 ECB : /* Build a minimal RTE for the rel */
8089 tgl 3650 GIC 9629 : rte = makeNode(RangeTblEntry);
7698 3651 9629 : rte->rtekind = RTE_RELATION;
8089 3652 9629 : rte->relid = relid;
4429 3653 9629 : rte->relkind = RELKIND_RELATION; /* no need for exactness here */
1652 3654 9629 : rte->rellockmode = AccessShareLock;
3852 3655 9629 : rte->alias = makeAlias(aliasname, NIL);
3656 9629 : rte->eref = rte->alias;
3897 3657 9629 : rte->lateral = false;
8089 3658 9629 : rte->inh = false;
3659 9629 : rte->inFromCl = true;
3660 :
3661 : /* Build one-element rtable */
6888 neilc 3662 9629 : dpns->rtable = list_make1(rte);
1215 tgl 3663 9629 : dpns->subplans = NIL;
5298 3664 9629 : dpns->ctes = NIL;
1215 3665 9629 : dpns->appendrels = NULL;
3852 tgl 3666 CBC 9629 : set_rtable_names(dpns, NIL, NULL);
3751 tgl 3667 GIC 9629 : set_simple_column_names(dpns);
3668 :
3669 : /* Return a one-deep namespace stack */
6888 neilc 3670 CBC 9629 : return list_make1(dpns);
3671 : }
3672 :
7698 tgl 3673 ECB : /*
1215 3674 : * deparse_context_for_plan_tree - Build deparse context for a Plan tree
3006 3675 : *
3676 : * When deparsing an expression in a Plan tree, we use the plan's rangetable
3677 : * to resolve names of simple Vars. The initialization of column names for
3678 : * this is rather expensive if the rangetable is large, and it'll be the same
3679 : * for every expression in the Plan tree; so we do it just once and re-use
3680 : * the result of this function for each expression. (Note that the result
3681 : * is not usable until set_deparse_context_plan() is applied to it.)
3682 : *
1215 3683 : * In addition to the PlannedStmt, pass the per-RTE alias names
3006 3684 : * assigned by a previous call to select_rtable_names_for_explain.
3685 : */
3686 : List *
1215 tgl 3687 CBC 9874 : deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
3006 tgl 3688 ECB : {
3689 : deparse_namespace *dpns;
3690 :
3006 tgl 3691 CBC 9874 : dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3006 tgl 3692 ECB :
3693 : /* Initialize fields that stay the same across the whole plan tree */
1215 tgl 3694 GIC 9874 : dpns->rtable = pstmt->rtable;
3006 3695 9874 : dpns->rtable_names = rtable_names;
1215 tgl 3696 CBC 9874 : dpns->subplans = pstmt->subplans;
3006 tgl 3697 GIC 9874 : dpns->ctes = NIL;
1215 3698 9874 : if (pstmt->appendRelations)
3699 : {
3700 : /* Set up the array, indexed by child relid */
3701 1637 : int ntables = list_length(dpns->rtable);
3702 : ListCell *lc;
1215 tgl 3703 ECB :
1215 tgl 3704 GIC 1637 : dpns->appendrels = (AppendRelInfo **)
3705 1637 : palloc0((ntables + 1) * sizeof(AppendRelInfo *));
1215 tgl 3706 CBC 9266 : foreach(lc, pstmt->appendRelations)
3707 : {
1215 tgl 3708 GIC 7629 : AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3709 7629 : Index crelid = appinfo->child_relid;
3710 :
3711 7629 : Assert(crelid > 0 && crelid <= ntables);
3712 7629 : Assert(dpns->appendrels[crelid] == NULL);
3713 7629 : dpns->appendrels[crelid] = appinfo;
3714 : }
3715 : }
3716 : else
3717 8237 : dpns->appendrels = NULL; /* don't need it */
3718 :
3719 : /*
3720 : * Set up column name aliases. We will get rather bogus results for join
3721 : * RTEs, but that doesn't matter because plan trees don't contain any join
3722 : * alias Vars.
3723 : */
3006 3724 9874 : set_simple_column_names(dpns);
3725 :
3726 : /* Return a one-deep namespace stack */
3727 9874 : return list_make1(dpns);
3728 : }
3729 :
3730 : /*
3731 : * set_deparse_context_plan - Specify Plan node containing expression
3732 : *
3733 : * When deparsing an expression in a Plan tree, we might have to resolve
3734 : * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
1215 tgl 3735 ECB : * provide the parent Plan node. Then OUTER_VAR and INNER_VAR references
3736 : * can be resolved by drilling down into the left and right child plans.
3737 : * Similarly, INDEX_VAR references can be resolved by reference to the
3738 : * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
3739 : * ForeignScan and CustomScan nodes. (Note that we don't currently support
2891 3740 : * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
3741 : * for those, we can only deparse the indexqualorig fields, which won't
3742 : * contain INDEX_VAR Vars.)
3743 : *
1215 3744 : * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
3745 : * the most-closely-nested first. This is needed to resolve PARAM_EXEC
3746 : * Params. Note we assume that all the Plan nodes share the same rtable.
7605 3747 : *
3748 : * Once this function has been called, deparse_expression() can be called on
3749 : * subsidiary expression(s) of the specified Plan node. To deparse
3750 : * expressions of a different Plan node in the same Plan tree, re-call this
3751 : * function to identify the new parent Plan node.
3752 : *
3753 : * The result is the same List passed in; this is a notational convenience.
3754 : */
3755 : List *
1215 tgl 3756 GIC 21439 : set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
3757 : {
7698 tgl 3758 ECB : deparse_namespace *dpns;
3759 :
3760 : /* Should always have one-entry namespace list for Plan deparsing */
3006 tgl 3761 GIC 21439 : Assert(list_length(dpcontext) == 1);
3006 tgl 3762 CBC 21439 : dpns = (deparse_namespace *) linitial(dpcontext);
3751 tgl 3763 ECB :
4653 3764 : /* Set our attention on the specific plan node passed in */
4653 tgl 3765 CBC 21439 : dpns->ancestors = ancestors;
545 3766 21439 : set_deparse_plan(dpns, plan);
4653 tgl 3767 ECB :
3006 tgl 3768 GIC 21439 : return dpcontext;
3769 : }
4653 tgl 3770 ECB :
3771 : /*
3772 : * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
3773 : *
3774 : * Determine the relation aliases we'll use during an EXPLAIN operation.
3775 : * This is just a frontend to set_rtable_names. We have to expose the aliases
3776 : * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
3777 : */
3778 : List *
3852 tgl 3779 GIC 9874 : select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
3780 : {
3781 : deparse_namespace dpns;
3782 :
3783 9874 : memset(&dpns, 0, sizeof(dpns));
3784 9874 : dpns.rtable = rtable;
1215 3785 9874 : dpns.subplans = NIL;
3852 3786 9874 : dpns.ctes = NIL;
1215 tgl 3787 CBC 9874 : dpns.appendrels = NULL;
3852 tgl 3788 GIC 9874 : set_rtable_names(&dpns, NIL, rels_used);
3789 : /* We needn't bother computing column aliases yet */
3790 :
3791 9874 : return dpns.rtable_names;
3792 : }
3793 :
3794 : /*
3795 : * set_rtable_names: select RTE aliases to be used in printing a query
3796 : *
3852 tgl 3797 ECB : * We fill in dpns->rtable_names with a list of names that is one-for-one with
3798 : * the already-filled dpns->rtable list. Each RTE name is unique among those
3799 : * in the new namespace plus any ancestor namespaces listed in
3800 : * parent_namespaces.
3801 : *
3802 : * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
3803 : *
3804 : * Note that this function is only concerned with relation names, not column
3805 : * names.
3806 : */
3807 : static void
3852 tgl 3808 CBC 21939 : set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
3852 tgl 3809 ECB : Bitmapset *rels_used)
3810 : {
3811 : HASHCTL hash_ctl;
3812 : HTAB *names_hash;
3813 : NameHashEntry *hentry;
3814 : bool found;
2701 3815 : int rtindex;
3816 : ListCell *lc;
3852 3817 :
3852 tgl 3818 GIC 21939 : dpns->rtable_names = NIL;
3819 : /* nothing more to do if empty rtable */
2701 tgl 3820 CBC 21939 : if (dpns->rtable == NIL)
2701 tgl 3821 GIC 232 : return;
2701 tgl 3822 ECB :
3823 : /*
3824 : * We use a hash table to hold known names, so that this process is O(N)
3825 : * not O(N^2) for N names.
3826 : */
2701 tgl 3827 GIC 21707 : hash_ctl.keysize = NAMEDATALEN;
3828 21707 : hash_ctl.entrysize = sizeof(NameHashEntry);
3829 21707 : hash_ctl.hcxt = CurrentMemoryContext;
3830 21707 : names_hash = hash_create("set_rtable_names names",
2701 tgl 3831 CBC 21707 : list_length(dpns->rtable),
3832 : &hash_ctl,
3833 : HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
3834 :
3835 : /* Preload the hash table with names appearing in parent_namespaces */
3836 22365 : foreach(lc, parent_namespaces)
2701 tgl 3837 ECB : {
2701 tgl 3838 GIC 658 : deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
2701 tgl 3839 ECB : ListCell *lc2;
3840 :
2701 tgl 3841 GIC 2189 : foreach(lc2, olddpns->rtable_names)
3842 : {
2701 tgl 3843 CBC 1531 : char *oldname = (char *) lfirst(lc2);
3844 :
3845 1531 : if (oldname == NULL)
2701 tgl 3846 GIC 114 : continue;
3847 1417 : hentry = (NameHashEntry *) hash_search(names_hash,
2701 tgl 3848 ECB : oldname,
3849 : HASH_ENTER,
3850 : &found);
3851 : /* we do not complain about duplicate names in parent namespaces */
2701 tgl 3852 GIC 1417 : hentry->counter = 0;
2701 tgl 3853 ECB : }
3854 : }
3855 :
3856 : /* Now we can scan the rtable */
2701 tgl 3857 GIC 21707 : rtindex = 1;
3852 tgl 3858 CBC 60652 : foreach(lc, dpns->rtable)
3859 : {
3860 38945 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3861 : char *refname;
3862 :
2701 tgl 3863 ECB : /* Just in case this takes an unreasonable amount of time ... */
2701 tgl 3864 GIC 38945 : CHECK_FOR_INTERRUPTS();
3865 :
3852 3866 38945 : if (rels_used && !bms_is_member(rtindex, rels_used))
3867 : {
3852 tgl 3868 ECB : /* Ignore unreferenced RTE */
3852 tgl 3869 GIC 5831 : refname = NULL;
3870 : }
3871 33114 : else if (rte->alias)
3872 : {
3873 : /* If RTE has a user-defined alias, prefer that */
3874 21727 : refname = rte->alias->aliasname;
3875 : }
3876 11387 : else if (rte->rtekind == RTE_RELATION)
3852 tgl 3877 ECB : {
3878 : /* Use the current actual name of the relation */
3852 tgl 3879 CBC 9798 : refname = get_rel_name(rte->relid);
3880 : }
3852 tgl 3881 GIC 1589 : else if (rte->rtekind == RTE_JOIN)
3882 : {
3852 tgl 3883 ECB : /* Unnamed join has no refname */
3852 tgl 3884 GIC 630 : refname = NULL;
3885 : }
3852 tgl 3886 ECB : else
3887 : {
3888 : /* Otherwise use whatever the parser assigned */
3852 tgl 3889 GIC 959 : refname = rte->eref->aliasname;
3890 : }
3891 :
3852 tgl 3892 ECB : /*
3893 : * If the selected name isn't unique, append digits to make it so, and
3894 : * make a new hash entry for it once we've got a unique name. For a
2701 3895 : * very long input name, we might have to truncate to stay within
3896 : * NAMEDATALEN.
3852 3897 : */
2701 tgl 3898 CBC 38945 : if (refname)
3899 : {
3900 32484 : hentry = (NameHashEntry *) hash_search(names_hash,
3901 : refname,
3902 : HASH_ENTER,
2701 tgl 3903 ECB : &found);
2701 tgl 3904 GIC 32484 : if (found)
3905 : {
3906 : /* Name already in use, must choose a new one */
2701 tgl 3907 CBC 6241 : int refnamelen = strlen(refname);
3908 6241 : char *modname = (char *) palloc(refnamelen + 16);
2701 tgl 3909 ECB : NameHashEntry *hentry2;
3910 :
3911 : do
3912 : {
2701 tgl 3913 GIC 6244 : hentry->counter++;
2701 tgl 3914 ECB : for (;;)
3915 : {
2701 tgl 3916 GIC 6250 : memcpy(modname, refname, refnamelen);
3917 6250 : sprintf(modname + refnamelen, "_%d", hentry->counter);
2701 tgl 3918 CBC 6250 : if (strlen(modname) < NAMEDATALEN)
3919 6244 : break;
3920 : /* drop chars from refname to keep all the digits */
2701 tgl 3921 GIC 6 : refnamelen = pg_mbcliplen(refname, refnamelen,
2701 tgl 3922 ECB : refnamelen - 1);
3923 : }
2701 tgl 3924 GIC 6244 : hentry2 = (NameHashEntry *) hash_search(names_hash,
3925 : modname,
3926 : HASH_ENTER,
3927 : &found);
3928 6244 : } while (found);
3929 6241 : hentry2->counter = 0; /* init new hash entry */
3930 6241 : refname = modname;
3931 : }
2701 tgl 3932 ECB : else
3933 : {
3934 : /* Name not previously used, need only initialize hentry */
2701 tgl 3935 GIC 26243 : hentry->counter = 0;
3936 : }
3937 : }
3938 :
3852 tgl 3939 CBC 38945 : dpns->rtable_names = lappend(dpns->rtable_names, refname);
3940 38945 : rtindex++;
3852 tgl 3941 ECB : }
3942 :
2701 tgl 3943 CBC 21707 : hash_destroy(names_hash);
3944 : }
3945 :
3751 tgl 3946 ECB : /*
3947 : * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
3948 : *
3949 : * For convenience, this is defined to initialize the deparse_namespace struct
3950 : * from scratch.
3951 : */
3952 : static void
3751 tgl 3953 GIC 2364 : set_deparse_for_query(deparse_namespace *dpns, Query *query,
3954 : List *parent_namespaces)
3751 tgl 3955 ECB : {
3956 : ListCell *lc;
3957 : ListCell *lc2;
3958 :
3959 : /* Initialize *dpns and fill rtable/ctes links */
3751 tgl 3960 GIC 2364 : memset(dpns, 0, sizeof(deparse_namespace));
3961 2364 : dpns->rtable = query->rtable;
1215 3962 2364 : dpns->subplans = NIL;
3751 3963 2364 : dpns->ctes = query->cteList;
1215 3964 2364 : dpns->appendrels = NULL;
3751 tgl 3965 ECB :
3966 : /* Assign a unique relation alias to each RTE */
3751 tgl 3967 GIC 2364 : set_rtable_names(dpns, parent_namespaces, NULL);
3968 :
3969 : /* Initialize dpns->rtable_columns to contain zeroed structs */
3970 2364 : dpns->rtable_columns = NIL;
3971 6395 : while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
3972 4031 : dpns->rtable_columns = lappend(dpns->rtable_columns,
3973 : palloc0(sizeof(deparse_columns)));
3974 :
3975 : /* If it's a utility query, it won't have a jointree */
3615 tgl 3976 CBC 2364 : if (query->jointree)
3977 : {
3615 tgl 3978 ECB : /* Detect whether global uniqueness of USING names is needed */
3615 tgl 3979 CBC 2356 : dpns->unique_using =
3547 tgl 3980 GIC 2356 : has_dangerous_join_using(dpns, (Node *) query->jointree);
3751 tgl 3981 ECB :
3615 3982 : /*
3983 : * Select names for columns merged by USING, via a recursive pass over
3984 : * the query jointree.
3985 : */
3265 tgl 3986 CBC 2356 : set_using_names(dpns, (Node *) query->jointree, NIL);
3987 : }
3988 :
3989 : /*
3990 : * Now assign remaining column aliases for each RTE. We do this in a
3991 : * linear scan of the rtable, so as to process RTEs whether or not they
3992 : * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
3993 : * etc). JOIN RTEs must be processed after their children, but this is
3994 : * okay because they appear later in the rtable list than their children
3995 : * (cf Asserts in identify_join_columns()).
3996 : */
3751 3997 6395 : forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
3998 : {
3751 tgl 3999 GIC 4031 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4000 4031 : deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4001 :
4002 4031 : if (rte->rtekind == RTE_JOIN)
3751 tgl 4003 CBC 500 : set_join_column_names(dpns, rte, colinfo);
3751 tgl 4004 ECB : else
3751 tgl 4005 CBC 3531 : set_relation_column_names(dpns, rte, colinfo);
4006 : }
3751 tgl 4007 GIC 2364 : }
4008 :
3751 tgl 4009 ECB : /*
4010 : * set_simple_column_names: fill in column aliases for non-query situations
4011 : *
4012 : * This handles EXPLAIN and cases where we only have relation RTEs. Without
4013 : * a join tree, we can't do anything smart about join RTEs, but we don't
4014 : * need to (note that EXPLAIN should never see join alias Vars anyway).
4015 : * If we do hit a join RTE we'll just process it like a non-table base RTE.
4016 : */
4017 : static void
3751 tgl 4018 GIC 19575 : set_simple_column_names(deparse_namespace *dpns)
4019 : {
4020 : ListCell *lc;
4021 : ListCell *lc2;
4022 :
4023 : /* Initialize dpns->rtable_columns to contain zeroed structs */
4024 19575 : dpns->rtable_columns = NIL;
4025 54489 : while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4026 34914 : dpns->rtable_columns = lappend(dpns->rtable_columns,
4027 : palloc0(sizeof(deparse_columns)));
4028 :
4029 : /* Assign unique column aliases within each RTE */
4030 54489 : forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4031 : {
4032 34914 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4033 34914 : deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4034 :
4035 34914 : set_relation_column_names(dpns, rte, colinfo);
4036 : }
4037 19575 : }
3751 tgl 4038 ECB :
4039 : /*
3547 4040 : * has_dangerous_join_using: search jointree for unnamed JOIN USING
4041 : *
4042 : * Merged columns of a JOIN USING may act differently from either of the input
4043 : * columns, either because they are merged with COALESCE (in a FULL JOIN) or
4044 : * because an implicit coercion of the underlying input column is required.
4045 : * In such a case the column must be referenced as a column of the JOIN not as
4046 : * a column of either input. And this is problematic if the join is unnamed
4047 : * (alias-less): we cannot qualify the column's name with an RTE name, since
4048 : * there is none. (Forcibly assigning an alias to the join is not a solution,
4049 : * since that will prevent legal references to tables below the join.)
4050 : * To ensure that every column in the query is unambiguously referenceable,
4051 : * we must assign such merged columns names that are globally unique across
4052 : * the whole query, aliasing other columns out of the way as necessary.
4053 : *
4054 : * Because the ensuing re-aliasing is fairly damaging to the readability of
3751 4055 : * the query, we don't do this unless we have to. So, we must pre-scan
4056 : * the join tree to see if we have to, before starting set_using_names().
4057 : */
4058 : static bool
3547 tgl 4059 GIC 5335 : has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
3751 tgl 4060 ECB : {
3751 tgl 4061 GIC 5335 : if (IsA(jtnode, RangeTblRef))
4062 : {
4063 : /* nothing to do here */
4064 : }
4065 2823 : else if (IsA(jtnode, FromExpr))
4066 : {
3751 tgl 4067 CBC 2356 : FromExpr *f = (FromExpr *) jtnode;
4068 : ListCell *lc;
4069 :
4070 4437 : foreach(lc, f->fromlist)
4071 : {
3547 4072 2117 : if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
3751 tgl 4073 GIC 36 : return true;
3751 tgl 4074 ECB : }
4075 : }
3751 tgl 4076 GIC 467 : else if (IsA(jtnode, JoinExpr))
4077 : {
4078 467 : JoinExpr *j = (JoinExpr *) jtnode;
4079 :
3547 tgl 4080 ECB : /* Is it an unnamed JOIN with USING? */
3547 tgl 4081 GBC 467 : if (j->alias == NULL && j->usingClause)
3547 tgl 4082 ECB : {
3547 tgl 4083 EUB : /*
4084 : * Yes, so check each join alias var to see if any of them are not
4085 : * simple references to underlying columns. If so, we have a
4086 : * dangerous situation and must pick unique aliases.
4087 : */
3547 tgl 4088 CBC 143 : RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4089 :
4090 : /* We need only examine the merged columns */
1186 tgl 4091 GIC 298 : for (int i = 0; i < jrte->joinmergedcols; i++)
4092 : {
4093 191 : Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4094 :
4095 191 : if (!IsA(aliasvar, Var))
3547 4096 36 : return true;
4097 : }
4098 : }
4099 :
4100 : /* Nope, but inspect children */
4101 431 : if (has_dangerous_join_using(dpns, j->larg))
3751 tgl 4102 UIC 0 : return true;
3547 tgl 4103 GIC 431 : if (has_dangerous_join_using(dpns, j->rarg))
3751 tgl 4104 LBC 0 : return true;
4105 : }
3751 tgl 4106 ECB : else
3751 tgl 4107 UIC 0 : elog(ERROR, "unrecognized node type: %d",
4108 : (int) nodeTag(jtnode));
3751 tgl 4109 GIC 5263 : return false;
3751 tgl 4110 ECB : }
4111 :
4112 : /*
4113 : * set_using_names: select column aliases to be used for merged USING columns
4114 : *
4115 : * We do this during a recursive descent of the query jointree.
4116 : * dpns->unique_using must already be set to determine the global strategy.
4117 : *
4118 : * Column alias info is saved in the dpns->rtable_columns list, which is
4119 : * assumed to be filled with pre-zeroed deparse_columns structs.
3265 4120 : *
4121 : * parentUsing is a list of all USING aliases assigned in parent joins of
4122 : * the current jointree node. (The passed-in list must not be modified.)
4123 : */
4124 : static void
3265 tgl 4125 GIC 5494 : set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
4126 : {
3751 4127 5494 : if (IsA(jtnode, RangeTblRef))
4128 : {
4129 : /* nothing to do now */
4130 : }
3751 tgl 4131 CBC 2856 : else if (IsA(jtnode, FromExpr))
3751 tgl 4132 ECB : {
3751 tgl 4133 CBC 2356 : FromExpr *f = (FromExpr *) jtnode;
4134 : ListCell *lc;
4135 :
4136 4494 : foreach(lc, f->fromlist)
3265 4137 2138 : set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4138 : }
3751 tgl 4139 GIC 500 : else if (IsA(jtnode, JoinExpr))
4140 : {
4141 500 : JoinExpr *j = (JoinExpr *) jtnode;
4142 500 : RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4143 500 : deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
3751 tgl 4144 ECB : int *leftattnos;
4145 : int *rightattnos;
4146 : deparse_columns *leftcolinfo;
4147 : deparse_columns *rightcolinfo;
4148 : int i;
4149 : ListCell *lc;
4150 :
4151 : /* Get info about the shape of the join */
3751 tgl 4152 GIC 500 : identify_join_columns(j, rte, colinfo);
4153 500 : leftattnos = colinfo->leftattnos;
3751 tgl 4154 CBC 500 : rightattnos = colinfo->rightattnos;
4155 :
3751 tgl 4156 ECB : /* Look up the not-yet-filled-in child deparse_columns structs */
3751 tgl 4157 CBC 500 : leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
3751 tgl 4158 GIC 500 : rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4159 :
4160 : /*
3751 tgl 4161 ECB : * If this join is unnamed, then we cannot substitute new aliases at
4162 : * this level, so any name requirements pushed down to here must be
4163 : * pushed down again to the children.
4164 : */
3751 tgl 4165 GIC 500 : if (rte->alias == NULL)
4166 : {
4167 515 : for (i = 0; i < colinfo->num_cols; i++)
4168 : {
4169 69 : char *colname = colinfo->colnames[i];
4170 :
4171 69 : if (colname == NULL)
4172 12 : continue;
4173 :
4174 : /* Push down to left column, unless it's a system column */
4175 57 : if (leftattnos[i] > 0)
4176 : {
4177 51 : expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4178 51 : leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4179 : }
4180 :
4181 : /* Same on the righthand side */
4182 57 : if (rightattnos[i] > 0)
4183 : {
4184 57 : expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4185 57 : rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4186 : }
4187 : }
4188 : }
4189 :
4190 : /*
4191 : * If there's a USING clause, select the USING column names and push
4192 : * those names down to the children. We have two strategies:
4193 : *
2062 peter_e 4194 ECB : * If dpns->unique_using is true, we force all USING names to be
4195 : * unique across the whole query level. In principle we'd only need
4196 : * the names of dangerous USING columns to be globally unique, but to
3547 tgl 4197 : * safely assign all USING names in a single pass, we have to enforce
4198 : * the same uniqueness rule for all of them. However, if a USING
4199 : * column's name has been pushed down from the parent, we should use
4200 : * it as-is rather than making a uniqueness adjustment. This is
4201 : * necessary when we're at an unnamed join, and it creates no risk of
4202 : * ambiguity. Also, if there's a user-written output alias for a
4203 : * merged column, we prefer to use that rather than the input name;
4204 : * this simplifies the logic and seems likely to lead to less aliasing
4205 : * overall.
4206 : *
2062 peter_e 4207 : * If dpns->unique_using is false, we only need USING names to be
4208 : * unique within their own join RTE. We still need to honor
4209 : * pushed-down names, though.
3751 tgl 4210 : *
4211 : * Though significantly different in results, these two strategies are
4212 : * implemented by the same code, with only the difference of whether
4213 : * to put assigned names into dpns->using_names.
4214 : */
3751 tgl 4215 CBC 500 : if (j->usingClause)
3751 tgl 4216 EUB : {
4217 : /* Copy the input parentUsing list so we don't modify it */
3265 tgl 4218 CBC 212 : parentUsing = list_copy(parentUsing);
3265 tgl 4219 ECB :
3751 4220 : /* USING names must correspond to the first join output columns */
3751 tgl 4221 GIC 212 : expand_colnames_array_to(colinfo, list_length(j->usingClause));
4222 212 : i = 0;
3751 tgl 4223 CBC 502 : foreach(lc, j->usingClause)
4224 : {
3751 tgl 4225 GIC 290 : char *colname = strVal(lfirst(lc));
4226 :
3751 tgl 4227 ECB : /* Assert it's a merged column */
3751 tgl 4228 CBC 290 : Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4229 :
4230 : /* Adopt passed-down name if any, else select unique name */
4231 290 : if (colinfo->colnames[i] != NULL)
3751 tgl 4232 GIC 51 : colname = colinfo->colnames[i];
3751 tgl 4233 ECB : else
4234 : {
4235 : /* Prefer user-written output alias if any */
3751 tgl 4236 GIC 239 : if (rte->alias && i < list_length(rte->alias->colnames))
3751 tgl 4237 UIC 0 : colname = strVal(list_nth(rte->alias->colnames, i));
3751 tgl 4238 ECB : /* Make it appropriately unique */
3751 tgl 4239 GIC 239 : colname = make_colname_unique(colname, dpns, colinfo);
3751 tgl 4240 CBC 239 : if (dpns->unique_using)
4241 63 : dpns->using_names = lappend(dpns->using_names,
4242 : colname);
4243 : /* Save it as output column name, too */
4244 239 : colinfo->colnames[i] = colname;
4245 : }
4246 :
4247 : /* Remember selected names for use later */
3751 tgl 4248 GIC 290 : colinfo->usingNames = lappend(colinfo->usingNames, colname);
3265 tgl 4249 CBC 290 : parentUsing = lappend(parentUsing, colname);
3751 tgl 4250 ECB :
4251 : /* Push down to left column, unless it's a system column */
3751 tgl 4252 GIC 290 : if (leftattnos[i] > 0)
3751 tgl 4253 ECB : {
3751 tgl 4254 CBC 290 : expand_colnames_array_to(leftcolinfo, leftattnos[i]);
3751 tgl 4255 GIC 290 : leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4256 : }
3751 tgl 4257 EUB :
4258 : /* Same on the righthand side */
3751 tgl 4259 CBC 290 : if (rightattnos[i] > 0)
4260 : {
3751 tgl 4261 GIC 290 : expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4262 290 : rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4263 : }
4264 :
4265 290 : i++;
4266 : }
4267 : }
4268 :
3265 tgl 4269 ECB : /* Mark child deparse_columns structs with correct parentUsing info */
3265 tgl 4270 GIC 500 : leftcolinfo->parentUsing = parentUsing;
4271 500 : rightcolinfo->parentUsing = parentUsing;
4272 :
4273 : /* Now recursively assign USING column names in children */
4274 500 : set_using_names(dpns, j->larg, parentUsing);
4275 500 : set_using_names(dpns, j->rarg, parentUsing);
4276 : }
4277 : else
3751 tgl 4278 UIC 0 : elog(ERROR, "unrecognized node type: %d",
4279 : (int) nodeTag(jtnode));
3751 tgl 4280 GIC 5494 : }
4281 :
4282 : /*
4283 : * set_relation_column_names: select column aliases for a non-join RTE
3751 tgl 4284 ECB : *
4285 : * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4286 : * If any colnames entries are already filled in, those override local
4287 : * choices.
4288 : */
4289 : static void
3751 tgl 4290 CBC 38445 : set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
3751 tgl 4291 ECB : deparse_columns *colinfo)
4292 : {
4293 : int ncolumns;
4294 : char **real_colnames;
4295 : bool changed_any;
4296 : int noldcolumns;
4297 : int i;
4298 : int j;
4299 :
4300 : /*
262 4301 : * Construct an array of the current "real" column names of the RTE.
4302 : * real_colnames[] will be indexed by physical column number, with NULL
4303 : * entries for dropped columns.
4304 : */
3751 tgl 4305 CBC 38445 : if (rte->rtekind == RTE_RELATION)
4306 : {
4307 : /* Relation --- look to the system catalogs for up-to-date info */
4308 : Relation rel;
4309 : TupleDesc tupdesc;
4310 :
3751 tgl 4311 GIC 32179 : rel = relation_open(rte->relid, AccessShareLock);
4312 32179 : tupdesc = RelationGetDescr(rel);
4313 :
4314 32179 : ncolumns = tupdesc->natts;
4315 32179 : real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4316 :
4317 207091 : for (i = 0; i < ncolumns; i++)
4318 : {
2058 andres 4319 174912 : Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4320 :
4321 174912 : if (attr->attisdropped)
3751 tgl 4322 1498 : real_colnames[i] = NULL;
4323 : else
2058 andres 4324 173414 : real_colnames[i] = pstrdup(NameStr(attr->attname));
4325 : }
3751 tgl 4326 32179 : relation_close(rel, AccessShareLock);
4327 : }
3751 tgl 4328 ECB : else
4329 : {
4330 : /* Otherwise get the column names from eref or expandRTE() */
262 4331 : List *colnames;
4332 : ListCell *lc;
4333 :
4334 : /*
4335 : * Functions returning composites have the annoying property that some
4336 : * of the composite type's columns might have been dropped since the
4337 : * query was parsed. If possible, use expandRTE() to handle that
4338 : * case, since it has the tedious logic needed to find out about
4339 : * dropped columns. However, if we're explaining a plan, then we
4340 : * don't have rte->functions because the planner thinks that won't be
4341 : * needed later, and that breaks expandRTE(). So in that case we have
4342 : * to rely on rte->eref, which may lead us to report a dropped
4343 : * column's old name; that seems close enough for EXPLAIN's purposes.
4344 : *
4345 : * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4346 : * which should be sufficiently up-to-date: no other RTE types can
4347 : * have columns get dropped from under them after parsing.
4348 : */
262 tgl 4349 CBC 6266 : if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
262 tgl 4350 ECB : {
4351 : /* Since we're not creating Vars, rtindex etc. don't matter */
262 tgl 4352 CBC 267 : expandRTE(rte, 1, 0, -1, true /* include dropped */ ,
4353 : &colnames, NULL);
4354 : }
4355 : else
262 tgl 4356 GIC 5999 : colnames = rte->eref->colnames;
4357 :
4358 6266 : ncolumns = list_length(colnames);
3751 4359 6266 : real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4360 :
4361 6266 : i = 0;
262 4362 33471 : foreach(lc, colnames)
4363 : {
3186 tgl 4364 ECB : /*
262 4365 : * If the column name we find here is an empty string, then it's a
4366 : * dropped column, so change to NULL.
4367 : */
3186 tgl 4368 GIC 27205 : char *cname = strVal(lfirst(lc));
4369 :
4370 27205 : if (cname[0] == '\0')
4371 27 : cname = NULL;
4372 27205 : real_colnames[i] = cname;
3751 4373 27205 : i++;
3751 tgl 4374 ECB : }
4375 : }
4376 :
4377 : /*
4378 : * Ensure colinfo->colnames has a slot for each column. (It could be long
4379 : * enough already, if we pushed down a name for the last column.) Note:
4380 : * it's possible that there are now more columns than there were when the
4381 : * query was parsed, ie colnames could be longer than rte->eref->colnames.
4382 : * We must assign unique aliases to the new columns too, else there could
4383 : * be unresolved conflicts when the view/rule is reloaded.
4384 : */
3751 tgl 4385 CBC 38445 : expand_colnames_array_to(colinfo, ncolumns);
4386 38445 : Assert(colinfo->num_cols == ncolumns);
3751 tgl 4387 ECB :
4388 : /*
4389 : * Make sufficiently large new_colnames and is_new_col arrays, too.
4390 : *
4391 : * Note: because we leave colinfo->num_new_cols zero until after the loop,
4392 : * colname_is_unique will not consult that array, which is fine because it
4393 : * would only be duplicate effort.
4394 : */
3751 tgl 4395 CBC 38445 : colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4396 38445 : colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4397 :
4398 : /*
4399 : * Scan the columns, select a unique alias for each one, and store it in
3751 tgl 4400 ECB : * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4401 : * entries for dropped columns, the latter omits them. Also mark
4402 : * new_colnames entries as to whether they are new since parse time; this
4403 : * is the case for entries beyond the length of rte->eref->colnames.
4404 : */
3751 tgl 4405 GIC 38445 : noldcolumns = list_length(rte->eref->colnames);
3751 tgl 4406 CBC 38445 : changed_any = false;
3751 tgl 4407 GIC 38445 : j = 0;
4408 240562 : for (i = 0; i < ncolumns; i++)
3751 tgl 4409 ECB : {
3751 tgl 4410 GIC 202117 : char *real_colname = real_colnames[i];
3751 tgl 4411 CBC 202117 : char *colname = colinfo->colnames[i];
4412 :
4413 : /* Skip dropped columns */
3751 tgl 4414 GIC 202117 : if (real_colname == NULL)
3751 tgl 4415 ECB : {
3751 tgl 4416 GIC 1525 : Assert(colname == NULL); /* colnames[i] is already NULL */
3751 tgl 4417 CBC 1525 : continue;
3751 tgl 4418 ECB : }
4419 :
4420 : /* If alias already assigned, that's what to use */
3751 tgl 4421 CBC 200592 : if (colname == NULL)
3751 tgl 4422 ECB : {
4423 : /* If user wrote an alias, prefer that over real column name */
3751 tgl 4424 GIC 200063 : if (rte->alias && i < list_length(rte->alias->colnames))
4425 19190 : colname = strVal(list_nth(rte->alias->colnames, i));
4426 : else
4427 180873 : colname = real_colname;
4428 :
4429 : /* Unique-ify and insert into colinfo */
4430 200063 : colname = make_colname_unique(colname, dpns, colinfo);
3751 tgl 4431 ECB :
3751 tgl 4432 GIC 200063 : colinfo->colnames[i] = colname;
4433 : }
4434 :
4435 : /* Put names of non-dropped columns in new_colnames[] too */
4436 200592 : colinfo->new_colnames[j] = colname;
4437 : /* And mark them as new or not */
4438 200592 : colinfo->is_new_col[j] = (i >= noldcolumns);
4439 200592 : j++;
4440 :
4441 : /* Remember if any assigned aliases differ from "real" name */
4442 200592 : if (!changed_any && strcmp(colname, real_colname) != 0)
3751 tgl 4443 CBC 1641 : changed_any = true;
3751 tgl 4444 ECB : }
4445 :
4446 : /*
4447 : * Set correct length for new_colnames[] array. (Note: if columns have
4448 : * been added, colinfo->num_cols includes them, which is not really quite
4449 : * right but is harmless, since any new columns must be at the end where
4450 : * they won't affect varattnos of pre-existing columns.)
4451 : */
3751 tgl 4452 CBC 38445 : colinfo->num_new_cols = j;
3751 tgl 4453 ECB :
4454 : /*
4455 : * For a relation RTE, we need only print the alias column names if any
4456 : * are different from the underlying "real" names. For a function RTE,
4457 : * always emit a complete column alias list; this is to protect against
4458 : * possible instability of the default column names (eg, from altering
4459 : * parameter names). For tablefunc RTEs, we never print aliases, because
4460 : * the column names are part of the clause itself. For other RTE types,
4461 : * print if we changed anything OR if there were user-written column
4462 : * aliases (since the latter would be part of the underlying "reality").
4463 : */
3751 tgl 4464 GIC 38445 : if (rte->rtekind == RTE_RELATION)
3751 tgl 4465 CBC 32179 : colinfo->printaliases = changed_any;
3751 tgl 4466 GIC 6266 : else if (rte->rtekind == RTE_FUNCTION)
4467 453 : colinfo->printaliases = true;
2223 alvherre 4468 5813 : else if (rte->rtekind == RTE_TABLEFUNC)
4469 28 : colinfo->printaliases = false;
3751 tgl 4470 5785 : else if (rte->alias && rte->alias->colnames != NIL)
4471 336 : colinfo->printaliases = true;
4472 : else
3751 tgl 4473 CBC 5449 : colinfo->printaliases = changed_any;
4474 38445 : }
4475 :
4476 : /*
4477 : * set_join_column_names: select column aliases for a join RTE
4478 : *
4479 : * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4480 : * If any colnames entries are already filled in, those override local
3751 tgl 4481 ECB : * choices. Also, names for USING columns were already chosen by
4482 : * set_using_names(). We further expect that column alias selection has been
4483 : * completed for both input RTEs.
4484 : */
4485 : static void
3751 tgl 4486 GIC 500 : set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4487 : deparse_columns *colinfo)
4488 : {
4489 : deparse_columns *leftcolinfo;
4490 : deparse_columns *rightcolinfo;
3751 tgl 4491 ECB : bool changed_any;
4492 : int noldcolumns;
4493 : int nnewcolumns;
3751 tgl 4494 GIC 500 : Bitmapset *leftmerged = NULL;
4495 500 : Bitmapset *rightmerged = NULL;
4496 : int i;
4497 : int j;
4498 : int ic;
4499 : int jc;
4500 :
3751 tgl 4501 ECB : /* Look up the previously-filled-in child deparse_columns structs */
3751 tgl 4502 CBC 500 : leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
3751 tgl 4503 GIC 500 : rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
3751 tgl 4504 ECB :
4505 : /*
4506 : * Ensure colinfo->colnames has a slot for each column. (It could be long
4507 : * enough already, if we pushed down a name for the last column.) Note:
4508 : * it's possible that one or both inputs now have more columns than there
4509 : * were when the query was parsed, but we'll deal with that below. We
4510 : * only need entries in colnames for pre-existing columns.
4511 : */
3751 tgl 4512 CBC 500 : noldcolumns = list_length(rte->eref->colnames);
4513 500 : expand_colnames_array_to(colinfo, noldcolumns);
4514 500 : Assert(colinfo->num_cols == noldcolumns);
4515 :
4516 : /*
4517 : * Scan the join output columns, select an alias for each one, and store
3751 tgl 4518 EUB : * it in colinfo->colnames. If there are USING columns, set_using_names()
4519 : * already selected their names, so we can start the loop at the first
4520 : * non-merged column.
4521 : */
3751 tgl 4522 CBC 500 : changed_any = false;
3751 tgl 4523 GIC 12818 : for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
3751 tgl 4524 ECB : {
3751 tgl 4525 CBC 12318 : char *colname = colinfo->colnames[i];
4526 : char *real_colname;
4527 :
4528 : /* Join column must refer to at least one input column */
1186 4529 12318 : Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4530 :
3751 tgl 4531 ECB : /* Get the child column name */
3751 tgl 4532 CBC 12318 : if (colinfo->leftattnos[i] > 0)
3751 tgl 4533 GIC 8558 : real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4534 3760 : else if (colinfo->rightattnos[i] > 0)
4535 3760 : real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
3751 tgl 4536 ECB : else
4537 : {
4538 : /* We're joining system columns --- use eref name */
3547 tgl 4539 LBC 0 : real_colname = strVal(list_nth(rte->eref->colnames, i));
3751 tgl 4540 ECB : }
4541 :
1186 4542 : /* If child col has been dropped, no need to assign a join colname */
1186 tgl 4543 GIC 12318 : if (real_colname == NULL)
4544 : {
1186 tgl 4545 CBC 3 : colinfo->colnames[i] = NULL;
1186 tgl 4546 GIC 3 : continue;
1186 tgl 4547 ECB : }
4548 :
4549 : /* In an unnamed join, just report child column names as-is */
3751 tgl 4550 GIC 12315 : if (rte->alias == NULL)
3751 tgl 4551 ECB : {
3751 tgl 4552 CBC 12126 : colinfo->colnames[i] = real_colname;
3751 tgl 4553 GIC 12126 : continue;
4554 : }
4555 :
4556 : /* If alias already assigned, that's what to use */
4557 189 : if (colname == NULL)
4558 : {
4559 : /* If user wrote an alias, prefer that over real column name */
4560 189 : if (rte->alias && i < list_length(rte->alias->colnames))
4561 48 : colname = strVal(list_nth(rte->alias->colnames, i));
3751 tgl 4562 ECB : else
3751 tgl 4563 CBC 141 : colname = real_colname;
3751 tgl 4564 ECB :
4565 : /* Unique-ify and insert into colinfo */
3751 tgl 4566 CBC 189 : colname = make_colname_unique(colname, dpns, colinfo);
4567 :
3751 tgl 4568 GIC 189 : colinfo->colnames[i] = colname;
4569 : }
4570 :
4571 : /* Remember if any assigned aliases differ from "real" name */
4572 189 : if (!changed_any && strcmp(colname, real_colname) != 0)
4573 12 : changed_any = true;
4574 : }
4575 :
4576 : /*
4577 : * Calculate number of columns the join would have if it were re-parsed
4578 : * now, and create storage for the new_colnames and is_new_col arrays.
4579 : *
4580 : * Note: colname_is_unique will be consulting new_colnames[] during the
4581 : * loops below, so its not-yet-filled entries must be zeroes.
4582 : */
4583 1000 : nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4584 500 : list_length(colinfo->usingNames);
3751 tgl 4585 CBC 500 : colinfo->num_new_cols = nnewcolumns;
4586 500 : colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
4587 500 : colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
3751 tgl 4588 ECB :
4589 : /*
4590 : * Generating the new_colnames array is a bit tricky since any new columns
4591 : * added since parse time must be inserted in the right places. This code
4592 : * must match the parser, which will order a join's columns as merged
4593 : * columns first (in USING-clause order), then non-merged columns from the
4594 : * left input (in attnum order), then non-merged columns from the right
4595 : * input (ditto). If one of the inputs is itself a join, its columns will
4596 : * be ordered according to the same rule, which means newly-added columns
4597 : * might not be at the end. We can figure out what's what by consulting
4598 : * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4599 : *
4600 : * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4601 : * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4602 : * meanings for the current child RTE.
4603 : */
4604 :
4605 : /* Handle merged columns; they are first and can't be new */
3751 tgl 4606 GIC 500 : i = j = 0;
3751 tgl 4607 CBC 500 : while (i < noldcolumns &&
3751 tgl 4608 GIC 790 : colinfo->leftattnos[i] != 0 &&
3751 tgl 4609 CBC 790 : colinfo->rightattnos[i] != 0)
4610 : {
4611 : /* column name is already determined and known unique */
4612 290 : colinfo->new_colnames[j] = colinfo->colnames[i];
4613 290 : colinfo->is_new_col[j] = false;
3751 tgl 4614 ECB :
4615 : /* build bitmapsets of child attnums of merged columns */
3751 tgl 4616 CBC 290 : if (colinfo->leftattnos[i] > 0)
3751 tgl 4617 GIC 290 : leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
3751 tgl 4618 CBC 290 : if (colinfo->rightattnos[i] > 0)
4619 290 : rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4620 :
4621 290 : i++, j++;
3751 tgl 4622 ECB : }
4623 :
4624 : /* Handle non-merged left-child columns */
3751 tgl 4625 CBC 500 : ic = 0;
3751 tgl 4626 GIC 9591 : for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
3751 tgl 4627 ECB : {
3751 tgl 4628 CBC 9091 : char *child_colname = leftcolinfo->new_colnames[jc];
4629 :
3751 tgl 4630 GIC 9091 : if (!leftcolinfo->is_new_col[jc])
4631 : {
4632 : /* Advance ic to next non-dropped old column of left child */
4633 8887 : while (ic < leftcolinfo->num_cols &&
4634 8887 : leftcolinfo->colnames[ic] == NULL)
4635 42 : ic++;
3751 tgl 4636 CBC 8845 : Assert(ic < leftcolinfo->num_cols);
3751 tgl 4637 GIC 8845 : ic++;
3751 tgl 4638 ECB : /* If it is a merged column, we already processed it */
3751 tgl 4639 CBC 8845 : if (bms_is_member(ic, leftmerged))
4640 290 : continue;
3751 tgl 4641 ECB : /* Else, advance i to the corresponding existing join column */
3751 tgl 4642 CBC 8558 : while (i < colinfo->num_cols &&
3751 tgl 4643 GIC 8558 : colinfo->colnames[i] == NULL)
4644 3 : i++;
3751 tgl 4645 CBC 8555 : Assert(i < colinfo->num_cols);
3751 tgl 4646 GIC 8555 : Assert(ic == colinfo->leftattnos[i]);
4647 : /* Use the already-assigned name of this column */
3751 tgl 4648 CBC 8555 : colinfo->new_colnames[j] = colinfo->colnames[i];
4649 8555 : i++;
4650 : }
4651 : else
4652 : {
3751 tgl 4653 ECB : /*
4654 : * Unique-ify the new child column name and assign, unless we're
4655 : * in an unnamed join, in which case just copy
4656 : */
3751 tgl 4657 GIC 246 : if (rte->alias != NULL)
3751 tgl 4658 ECB : {
3751 tgl 4659 GIC 132 : colinfo->new_colnames[j] =
4660 66 : make_colname_unique(child_colname, dpns, colinfo);
3751 tgl 4661 CBC 66 : if (!changed_any &&
4662 54 : strcmp(colinfo->new_colnames[j], child_colname) != 0)
3751 tgl 4663 GBC 6 : changed_any = true;
3751 tgl 4664 ECB : }
4665 : else
3751 tgl 4666 GIC 180 : colinfo->new_colnames[j] = child_colname;
3751 tgl 4667 ECB : }
4668 :
3751 tgl 4669 GIC 8801 : colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
3751 tgl 4670 CBC 8801 : j++;
3751 tgl 4671 ECB : }
3751 tgl 4672 EUB :
3751 tgl 4673 ECB : /* Handle non-merged right-child columns in exactly the same way */
3751 tgl 4674 CBC 500 : ic = 0;
3751 tgl 4675 GIC 4634 : for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
3751 tgl 4676 ECB : {
3751 tgl 4677 CBC 4134 : char *child_colname = rightcolinfo->new_colnames[jc];
4678 :
3751 tgl 4679 GIC 4134 : if (!rightcolinfo->is_new_col[jc])
4680 : {
4681 : /* Advance ic to next non-dropped old column of right child */
4682 4050 : while (ic < rightcolinfo->num_cols &&
4683 4050 : rightcolinfo->colnames[ic] == NULL)
3751 tgl 4684 UIC 0 : ic++;
3751 tgl 4685 CBC 4050 : Assert(ic < rightcolinfo->num_cols);
3751 tgl 4686 GIC 4050 : ic++;
3751 tgl 4687 ECB : /* If it is a merged column, we already processed it */
3751 tgl 4688 CBC 4050 : if (bms_is_member(ic, rightmerged))
4689 290 : continue;
3751 tgl 4690 ECB : /* Else, advance i to the corresponding existing join column */
3751 tgl 4691 CBC 3760 : while (i < colinfo->num_cols &&
3751 tgl 4692 GIC 3760 : colinfo->colnames[i] == NULL)
3751 tgl 4693 UIC 0 : i++;
3751 tgl 4694 CBC 3760 : Assert(i < colinfo->num_cols);
3751 tgl 4695 GIC 3760 : Assert(ic == colinfo->rightattnos[i]);
4696 : /* Use the already-assigned name of this column */
3751 tgl 4697 CBC 3760 : colinfo->new_colnames[j] = colinfo->colnames[i];
4698 3760 : i++;
4699 : }
4700 : else
4701 : {
4702 : /*
3751 tgl 4703 ECB : * Unique-ify the new child column name and assign, unless we're
3751 tgl 4704 EUB : * in an unnamed join, in which case just copy
3751 tgl 4705 ECB : */
3751 tgl 4706 CBC 84 : if (rte->alias != NULL)
4707 : {
3751 tgl 4708 GIC 24 : colinfo->new_colnames[j] =
4709 12 : make_colname_unique(child_colname, dpns, colinfo);
4710 12 : if (!changed_any &&
4711 12 : strcmp(colinfo->new_colnames[j], child_colname) != 0)
4712 6 : changed_any = true;
3751 tgl 4713 ECB : }
4714 : else
3751 tgl 4715 GIC 72 : colinfo->new_colnames[j] = child_colname;
3751 tgl 4716 ECB : }
4717 :
3751 tgl 4718 GIC 3844 : colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4719 3844 : j++;
4720 : }
4721 :
4722 : /* Assert we processed the right number of columns */
4723 : #ifdef USE_ASSERT_CHECKING
4724 500 : while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
3751 tgl 4725 LBC 0 : i++;
3751 tgl 4726 GIC 500 : Assert(i == colinfo->num_cols);
4727 500 : Assert(j == nnewcolumns);
4728 : #endif
4729 :
4730 : /*
4731 : * For a named join, print column aliases if we changed any from the child
3751 tgl 4732 ECB : * names. Unnamed joins cannot print aliases.
4733 : */
3751 tgl 4734 CBC 500 : if (rte->alias != NULL)
3751 tgl 4735 GIC 54 : colinfo->printaliases = changed_any;
3751 tgl 4736 ECB : else
3751 tgl 4737 CBC 446 : colinfo->printaliases = false;
3751 tgl 4738 GIC 500 : }
4739 :
4740 : /*
4741 : * colname_is_unique: is colname distinct from already-chosen column names?
4742 : *
4743 : * dpns is query-wide info, colinfo is for the column's RTE
3751 tgl 4744 ECB : */
4745 : static bool
1986 peter_e 4746 CBC 209077 : colname_is_unique(const char *colname, deparse_namespace *dpns,
4747 : deparse_columns *colinfo)
3751 tgl 4748 ECB : {
4749 : int i;
4750 : ListCell *lc;
4751 :
4752 : /* Check against already-assigned column aliases within RTE */
3751 tgl 4753 CBC 3170987 : for (i = 0; i < colinfo->num_cols; i++)
4754 : {
4755 2970382 : char *oldname = colinfo->colnames[i];
4756 :
4757 2970382 : if (oldname && strcmp(oldname, colname) == 0)
4758 8472 : return false;
4759 : }
4760 :
4761 : /*
3751 tgl 4762 ECB : * If we're building a new_colnames array, check that too (this will be
4763 : * partially but not completely redundant with the previous checks)
4764 : */
3751 tgl 4765 GIC 201241 : for (i = 0; i < colinfo->num_new_cols; i++)
3751 tgl 4766 ECB : {
3751 tgl 4767 CBC 648 : char *oldname = colinfo->new_colnames[i];
4768 :
3751 tgl 4769 GIC 648 : if (oldname && strcmp(oldname, colname) == 0)
3751 tgl 4770 CBC 12 : return false;
4771 : }
4772 :
4773 : /* Also check against USING-column names that must be globally unique */
3751 tgl 4774 GIC 201013 : foreach(lc, dpns->using_names)
4775 : {
4776 441 : char *oldname = (char *) lfirst(lc);
4777 :
4778 441 : if (strcmp(oldname, colname) == 0)
3751 tgl 4779 CBC 21 : return false;
4780 : }
4781 :
4782 : /* Also check against names already assigned for parent-join USING cols */
3265 tgl 4783 GIC 201868 : foreach(lc, colinfo->parentUsing)
4784 : {
4785 1299 : char *oldname = (char *) lfirst(lc);
4786 :
3265 tgl 4787 CBC 1299 : if (strcmp(oldname, colname) == 0)
3265 tgl 4788 GIC 3 : return false;
3265 tgl 4789 ECB : }
4790 :
3751 tgl 4791 CBC 200569 : return true;
4792 : }
4793 :
4794 : /*
3751 tgl 4795 ECB : * make_colname_unique: modify colname if necessary to make it unique
4796 : *
4797 : * dpns is query-wide info, colinfo is for the column's RTE
4798 : */
4799 : static char *
3751 tgl 4800 CBC 200569 : make_colname_unique(char *colname, deparse_namespace *dpns,
3751 tgl 4801 ECB : deparse_columns *colinfo)
4802 : {
3751 tgl 4803 EUB : /*
4804 : * If the selected name isn't unique, append digits to make it so. For a
4805 : * very long input name, we might have to truncate to stay within
2701 tgl 4806 ECB : * NAMEDATALEN.
3751 4807 : */
3751 tgl 4808 GIC 200569 : if (!colname_is_unique(colname, dpns, colinfo))
3751 tgl 4809 ECB : {
2701 tgl 4810 GIC 7412 : int colnamelen = strlen(colname);
4811 7412 : char *modname = (char *) palloc(colnamelen + 16);
3751 4812 7412 : int i = 0;
4813 :
4814 : do
4815 : {
2701 4816 8508 : i++;
4817 : for (;;)
2701 tgl 4818 ECB : {
2701 tgl 4819 GIC 8508 : memcpy(modname, colname, colnamelen);
2701 tgl 4820 CBC 8508 : sprintf(modname + colnamelen, "_%d", i);
2701 tgl 4821 GIC 8508 : if (strlen(modname) < NAMEDATALEN)
2701 tgl 4822 CBC 8508 : break;
2701 tgl 4823 ECB : /* drop chars from colname to keep all the digits */
2701 tgl 4824 UIC 0 : colnamelen = pg_mbcliplen(colname, colnamelen,
2701 tgl 4825 ECB : colnamelen - 1);
4826 : }
3751 tgl 4827 GIC 8508 : } while (!colname_is_unique(modname, dpns, colinfo));
3751 tgl 4828 CBC 7412 : colname = modname;
4829 : }
3751 tgl 4830 GIC 200569 : return colname;
4831 : }
4832 :
4833 : /*
4834 : * expand_colnames_array_to: make colinfo->colnames at least n items long
4835 : *
4836 : * Any added array entries are initialized to zero.
3751 tgl 4837 ECB : */
4838 : static void
3751 tgl 4839 GIC 39845 : expand_colnames_array_to(deparse_columns *colinfo, int n)
4840 : {
4841 39845 : if (n > colinfo->num_cols)
4842 : {
4843 38860 : if (colinfo->colnames == NULL)
148 peter 4844 GNC 38152 : colinfo->colnames = palloc0_array(char *, n);
4845 : else
4846 708 : colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
3751 tgl 4847 GIC 38860 : colinfo->num_cols = n;
3751 tgl 4848 ECB : }
3751 tgl 4849 CBC 39845 : }
3751 tgl 4850 EUB :
4851 : /*
4852 : * identify_join_columns: figure out where columns of a join come from
4853 : *
4854 : * Fills the join-specific fields of the colinfo struct, except for
4855 : * usingNames which is filled later.
4856 : */
3751 tgl 4857 ECB : static void
3751 tgl 4858 CBC 500 : identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
4859 : deparse_columns *colinfo)
4860 : {
3751 tgl 4861 ECB : int numjoincols;
1186 4862 : int jcolno;
4863 : int rcolno;
3751 4864 : ListCell *lc;
4865 :
4866 : /* Extract left/right child RT indexes */
3751 tgl 4867 GIC 500 : if (IsA(j->larg, RangeTblRef))
4868 335 : colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
4869 165 : else if (IsA(j->larg, JoinExpr))
4870 165 : colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
4871 : else
3751 tgl 4872 UIC 0 : elog(ERROR, "unrecognized node type in jointree: %d",
3751 tgl 4873 ECB : (int) nodeTag(j->larg));
3751 tgl 4874 CBC 500 : if (IsA(j->rarg, RangeTblRef))
3751 tgl 4875 GIC 500 : colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
3751 tgl 4876 LBC 0 : else if (IsA(j->rarg, JoinExpr))
3751 tgl 4877 UIC 0 : colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
3751 tgl 4878 ECB : else
3751 tgl 4879 UIC 0 : elog(ERROR, "unrecognized node type in jointree: %d",
3751 tgl 4880 ECB : (int) nodeTag(j->rarg));
4881 :
4882 : /* Assert children will be processed earlier than join in second pass */
3751 tgl 4883 CBC 500 : Assert(colinfo->leftrti < j->rtindex);
3751 tgl 4884 GIC 500 : Assert(colinfo->rightrti < j->rtindex);
3751 tgl 4885 ECB :
4886 : /* Initialize result arrays with zeroes */
3751 tgl 4887 GIC 500 : numjoincols = list_length(jrte->joinaliasvars);
3751 tgl 4888 CBC 500 : Assert(numjoincols == list_length(jrte->eref->colnames));
4889 500 : colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
3751 tgl 4890 GIC 500 : colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
3751 tgl 4891 ECB :
4892 : /*
4893 : * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
4894 : * Recall that the column(s) merged due to USING are the first column(s)
4895 : * of the join output. We need not do anything special while scanning
4896 : * joinleftcols, but while scanning joinrightcols we must distinguish
4897 : * merged from unmerged columns.
4898 : */
1186 tgl 4899 GIC 500 : jcolno = 0;
1186 tgl 4900 CBC 9348 : foreach(lc, jrte->joinleftcols)
4901 : {
4902 8848 : int leftattno = lfirst_int(lc);
4903 :
4904 8848 : colinfo->leftattnos[jcolno++] = leftattno;
3751 tgl 4905 ECB : }
1186 tgl 4906 GIC 500 : rcolno = 0;
4907 4550 : foreach(lc, jrte->joinrightcols)
4908 : {
4909 4050 : int rightattno = lfirst_int(lc);
4910 :
4911 4050 : if (rcolno < jrte->joinmergedcols) /* merged column? */
4912 290 : colinfo->rightattnos[rcolno] = rightattno;
4913 : else
4914 3760 : colinfo->rightattnos[jcolno++] = rightattno;
4915 4050 : rcolno++;
4916 : }
4917 500 : Assert(jcolno == numjoincols);
3751 4918 500 : }
3751 tgl 4919 ECB :
4920 : /*
3852 4921 : * get_rtable_name: convenience function to get a previously assigned RTE alias
4922 : *
4923 : * The RTE must belong to the topmost namespace level in "context".
4924 : */
4925 : static char *
3852 tgl 4926 GIC 2564 : get_rtable_name(int rtindex, deparse_context *context)
4927 : {
4928 2564 : deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
3852 tgl 4929 ECB :
3852 tgl 4930 CBC 2564 : Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
4931 2564 : return (char *) list_nth(dpns->rtable_names, rtindex - 1);
3852 tgl 4932 ECB : }
4933 :
4653 4934 : /*
4935 : * set_deparse_plan: set up deparse_namespace to parse subexpressions
1215 4936 : * of a given Plan node
4653 4937 : *
4938 : * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
545 4939 : * and index_tlist fields. Caller must already have adjusted the ancestors
4940 : * list if necessary. Note that the rtable, subplans, and ctes fields do
4941 : * not need to change when shifting attention to different plan nodes in a
4942 : * single plan tree.
4943 : */
4944 : static void
1215 tgl 4945 GIC 49052 : set_deparse_plan(deparse_namespace *dpns, Plan *plan)
4946 : {
4947 49052 : dpns->plan = plan;
4948 :
4949 : /*
4950 : * We special-case Append and MergeAppend to pretend that the first child
4951 : * plan is the OUTER referent; we have to interpret OUTER Vars in their
4952 : * tlists according to one of the children, and the first one is the most
4953 : * natural choice.
4954 : */
1215 tgl 4955 CBC 49052 : if (IsA(plan, Append))
4956 1924 : dpns->outer_plan = linitial(((Append *) plan)->appendplans);
4957 47128 : else if (IsA(plan, MergeAppend))
4958 213 : dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
4653 tgl 4959 ECB : else
1215 tgl 4960 CBC 46915 : dpns->outer_plan = outerPlan(plan);
4653 tgl 4961 ECB :
1215 tgl 4962 GIC 49052 : if (dpns->outer_plan)
1215 tgl 4963 CBC 21939 : dpns->outer_tlist = dpns->outer_plan->targetlist;
4653 tgl 4964 ECB : else
4198 tgl 4965 GIC 27113 : dpns->outer_tlist = NIL;
5298 tgl 4966 ECB :
4967 : /*
4653 4968 : * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
4969 : * use OUTER because that could someday conflict with the normal meaning.)
4970 : * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
570 4971 : * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
4972 : * that as INNER referent.
4973 : *
4974 : * For MERGE, make the inner tlist point to the merge source tlist, which
377 alvherre 4975 : * is same as the targetlist that the ModifyTable's source plan provides.
2893 andres 4976 : * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
4977 : * excluded expression's tlist. (Similar to the SubqueryScan we don't want
4978 : * to reuse OUTER, it's used for RETURNING in some modify table cases,
4979 : * although not INSERT .. CONFLICT).
4980 : */
1215 tgl 4981 CBC 49052 : if (IsA(plan, SubqueryScan))
4982 238 : dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
4983 48814 : else if (IsA(plan, CteScan))
4984 240 : dpns->inner_plan = list_nth(dpns->subplans,
4985 240 : ((CteScan *) plan)->ctePlanId - 1);
570 tgl 4986 GBC 48574 : else if (IsA(plan, WorkTableScan))
570 tgl 4987 GIC 87 : dpns->inner_plan = find_recursive_union(dpns,
570 tgl 4988 ECB : (WorkTableScan *) plan);
1215 tgl 4989 CBC 48487 : else if (IsA(plan, ModifyTable))
1215 tgl 4990 GIC 107 : dpns->inner_plan = plan;
4991 : else
4992 48380 : dpns->inner_plan = innerPlan(plan);
4993 :
4994 49052 : if (IsA(plan, ModifyTable))
4995 : {
377 alvherre 4996 107 : if (((ModifyTable *) plan)->operation == CMD_MERGE)
354 alvherre 4997 CBC 3 : dpns->inner_tlist = dpns->outer_tlist;
4998 : else
377 alvherre 4999 GIC 104 : dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5000 : }
1215 tgl 5001 CBC 48945 : else if (dpns->inner_plan)
1215 tgl 5002 GIC 7593 : dpns->inner_tlist = dpns->inner_plan->targetlist;
4653 tgl 5003 ECB : else
4198 tgl 5004 GIC 41352 : dpns->inner_tlist = NIL;
4198 tgl 5005 ECB :
2891 5006 : /* Set up referent for INDEX_VAR Vars, if needed */
1215 tgl 5007 CBC 49052 : if (IsA(plan, IndexOnlyScan))
1215 tgl 5008 GIC 1229 : dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
1215 tgl 5009 GBC 47823 : else if (IsA(plan, ForeignScan))
1215 tgl 5010 GIC 1360 : dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5011 46463 : else if (IsA(plan, CustomScan))
1215 tgl 5012 UIC 0 : dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5013 : else
4198 tgl 5014 GIC 46463 : dpns->index_tlist = NIL;
4653 5015 49052 : }
5016 :
5017 : /*
5018 : * Locate the ancestor plan node that is the RecursiveUnion generating
5019 : * the WorkTableScan's work table. We can match on wtParam, since that
5020 : * should be unique within the plan tree.
5021 : */
5022 : static Plan *
570 5023 87 : find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
5024 : {
5025 : ListCell *lc;
5026 :
570 tgl 5027 CBC 219 : foreach(lc, dpns->ancestors)
5028 : {
570 tgl 5029 GIC 219 : Plan *ancestor = (Plan *) lfirst(lc);
5030 :
570 tgl 5031 CBC 219 : if (IsA(ancestor, RecursiveUnion) &&
570 tgl 5032 GIC 87 : ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5033 87 : return ancestor;
570 tgl 5034 ECB : }
570 tgl 5035 UIC 0 : elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5036 : wtscan->wtParam);
570 tgl 5037 ECB : return NULL;
5038 : }
5039 :
5040 : /*
5041 : * push_child_plan: temporarily transfer deparsing attention to a child plan
5042 : *
5043 : * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
4198 5044 : * deparse context in case the referenced expression itself uses
5045 : * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
5046 : * affecting levelsup issues (although in a Plan tree there really shouldn't
5047 : * be any).
5048 : *
4653 5049 : * Caller must provide a local deparse_namespace variable to save the
5050 : * previous state for pop_child_plan.
5051 : */
5052 : static void
1215 tgl 5053 GIC 26217 : push_child_plan(deparse_namespace *dpns, Plan *plan,
5054 : deparse_namespace *save_dpns)
4653 tgl 5055 ECB : {
5056 : /* Save state for restoration later */
4653 tgl 5057 GIC 26217 : *save_dpns = *dpns;
5058 :
5059 : /* Link current plan node into ancestors list */
1215 5060 26217 : dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5061 :
5062 : /* Set attention on selected child */
5063 26217 : set_deparse_plan(dpns, plan);
8089 5064 26217 : }
5065 :
5066 : /*
5067 : * pop_child_plan: undo the effects of push_child_plan
5068 : */
5069 : static void
4653 5070 26217 : pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5071 : {
5072 : List *ancestors;
5073 :
3874 tgl 5074 ECB : /* Get rid of ancestors list cell added by push_child_plan */
3874 tgl 5075 GIC 26217 : ancestors = list_delete_first(dpns->ancestors);
5076 :
4653 tgl 5077 ECB : /* Restore fields changed by push_child_plan */
4653 tgl 5078 GIC 26217 : *dpns = *save_dpns;
5079 :
3874 tgl 5080 ECB : /* Make sure dpns->ancestors is right (may be unnecessary) */
3874 tgl 5081 GIC 26217 : dpns->ancestors = ancestors;
4653 5082 26217 : }
4653 tgl 5083 ECB :
5084 : /*
5085 : * push_ancestor_plan: temporarily transfer deparsing attention to an
5086 : * ancestor plan
5087 : *
5088 : * When expanding a Param reference, we must adjust the deparse context
5089 : * to match the plan node that contains the expression being printed;
5090 : * otherwise we'd fail if that expression itself contains a Param or
5091 : * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
5092 : *
5093 : * The target ancestor is conveniently identified by the ListCell holding it
5094 : * in dpns->ancestors.
5095 : *
5096 : * Caller must provide a local deparse_namespace variable to save the
5097 : * previous state for pop_ancestor_plan.
5098 : */
5099 : static void
4653 tgl 5100 GIC 1396 : push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
4653 tgl 5101 ECB : deparse_namespace *save_dpns)
5102 : {
1215 tgl 5103 GIC 1396 : Plan *plan = (Plan *) lfirst(ancestor_cell);
5104 :
5105 : /* Save state for restoration later */
4653 5106 1396 : *save_dpns = *dpns;
5107 :
5108 : /* Build a new ancestor list with just this node's ancestors */
1364 5109 1396 : dpns->ancestors =
5110 1396 : list_copy_tail(dpns->ancestors,
1364 tgl 5111 CBC 1396 : list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5112 :
5113 : /* Set attention on selected ancestor */
1215 tgl 5114 GIC 1396 : set_deparse_plan(dpns, plan);
4653 5115 1396 : }
5116 :
5117 : /*
5118 : * pop_ancestor_plan: undo the effects of push_ancestor_plan
5119 : */
5120 : static void
5121 1396 : pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
4653 tgl 5122 ECB : {
5123 : /* Free the ancestor list made in push_ancestor_plan */
4653 tgl 5124 GIC 1396 : list_free(dpns->ancestors);
5125 :
5126 : /* Restore fields changed by push_ancestor_plan */
5127 1396 : *dpns = *save_dpns;
5128 1396 : }
5129 :
4653 tgl 5130 ECB :
8994 bruce 5131 : /* ----------
5132 : * make_ruledef - reconstruct the CREATE RULE command
5133 : * for a given pg_rewrite tuple
5134 : * ----------
5135 : */
8590 tgl 5136 : static void
7193 tgl 5137 CBC 264 : make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
7193 tgl 5138 ECB : int prettyFlags)
5139 : {
7661 5140 : char *rulename;
8986 bruce 5141 : char ev_type;
5142 : Oid ev_class;
5143 : bool is_instead;
5144 : char *ev_qual;
5145 : char *ev_action;
888 tgl 5146 : List *actions;
2085 5147 : Relation ev_relation;
2085 tgl 5148 CBC 264 : TupleDesc viewResultDesc = NULL;
5149 : int fno;
7661 tgl 5150 ECB : Datum dat;
8986 bruce 5151 : bool isnull;
5152 :
5153 : /*
5154 : * Get the attribute values from the rules tuple
5155 : */
7661 tgl 5156 CBC 264 : fno = SPI_fnumber(rulettc, "rulename");
5157 264 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5158 264 : Assert(!isnull);
7661 tgl 5159 GBC 264 : rulename = NameStr(*(DatumGetName(dat)));
5160 :
8986 bruce 5161 CBC 264 : fno = SPI_fnumber(rulettc, "ev_type");
7661 tgl 5162 GIC 264 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5163 264 : Assert(!isnull);
5164 264 : ev_type = DatumGetChar(dat);
5165 :
8986 bruce 5166 CBC 264 : fno = SPI_fnumber(rulettc, "ev_class");
7661 tgl 5167 GIC 264 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5168 264 : Assert(!isnull);
7661 tgl 5169 CBC 264 : ev_class = DatumGetObjectId(dat);
8986 bruce 5170 ECB :
8986 bruce 5171 GIC 264 : fno = SPI_fnumber(rulettc, "is_instead");
7661 tgl 5172 GBC 264 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
7661 tgl 5173 GIC 264 : Assert(!isnull);
5174 264 : is_instead = DatumGetBool(dat);
8986 bruce 5175 ECB :
8986 bruce 5176 GIC 264 : fno = SPI_fnumber(rulettc, "ev_qual");
8986 bruce 5177 CBC 264 : ev_qual = SPI_getvalue(ruletup, rulettc, fno);
888 tgl 5178 264 : Assert(ev_qual != NULL);
8986 bruce 5179 ECB :
8986 bruce 5180 CBC 264 : fno = SPI_fnumber(rulettc, "ev_action");
8986 bruce 5181 GIC 264 : ev_action = SPI_getvalue(ruletup, rulettc, fno);
888 tgl 5182 CBC 264 : Assert(ev_action != NULL);
5183 264 : actions = (List *) stringToNode(ev_action);
5184 264 : if (actions == NIL)
888 tgl 5185 UIC 0 : elog(ERROR, "invalid empty ev_action list");
8986 bruce 5186 ECB :
1539 andres 5187 CBC 264 : ev_relation = table_open(ev_class, AccessShareLock);
2085 tgl 5188 ECB :
5189 : /*
8986 bruce 5190 : * Build the rules definition text
5191 : */
7193 tgl 5192 CBC 264 : appendStringInfo(buf, "CREATE RULE %s AS",
5193 : quote_identifier(rulename));
8986 bruce 5194 EUB :
7193 tgl 5195 GBC 264 : if (prettyFlags & PRETTYFLAG_INDENT)
7188 bruce 5196 GIC 264 : appendStringInfoString(buf, "\n ON ");
5197 : else
7188 bruce 5198 UIC 0 : appendStringInfoString(buf, " ON ");
5199 :
5200 : /* The event the rule is fired for */
8986 bruce 5201 GIC 264 : switch (ev_type)
5202 : {
8986 bruce 5203 CBC 3 : case '1':
3447 rhaas 5204 3 : appendStringInfoString(buf, "SELECT");
2085 tgl 5205 3 : viewResultDesc = RelationGetDescr(ev_relation);
8994 bruce 5206 3 : break;
5207 :
8986 bruce 5208 GIC 71 : case '2':
3447 rhaas 5209 CBC 71 : appendStringInfoString(buf, "UPDATE");
8994 bruce 5210 GIC 71 : break;
5211 :
8986 5212 138 : case '3':
3447 rhaas 5213 138 : appendStringInfoString(buf, "INSERT");
8994 bruce 5214 138 : break;
5215 :
8986 bruce 5216 CBC 52 : case '4':
3447 rhaas 5217 52 : appendStringInfoString(buf, "DELETE");
8994 bruce 5218 52 : break;
5219 :
8986 bruce 5220 LBC 0 : default:
7196 tgl 5221 UIC 0 : ereport(ERROR,
5222 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5223 : errmsg("rule \"%s\" has unsupported event type %d",
5224 : rulename, ev_type)));
5225 : break;
5226 : }
8994 bruce 5227 ECB :
5228 : /* The relation the rule is fired on */
1868 tgl 5229 GIC 264 : appendStringInfo(buf, " TO %s",
5230 264 : (prettyFlags & PRETTYFLAG_SCHEMA) ?
5231 48 : generate_relation_name(ev_class, NIL) :
5232 216 : generate_qualified_relation_name(ev_class));
5233 :
8986 bruce 5234 ECB : /* If the rule has an event qualification, add it */
888 tgl 5235 GIC 264 : if (strcmp(ev_qual, "<>") != 0)
5236 : {
8986 bruce 5237 ECB : Node *qual;
5238 : Query *query;
8397 5239 : deparse_context context;
8089 tgl 5240 : deparse_namespace dpns;
8589 5241 :
7193 tgl 5242 CBC 58 : if (prettyFlags & PRETTYFLAG_INDENT)
7188 bruce 5243 58 : appendStringInfoString(buf, "\n ");
3447 rhaas 5244 58 : appendStringInfoString(buf, " WHERE ");
8994 bruce 5245 ECB :
8986 bruce 5246 CBC 58 : qual = stringToNode(ev_qual);
7804 tgl 5247 ECB :
5248 : /*
5249 : * We need to make a context for recognizing any Vars in the qual
6385 bruce 5250 : * (which can only be references to OLD and NEW). Use the rtable of
5251 : * the first query in the action list for this purpose.
7804 tgl 5252 : */
6892 neilc 5253 GIC 58 : query = (Query *) linitial(actions);
5254 :
7804 tgl 5255 ECB : /*
5256 : * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5257 : * into the SELECT, and that's what we need to look at. (Ugly kluge
6385 bruce 5258 : * ... try to fix this when we redesign querytrees.)
7804 tgl 5259 : */
7804 tgl 5260 GIC 58 : query = getInsertSelectQuery(query, NULL);
5261 :
6519 tgl 5262 ECB : /* Must acquire locks right away; see notes in get_query_def() */
3321 tgl 5263 GIC 58 : AcquireRewriteLocks(query, false, false);
5264 :
8589 5265 58 : context.buf = buf;
6888 neilc 5266 58 : context.namespaces = list_make1(&dpns);
5215 tgl 5267 CBC 58 : context.windowClause = NIL;
5268 58 : context.windowTList = NIL;
6888 neilc 5269 GIC 58 : context.varprefix = (list_length(query->rtable) != 1);
7193 tgl 5270 CBC 58 : context.prettyFlags = prettyFlags;
3758 5271 58 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
7193 tgl 5272 GIC 58 : context.indentLevel = PRETTYINDENT_STD;
2885 andres 5273 CBC 58 : context.special_exprkind = EXPR_KIND_NONE;
1215 tgl 5274 58 : context.appendparents = NULL;
5275 :
3751 tgl 5276 GBC 58 : set_deparse_for_query(&dpns, query, NIL);
5277 :
7507 tgl 5278 CBC 58 : get_rule_expr(qual, &context, false);
5279 : }
5280 :
3447 rhaas 5281 GIC 264 : appendStringInfoString(buf, " DO ");
5282 :
5283 : /* The INSTEAD keyword (if so) */
8986 bruce 5284 CBC 264 : if (is_instead)
3447 rhaas 5285 162 : appendStringInfoString(buf, "INSTEAD ");
5286 :
8986 bruce 5287 ECB : /* Finally the rules actions */
6888 neilc 5288 GIC 264 : if (list_length(actions) > 1)
5289 : {
6892 neilc 5290 ECB : ListCell *action;
8986 bruce 5291 : Query *query;
5292 :
3447 rhaas 5293 GIC 10 : appendStringInfoChar(buf, '(');
8986 bruce 5294 30 : foreach(action, actions)
5295 : {
5296 20 : query = (Query *) lfirst(action);
323 tgl 5297 20 : get_query_def(query, buf, NIL, viewResultDesc, true,
5298 : prettyFlags, WRAP_COLUMN_DEFAULT, 0);
7193 5299 20 : if (prettyFlags)
3447 rhaas 5300 CBC 20 : appendStringInfoString(buf, ";\n");
5301 : else
3447 rhaas 5302 UIC 0 : appendStringInfoString(buf, "; ");
5303 : }
3447 rhaas 5304 GIC 10 : appendStringInfoString(buf, ");");
5305 : }
5306 : else
5307 : {
5308 : Query *query;
5309 :
6892 neilc 5310 254 : query = (Query *) linitial(actions);
323 tgl 5311 254 : get_query_def(query, buf, NIL, viewResultDesc, true,
5312 : prettyFlags, WRAP_COLUMN_DEFAULT, 0);
3447 rhaas 5313 254 : appendStringInfoChar(buf, ';');
5314 : }
5315 :
1539 andres 5316 264 : table_close(ev_relation, AccessShareLock);
8994 bruce 5317 264 : }
8994 bruce 5318 ECB :
5319 :
5320 : /* ----------
5321 : * make_viewdef - reconstruct the SELECT part of a
5322 : * view rewrite rule
5323 : * ----------
5324 : */
8590 tgl 5325 : static void
7193 tgl 5326 CBC 1408 : make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5327 : int prettyFlags, int wrapColumn)
8994 bruce 5328 ECB : {
8986 5329 : Query *query;
5330 : char ev_type;
5331 : Oid ev_class;
5332 : bool is_instead;
5333 : char *ev_qual;
5334 : char *ev_action;
888 tgl 5335 : List *actions;
5336 : Relation ev_relation;
8986 bruce 5337 : int fno;
2085 tgl 5338 : Datum dat;
8986 bruce 5339 : bool isnull;
5340 :
5341 : /*
5342 : * Get the attribute values from the rules tuple
5343 : */
8986 bruce 5344 GIC 1408 : fno = SPI_fnumber(rulettc, "ev_type");
2085 tgl 5345 GBC 1408 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2085 tgl 5346 GIC 1408 : Assert(!isnull);
5347 1408 : ev_type = DatumGetChar(dat);
8986 bruce 5348 ECB :
8986 bruce 5349 GIC 1408 : fno = SPI_fnumber(rulettc, "ev_class");
2085 tgl 5350 CBC 1408 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5351 1408 : Assert(!isnull);
2085 tgl 5352 GIC 1408 : ev_class = DatumGetObjectId(dat);
5353 :
8986 bruce 5354 GBC 1408 : fno = SPI_fnumber(rulettc, "is_instead");
2085 tgl 5355 GIC 1408 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5356 1408 : Assert(!isnull);
2085 tgl 5357 CBC 1408 : is_instead = DatumGetBool(dat);
5358 :
8986 bruce 5359 1408 : fno = SPI_fnumber(rulettc, "ev_qual");
8986 bruce 5360 GIC 1408 : ev_qual = SPI_getvalue(ruletup, rulettc, fno);
888 tgl 5361 CBC 1408 : Assert(ev_qual != NULL);
5362 :
8986 bruce 5363 1408 : fno = SPI_fnumber(rulettc, "ev_action");
8986 bruce 5364 GIC 1408 : ev_action = SPI_getvalue(ruletup, rulettc, fno);
888 tgl 5365 1408 : Assert(ev_action != NULL);
5366 1408 : actions = (List *) stringToNode(ev_action);
5367 :
6888 neilc 5368 1408 : if (list_length(actions) != 1)
5369 : {
5370 : /* keep output buffer empty and leave */
8590 tgl 5371 UIC 0 : return;
5372 : }
5373 :
6892 neilc 5374 GIC 1408 : query = (Query *) linitial(actions);
5375 :
3503 kgrittn 5376 1408 : if (ev_type != '1' || !is_instead ||
7549 tgl 5377 1408 : strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5378 : {
5379 : /* keep output buffer empty and leave */
8590 tgl 5380 UIC 0 : return;
5381 : }
5382 :
1539 andres 5383 GIC 1408 : ev_relation = table_open(ev_class, AccessShareLock);
5384 :
323 tgl 5385 CBC 1408 : get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
5386 : prettyFlags, wrapColumn, 0);
3447 rhaas 5387 GIC 1408 : appendStringInfoChar(buf, ';');
5388 :
1539 andres 5389 1408 : table_close(ev_relation, AccessShareLock);
5390 : }
5391 :
5392 :
8994 bruce 5393 ECB : /* ----------
7549 tgl 5394 : * get_query_def - Parse back one query parsetree
5395 : *
5396 : * query: parsetree to be displayed
5397 : * buf: output text is appended to buf
5398 : * parentnamespace: list (initially empty) of outer-level deparse_namespace's
5399 : * resultDesc: if not NULL, the output tuple descriptor for the view
5400 : * represented by a SELECT query. We use the column names from it
5401 : * to label SELECT output columns, in preference to names in the query
5402 : * colNamesVisible: true if the surrounding context cares about the output
5403 : * column names at all (as, for example, an EXISTS() context does not);
5404 : * when false, we can suppress dummy column labels such as "?column?"
323 5405 : * prettyFlags: bitmask of PRETTYFLAG_XXX options
5406 : * wrapColumn: maximum line length, or -1 to disable wrapping
5407 : * startIndent: initial indentation amount
8994 bruce 5408 : * ----------
5409 : */
8590 tgl 5410 : static void
7549 tgl 5411 CBC 2294 : get_query_def(Query *query, StringInfo buf, List *parentnamespace,
323 tgl 5412 ECB : TupleDesc resultDesc, bool colNamesVisible,
3758 5413 : int prettyFlags, int wrapColumn, int startIndent)
8994 bruce 5414 : {
8397 5415 : deparse_context context;
8089 tgl 5416 : deparse_namespace dpns;
8955 bruce 5417 :
5418 : /* Guard against excessively long or deeply-nested queries */
3266 tgl 5419 CBC 2294 : CHECK_FOR_INTERRUPTS();
3266 tgl 5420 GIC 2294 : check_stack_depth();
3266 tgl 5421 ECB :
5422 : /*
6519 5423 : * Before we begin to examine the query, acquire locks on referenced
3260 bruce 5424 : * relations, and fix up deleted columns in JOIN RTEs. This ensures
5425 : * consistent results. Note we assume it's OK to scribble on the passed
5426 : * querytree!
3321 tgl 5427 : *
5428 : * We are only deparsing the query (we are not about to execute it), so we
5429 : * only need AccessShareLock on the relations it mentions.
5430 : */
3321 tgl 5431 CBC 2294 : AcquireRewriteLocks(query, false, false);
6519 tgl 5432 ECB :
8589 tgl 5433 CBC 2294 : context.buf = buf;
6892 neilc 5434 GIC 2294 : context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5215 tgl 5435 CBC 2294 : context.windowClause = NIL;
5436 2294 : context.windowTList = NIL;
8089 5437 3976 : context.varprefix = (parentnamespace != NIL ||
6888 neilc 5438 GIC 1682 : list_length(query->rtable) != 1);
7193 tgl 5439 CBC 2294 : context.prettyFlags = prettyFlags;
3758 5440 2294 : context.wrapColumn = wrapColumn;
7193 5441 2294 : context.indentLevel = startIndent;
2885 andres 5442 GIC 2294 : context.special_exprkind = EXPR_KIND_NONE;
1215 tgl 5443 CBC 2294 : context.appendparents = NULL;
7193 tgl 5444 ECB :
3751 tgl 5445 CBC 2294 : set_deparse_for_query(&dpns, query, parentnamespace);
5446 :
8986 bruce 5447 GBC 2294 : switch (query->commandType)
8986 bruce 5448 EUB : {
8720 bruce 5449 GIC 2004 : case CMD_SELECT:
323 tgl 5450 2004 : get_select_query_def(query, &context, resultDesc, colNamesVisible);
8986 bruce 5451 2004 : break;
8986 bruce 5452 ECB :
8986 bruce 5453 GIC 65 : case CMD_UPDATE:
323 tgl 5454 65 : get_update_query_def(query, &context, colNamesVisible);
8986 bruce 5455 65 : break;
5456 :
5457 161 : case CMD_INSERT:
323 tgl 5458 161 : get_insert_query_def(query, &context, colNamesVisible);
8986 bruce 5459 CBC 161 : break;
5460 :
5461 38 : case CMD_DELETE:
323 tgl 5462 38 : get_delete_query_def(query, &context, colNamesVisible);
8986 bruce 5463 GIC 38 : break;
5464 :
8986 bruce 5465 CBC 18 : case CMD_NOTHING:
3447 rhaas 5466 GIC 18 : appendStringInfoString(buf, "NOTHING");
8986 bruce 5467 CBC 18 : break;
5468 :
8131 tgl 5469 8 : case CMD_UTILITY:
5470 8 : get_utility_query_def(query, &context);
8131 tgl 5471 GIC 8 : break;
5472 :
8986 bruce 5473 LBC 0 : default:
7196 tgl 5474 0 : elog(ERROR, "unrecognized query command type: %d",
5475 : query->commandType);
8986 bruce 5476 ECB : break;
5477 : }
8994 bruce 5478 CBC 2294 : }
8994 bruce 5479 ECB :
5480 : /* ----------
6094 mail 5481 : * get_values_def - Parse back a VALUES list
5482 : * ----------
5483 : */
5484 : static void
6094 mail 5485 GIC 130 : get_values_def(List *values_lists, deparse_context *context)
6094 mail 5486 ECB : {
6094 mail 5487 GIC 130 : StringInfo buf = context->buf;
5488 130 : bool first_list = true;
5489 : ListCell *vtl;
5490 :
6094 mail 5491 CBC 130 : appendStringInfoString(buf, "VALUES ");
5492 :
5493 374 : foreach(vtl, values_lists)
5494 : {
5495 244 : List *sublist = (List *) lfirst(vtl);
6094 mail 5496 GIC 244 : bool first_col = true;
5497 : ListCell *lc;
5498 :
5499 244 : if (first_list)
5500 130 : first_list = false;
5501 : else
6094 mail 5502 CBC 114 : appendStringInfoString(buf, ", ");
5503 :
5504 244 : appendStringInfoChar(buf, '(');
6094 mail 5505 GIC 955 : foreach(lc, sublist)
5506 : {
6031 bruce 5507 711 : Node *col = (Node *) lfirst(lc);
6094 mail 5508 ECB :
6094 mail 5509 CBC 711 : if (first_col)
6094 mail 5510 GIC 244 : first_col = false;
6094 mail 5511 ECB : else
6094 mail 5512 GIC 467 : appendStringInfoChar(buf, ',');
6094 mail 5513 ECB :
5514 : /*
5515 : * Print the value. Whole-row Vars need special treatment.
5516 : */
2440 tgl 5517 CBC 711 : get_rule_expr_toplevel(col, context, false);
6094 mail 5518 ECB : }
6094 mail 5519 GIC 244 : appendStringInfoChar(buf, ')');
6094 mail 5520 ECB : }
6094 mail 5521 CBC 130 : }
5522 :
5300 tgl 5523 ECB : /* ----------
5524 : * get_with_clause - Parse back a WITH clause
5525 : * ----------
5526 : */
5527 : static void
5300 tgl 5528 GIC 2268 : get_with_clause(Query *query, deparse_context *context)
5300 tgl 5529 ECB : {
5300 tgl 5530 GIC 2268 : StringInfo buf = context->buf;
5531 : const char *sep;
5050 bruce 5532 ECB : ListCell *l;
5300 tgl 5533 :
5300 tgl 5534 GIC 2268 : if (query->cteList == NIL)
5300 tgl 5535 CBC 2226 : return;
5300 tgl 5536 ECB :
5300 tgl 5537 GIC 42 : if (PRETTY_INDENT(context))
5300 tgl 5538 ECB : {
5300 tgl 5539 CBC 42 : context->indentLevel += PRETTYINDENT_STD;
5540 42 : appendStringInfoChar(buf, ' ');
5541 : }
5300 tgl 5542 ECB :
5300 tgl 5543 GIC 42 : if (query->hasRecursive)
5300 tgl 5544 CBC 28 : sep = "WITH RECURSIVE ";
5300 tgl 5545 ECB : else
5300 tgl 5546 GIC 14 : sep = "WITH ";
5300 tgl 5547 CBC 100 : foreach(l, query->cteList)
5300 tgl 5548 ECB : {
5300 tgl 5549 CBC 58 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5300 tgl 5550 ECB :
5300 tgl 5551 CBC 58 : appendStringInfoString(buf, sep);
5300 tgl 5552 GBC 58 : appendStringInfoString(buf, quote_identifier(cte->ctename));
5553 58 : if (cte->aliascolnames)
5300 tgl 5554 EUB : {
5300 tgl 5555 GIC 22 : bool first = true;
5300 tgl 5556 ECB : ListCell *col;
5557 :
5300 tgl 5558 CBC 22 : appendStringInfoChar(buf, '(');
5559 62 : foreach(col, cte->aliascolnames)
5560 : {
5300 tgl 5561 GIC 40 : if (first)
5562 22 : first = false;
5300 tgl 5563 ECB : else
5300 tgl 5564 CBC 18 : appendStringInfoString(buf, ", ");
5565 40 : appendStringInfoString(buf,
5300 tgl 5566 GIC 40 : quote_identifier(strVal(lfirst(col))));
5300 tgl 5567 ECB : }
5300 tgl 5568 GIC 22 : appendStringInfoChar(buf, ')');
5300 tgl 5569 ECB : }
1513 tgl 5570 GIC 58 : appendStringInfoString(buf, " AS ");
5571 58 : switch (cte->ctematerialized)
1513 tgl 5572 ECB : {
1513 tgl 5573 CBC 52 : case CTEMaterializeDefault:
1513 tgl 5574 GIC 52 : break;
1513 tgl 5575 CBC 6 : case CTEMaterializeAlways:
1513 tgl 5576 GIC 6 : appendStringInfoString(buf, "MATERIALIZED ");
1513 tgl 5577 CBC 6 : break;
1513 tgl 5578 LBC 0 : case CTEMaterializeNever:
1513 tgl 5579 UIC 0 : appendStringInfoString(buf, "NOT MATERIALIZED ");
1513 tgl 5580 LBC 0 : break;
1513 tgl 5581 ECB : }
1513 tgl 5582 CBC 58 : appendStringInfoChar(buf, '(');
5300 tgl 5583 GIC 58 : if (PRETTY_INDENT(context))
5584 58 : appendContextKeyword(context, "", 0, 0, 0);
5300 tgl 5585 CBC 58 : get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5586 : true,
5587 : context->prettyFlags, context->wrapColumn,
3758 tgl 5588 ECB : context->indentLevel);
5300 tgl 5589 GIC 58 : if (PRETTY_INDENT(context))
5300 tgl 5590 CBC 58 : appendContextKeyword(context, "", 0, 0, 0);
5300 tgl 5591 GIC 58 : appendStringInfoChar(buf, ')');
5592 :
797 peter 5593 CBC 58 : if (cte->search_clause)
5594 : {
5595 3 : bool first = true;
5596 : ListCell *lc;
797 peter 5597 ECB :
797 peter 5598 CBC 3 : appendStringInfo(buf, " SEARCH %s FIRST BY ",
797 peter 5599 GIC 3 : cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
797 peter 5600 ECB :
797 peter 5601 CBC 9 : foreach(lc, cte->search_clause->search_col_list)
797 peter 5602 ECB : {
797 peter 5603 GIC 6 : if (first)
5604 3 : first = false;
797 peter 5605 ECB : else
797 peter 5606 GIC 3 : appendStringInfoString(buf, ", ");
5607 6 : appendStringInfoString(buf,
797 peter 5608 CBC 6 : quote_identifier(strVal(lfirst(lc))));
797 peter 5609 ECB : }
5610 :
797 peter 5611 CBC 3 : appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
797 peter 5612 ECB : }
5613 :
797 peter 5614 CBC 58 : if (cte->cycle_clause)
797 peter 5615 ECB : {
797 peter 5616 CBC 6 : bool first = true;
797 peter 5617 ECB : ListCell *lc;
5618 :
797 peter 5619 GIC 6 : appendStringInfoString(buf, " CYCLE ");
5620 :
797 peter 5621 CBC 18 : foreach(lc, cte->cycle_clause->cycle_col_list)
5622 : {
797 peter 5623 GIC 12 : if (first)
797 peter 5624 CBC 6 : first = false;
5625 : else
797 peter 5626 GIC 6 : appendStringInfoString(buf, ", ");
797 peter 5627 CBC 12 : appendStringInfoString(buf,
797 peter 5628 GIC 12 : quote_identifier(strVal(lfirst(lc))));
797 peter 5629 ECB : }
5630 :
797 peter 5631 GIC 6 : appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5632 :
771 peter 5633 EUB : {
771 peter 5634 GIC 6 : Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5635 6 : Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5636 :
5637 9 : if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5638 3 : cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5639 : {
5640 3 : appendStringInfoString(buf, " TO ");
771 peter 5641 CBC 3 : get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
771 peter 5642 GIC 3 : appendStringInfoString(buf, " DEFAULT ");
5643 3 : get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
771 peter 5644 ECB : }
5645 : }
5646 :
797 peter 5647 GIC 6 : appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5648 : }
5649 :
5300 tgl 5650 58 : sep = ", ";
5300 tgl 5651 ECB : }
5652 :
5300 tgl 5653 GIC 42 : if (PRETTY_INDENT(context))
5300 tgl 5654 ECB : {
5300 tgl 5655 CBC 42 : context->indentLevel -= PRETTYINDENT_STD;
5656 42 : appendContextKeyword(context, "", 0, 0, 0);
5300 tgl 5657 ECB : }
5658 : else
5300 tgl 5659 UIC 0 : appendStringInfoChar(buf, ' ');
5660 : }
5661 :
5662 : /* ----------
5663 : * get_select_query_def - Parse back a SELECT parsetree
8994 bruce 5664 ECB : * ----------
5665 : */
8590 tgl 5666 : static void
7549 tgl 5667 GIC 2004 : get_select_query_def(Query *query, deparse_context *context,
5668 : TupleDesc resultDesc, bool colNamesVisible)
8221 tgl 5669 ECB : {
8221 tgl 5670 GIC 2004 : StringInfo buf = context->buf;
5671 : List *save_windowclause;
5672 : List *save_windowtlist;
8029 tgl 5673 ECB : bool force_colno;
6892 neilc 5674 : ListCell *l;
5675 :
5676 : /* Insert the WITH clause if given */
5300 tgl 5677 GIC 2004 : get_with_clause(query, context);
5300 tgl 5678 ECB :
5679 : /* Set up context for possible window functions */
5215 tgl 5680 CBC 2004 : save_windowclause = context->windowClause;
5215 tgl 5681 GIC 2004 : context->windowClause = query->windowClause;
5215 tgl 5682 CBC 2004 : save_windowtlist = context->windowTList;
5215 tgl 5683 GIC 2004 : context->windowTList = query->targetList;
5684 :
5685 : /*
5686 : * If the Query node has a setOperations tree, then it's the top level of
5687 : * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5688 : * fields are interesting in the top query itself.
5689 : */
8221 tgl 5690 CBC 2004 : if (query->setOperations)
5691 : {
323 5692 70 : get_setop_query(query->setOperations, query, context, resultDesc,
5693 : colNamesVisible);
8221 tgl 5694 ECB : /* ORDER BY clauses must be simple in this case */
8029 tgl 5695 GIC 70 : force_colno = true;
8221 tgl 5696 ECB : }
5697 : else
5698 : {
323 tgl 5699 GIC 1934 : get_basic_select_query(query, context, resultDesc, colNamesVisible);
8029 tgl 5700 CBC 1934 : force_colno = false;
5701 : }
8221 tgl 5702 ECB :
5703 : /* Add the ORDER BY clause if given */
8221 tgl 5704 GIC 2004 : if (query->sortClause != NIL)
5705 : {
7188 bruce 5706 64 : appendContextKeyword(context, " ORDER BY ",
7188 bruce 5707 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5215 tgl 5708 GIC 64 : get_rule_orderby(query->sortClause, query->targetList,
5215 tgl 5709 ECB : force_colno, context);
8221 5710 : }
8200 5711 :
5712 : /*
1097 alvherre 5713 : * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5714 : * standard spelling of LIMIT.
5715 : */
8200 tgl 5716 GIC 2004 : if (query->limitOffset != NULL)
5717 : {
7193 tgl 5718 CBC 16 : appendContextKeyword(context, " OFFSET ",
5719 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
7507 5720 16 : get_rule_expr(query->limitOffset, context, false);
5721 : }
8200 5722 2004 : if (query->limitCount != NULL)
5723 : {
1097 alvherre 5724 GIC 35 : if (query->limitOption == LIMIT_OPTION_WITH_TIES)
1097 alvherre 5725 ECB : {
1097 alvherre 5726 GBC 16 : appendContextKeyword(context, " FETCH FIRST ",
5727 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
7507 tgl 5728 CBC 16 : get_rule_expr(query->limitCount, context, false);
906 drowley 5729 GIC 16 : appendStringInfoString(buf, " ROWS WITH TIES");
1097 alvherre 5730 EUB : }
5731 : else
5732 : {
1097 alvherre 5733 GIC 19 : appendContextKeyword(context, " LIMIT ",
5734 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
1097 alvherre 5735 GBC 19 : if (IsA(query->limitCount, Const) &&
5736 8 : ((Const *) query->limitCount)->constisnull)
1097 alvherre 5737 GIC 8 : appendStringInfoString(buf, "ALL");
1097 alvherre 5738 EUB : else
1097 alvherre 5739 GBC 11 : get_rule_expr(query->limitCount, context, false);
1097 alvherre 5740 EUB : }
5741 : }
6523 tgl 5742 :
3728 alvherre 5743 : /* Add FOR [KEY] UPDATE/SHARE clauses if present */
4911 tgl 5744 GBC 2004 : if (query->hasForUpdate)
5745 : {
5746 6 : foreach(l, query->rowMarks)
4911 tgl 5747 ECB : {
4911 tgl 5748 CBC 3 : RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5749 :
4911 tgl 5750 ECB : /* don't print implicit clauses */
4911 tgl 5751 GIC 3 : if (rc->pushedDown)
4911 tgl 5752 UIC 0 : continue;
4911 tgl 5753 ECB :
3728 alvherre 5754 CBC 3 : switch (rc->strength)
5755 : {
2947 tgl 5756 LBC 0 : case LCS_NONE:
2947 tgl 5757 EUB : /* we intentionally throw an error for LCS_NONE */
2947 tgl 5758 LBC 0 : elog(ERROR, "unrecognized LockClauseStrength %d",
2947 tgl 5759 EUB : (int) rc->strength);
5760 : break;
3728 alvherre 5761 UIC 0 : case LCS_FORKEYSHARE:
5762 0 : appendContextKeyword(context, " FOR KEY SHARE",
2118 tgl 5763 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
3728 alvherre 5764 LBC 0 : break;
5765 0 : case LCS_FORSHARE:
3728 alvherre 5766 UIC 0 : appendContextKeyword(context, " FOR SHARE",
5767 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5768 0 : break;
5769 0 : case LCS_FORNOKEYUPDATE:
5770 0 : appendContextKeyword(context, " FOR NO KEY UPDATE",
5771 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5772 0 : break;
3728 alvherre 5773 CBC 3 : case LCS_FORUPDATE:
3728 alvherre 5774 GIC 3 : appendContextKeyword(context, " FOR UPDATE",
2118 tgl 5775 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
3728 alvherre 5776 GIC 3 : break;
5777 : }
5778 :
4911 tgl 5779 3 : appendStringInfo(buf, " OF %s",
3852 5780 3 : quote_identifier(get_rtable_name(rc->rti,
5781 : context)));
3106 alvherre 5782 3 : if (rc->waitPolicy == LockWaitError)
3447 rhaas 5783 LBC 0 : appendStringInfoString(buf, " NOWAIT");
3106 alvherre 5784 GIC 3 : else if (rc->waitPolicy == LockWaitSkip)
3106 alvherre 5785 LBC 0 : appendStringInfoString(buf, " SKIP LOCKED");
5786 : }
6523 tgl 5787 ECB : }
5788 :
5215 tgl 5789 CBC 2004 : context->windowClause = save_windowclause;
5790 2004 : context->windowTList = save_windowtlist;
8221 5791 2004 : }
5792 :
3885 tgl 5793 ECB : /*
1240 5794 : * Detect whether query looks like SELECT ... FROM VALUES(),
5795 : * with no need to rename the output columns of the VALUES RTE.
5796 : * If so, return the VALUES RTE. Otherwise return NULL.
5797 : */
5798 : static RangeTblEntry *
1240 tgl 5799 GIC 1934 : get_simple_values_rte(Query *query, TupleDesc resultDesc)
5800 : {
3885 5801 1934 : RangeTblEntry *result = NULL;
5802 : ListCell *lc;
5803 :
5804 : /*
5805 : * We want to detect a match even if the Query also contains OLD or NEW
5806 : * rule RTEs. So the idea is to scan the rtable and see if there is only
5807 : * one inFromCl RTE that is a VALUES RTE.
3885 tgl 5808 ECB : */
3885 tgl 5809 GIC 2105 : foreach(lc, query->rtable)
5810 : {
5811 1756 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
5812 :
3885 tgl 5813 CBC 1756 : if (rte->rtekind == RTE_VALUES && rte->inFromCl)
3885 tgl 5814 EUB : {
3885 tgl 5815 CBC 111 : if (result)
5816 1585 : return NULL; /* multiple VALUES (probably not possible) */
3885 tgl 5817 GIC 111 : result = rte;
3885 tgl 5818 ECB : }
3885 tgl 5819 CBC 1645 : else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
3885 tgl 5820 GIC 60 : continue; /* ignore rule entries */
5821 : else
3885 tgl 5822 CBC 1585 : return NULL; /* something else -> not simple VALUES */
3885 tgl 5823 ECB : }
5824 :
5825 : /*
2965 5826 : * We don't need to check the targetlist in any great detail, because
5827 : * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
5828 : * appear inside auto-generated sub-queries with very restricted
5829 : * structure. However, DefineView might have modified the tlist by
1240 5830 : * injecting new column aliases, or we might have some other column
5831 : * aliases forced by a resultDesc. We can only simplify if the RTE's
5832 : * column names match the names that get_target_list() would select.
2965 5833 : */
2965 tgl 5834 CBC 349 : if (result)
5835 : {
5836 : ListCell *lcn;
5837 : int colno;
2965 tgl 5838 ECB :
2965 tgl 5839 GIC 111 : if (list_length(query->targetList) != list_length(result->eref->colnames))
2965 tgl 5840 UIC 0 : return NULL; /* this probably cannot happen */
1240 tgl 5841 GIC 111 : colno = 0;
2965 tgl 5842 CBC 415 : forboth(lc, query->targetList, lcn, result->eref->colnames)
5843 : {
2965 tgl 5844 GIC 310 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
2965 tgl 5845 CBC 310 : char *cname = strVal(lfirst(lcn));
5846 : char *colname;
5847 :
2965 tgl 5848 GIC 310 : if (tle->resjunk)
5849 6 : return NULL; /* this probably cannot happen */
1240 tgl 5850 ECB :
5851 : /* compute name that get_target_list would use for column */
1240 tgl 5852 CBC 310 : colno++;
5853 310 : if (resultDesc && colno <= resultDesc->natts)
1240 tgl 5854 GIC 15 : colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
5855 : else
5856 295 : colname = tle->resname;
5857 :
5858 : /* does it match the VALUES RTE? */
5859 310 : if (colname == NULL || strcmp(colname, cname) != 0)
2965 5860 6 : return NULL; /* column name has been changed */
2965 tgl 5861 ECB : }
5862 : }
5863 :
3885 tgl 5864 CBC 343 : return result;
3885 tgl 5865 ECB : }
5866 :
5867 : static void
7549 tgl 5868 GIC 1934 : get_basic_select_query(Query *query, deparse_context *context,
5869 : TupleDesc resultDesc, bool colNamesVisible)
5870 : {
8589 tgl 5871 CBC 1934 : StringInfo buf = context->buf;
3885 tgl 5872 ECB : RangeTblEntry *values_rte;
5873 : char *sep;
6892 neilc 5874 : ListCell *l;
5875 :
7193 tgl 5876 GIC 1934 : if (PRETTY_INDENT(context))
7193 tgl 5877 ECB : {
7188 bruce 5878 GIC 1912 : context->indentLevel += PRETTYINDENT_STD;
7188 bruce 5879 GBC 1912 : appendStringInfoChar(buf, ' ');
5880 : }
6094 mail 5881 EUB :
5882 : /*
6031 bruce 5883 : * If the query looks like SELECT * FROM (VALUES ...), then print just the
5884 : * VALUES part. This reverses what transformValuesClause() did at parse
3885 tgl 5885 : * time.
5886 : */
1240 tgl 5887 GBC 1934 : values_rte = get_simple_values_rte(query, resultDesc);
3885 5888 1934 : if (values_rte)
5889 : {
5890 105 : get_values_def(values_rte->values_lists, context);
3885 tgl 5891 GIC 105 : return;
6094 mail 5892 EUB : }
5893 :
5894 : /*
5895 : * Build up the query string - first we say SELECT
5896 : */
732 peter 5897 GIC 1829 : if (query->isReturn)
5898 25 : appendStringInfoString(buf, "RETURN");
732 peter 5899 ECB : else
732 peter 5900 GIC 1804 : appendStringInfoString(buf, "SELECT");
5901 :
8221 tgl 5902 ECB : /* Add the DISTINCT clause if given */
8221 tgl 5903 GIC 1829 : if (query->distinctClause != NIL)
5904 : {
5363 tgl 5905 LBC 0 : if (query->hasDistinctOn)
5906 : {
3447 rhaas 5907 0 : appendStringInfoString(buf, " DISTINCT ON (");
8221 tgl 5908 UIC 0 : sep = "";
8221 tgl 5909 LBC 0 : foreach(l, query->distinctClause)
5910 : {
5363 tgl 5911 UIC 0 : SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5912 :
6553 neilc 5913 LBC 0 : appendStringInfoString(buf, sep);
2885 andres 5914 UIC 0 : get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList,
5915 : false, context);
8221 tgl 5916 0 : sep = ", ";
8221 tgl 5917 ECB : }
3447 rhaas 5918 UIC 0 : appendStringInfoChar(buf, ')');
8221 tgl 5919 ECB : }
7922 tgl 5920 EUB : else
3447 rhaas 5921 UIC 0 : appendStringInfoString(buf, " DISTINCT");
8221 tgl 5922 ECB : }
5923 :
5924 : /* Then we tell what to select (the targetlist) */
323 tgl 5925 CBC 1829 : get_target_list(query->targetList, context, resultDesc, colNamesVisible);
5926 :
6084 tgl 5927 ECB : /* Add the FROM clause if needed */
6084 tgl 5928 CBC 1829 : get_from_clause(query, " FROM ", context);
5929 :
6084 tgl 5930 ECB : /* Add the WHERE clause if given */
6084 tgl 5931 GIC 1829 : if (query->jointree->quals != NULL)
6084 tgl 5932 ECB : {
6084 tgl 5933 CBC 534 : appendContextKeyword(context, " WHERE ",
5934 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5935 534 : get_rule_expr(query->jointree->quals, context, false);
5936 : }
5937 :
5938 : /* Add the GROUP BY clause if given */
2885 andres 5939 GIC 1829 : if (query->groupClause != NULL || query->groupingSets != NULL)
6084 tgl 5940 ECB : {
2878 bruce 5941 : ParseExprKind save_exprkind;
5942 :
6084 tgl 5943 CBC 37 : appendContextKeyword(context, " GROUP BY ",
5944 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
752 tomas.vondra 5945 37 : if (query->groupDistinct)
752 tomas.vondra 5946 LBC 0 : appendStringInfoString(buf, "DISTINCT ");
2885 andres 5947 ECB :
2885 andres 5948 GIC 37 : save_exprkind = context->special_exprkind;
5949 37 : context->special_exprkind = EXPR_KIND_GROUP_BY;
5950 :
2885 andres 5951 CBC 37 : if (query->groupingSets == NIL)
5952 : {
2885 andres 5953 GIC 34 : sep = "";
5954 85 : foreach(l, query->groupClause)
2885 andres 5955 ECB : {
2885 andres 5956 GIC 51 : SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6084 tgl 5957 ECB :
2885 andres 5958 GIC 51 : appendStringInfoString(buf, sep);
2885 andres 5959 CBC 51 : get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList,
5960 : false, context);
2885 andres 5961 GIC 51 : sep = ", ";
5962 : }
6084 tgl 5963 ECB : }
2885 andres 5964 : else
5965 : {
2885 andres 5966 GIC 3 : sep = "";
5967 6 : foreach(l, query->groupingSets)
5968 : {
5969 3 : GroupingSet *grp = lfirst(l);
5970 :
5971 3 : appendStringInfoString(buf, sep);
5972 3 : get_rule_groupingset(grp, query->targetList, true, context);
5973 3 : sep = ", ";
5974 : }
5975 : }
2885 andres 5976 ECB :
2885 andres 5977 GIC 37 : context->special_exprkind = save_exprkind;
5978 : }
6084 tgl 5979 ECB :
5980 : /* Add the HAVING clause if given */
6084 tgl 5981 CBC 1829 : if (query->havingQual != NULL)
5982 : {
6084 tgl 5983 GIC 5 : appendContextKeyword(context, " HAVING ",
5984 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5985 5 : get_rule_expr(query->havingQual, context, false);
5986 : }
5215 tgl 5987 ECB :
5988 : /* Add the WINDOW clause if needed */
5215 tgl 5989 CBC 1829 : if (query->windowClause != NIL)
5990 21 : get_rule_windowclause(query, context);
6084 tgl 5991 ECB : }
5992 :
5993 : /* ----------
5994 : * get_target_list - Parse back a SELECT target list
5995 : *
5996 : * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
323 5997 : *
5998 : * resultDesc and colNamesVisible are as for get_query_def()
5999 : * ----------
6084 6000 : */
6001 : static void
6084 tgl 6002 CBC 1887 : get_target_list(List *targetList, deparse_context *context,
6003 : TupleDesc resultDesc, bool colNamesVisible)
6004 : {
6084 tgl 6005 GIC 1887 : StringInfo buf = context->buf;
6006 : StringInfoData targetbuf;
3758 6007 1887 : bool last_was_multiline = false;
6084 tgl 6008 ECB : char *sep;
6009 : int colno;
6010 : ListCell *l;
6011 :
6012 : /* we use targetbuf to hold each TLE's text temporarily */
3758 tgl 6013 GIC 1887 : initStringInfo(&targetbuf);
6014 :
8994 bruce 6015 1887 : sep = " ";
7549 tgl 6016 1887 : colno = 0;
6084 6017 8180 : foreach(l, targetList)
6018 : {
8244 6019 6293 : TargetEntry *tle = (TargetEntry *) lfirst(l);
6020 : char *colname;
6282 tgl 6021 ECB : char *attname;
6022 :
6577 tgl 6023 CBC 6293 : if (tle->resjunk)
8227 tgl 6024 GIC 20 : continue; /* ignore junk entries */
6025 :
6553 neilc 6026 6273 : appendStringInfoString(buf, sep);
8986 bruce 6027 CBC 6273 : sep = ", ";
7549 tgl 6028 GIC 6273 : colno++;
6029 :
6030 : /*
6031 : * Put the new field text into targetbuf so we can decide after we've
6032 : * got it whether or not it needs to go on a new line.
6033 : */
3758 tgl 6034 CBC 6273 : resetStringInfo(&targetbuf);
4067 andrew 6035 GIC 6273 : context->buf = &targetbuf;
6036 :
6037 : /*
6038 : * We special-case Var nodes rather than using get_rule_expr. This is
6039 : * needed because get_rule_expr will display a whole-row Var as
6040 : * "foo.*", which is the preferred notation in most contexts, but at
6041 : * the top level of a SELECT list it's not right (the parser will
6042 : * expand that notation into multiple columns, yielding behavior
3999 tgl 6043 ECB : * different from a whole-row Var). We need to call get_variable
2702 6044 : * directly so that we can tell it to do the right thing, and so that
6045 : * we can get the attribute name which is the default AS label.
6282 6046 : */
2885 andres 6047 GIC 6273 : if (tle->expr && (IsA(tle->expr, Var)))
6048 : {
3999 tgl 6049 CBC 4813 : attname = get_variable((Var *) tle->expr, 0, true, context);
6050 : }
6282 tgl 6051 ECB : else
6052 : {
6282 tgl 6053 GIC 1460 : get_rule_expr((Node *) tle->expr, context, true);
6054 :
6055 : /*
323 tgl 6056 ECB : * When colNamesVisible is true, we should always show the
6057 : * assigned column name explicitly. Otherwise, show it only if
6058 : * it's not FigureColname's fallback.
6059 : */
323 tgl 6060 GIC 1460 : attname = colNamesVisible ? NULL : "?column?";
6061 : }
6062 :
6063 : /*
3260 bruce 6064 ECB : * Figure out what the result column should be called. In the context
6385 6065 : * of a view, use the view's tuple descriptor (so as to pick up the
6066 : * effects of any column RENAME that's been done on the view).
6067 : * Otherwise, just use what we can find in the TLE.
6068 : */
7549 tgl 6069 GIC 6273 : if (resultDesc && colno <= resultDesc->natts)
2058 andres 6070 CBC 5681 : colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6071 : else
6577 tgl 6072 GIC 592 : colname = tle->resname;
7549 tgl 6073 ECB :
6074 : /* Show AS unless the column's name is correct as-is */
7181 tgl 6075 GIC 6273 : if (colname) /* resname could be NULL */
6076 : {
6282 6077 6248 : if (attname == NULL || strcmp(attname, colname) != 0)
4067 andrew 6078 1941 : appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6079 : }
4067 andrew 6080 ECB :
3758 tgl 6081 : /* Restore context's output buffer */
4067 andrew 6082 CBC 6273 : context->buf = buf;
6083 :
3758 tgl 6084 ECB : /* Consider line-wrapping if enabled */
3758 tgl 6085 GIC 6273 : if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6086 : {
6087 : int leading_nl_pos;
6088 :
6089 : /* Does the new field start with a new line? */
3436 6090 6251 : if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
3436 tgl 6091 CBC 111 : leading_nl_pos = 0;
3436 tgl 6092 ECB : else
3436 tgl 6093 GIC 6140 : leading_nl_pos = -1;
3436 tgl 6094 ECB :
6095 : /* If so, we shouldn't add anything */
3436 tgl 6096 GIC 6251 : if (leading_nl_pos >= 0)
6097 : {
6098 : /* instead, remove any trailing spaces currently in buf */
3436 tgl 6099 CBC 111 : removeStringInfoSpaces(buf);
4067 andrew 6100 ECB : }
6101 : else
6102 : {
6103 : char *trailing_nl;
6104 :
6105 : /* Locate the start of the current line in the output buffer */
3436 tgl 6106 GIC 6140 : trailing_nl = strrchr(buf->data, '\n');
6107 6140 : if (trailing_nl == NULL)
3436 tgl 6108 CBC 2229 : trailing_nl = buf->data;
3436 tgl 6109 ECB : else
3436 tgl 6110 GIC 3911 : trailing_nl++;
6111 :
3436 tgl 6112 ECB : /*
6113 : * Add a newline, plus some indentation, if the new field is
6114 : * not the first and either the new field would cause an
6115 : * overflow or the last field used more than one line.
6116 : */
3436 tgl 6117 GIC 6140 : if (colno > 1 &&
6118 4283 : ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
3436 tgl 6119 ECB : last_was_multiline))
3436 tgl 6120 CBC 4283 : appendContextKeyword(context, "", -PRETTYINDENT_STD,
6121 : PRETTYINDENT_STD, PRETTYINDENT_VAR);
3436 tgl 6122 ECB : }
6123 :
3758 6124 : /* Remember this field's multiline status for next iteration */
3758 tgl 6125 CBC 6251 : last_was_multiline =
6126 6251 : (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6127 : }
4067 andrew 6128 ECB :
6129 : /* Add the new field */
1356 drowley 6130 GIC 6273 : appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
8994 bruce 6131 ECB : }
3758 tgl 6132 :
6133 : /* clean up */
3758 tgl 6134 CBC 1887 : pfree(targetbuf.data);
8221 6135 1887 : }
8221 tgl 6136 ECB :
8221 tgl 6137 EUB : static void
7549 tgl 6138 CBC 276 : get_setop_query(Node *setOp, Query *query, deparse_context *context,
6139 : TupleDesc resultDesc, bool colNamesVisible)
6140 : {
8221 tgl 6141 GIC 276 : StringInfo buf = context->buf;
6851 tgl 6142 ECB : bool need_paren;
8221 tgl 6143 EUB :
6144 : /* Guard against excessively long or deeply-nested queries */
3266 tgl 6145 CBC 276 : CHECK_FOR_INTERRUPTS();
3266 tgl 6146 GIC 276 : check_stack_depth();
3266 tgl 6147 ECB :
8221 tgl 6148 GIC 276 : if (IsA(setOp, RangeTblRef))
6149 : {
6150 173 : RangeTblRef *rtr = (RangeTblRef *) setOp;
6151 173 : RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
8053 bruce 6152 173 : Query *subquery = rte->subquery;
6153 :
8221 tgl 6154 173 : Assert(subquery != NULL);
6851 6155 173 : Assert(subquery->setOperations == NULL);
6156 : /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
5300 6157 519 : need_paren = (subquery->cteList ||
6158 173 : subquery->sortClause ||
6851 6159 173 : subquery->rowMarks ||
6160 519 : subquery->limitOffset ||
6851 tgl 6161 CBC 173 : subquery->limitCount);
6851 tgl 6162 GIC 173 : if (need_paren)
6851 tgl 6163 LBC 0 : appendStringInfoChar(buf, '(');
7193 tgl 6164 GIC 173 : get_query_def(subquery, buf, context->namespaces, resultDesc,
323 tgl 6165 ECB : colNamesVisible,
3758 6166 : context->prettyFlags, context->wrapColumn,
6167 : context->indentLevel);
6851 tgl 6168 GBC 173 : if (need_paren)
6851 tgl 6169 UIC 0 : appendStringInfoChar(buf, ')');
6170 : }
8221 tgl 6171 CBC 103 : else if (IsA(setOp, SetOperationStmt))
6172 : {
6173 103 : SetOperationStmt *op = (SetOperationStmt *) setOp;
6174 : int subindent;
5300 tgl 6175 EUB :
6851 6176 : /*
3266 6177 : * We force parens when nesting two SetOperationStmts, except when the
6178 : * lefthand input is another setop of the same kind. Syntactically,
6179 : * we could omit parens in rather more cases, but it seems best to use
3266 tgl 6180 ECB : * parens to flag cases where the setop operator changes. If we use
6181 : * parens, we also increase the indentation level for the child query.
6182 : *
6183 : * There are some cases in which parens are needed around a leaf query
6184 : * too, but those are more easily handled at the next level down (see
3266 tgl 6185 EUB : * code above).
6851 tgl 6186 ECB : */
3266 tgl 6187 CBC 103 : if (IsA(op->larg, SetOperationStmt))
6188 : {
3266 tgl 6189 GBC 33 : SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6190 :
3266 tgl 6191 CBC 33 : if (op->op == lop->op && op->all == lop->all)
3266 tgl 6192 GIC 33 : need_paren = false;
3266 tgl 6193 ECB : else
3266 tgl 6194 LBC 0 : need_paren = true;
3266 tgl 6195 ECB : }
3266 tgl 6196 EUB : else
3266 tgl 6197 GBC 70 : need_paren = false;
8221 tgl 6198 EUB :
6851 tgl 6199 GBC 103 : if (need_paren)
3266 tgl 6200 EUB : {
6851 tgl 6201 UBC 0 : appendStringInfoChar(buf, '(');
3266 6202 0 : subindent = PRETTYINDENT_STD;
6203 0 : appendContextKeyword(context, "", subindent, 0, 0);
6204 : }
6205 : else
3266 tgl 6206 CBC 103 : subindent = 0;
3266 tgl 6207 ECB :
323 tgl 6208 GIC 103 : get_setop_query(op->larg, query, context, resultDesc, colNamesVisible);
6209 :
3266 tgl 6210 CBC 103 : if (need_paren)
3266 tgl 6211 UIC 0 : appendContextKeyword(context, ") ", -subindent, 0, 0);
3266 tgl 6212 GIC 103 : else if (PRETTY_INDENT(context))
6213 103 : appendContextKeyword(context, "", -subindent, 0, 0);
6214 : else
7188 bruce 6215 UIC 0 : appendStringInfoChar(buf, ' ');
6216 :
8221 tgl 6217 CBC 103 : switch (op->op)
6218 : {
8221 tgl 6219 GBC 103 : case SETOP_UNION:
3266 6220 103 : appendStringInfoString(buf, "UNION ");
8221 tgl 6221 GIC 103 : break;
8221 tgl 6222 UIC 0 : case SETOP_INTERSECT:
3266 tgl 6223 LBC 0 : appendStringInfoString(buf, "INTERSECT ");
8221 6224 0 : break;
8221 tgl 6225 UIC 0 : case SETOP_EXCEPT:
3266 tgl 6226 LBC 0 : appendStringInfoString(buf, "EXCEPT ");
8221 tgl 6227 UIC 0 : break;
8221 tgl 6228 LBC 0 : default:
7196 6229 0 : elog(ERROR, "unrecognized set op: %d",
8221 tgl 6230 ECB : (int) op->op);
8221 tgl 6231 EUB : }
8221 tgl 6232 GIC 103 : if (op->all)
3447 rhaas 6233 97 : appendStringInfoString(buf, "ALL ");
6234 :
3266 tgl 6235 EUB : /* Always parenthesize if RHS is another setop */
3266 tgl 6236 GIC 103 : need_paren = IsA(op->rarg, SetOperationStmt);
6237 :
3266 tgl 6238 ECB : /*
6239 : * The indentation code here is deliberately a bit different from that
6240 : * for the lefthand input, because we want the line breaks in
6241 : * different places.
6242 : */
6851 tgl 6243 GIC 103 : if (need_paren)
6244 : {
6851 tgl 6245 UIC 0 : appendStringInfoChar(buf, '(');
3266 tgl 6246 LBC 0 : subindent = PRETTYINDENT_STD;
6247 : }
6248 : else
3266 tgl 6249 CBC 103 : subindent = 0;
3266 tgl 6250 GIC 103 : appendContextKeyword(context, "", subindent, 0, 0);
6251 :
323 6252 103 : get_setop_query(op->rarg, query, context, resultDesc, false);
5300 tgl 6253 ECB :
5300 tgl 6254 CBC 103 : if (PRETTY_INDENT(context))
3266 tgl 6255 GIC 103 : context->indentLevel -= subindent;
6256 103 : if (need_paren)
3266 tgl 6257 UIC 0 : appendContextKeyword(context, ")", 0, 0, 0);
6258 : }
6259 : else
6260 : {
7196 6261 0 : elog(ERROR, "unrecognized node type: %d",
6262 : (int) nodeTag(setOp));
6263 : }
8221 tgl 6264 GIC 276 : }
8221 tgl 6265 ECB :
6266 : /*
8029 tgl 6267 EUB : * Display a sort/group clause.
7646 6268 : *
6269 : * Also returns the expression tree, so caller need not find it again.
8029 tgl 6270 ECB : */
7646 tgl 6271 EUB : static Node *
2885 andres 6272 CBC 216 : get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
8029 tgl 6273 ECB : deparse_context *context)
6274 : {
8029 tgl 6275 GIC 216 : StringInfo buf = context->buf;
6276 : TargetEntry *tle;
6277 : Node *expr;
6278 :
2885 andres 6279 216 : tle = get_sortgroupref_tle(ref, tlist);
7423 tgl 6280 216 : expr = (Node *) tle->expr;
6281 :
6282 : /*
2878 bruce 6283 ECB : * Use column-number form if requested by caller. Otherwise, if
6284 : * expression is a constant, force it to be dumped with an explicit cast
6285 : * as decoration --- this is because a simple integer constant is
6286 : * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
6287 : * dump it without any decoration. If it's anything more complex than a
6288 : * simple Var, then force extra parens around it, to ensure it can't be
6289 : * misinterpreted as a cube() or rollup() construct.
8029 tgl 6290 : */
5572 tgl 6291 CBC 216 : if (force_colno)
8029 tgl 6292 ECB : {
6577 tgl 6293 LBC 0 : Assert(!tle->resjunk);
6577 tgl 6294 UIC 0 : appendStringInfo(buf, "%d", tle->resno);
6295 : }
5572 tgl 6296 CBC 216 : else if (expr && IsA(expr, Const))
5572 tgl 6297 UIC 0 : get_const_expr((Const *) expr, context, 1);
2885 andres 6298 GIC 216 : else if (!expr || IsA(expr, Var))
6299 199 : get_rule_expr(expr, context, true);
6300 : else
6301 : {
6302 : /*
2885 andres 6303 ECB : * We must force parens for function-like expressions even if
6304 : * PRETTY_PAREN is off, since those are the ones in danger of
6305 : * misparsing. For other expressions we need to force them only if
6306 : * PRETTY_PAREN is on, since otherwise the expression will output them
2878 bruce 6307 : * itself. (We can't skip the parens.)
2885 andres 6308 : */
2878 bruce 6309 CBC 34 : bool need_paren = (PRETTY_PAREN(context)
2878 bruce 6310 GIC 17 : || IsA(expr, FuncExpr)
1058 tgl 6311 CBC 15 : || IsA(expr, Aggref)
11 alvherre 6312 GNC 15 : || IsA(expr, WindowFunc)
6313 34 : || IsA(expr, JsonConstructorExpr));
2878 bruce 6314 EUB :
2885 andres 6315 GBC 17 : if (need_paren)
2063 peter_e 6316 2 : appendStringInfoChar(context->buf, '(');
7507 tgl 6317 GIC 17 : get_rule_expr(expr, context, true);
2885 andres 6318 CBC 17 : if (need_paren)
2063 peter_e 6319 GIC 2 : appendStringInfoChar(context->buf, ')');
2885 andres 6320 ECB : }
7646 tgl 6321 :
7646 tgl 6322 GIC 216 : return expr;
8029 tgl 6323 ECB : }
6324 :
2885 andres 6325 : /*
6326 : * Display a GroupingSet
6327 : */
6328 : static void
2885 andres 6329 GIC 9 : get_rule_groupingset(GroupingSet *gset, List *targetlist,
2885 andres 6330 ECB : bool omit_parens, deparse_context *context)
6331 : {
6332 : ListCell *l;
2885 andres 6333 CBC 9 : StringInfo buf = context->buf;
6334 9 : bool omit_child_parens = true;
2885 andres 6335 GIC 9 : char *sep = "";
2885 andres 6336 ECB :
2885 andres 6337 GIC 9 : switch (gset->kind)
2885 andres 6338 ECB : {
2885 andres 6339 LBC 0 : case GROUPING_SET_EMPTY:
6340 0 : appendStringInfoString(buf, "()");
2885 andres 6341 UBC 0 : return;
2885 andres 6342 EUB :
2885 andres 6343 GBC 6 : case GROUPING_SET_SIMPLE:
2885 andres 6344 EUB : {
2885 andres 6345 GBC 6 : if (!omit_parens || list_length(gset->content) != 1)
2063 peter_e 6346 6 : appendStringInfoChar(buf, '(');
2885 andres 6347 EUB :
2885 andres 6348 GIC 21 : foreach(l, gset->content)
6349 : {
2878 bruce 6350 CBC 15 : Index ref = lfirst_int(l);
6351 :
2885 andres 6352 15 : appendStringInfoString(buf, sep);
6353 15 : get_rule_sortgroupclause(ref, targetlist,
2885 andres 6354 ECB : false, context);
2885 andres 6355 GIC 15 : sep = ", ";
6356 : }
2885 andres 6357 ECB :
2885 andres 6358 GIC 6 : if (!omit_parens || list_length(gset->content) != 1)
2063 peter_e 6359 6 : appendStringInfoChar(buf, ')');
6360 : }
2885 andres 6361 6 : return;
6362 :
6363 3 : case GROUPING_SET_ROLLUP:
2885 andres 6364 CBC 3 : appendStringInfoString(buf, "ROLLUP(");
2885 andres 6365 GIC 3 : break;
2885 andres 6366 UIC 0 : case GROUPING_SET_CUBE:
2885 andres 6367 LBC 0 : appendStringInfoString(buf, "CUBE(");
2885 andres 6368 UIC 0 : break;
6369 0 : case GROUPING_SET_SETS:
6370 0 : appendStringInfoString(buf, "GROUPING SETS (");
2885 andres 6371 LBC 0 : omit_child_parens = false;
6372 0 : break;
6373 : }
2885 andres 6374 ECB :
2885 andres 6375 GIC 9 : foreach(l, gset->content)
6376 : {
6377 6 : appendStringInfoString(buf, sep);
6378 6 : get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
2885 andres 6379 CBC 6 : sep = ", ";
2885 andres 6380 ECB : }
6381 :
2063 peter_e 6382 CBC 3 : appendStringInfoChar(buf, ')');
6383 : }
2885 andres 6384 ECB :
6385 : /*
5215 tgl 6386 : * Display an ORDER BY list.
6387 : */
6388 : static void
5215 tgl 6389 CBC 134 : get_rule_orderby(List *orderList, List *targetList,
5215 tgl 6390 EUB : bool force_colno, deparse_context *context)
6391 : {
5215 tgl 6392 CBC 134 : StringInfo buf = context->buf;
6393 : const char *sep;
5215 tgl 6394 ECB : ListCell *l;
6395 :
5215 tgl 6396 CBC 134 : sep = "";
6397 284 : foreach(l, orderList)
6398 : {
5215 tgl 6399 GIC 150 : SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6400 : Node *sortexpr;
5215 tgl 6401 ECB : Oid sortcoltype;
6402 : TypeCacheEntry *typentry;
6403 :
5215 tgl 6404 GIC 150 : appendStringInfoString(buf, sep);
2885 andres 6405 150 : sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
5215 tgl 6406 ECB : force_colno, context);
5215 tgl 6407 GBC 150 : sortcoltype = exprType(sortexpr);
6408 : /* See whether operator is default < or > for datatype */
5215 tgl 6409 CBC 150 : typentry = lookup_type_cache(sortcoltype,
6410 : TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
6411 150 : if (srt->sortop == typentry->lt_opr)
6412 : {
5215 tgl 6413 ECB : /* ASC is default, so emit nothing for it */
5215 tgl 6414 GIC 136 : if (srt->nulls_first)
3447 rhaas 6415 UIC 0 : appendStringInfoString(buf, " NULLS FIRST");
6416 : }
5215 tgl 6417 GIC 14 : else if (srt->sortop == typentry->gt_opr)
6418 : {
3447 rhaas 6419 5 : appendStringInfoString(buf, " DESC");
6420 : /* DESC defaults to NULLS FIRST */
5215 tgl 6421 5 : if (!srt->nulls_first)
3447 rhaas 6422 CBC 1 : appendStringInfoString(buf, " NULLS LAST");
6423 : }
5215 tgl 6424 ECB : else
6425 : {
5215 tgl 6426 GIC 9 : appendStringInfo(buf, " USING %s",
6427 : generate_operator_name(srt->sortop,
5215 tgl 6428 ECB : sortcoltype,
6429 : sortcoltype));
6430 : /* be specific to eliminate ambiguity */
5215 tgl 6431 CBC 9 : if (srt->nulls_first)
3447 rhaas 6432 UIC 0 : appendStringInfoString(buf, " NULLS FIRST");
5215 tgl 6433 ECB : else
3447 rhaas 6434 CBC 9 : appendStringInfoString(buf, " NULLS LAST");
6435 : }
5215 tgl 6436 GBC 150 : sep = ", ";
5215 tgl 6437 EUB : }
5215 tgl 6438 GIC 134 : }
6439 :
5215 tgl 6440 EUB : /*
6441 : * Display a WINDOW clause.
6442 : *
6443 : * Note that the windowClause list might contain only anonymous window
6444 : * specifications, in which case we should print nothing here.
6445 : */
6446 : static void
5215 tgl 6447 GIC 21 : get_rule_windowclause(Query *query, deparse_context *context)
5215 tgl 6448 ECB : {
5215 tgl 6449 GIC 21 : StringInfo buf = context->buf;
6450 : const char *sep;
6451 : ListCell *l;
6452 :
6453 21 : sep = NULL;
5215 tgl 6454 CBC 42 : foreach(l, query->windowClause)
6455 : {
5215 tgl 6456 GIC 21 : WindowClause *wc = (WindowClause *) lfirst(l);
5215 tgl 6457 ECB :
5215 tgl 6458 CBC 21 : if (wc->name == NULL)
5215 tgl 6459 GIC 21 : continue; /* ignore anonymous windows */
6460 :
5215 tgl 6461 UIC 0 : if (sep == NULL)
5215 tgl 6462 LBC 0 : appendContextKeyword(context, " WINDOW ",
5215 tgl 6463 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6464 : else
5215 tgl 6465 UBC 0 : appendStringInfoString(buf, sep);
5215 tgl 6466 EUB :
5215 tgl 6467 UIC 0 : appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6468 :
5215 tgl 6469 LBC 0 : get_rule_windowspec(wc, query->targetList, context);
6470 :
5215 tgl 6471 UBC 0 : sep = ", ";
5215 tgl 6472 EUB : }
5215 tgl 6473 GBC 21 : }
5215 tgl 6474 EUB :
6475 : /*
6476 : * Display a window definition
6477 : */
6478 : static void
5215 tgl 6479 GBC 21 : get_rule_windowspec(WindowClause *wc, List *targetList,
5215 tgl 6480 EUB : deparse_context *context)
6481 : {
5215 tgl 6482 GBC 21 : StringInfo buf = context->buf;
5215 tgl 6483 GIC 21 : bool needspace = false;
5215 tgl 6484 EUB : const char *sep;
6485 : ListCell *l;
6486 :
5215 tgl 6487 CBC 21 : appendStringInfoChar(buf, '(');
5215 tgl 6488 GIC 21 : if (wc->refname)
5215 tgl 6489 ECB : {
5215 tgl 6490 UBC 0 : appendStringInfoString(buf, quote_identifier(wc->refname));
5215 tgl 6491 LBC 0 : needspace = true;
5215 tgl 6492 ECB : }
5212 6493 : /* partition clauses are always inherited, so only print if no refname */
5215 tgl 6494 GIC 21 : if (wc->partitionClause && !wc->refname)
6495 : {
5215 tgl 6496 LBC 0 : if (needspace)
5215 tgl 6497 UIC 0 : appendStringInfoChar(buf, ' ');
5215 tgl 6498 LBC 0 : appendStringInfoString(buf, "PARTITION BY ");
6499 0 : sep = "";
6500 0 : foreach(l, wc->partitionClause)
5215 tgl 6501 ECB : {
5215 tgl 6502 LBC 0 : SortGroupClause *grp = (SortGroupClause *) lfirst(l);
5215 tgl 6503 ECB :
5215 tgl 6504 LBC 0 : appendStringInfoString(buf, sep);
2885 andres 6505 0 : get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
6506 : false, context);
5215 tgl 6507 UBC 0 : sep = ", ";
5215 tgl 6508 ECB : }
5215 tgl 6509 LBC 0 : needspace = true;
5215 tgl 6510 ECB : }
5212 tgl 6511 EUB : /* print ordering clause only if not inherited */
5215 tgl 6512 CBC 21 : if (wc->orderClause && !wc->copiedOrder)
5215 tgl 6513 EUB : {
5215 tgl 6514 CBC 21 : if (needspace)
5215 tgl 6515 UIC 0 : appendStringInfoChar(buf, ' ');
5215 tgl 6516 CBC 21 : appendStringInfoString(buf, "ORDER BY ");
6517 21 : get_rule_orderby(wc->orderClause, targetList, false, context);
6518 21 : needspace = true;
5215 tgl 6519 EUB : }
5212 6520 : /* framing clause is never inherited, so print unless it's default */
5212 tgl 6521 GIC 21 : if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
5212 tgl 6522 EUB : {
5212 tgl 6523 GIC 21 : if (needspace)
6524 21 : appendStringInfoChar(buf, ' ');
5212 tgl 6525 GBC 21 : if (wc->frameOptions & FRAMEOPTION_RANGE)
5212 tgl 6526 CBC 3 : appendStringInfoString(buf, "RANGE ");
5212 tgl 6527 GIC 18 : else if (wc->frameOptions & FRAMEOPTION_ROWS)
5212 tgl 6528 CBC 15 : appendStringInfoString(buf, "ROWS ");
1887 6529 3 : else if (wc->frameOptions & FRAMEOPTION_GROUPS)
1887 tgl 6530 GBC 3 : appendStringInfoString(buf, "GROUPS ");
5212 tgl 6531 ECB : else
5212 tgl 6532 UBC 0 : Assert(false);
5212 tgl 6533 CBC 21 : if (wc->frameOptions & FRAMEOPTION_BETWEEN)
5212 tgl 6534 GIC 21 : appendStringInfoString(buf, "BETWEEN ");
5212 tgl 6535 CBC 21 : if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
5212 tgl 6536 LBC 0 : appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
5212 tgl 6537 GBC 21 : else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
5212 tgl 6538 LBC 0 : appendStringInfoString(buf, "CURRENT ROW ");
1887 tgl 6539 CBC 21 : else if (wc->frameOptions & FRAMEOPTION_START_OFFSET)
6540 : {
4804 tgl 6541 GBC 21 : get_rule_expr(wc->startOffset, context, false);
1887 tgl 6542 GIC 21 : if (wc->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
4804 6543 21 : appendStringInfoString(buf, " PRECEDING ");
1887 tgl 6544 UBC 0 : else if (wc->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
4804 tgl 6545 UIC 0 : appendStringInfoString(buf, " FOLLOWING ");
4804 tgl 6546 ECB : else
4804 tgl 6547 LBC 0 : Assert(false);
4804 tgl 6548 ECB : }
5212 6549 : else
5212 tgl 6550 LBC 0 : Assert(false);
5212 tgl 6551 CBC 21 : if (wc->frameOptions & FRAMEOPTION_BETWEEN)
6552 : {
6553 21 : appendStringInfoString(buf, "AND ");
5212 tgl 6554 GIC 21 : if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
5212 tgl 6555 LBC 0 : appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
5212 tgl 6556 CBC 21 : else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
5212 tgl 6557 UIC 0 : appendStringInfoString(buf, "CURRENT ROW ");
1887 tgl 6558 GIC 21 : else if (wc->frameOptions & FRAMEOPTION_END_OFFSET)
6559 : {
4804 6560 21 : get_rule_expr(wc->endOffset, context, false);
1887 6561 21 : if (wc->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
4804 tgl 6562 UIC 0 : appendStringInfoString(buf, " PRECEDING ");
1887 tgl 6563 CBC 21 : else if (wc->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
4804 tgl 6564 GIC 21 : appendStringInfoString(buf, " FOLLOWING ");
6565 : else
4804 tgl 6566 LBC 0 : Assert(false);
4804 tgl 6567 ECB : }
5212 6568 : else
5212 tgl 6569 UIC 0 : Assert(false);
6570 : }
1887 tgl 6571 GIC 21 : if (wc->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
6572 3 : appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6573 18 : else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6574 3 : appendStringInfoString(buf, "EXCLUDE GROUP ");
1887 tgl 6575 CBC 15 : else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
1887 tgl 6576 GIC 3 : appendStringInfoString(buf, "EXCLUDE TIES ");
6577 : /* we will now have a trailing space; remove it */
5212 6578 21 : buf->len--;
6579 : }
5215 6580 21 : appendStringInfoChar(buf, ')');
5215 tgl 6581 CBC 21 : }
6582 :
8994 bruce 6583 ECB : /* ----------
6584 : * get_insert_query_def - Parse back an INSERT parsetree
6585 : * ----------
6586 : */
8590 tgl 6587 : static void
323 tgl 6588 GBC 161 : get_insert_query_def(Query *query, deparse_context *context,
323 tgl 6589 ECB : bool colNamesVisible)
6590 : {
8589 tgl 6591 GIC 161 : StringInfo buf = context->buf;
8221 tgl 6592 CBC 161 : RangeTblEntry *select_rte = NULL;
6094 mail 6593 GIC 161 : RangeTblEntry *values_rte = NULL;
8244 tgl 6594 ECB : RangeTblEntry *rte;
8221 tgl 6595 EUB : char *sep;
6892 neilc 6596 ECB : ListCell *l;
6597 : List *strippedexprs;
6598 :
4559 tgl 6599 : /* Insert the WITH clause if given */
4559 tgl 6600 GBC 161 : get_with_clause(query, context);
6601 :
6602 : /*
6603 : * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6604 : * single RTE for the SELECT or VALUES. Plain VALUES has neither.
8986 bruce 6605 ECB : */
8986 bruce 6606 CBC 625 : foreach(l, query->rtable)
6607 : {
6608 464 : rte = (RangeTblEntry *) lfirst(l);
6609 :
6094 mail 6610 464 : if (rte->rtekind == RTE_SUBQUERY)
6094 mail 6611 ECB : {
6094 mail 6612 GIC 22 : if (select_rte)
6094 mail 6613 LBC 0 : elog(ERROR, "too many subquery RTEs in INSERT");
6094 mail 6614 GIC 22 : select_rte = rte;
6615 : }
6616 :
6094 mail 6617 CBC 464 : if (rte->rtekind == RTE_VALUES)
6618 : {
6094 mail 6619 GIC 19 : if (values_rte)
6094 mail 6620 LBC 0 : elog(ERROR, "too many values RTEs in INSERT");
6094 mail 6621 GIC 19 : values_rte = rte;
6622 : }
6623 : }
6624 161 : if (select_rte && values_rte)
6094 mail 6625 UIC 0 : elog(ERROR, "both subquery and values RTEs in INSERT");
8986 bruce 6626 ECB :
8053 6627 : /*
8986 6628 : * Start the query with INSERT INTO relname
6629 : */
8561 tgl 6630 CBC 161 : rte = rt_fetch(query->resultRelation, query->rtable);
7646 tgl 6631 GIC 161 : Assert(rte->rtekind == RTE_RELATION);
7193 tgl 6632 ECB :
7193 tgl 6633 GIC 161 : if (PRETTY_INDENT(context))
7193 tgl 6634 ECB : {
7188 bruce 6635 GBC 161 : context->indentLevel += PRETTYINDENT_STD;
7188 bruce 6636 GIC 161 : appendStringInfoChar(buf, ' ');
7193 tgl 6637 ECB : }
51 tgl 6638 CBC 161 : appendStringInfo(buf, "INSERT INTO %s",
6639 : generate_relation_name(rte->relid, NIL));
6640 :
6641 : /* Print the relation alias, if needed; INSERT requires explicit AS */
51 tgl 6642 GIC 161 : get_rte_alias(rte, query->resultRelation, true, context);
6643 :
51 tgl 6644 ECB : /* always want a space here */
51 tgl 6645 CBC 161 : appendStringInfoChar(buf, ' ');
8986 bruce 6646 ECB :
6647 : /*
6648 : * Add the insert-column-names list. Any indirection decoration needed on
6649 : * the column names can be inferred from the top targetlist.
6650 : */
6878 tgl 6651 GIC 161 : strippedexprs = NIL;
6652 161 : sep = "";
3824 6653 161 : if (query->targetList)
6654 161 : appendStringInfoChar(buf, '(');
8986 bruce 6655 594 : foreach(l, query->targetList)
6656 : {
8244 tgl 6657 CBC 433 : TargetEntry *tle = (TargetEntry *) lfirst(l);
8986 bruce 6658 ECB :
6577 tgl 6659 GIC 433 : if (tle->resjunk)
8227 tgl 6660 UIC 0 : continue; /* ignore junk entries */
8227 tgl 6661 ECB :
6553 neilc 6662 CBC 433 : appendStringInfoString(buf, sep);
8986 bruce 6663 GIC 433 : sep = ", ";
6878 tgl 6664 ECB :
6665 : /*
6878 tgl 6666 EUB : * Put out name of target column; look in the catalogs, not at
6667 : * tle->resname, since resname will fail to track RENAME.
6668 : */
7008 neilc 6669 GBC 433 : appendStringInfoString(buf,
1882 alvherre 6670 GIC 433 : quote_identifier(get_attname(rte->relid,
6671 433 : tle->resno,
1882 alvherre 6672 ECB : false)));
6673 :
6674 : /*
6385 bruce 6675 : * Print any indirection needed (subfields or subscripts), and strip
6676 : * off the top-level nodes representing the indirection assignments.
6677 : * Add the stripped expressions to strippedexprs. (If it's a
6678 : * single-VALUES statement, the stripped expressions are the VALUES to
6679 : * print below. Otherwise they're just Vars and not really
2440 tgl 6680 : * interesting.)
6681 : */
2440 tgl 6682 GIC 433 : strippedexprs = lappend(strippedexprs,
2440 tgl 6683 CBC 433 : processIndirection((Node *) tle->expr,
6684 : context));
8986 bruce 6685 ECB : }
3824 tgl 6686 GIC 161 : if (query->targetList)
3447 rhaas 6687 161 : appendStringInfoString(buf, ") ");
8986 bruce 6688 ECB :
2194 peter_e 6689 GIC 161 : if (query->override)
2194 peter_e 6690 ECB : {
2194 peter_e 6691 LBC 0 : if (query->override == OVERRIDING_SYSTEM_VALUE)
2194 peter_e 6692 UIC 0 : appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
6693 0 : else if (query->override == OVERRIDING_USER_VALUE)
6694 0 : appendStringInfoString(buf, "OVERRIDING USER VALUE ");
6695 : }
2194 peter_e 6696 EUB :
6094 mail 6697 GIC 161 : if (select_rte)
6698 : {
6699 : /* Add the SELECT */
508 tgl 6700 CBC 22 : get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
6701 : false,
3758 tgl 6702 ECB : context->prettyFlags, context->wrapColumn,
6703 : context->indentLevel);
6094 mail 6704 : }
6094 mail 6705 GIC 139 : else if (values_rte)
6094 mail 6706 ECB : {
6707 : /* Add the multi-VALUES expression lists */
6094 mail 6708 GIC 19 : get_values_def(values_rte->values_lists, context);
6094 mail 6709 ECB : }
3824 tgl 6710 CBC 120 : else if (strippedexprs)
8986 bruce 6711 ECB : {
6712 : /* Add the single-VALUES expression list */
7193 tgl 6713 GIC 120 : appendContextKeyword(context, "VALUES (",
7193 tgl 6714 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
451 tgl 6715 GIC 120 : get_rule_list_toplevel(strippedexprs, context, false);
8449 6716 120 : appendStringInfoChar(buf, ')');
6717 : }
6718 : else
6719 : {
6720 : /* No expressions, so it must be DEFAULT VALUES */
3447 rhaas 6721 UIC 0 : appendStringInfoString(buf, "DEFAULT VALUES");
6722 : }
6084 tgl 6723 ECB :
2893 andres 6724 : /* Add ON CONFLICT if present */
2893 andres 6725 GIC 161 : if (query->onConflict)
2893 andres 6726 ECB : {
2893 andres 6727 GIC 15 : OnConflictExpr *confl = query->onConflict;
2893 andres 6728 ECB :
2838 heikki.linnakangas 6729 GIC 15 : appendStringInfoString(buf, " ON CONFLICT");
2882 andres 6730 ECB :
2882 andres 6731 GIC 15 : if (confl->arbiterElems)
6732 : {
2882 andres 6733 ECB : /* Add the single-VALUES expression list */
2882 andres 6734 GIC 12 : appendStringInfoChar(buf, '(');
2882 andres 6735 GBC 12 : get_rule_expr((Node *) confl->arbiterElems, context, false);
2882 andres 6736 GIC 12 : appendStringInfoChar(buf, ')');
2882 andres 6737 EUB :
6738 : /* Add a WHERE clause (for partial indexes) if given */
2882 andres 6739 GIC 12 : if (confl->arbiterWhere != NULL)
2882 andres 6740 EUB : {
6741 : bool save_varprefix;
6742 :
6743 : /*
2618 tgl 6744 ECB : * Force non-prefixing of Vars, since parser assumes that they
6745 : * belong to target relation. WHERE clause does not use
6746 : * InferenceElem, so this is separately required.
6747 : */
2618 tgl 6748 GIC 6 : save_varprefix = context->varprefix;
6749 6 : context->varprefix = false;
2618 tgl 6750 ECB :
2882 andres 6751 GIC 6 : appendContextKeyword(context, " WHERE ",
2882 andres 6752 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2882 andres 6753 GIC 6 : get_rule_expr(confl->arbiterWhere, context, false);
6754 :
2618 tgl 6755 6 : context->varprefix = save_varprefix;
2882 andres 6756 ECB : }
6757 : }
2524 tgl 6758 CBC 3 : else if (OidIsValid(confl->constraint))
6759 : {
2878 bruce 6760 LBC 0 : char *constraint = get_constraint_name(confl->constraint);
6761 :
2524 tgl 6762 UIC 0 : if (!constraint)
6763 0 : elog(ERROR, "cache lookup failed for constraint %u",
6764 : confl->constraint);
2882 andres 6765 0 : appendStringInfo(buf, " ON CONSTRAINT %s",
2524 tgl 6766 ECB : quote_identifier(constraint));
6767 : }
2882 andres 6768 :
2893 andres 6769 GIC 15 : if (confl->action == ONCONFLICT_NOTHING)
2893 andres 6770 ECB : {
2882 andres 6771 GIC 9 : appendStringInfoString(buf, " DO NOTHING");
2893 andres 6772 ECB : }
6773 : else
6774 : {
2882 andres 6775 GIC 6 : appendStringInfoString(buf, " DO UPDATE SET ");
6776 : /* Deparse targetlist */
2893 6777 6 : get_update_query_targetlist_def(query, confl->onConflictSet,
6778 : context, rte);
6779 :
2893 andres 6780 ECB : /* Add a WHERE clause if given */
2893 andres 6781 GIC 6 : if (confl->onConflictWhere != NULL)
6782 : {
2893 andres 6783 CBC 6 : appendContextKeyword(context, " WHERE ",
6784 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2893 andres 6785 GIC 6 : get_rule_expr(confl->onConflictWhere, context, false);
6786 : }
2893 andres 6787 ECB : }
6788 : }
6789 :
6790 : /* Add RETURNING if present */
6084 tgl 6791 GIC 161 : if (query->returningList)
6084 tgl 6792 ECB : {
6084 tgl 6793 CBC 39 : appendContextKeyword(context, " RETURNING",
6084 tgl 6794 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
323 tgl 6795 GIC 39 : get_target_list(query->returningList, context, NULL, colNamesVisible);
6084 tgl 6796 ECB : }
8994 bruce 6797 CBC 161 : }
6798 :
8994 bruce 6799 ECB :
6800 : /* ----------
6801 : * get_update_query_def - Parse back an UPDATE parsetree
6802 : * ----------
6803 : */
8590 tgl 6804 : static void
323 tgl 6805 GIC 65 : get_update_query_def(Query *query, deparse_context *context,
323 tgl 6806 ECB : bool colNamesVisible)
6807 : {
6797 bruce 6808 GIC 65 : StringInfo buf = context->buf;
6797 bruce 6809 ECB : RangeTblEntry *rte;
6810 :
6811 : /* Insert the WITH clause if given */
4559 tgl 6812 CBC 65 : get_with_clause(query, context);
6813 :
6814 : /*
8986 bruce 6815 ECB : * Start the query with UPDATE relname SET
6816 : */
8561 tgl 6817 CBC 65 : rte = rt_fetch(query->resultRelation, query->rtable);
7646 tgl 6818 GIC 65 : Assert(rte->rtekind == RTE_RELATION);
7193 tgl 6819 CBC 65 : if (PRETTY_INDENT(context))
6820 : {
7188 bruce 6821 GIC 65 : appendStringInfoChar(buf, ' ');
6822 65 : context->indentLevel += PRETTYINDENT_STD;
7193 tgl 6823 ECB : }
5454 tgl 6824 GIC 130 : appendStringInfo(buf, "UPDATE %s%s",
8338 tgl 6825 CBC 65 : only_marker(rte),
6826 : generate_relation_name(rte->relid, NIL));
51 tgl 6827 ECB :
6828 : /* Print the relation alias, if needed */
51 tgl 6829 CBC 65 : get_rte_alias(rte, query->resultRelation, false, context);
6830 :
5454 tgl 6831 GIC 65 : appendStringInfoString(buf, " SET ");
6832 :
6833 : /* Deparse targetlist */
2893 andres 6834 65 : get_update_query_targetlist_def(query, query->targetList, context, rte);
6835 :
6836 : /* Add the FROM clause if needed */
2893 andres 6837 CBC 65 : get_from_clause(query, " FROM ", context);
6838 :
6839 : /* Add a WHERE clause if given */
6840 65 : if (query->jointree->quals != NULL)
6841 : {
2893 andres 6842 GIC 57 : appendContextKeyword(context, " WHERE ",
6843 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6844 57 : get_rule_expr(query->jointree->quals, context, false);
6845 : }
6846 :
6847 : /* Add RETURNING if present */
6848 65 : if (query->returningList)
6849 : {
6850 11 : appendContextKeyword(context, " RETURNING",
6851 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
323 tgl 6852 11 : get_target_list(query->returningList, context, NULL, colNamesVisible);
2893 andres 6853 ECB : }
2893 andres 6854 CBC 65 : }
6855 :
2893 andres 6856 ECB :
6857 : /* ----------
6858 : * get_update_query_targetlist_def - Parse back an UPDATE targetlist
6859 : * ----------
6860 : */
6861 : static void
2893 andres 6862 CBC 71 : get_update_query_targetlist_def(Query *query, List *targetList,
6863 : deparse_context *context, RangeTblEntry *rte)
2893 andres 6864 ECB : {
2893 andres 6865 GIC 71 : StringInfo buf = context->buf;
2893 andres 6866 ECB : ListCell *l;
6867 : ListCell *next_ma_cell;
6868 : int remaining_ma_columns;
6869 : const char *sep;
6870 : SubLink *cur_ma_sublink;
6871 : List *ma_sublinks;
6872 :
3217 tgl 6873 : /*
6874 : * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
6875 : * into a list. We expect them to appear, in ID order, in resjunk tlist
6876 : * entries.
6877 : */
3217 tgl 6878 CBC 71 : ma_sublinks = NIL;
3217 tgl 6879 GIC 71 : if (query->hasSubLinks) /* else there can't be any */
3217 tgl 6880 ECB : {
2893 andres 6881 GIC 15 : foreach(l, targetList)
6882 : {
3217 tgl 6883 CBC 12 : TargetEntry *tle = (TargetEntry *) lfirst(l);
3217 tgl 6884 ECB :
3217 tgl 6885 GIC 12 : if (tle->resjunk && IsA(tle->expr, SubLink))
6886 : {
3217 tgl 6887 CBC 3 : SubLink *sl = (SubLink *) tle->expr;
3217 tgl 6888 ECB :
3217 tgl 6889 GIC 3 : if (sl->subLinkType == MULTIEXPR_SUBLINK)
6890 : {
6891 3 : ma_sublinks = lappend(ma_sublinks, sl);
6892 3 : Assert(sl->subLinkId == list_length(ma_sublinks));
6893 : }
3217 tgl 6894 ECB : }
6895 : }
6896 : }
3217 tgl 6897 GIC 71 : next_ma_cell = list_head(ma_sublinks);
6898 71 : cur_ma_sublink = NULL;
6899 71 : remaining_ma_columns = 0;
6900 :
6901 : /* Add the comma separated list of 'attname = value' */
8986 bruce 6902 71 : sep = "";
2893 andres 6903 193 : foreach(l, targetList)
6904 : {
8227 tgl 6905 CBC 122 : TargetEntry *tle = (TargetEntry *) lfirst(l);
6797 bruce 6906 ECB : Node *expr;
6907 :
6577 tgl 6908 CBC 122 : if (tle->resjunk)
8227 tgl 6909 GIC 3 : continue; /* ignore junk entries */
8986 bruce 6910 EUB :
6911 : /* Emit separator (OK whether we're in multiassignment or not) */
6553 neilc 6912 GBC 119 : appendStringInfoString(buf, sep);
8986 bruce 6913 GIC 119 : sep = ", ";
8053 bruce 6914 ECB :
6915 : /*
3217 tgl 6916 : * Check to see if we're starting a multiassignment group: if so,
6917 : * output a left paren.
6918 : */
3217 tgl 6919 GBC 119 : if (next_ma_cell != NULL && cur_ma_sublink == NULL)
6920 : {
3217 tgl 6921 ECB : /*
6922 : * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
1528 alvherre 6923 : * Param. That could be buried under FieldStores and
6924 : * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
1528 alvherre 6925 EUB : * and underneath those there could be an implicit type coercion.
6926 : * Because we would ignore implicit type coercions anyway, we
6927 : * don't need to be as careful as processIndirection() is about
6928 : * descending past implicit CoerceToDomains.
3217 tgl 6929 : */
3217 tgl 6930 GIC 3 : expr = (Node *) tle->expr;
6931 6 : while (expr)
3217 tgl 6932 ECB : {
3217 tgl 6933 GIC 6 : if (IsA(expr, FieldStore))
3217 tgl 6934 ECB : {
3217 tgl 6935 UIC 0 : FieldStore *fstore = (FieldStore *) expr;
3217 tgl 6936 ECB :
3217 tgl 6937 LBC 0 : expr = (Node *) linitial(fstore->newvals);
6938 : }
1528 alvherre 6939 CBC 6 : else if (IsA(expr, SubscriptingRef))
3217 tgl 6940 ECB : {
1528 alvherre 6941 CBC 3 : SubscriptingRef *sbsref = (SubscriptingRef *) expr;
3217 tgl 6942 ECB :
1528 alvherre 6943 GIC 3 : if (sbsref->refassgnexpr == NULL)
3217 tgl 6944 LBC 0 : break;
6945 :
1528 alvherre 6946 GIC 3 : expr = (Node *) sbsref->refassgnexpr;
6947 : }
2097 tgl 6948 3 : else if (IsA(expr, CoerceToDomain))
6949 : {
2097 tgl 6950 UIC 0 : CoerceToDomain *cdomain = (CoerceToDomain *) expr;
6951 :
2097 tgl 6952 LBC 0 : if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
6953 0 : break;
6954 0 : expr = (Node *) cdomain->arg;
6955 : }
6956 : else
3217 tgl 6957 GIC 3 : break;
6958 : }
6959 3 : expr = strip_implicit_coercions(expr);
6960 :
3217 tgl 6961 CBC 3 : if (expr && IsA(expr, Param) &&
3217 tgl 6962 GIC 3 : ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
6963 : {
6964 3 : cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
1364 6965 3 : next_ma_cell = lnext(ma_sublinks, next_ma_cell);
1165 alvherre 6966 3 : remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
3217 tgl 6967 3 : Assert(((Param *) expr)->paramid ==
3217 tgl 6968 ECB : ((cur_ma_sublink->subLinkId << 16) | 1));
3217 tgl 6969 GIC 3 : appendStringInfoChar(buf, '(');
3217 tgl 6970 ECB : }
6971 : }
6972 :
8275 6973 : /*
6878 6974 : * Put out name of target column; look in the catalogs, not at
6975 : * tle->resname, since resname will fail to track RENAME.
6976 : */
6878 tgl 6977 CBC 119 : appendStringInfoString(buf,
1882 alvherre 6978 GIC 119 : quote_identifier(get_attname(rte->relid,
1882 alvherre 6979 CBC 119 : tle->resno,
6980 : false)));
6878 tgl 6981 ECB :
6982 : /*
6983 : * Print any indirection needed (subfields or subscripts), and strip
6984 : * off the top-level nodes representing the indirection assignments.
6985 : */
2440 tgl 6986 GIC 119 : expr = processIndirection((Node *) tle->expr, context);
6987 :
6988 : /*
3217 tgl 6989 ECB : * If we're in a multiassignment, skip printing anything more, unless
6990 : * this is the last column; in which case, what we print should be the
6991 : * sublink, not the Param.
6992 : */
3217 tgl 6993 GIC 119 : if (cur_ma_sublink != NULL)
6994 : {
6995 9 : if (--remaining_ma_columns > 0)
3217 tgl 6996 CBC 6 : continue; /* not the last column of multiassignment */
3217 tgl 6997 GIC 3 : appendStringInfoChar(buf, ')');
6998 3 : expr = (Node *) cur_ma_sublink;
6999 3 : cur_ma_sublink = NULL;
7000 : }
3217 tgl 7001 ECB :
3447 rhaas 7002 CBC 113 : appendStringInfoString(buf, " = ");
6878 tgl 7003 ECB :
6878 tgl 7004 GIC 113 : get_rule_expr(expr, context, false);
8986 bruce 7005 ECB : }
8994 bruce 7006 CBC 71 : }
7007 :
8994 bruce 7008 ECB :
7009 : /* ----------
7010 : * get_delete_query_def - Parse back a DELETE parsetree
7011 : * ----------
7012 : */
8590 tgl 7013 : static void
323 tgl 7014 GIC 38 : get_delete_query_def(Query *query, deparse_context *context,
7015 : bool colNamesVisible)
8994 bruce 7016 ECB : {
8589 tgl 7017 GIC 38 : StringInfo buf = context->buf;
7018 : RangeTblEntry *rte;
8986 bruce 7019 ECB :
7020 : /* Insert the WITH clause if given */
4559 tgl 7021 CBC 38 : get_with_clause(query, context);
7022 :
8053 bruce 7023 ECB : /*
7024 : * Start the query with DELETE FROM relname
7025 : */
8561 tgl 7026 GIC 38 : rte = rt_fetch(query->resultRelation, query->rtable);
7646 tgl 7027 CBC 38 : Assert(rte->rtekind == RTE_RELATION);
7193 tgl 7028 GIC 38 : if (PRETTY_INDENT(context))
7193 tgl 7029 ECB : {
7188 bruce 7030 GIC 38 : appendStringInfoChar(buf, ' ');
5454 tgl 7031 CBC 38 : context->indentLevel += PRETTYINDENT_STD;
7032 : }
8561 7033 76 : appendStringInfo(buf, "DELETE FROM %s%s",
8338 tgl 7034 GIC 38 : only_marker(rte),
7035 : generate_relation_name(rte->relid, NIL));
7036 :
7037 : /* Print the relation alias, if needed */
51 7038 38 : get_rte_alias(rte, query->resultRelation, false, context);
7039 :
7040 : /* Add the USING clause if given */
6460 tgl 7041 CBC 38 : get_from_clause(query, " USING ", context);
7042 :
8986 bruce 7043 ECB : /* Add a WHERE clause if given */
8227 tgl 7044 GIC 38 : if (query->jointree->quals != NULL)
8986 bruce 7045 ECB : {
7193 tgl 7046 CBC 38 : appendContextKeyword(context, " WHERE ",
7193 tgl 7047 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7507 tgl 7048 GIC 38 : get_rule_expr(query->jointree->quals, context, false);
8986 bruce 7049 ECB : }
7050 :
6084 tgl 7051 : /* Add RETURNING if present */
6084 tgl 7052 CBC 38 : if (query->returningList)
6084 tgl 7053 ECB : {
6084 tgl 7054 GIC 8 : appendContextKeyword(context, " RETURNING",
6084 tgl 7055 EUB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
323 tgl 7056 GBC 8 : get_target_list(query->returningList, context, NULL, colNamesVisible);
7057 : }
8994 bruce 7058 GIC 38 : }
7059 :
7060 :
7061 : /* ----------
8131 tgl 7062 EUB : * get_utility_query_def - Parse back a UTILITY parsetree
7063 : * ----------
8131 tgl 7064 ECB : */
7065 : static void
8131 tgl 7066 GIC 8 : get_utility_query_def(Query *query, deparse_context *context)
7067 : {
7068 8 : StringInfo buf = context->buf;
7069 :
7070 8 : if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7071 8 : {
7072 8 : NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7073 :
7193 7074 8 : appendContextKeyword(context, "",
7075 : 0, PRETTYINDENT_STD, 1);
7688 7076 8 : appendStringInfo(buf, "NOTIFY %s",
5333 7077 8 : quote_identifier(stmt->conditionname));
4800 7078 8 : if (stmt->payload)
7079 : {
4800 tgl 7080 UIC 0 : appendStringInfoString(buf, ", ");
7081 0 : simple_quote_literal(buf, stmt->payload);
7082 : }
7083 : }
7084 : else
7085 : {
7196 tgl 7086 ECB : /* Currently only NOTIFY utility commands can appear in rules */
7196 tgl 7087 UIC 0 : elog(ERROR, "unexpected utility statement type");
7196 tgl 7088 ECB : }
8131 tgl 7089 GIC 8 : }
7090 :
7091 : /*
7092 : * Display a Var appropriately.
7093 : *
7094 : * In some cases (currently only when recursing into an unnamed join)
7095 : * the Var's varlevelsup has to be interpreted with respect to a context
7096 : * above the current one; levelsup indicates the offset.
7097 : *
7098 : * If istoplevel is true, the Var is at the top level of a SELECT's
7099 : * targetlist, which means we need special treatment of whole-row Vars.
3999 tgl 7100 ECB : * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
7101 : * dirty hack to prevent "tab.*" from being expanded into multiple columns.
3999 tgl 7102 EUB : * (The parser will strip the useless coercion, so no inefficiency is added in
7103 : * dump and reload.) We used to print just "tab" in such cases, but that is
3999 tgl 7104 ECB : * ambiguous and will yield the wrong result if "tab" is also a plain column
7105 : * name in the query.
7106 : *
7107 : * Returns the attname of the Var, or NULL if the Var has no attname (because
7108 : * it is a whole-row Var or a subplan output reference).
7109 : */
7110 : static char *
3999 tgl 7111 GIC 64306 : get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
7112 : {
5889 7113 64306 : StringInfo buf = context->buf;
7114 : RangeTblEntry *rte;
5889 tgl 7115 ECB : AttrNumber attnum;
7116 : int netlevelsup;
8089 7117 : deparse_namespace *dpns;
571 7118 : int varno;
7119 : AttrNumber varattno;
7120 : deparse_columns *colinfo;
7121 : char *refname;
5889 7122 : char *attname;
6210 7123 :
7124 : /* Find appropriate nesting depth */
6660 tgl 7125 GIC 64306 : netlevelsup = var->varlevelsup + levelsup;
7126 64306 : if (netlevelsup >= list_length(context->namespaces))
6660 tgl 7127 UIC 0 : elog(ERROR, "bogus varlevelsup: %d offset %d",
7128 : var->varlevelsup, levelsup);
6892 tgl 7129 GIC 64306 : dpns = (deparse_namespace *) list_nth(context->namespaces,
7130 : netlevelsup);
7131 :
1186 tgl 7132 ECB : /*
7133 : * If we have a syntactic referent for the Var, and we're working from a
7134 : * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7135 : * on the semantic referent. (Forcing use of the semantic referent when
7136 : * printing plan trees is a design choice that's perhaps more motivated by
7137 : * backwards compatibility than anything else. But it does have the
7138 : * advantage of making plans more explicit.)
7139 : */
1186 tgl 7140 CBC 64306 : if (var->varnosyn > 0 && dpns->plan == NULL)
1186 tgl 7141 ECB : {
1186 tgl 7142 CBC 12577 : varno = var->varnosyn;
1186 tgl 7143 GIC 12577 : varattno = var->varattnosyn;
7144 : }
1186 tgl 7145 ECB : else
7146 : {
1186 tgl 7147 CBC 51729 : varno = var->varno;
1186 tgl 7148 GIC 51729 : varattno = var->varattno;
1186 tgl 7149 ECB : }
7150 :
7151 : /*
6210 7152 : * Try to find the relevant RTE in this rtable. In a plan tree, it's
4198 tgl 7153 EUB : * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
3751 tgl 7154 ECB : * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7155 : * find the aliases previously assigned for this RTE.
6210 tgl 7156 EUB : */
1186 tgl 7157 GIC 64306 : if (varno >= 1 && varno <= list_length(dpns->rtable))
7158 : {
1215 tgl 7159 ECB : /*
7160 : * We might have been asked to map child Vars to some parent relation.
7161 : */
1215 tgl 7162 GIC 48323 : if (context->appendparents && dpns->appendrels)
1215 tgl 7163 ECB : {
571 tgl 7164 CBC 1741 : int pvarno = varno;
1215 tgl 7165 GIC 1741 : AttrNumber pvarattno = varattno;
7166 1741 : AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7167 1741 : bool found = false;
7168 :
7169 : /* Only map up to inheritance parents, not UNION ALL appendrels */
7170 3539 : while (appinfo &&
1215 tgl 7171 CBC 1935 : rt_fetch(appinfo->parent_relid,
1215 tgl 7172 GIC 1935 : dpns->rtable)->rtekind == RTE_RELATION)
1215 tgl 7173 ECB : {
1215 tgl 7174 CBC 1798 : found = false;
1215 tgl 7175 GIC 1798 : if (pvarattno > 0) /* system columns stay as-is */
7176 : {
7177 1661 : if (pvarattno > appinfo->num_child_cols)
1215 tgl 7178 LBC 0 : break; /* safety check */
1215 tgl 7179 CBC 1661 : pvarattno = appinfo->parent_colnos[pvarattno - 1];
7180 1661 : if (pvarattno == 0)
1215 tgl 7181 LBC 0 : break; /* Var is local to child */
7182 : }
7183 :
1215 tgl 7184 GIC 1798 : pvarno = appinfo->parent_relid;
1215 tgl 7185 CBC 1798 : found = true;
7186 :
1215 tgl 7187 ECB : /* If the parent is itself a child, continue up. */
1215 tgl 7188 GIC 1798 : Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7189 1798 : appinfo = dpns->appendrels[pvarno];
7190 : }
7191 :
7192 : /*
7193 : * If we found an ancestral rel, and that rel is included in
7194 : * appendparents, print that column not the original one.
7195 : */
7196 1741 : if (found && bms_is_member(pvarno, context->appendparents))
7197 : {
7198 1439 : varno = pvarno;
7199 1439 : varattno = pvarattno;
7200 : }
1215 tgl 7201 ECB : }
7202 :
1215 tgl 7203 CBC 48323 : rte = rt_fetch(varno, dpns->rtable);
1215 tgl 7204 GIC 48323 : refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7205 48323 : colinfo = deparse_columns_fetch(varno, dpns);
7206 48323 : attnum = varattno;
7207 : }
5889 tgl 7208 ECB : else
7209 : {
1215 tgl 7210 GBC 15983 : resolve_special_varno((Node *) var, context,
7211 : get_special_variable, NULL);
2538 rhaas 7212 GIC 15983 : return NULL;
5889 tgl 7213 ECB : }
7214 :
7215 : /*
7216 : * The planner will sometimes emit Vars referencing resjunk elements of a
7217 : * subquery's target list (this is currently only possible if it chooses
7218 : * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7219 : * Although we prefer to print subquery-referencing Vars using the
4657 7220 : * subquery's alias, that's not possible for resjunk items since they have
4657 tgl 7221 EUB : * no alias. So in that case, drill down to the subplan and print the
4657 tgl 7222 ECB : * contents of the referenced tlist item. This works because in a plan
4382 bruce 7223 : * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
1215 tgl 7224 EUB : * we'll have set dpns->inner_plan to reference the child plan node.
7225 : */
4657 tgl 7226 CBC 49913 : if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7227 1590 : attnum > list_length(rte->eref->colnames) &&
1215 tgl 7228 GIC 1 : dpns->inner_plan)
7229 : {
7230 : TargetEntry *tle;
7231 : deparse_namespace save_dpns;
7232 :
7233 1 : tle = get_tle_by_resno(dpns->inner_tlist, attnum);
4657 7234 1 : if (!tle)
2473 tgl 7235 UIC 0 : elog(ERROR, "invalid attnum %d for relation \"%s\"",
7236 : attnum, rte->eref->aliasname);
7237 :
4657 tgl 7238 GIC 1 : Assert(netlevelsup == 0);
1215 7239 1 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7240 :
7241 : /*
4657 tgl 7242 ECB : * Force parentheses because our caller probably assumed a Var is a
7243 : * simple expression.
7244 : */
4657 tgl 7245 GBC 1 : if (!IsA(tle->expr, Var))
4657 tgl 7246 LBC 0 : appendStringInfoChar(buf, '(');
4657 tgl 7247 GIC 1 : get_rule_expr((Node *) tle->expr, context, true);
7248 1 : if (!IsA(tle->expr, Var))
4657 tgl 7249 UIC 0 : appendStringInfoChar(buf, ')');
4657 tgl 7250 ECB :
4653 tgl 7251 GIC 1 : pop_child_plan(dpns, &save_dpns);
4657 tgl 7252 CBC 1 : return NULL;
7253 : }
4657 tgl 7254 EUB :
7255 : /*
7256 : * If it's an unnamed join, look at the expansion of the alias variable.
7257 : * If it's a simple reference to one of the input vars, then recursively
7258 : * print the name of that var instead. When it's not a simple reference,
7259 : * we have to just print the unqualified join column name. (This can only
7260 : * happen with "dangerous" merged columns in a JOIN USING; we took pains
7261 : * previously to make the unqualified column name unique in such cases.)
7262 : *
7263 : * This wouldn't work in decompiling plan trees, because we don't store
3852 tgl 7264 ECB : * joinaliasvars lists after planning; but a plan tree should never
7265 : * contain a join alias variable.
7266 : */
3852 tgl 7267 CBC 48322 : if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7549 tgl 7268 ECB : {
3852 tgl 7269 CBC 48 : if (rte->joinaliasvars == NIL)
3852 tgl 7270 UIC 0 : elog(ERROR, "cannot decompile join alias var in plan tree");
3852 tgl 7271 GIC 48 : if (attnum > 0)
7549 tgl 7272 ECB : {
3852 tgl 7273 EUB : Var *aliasvar;
7274 :
3852 tgl 7275 CBC 48 : aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7276 : /* we intentionally don't strip implicit coercions here */
3547 tgl 7277 GIC 48 : if (aliasvar && IsA(aliasvar, Var))
7278 : {
3852 tgl 7279 UIC 0 : return get_variable(aliasvar, var->varlevelsup + levelsup,
7280 : istoplevel, context);
7281 : }
7282 : }
7283 :
3852 tgl 7284 ECB : /*
7285 : * Unnamed join has no refname. (Note: since it's unnamed, there is
7286 : * no way the user could have referenced it to create a whole-row Var
7287 : * for it. So we don't have to cover that case below.)
7288 : */
3852 tgl 7289 GIC 48 : Assert(refname == NULL);
7549 tgl 7290 ECB : }
7291 :
6210 tgl 7292 GIC 48322 : if (attnum == InvalidAttrNumber)
5889 tgl 7293 CBC 379 : attname = NULL;
3751 tgl 7294 GIC 47943 : else if (attnum > 0)
3751 tgl 7295 ECB : {
7296 : /* Get column name to use from the colinfo struct */
2473 tgl 7297 GIC 47342 : if (attnum > colinfo->num_cols)
2473 tgl 7298 LBC 0 : elog(ERROR, "invalid attnum %d for relation \"%s\"",
2473 tgl 7299 ECB : attnum, rte->eref->aliasname);
3751 tgl 7300 GIC 47342 : attname = colinfo->colnames[attnum - 1];
7301 :
262 tgl 7302 ECB : /*
7303 : * If we find a Var referencing a dropped column, it seems better to
7304 : * print something (anything) than to fail. In general this should
7305 : * not happen, but it used to be possible for some cases involving
7306 : * functions returning named composite types, and perhaps there are
7307 : * still bugs out there.
7308 : */
262 tgl 7309 CBC 47342 : if (attname == NULL)
262 tgl 7310 GIC 3 : attname = "?dropped?column?";
7311 : }
7312 : else
7313 : {
7314 : /* System column - name is fixed, get it from the catalog */
5889 7315 601 : attname = get_rte_attribute_name(rte, attnum);
7316 : }
7317 :
7318 48322 : if (refname && (context->varprefix || attname == NULL))
7319 : {
4903 tgl 7320 CBC 22198 : appendStringInfoString(buf, quote_identifier(refname));
3999 tgl 7321 GIC 22198 : appendStringInfoChar(buf, '.');
5889 tgl 7322 ECB : }
5889 tgl 7323 GIC 48322 : if (attname)
7324 47943 : appendStringInfoString(buf, quote_identifier(attname));
7325 : else
7326 : {
7327 379 : appendStringInfoChar(buf, '*');
3999 tgl 7328 CBC 379 : if (istoplevel)
7329 36 : appendStringInfo(buf, "::%s",
3999 tgl 7330 ECB : format_type_with_typemod(var->vartype,
7331 : var->vartypmod));
7332 : }
5889 7333 :
5889 tgl 7334 GIC 48322 : return attname;
7335 : }
7336 :
7337 : /*
7338 : * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
7339 : * routine is actually a callback for resolve_special_varno, which handles
7340 : * finding the correct TargetEntry. We get the expression contained in that
2538 rhaas 7341 ECB : * TargetEntry and just need to deparse it, a job we can throw back on
7342 : * get_rule_expr.
7343 : */
7344 : static void
1215 tgl 7345 GIC 15983 : get_special_variable(Node *node, deparse_context *context, void *callback_arg)
7346 : {
2538 rhaas 7347 15983 : StringInfo buf = context->buf;
2538 rhaas 7348 ECB :
7349 : /*
7350 : * For a non-Var referent, force parentheses because our caller probably
1215 tgl 7351 : * assumed a Var is a simple expression.
7352 : */
2538 rhaas 7353 CBC 15983 : if (!IsA(node, Var))
7354 1506 : appendStringInfoChar(buf, '(');
2538 rhaas 7355 GIC 15983 : get_rule_expr(node, context, true);
7356 15983 : if (!IsA(node, Var))
7357 1506 : appendStringInfoChar(buf, ')');
2538 rhaas 7358 CBC 15983 : }
2538 rhaas 7359 ECB :
7360 : /*
7361 : * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
7362 : * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
7363 : * invoke the callback provided.
7364 : */
7365 : static void
1215 tgl 7366 CBC 44201 : resolve_special_varno(Node *node, deparse_context *context,
7367 : rsv_callback callback, void *callback_arg)
7368 : {
7369 : Var *var;
7370 : deparse_namespace *dpns;
7371 :
1215 tgl 7372 ECB : /* This function is recursive, so let's be paranoid. */
1215 tgl 7373 CBC 44201 : check_stack_depth();
1215 tgl 7374 EUB :
7375 : /* If it's not a Var, invoke the callback. */
2538 rhaas 7376 GIC 44201 : if (!IsA(node, Var))
7377 : {
1215 tgl 7378 1636 : (*callback) (node, context, callback_arg);
2538 rhaas 7379 1636 : return;
7380 : }
2538 rhaas 7381 ECB :
7382 : /* Find appropriate nesting depth */
2538 rhaas 7383 CBC 42565 : var = (Var *) node;
7384 42565 : dpns = (deparse_namespace *) list_nth(context->namespaces,
7385 42565 : var->varlevelsup);
2538 rhaas 7386 ECB :
7387 : /*
1186 tgl 7388 : * If varno is special, recurse. (Don't worry about varnosyn; if we're
7389 : * here, we already decided not to use that.)
2538 rhaas 7390 : */
2538 rhaas 7391 CBC 42565 : if (var->varno == OUTER_VAR && dpns->outer_tlist)
7392 : {
2538 rhaas 7393 ECB : TargetEntry *tle;
7394 : deparse_namespace save_dpns;
1215 tgl 7395 : Bitmapset *save_appendparents;
7396 :
2538 rhaas 7397 CBC 21079 : tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
2538 rhaas 7398 GIC 21079 : if (!tle)
2538 rhaas 7399 UIC 0 : elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7400 :
7401 : /*
1215 tgl 7402 ECB : * If we're descending to the first child of an Append or MergeAppend,
7403 : * update appendparents. This will affect deparsing of all Vars
1215 tgl 7404 EUB : * appearing within the eventually-resolved subexpression.
7405 : */
1215 tgl 7406 CBC 21079 : save_appendparents = context->appendparents;
1215 tgl 7407 ECB :
1215 tgl 7408 GIC 21079 : if (IsA(dpns->plan, Append))
1215 tgl 7409 CBC 1948 : context->appendparents = bms_union(context->appendparents,
7410 1948 : ((Append *) dpns->plan)->apprelids);
1215 tgl 7411 GIC 19131 : else if (IsA(dpns->plan, MergeAppend))
1215 tgl 7412 CBC 243 : context->appendparents = bms_union(context->appendparents,
1215 tgl 7413 GIC 243 : ((MergeAppend *) dpns->plan)->apprelids);
7414 :
7415 21079 : push_child_plan(dpns, dpns->outer_plan, &save_dpns);
1215 tgl 7416 CBC 21079 : resolve_special_varno((Node *) tle->expr, context,
1215 tgl 7417 ECB : callback, callback_arg);
2538 rhaas 7418 GBC 21079 : pop_child_plan(dpns, &save_dpns);
1215 tgl 7419 GIC 21079 : context->appendparents = save_appendparents;
2538 rhaas 7420 CBC 21079 : return;
7421 : }
7422 21486 : else if (var->varno == INNER_VAR && dpns->inner_tlist)
7423 : {
2538 rhaas 7424 ECB : TargetEntry *tle;
2538 rhaas 7425 EUB : deparse_namespace save_dpns;
7426 :
2538 rhaas 7427 GIC 5083 : tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
2538 rhaas 7428 CBC 5083 : if (!tle)
2538 rhaas 7429 UIC 0 : elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7430 :
1215 tgl 7431 GIC 5083 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7432 5083 : resolve_special_varno((Node *) tle->expr, context,
7433 : callback, callback_arg);
2538 rhaas 7434 5083 : pop_child_plan(dpns, &save_dpns);
7435 5083 : return;
7436 : }
7437 16403 : else if (var->varno == INDEX_VAR && dpns->index_tlist)
7438 : {
7439 : TargetEntry *tle;
7440 :
7441 1926 : tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
7442 1926 : if (!tle)
2538 rhaas 7443 UIC 0 : elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
7444 :
1215 tgl 7445 GIC 1926 : resolve_special_varno((Node *) tle->expr, context,
7446 : callback, callback_arg);
2538 rhaas 7447 1926 : return;
7448 : }
2538 rhaas 7449 CBC 14477 : else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
2538 rhaas 7450 UIC 0 : elog(ERROR, "bogus varno: %d", var->varno);
7451 :
7452 : /* Not special. Just invoke the callback. */
1215 tgl 7453 GIC 14477 : (*callback) (node, context, callback_arg);
7454 : }
7455 :
7456 : /*
7457 : * Get the name of a field of an expression of composite type. The
7458 : * expression is usually a Var, but we handle other cases too.
7459 : *
7460 : * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
7461 : *
7462 : * This is fairly straightforward when the expression has a named composite
7463 : * type; we need only look up the type in the catalogs. However, the type
7464 : * could also be RECORD. Since no actual table or view column is allowed to
7465 : * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
4232 tgl 7466 ECB : * or to a subquery output. We drill down to find the ultimate defining
7467 : * expression and attempt to infer the field name from it. We ereport if we
7468 : * can't determine the name.
7469 : *
7470 : * Similarly, a PARAM of type RECORD has to refer to some expression of
7471 : * a determinable composite type.
7472 : */
7473 : static const char *
6522 tgl 7474 GIC 376 : get_name_for_var_field(Var *var, int fieldno,
7475 : int levelsup, deparse_context *context)
7476 : {
6522 tgl 7477 ECB : RangeTblEntry *rte;
7478 : AttrNumber attnum;
5889 7479 : int netlevelsup;
7480 : deparse_namespace *dpns;
7481 : int varno;
1186 7482 : AttrNumber varattno;
6522 7483 : TupleDesc tupleDesc;
7484 : Node *expr;
7485 :
7486 : /*
7487 : * If it's a RowExpr that was expanded from a whole-row Var, use the
7488 : * column names attached to it. (We could let get_expr_result_tupdesc()
175 7489 : * handle this, but it's much cheaper to just pull out the name we need.)
5298 7490 : */
5298 tgl 7491 GIC 376 : if (IsA(var, RowExpr))
5298 tgl 7492 ECB : {
5050 bruce 7493 CBC 18 : RowExpr *r = (RowExpr *) var;
7494 :
5298 tgl 7495 GIC 18 : if (fieldno > 0 && fieldno <= list_length(r->colnames))
7496 18 : return strVal(list_nth(r->colnames, fieldno - 1));
7497 : }
7498 :
7499 : /*
7500 : * If it's a Param of type RECORD, try to find what the Param refers to.
4232 tgl 7501 ECB : */
4232 tgl 7502 CBC 358 : if (IsA(var, Param))
7503 : {
7504 6 : Param *param = (Param *) var;
7505 : ListCell *ancestor_cell;
4232 tgl 7506 ECB :
4232 tgl 7507 CBC 6 : expr = find_param_referent(param, context, &dpns, &ancestor_cell);
4232 tgl 7508 GIC 6 : if (expr)
7509 : {
7510 : /* Found a match, so recurse to decipher the field name */
4232 tgl 7511 ECB : deparse_namespace save_dpns;
7512 : const char *result;
4232 tgl 7513 EUB :
4232 tgl 7514 GIC 6 : push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
4232 tgl 7515 CBC 6 : result = get_name_for_var_field((Var *) expr, fieldno,
7516 : 0, context);
4232 tgl 7517 GIC 6 : pop_ancestor_plan(dpns, &save_dpns);
7518 6 : return result;
7519 : }
7520 : }
7521 :
7522 : /*
5889 tgl 7523 ECB : * If it's a Var of type RECORD, we have to find what the Var refers to;
7524 : * if not, we can use get_expr_result_tupdesc().
7525 : */
5889 tgl 7526 CBC 352 : if (!IsA(var, Var) ||
5889 tgl 7527 GIC 324 : var->vartype != RECORDOID)
7528 : {
1991 7529 271 : tupleDesc = get_expr_result_tupdesc((Node *) var, false);
5889 tgl 7530 ECB : /* Got the tupdesc, so we can extract the field name */
5889 tgl 7531 CBC 271 : Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
2058 andres 7532 GIC 271 : return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7533 : }
7534 :
7535 : /* Find appropriate nesting depth */
5889 tgl 7536 81 : netlevelsup = var->varlevelsup + levelsup;
7537 81 : if (netlevelsup >= list_length(context->namespaces))
5889 tgl 7538 UIC 0 : elog(ERROR, "bogus varlevelsup: %d offset %d",
7539 : var->varlevelsup, levelsup);
5889 tgl 7540 GIC 81 : dpns = (deparse_namespace *) list_nth(context->namespaces,
7541 : netlevelsup);
7542 :
1186 tgl 7543 ECB : /*
7544 : * If we have a syntactic referent for the Var, and we're working from a
7545 : * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7546 : * on the semantic referent. (See comments in get_variable().)
7547 : */
1186 tgl 7548 CBC 81 : if (var->varnosyn > 0 && dpns->plan == NULL)
7549 : {
1186 tgl 7550 GIC 27 : varno = var->varnosyn;
7551 27 : varattno = var->varattnosyn;
7552 : }
7553 : else
1186 tgl 7554 ECB : {
1186 tgl 7555 CBC 54 : varno = var->varno;
1186 tgl 7556 GBC 54 : varattno = var->varattno;
7557 : }
1186 tgl 7558 ECB :
5889 7559 : /*
7560 : * Try to find the relevant RTE in this rtable. In a plan tree, it's
4198 7561 : * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7562 : * down into the subplans, or INDEX_VAR, which is resolved similarly.
7563 : *
1215 7564 : * Note: unlike get_variable and resolve_special_varno, we need not worry
7565 : * about inheritance mapping: a child Var should have the same datatype as
7566 : * its parent, and here we're really only interested in the Var's type.
5889 7567 : */
1186 tgl 7568 GIC 81 : if (varno >= 1 && varno <= list_length(dpns->rtable))
7569 : {
7570 42 : rte = rt_fetch(varno, dpns->rtable);
7571 42 : attnum = varattno;
7572 : }
1186 tgl 7573 CBC 39 : else if (varno == OUTER_VAR && dpns->outer_tlist)
5889 tgl 7574 ECB : {
5889 tgl 7575 EUB : TargetEntry *tle;
7576 : deparse_namespace save_dpns;
5889 tgl 7577 ECB : const char *result;
7578 :
1186 tgl 7579 GIC 30 : tle = get_tle_by_resno(dpns->outer_tlist, varattno);
5889 tgl 7580 CBC 30 : if (!tle)
1186 tgl 7581 UIC 0 : elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
7582 :
5889 tgl 7583 CBC 30 : Assert(netlevelsup == 0);
1215 7584 30 : push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7585 :
5889 tgl 7586 GBC 30 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
7587 : levelsup, context);
7588 :
4653 tgl 7589 GIC 30 : pop_child_plan(dpns, &save_dpns);
5889 7590 30 : return result;
5889 tgl 7591 EUB : }
1186 tgl 7592 GBC 9 : else if (varno == INNER_VAR && dpns->inner_tlist)
5889 tgl 7593 EUB : {
7594 : TargetEntry *tle;
4653 7595 : deparse_namespace save_dpns;
7596 : const char *result;
5889 7597 :
1186 tgl 7598 GIC 9 : tle = get_tle_by_resno(dpns->inner_tlist, varattno);
5889 7599 9 : if (!tle)
1186 tgl 7600 UBC 0 : elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
7601 :
5889 tgl 7602 GIC 9 : Assert(netlevelsup == 0);
1215 7603 9 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
5889 tgl 7604 EUB :
5889 tgl 7605 GIC 9 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
7606 : levelsup, context);
7607 :
4653 tgl 7608 CBC 9 : pop_child_plan(dpns, &save_dpns);
5889 tgl 7609 GIC 9 : return result;
7610 : }
1186 tgl 7611 LBC 0 : else if (varno == INDEX_VAR && dpns->index_tlist)
7612 : {
7613 : TargetEntry *tle;
7614 : const char *result;
7615 :
1186 tgl 7616 UIC 0 : tle = get_tle_by_resno(dpns->index_tlist, varattno);
4198 7617 0 : if (!tle)
1186 7618 0 : elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
7619 :
4198 7620 0 : Assert(netlevelsup == 0);
4198 tgl 7621 ECB :
4198 tgl 7622 UIC 0 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
4198 tgl 7623 ECB : levelsup, context);
7624 :
4198 tgl 7625 UBC 0 : return result;
7626 : }
7627 : else
7628 : {
1186 tgl 7629 UIC 0 : elog(ERROR, "bogus varno: %d", varno);
7630 : return NULL; /* keep compiler quiet */
7631 : }
7632 :
6522 tgl 7633 GIC 42 : if (attnum == InvalidAttrNumber)
7634 : {
6522 tgl 7635 EUB : /* Var is whole-row reference to RTE, so select the right field */
6522 tgl 7636 CBC 12 : return get_rte_attribute_name(rte, fieldno);
7637 : }
7638 :
5889 tgl 7639 ECB : /*
7640 : * This part has essentially the same logic as the parser's
7641 : * expandRecordVariable() function, but we are dealing with a different
7642 : * representation of the input context, and we only need one field name
7643 : * not a TupleDesc. Also, we need special cases for finding subquery and
5050 bruce 7644 : * CTE subplans when deparsing Plan trees.
5889 tgl 7645 EUB : */
6522 tgl 7646 GIC 30 : expr = (Node *) var; /* default if we can't drill down */
6522 tgl 7647 ECB :
6522 tgl 7648 CBC 30 : switch (rte->rtekind)
7649 : {
6522 tgl 7650 UIC 0 : case RTE_RELATION:
7651 : case RTE_VALUES:
7652 : case RTE_NAMEDTUPLESTORE:
7653 : case RTE_RESULT:
7654 :
7655 : /*
7656 : * This case should not occur: a column of a table, values list,
7657 : * or ENR shouldn't have type RECORD. Fall through and fail (most
7658 : * likely) at the bottom.
6522 tgl 7659 ECB : */
6522 tgl 7660 UIC 0 : break;
6522 tgl 7661 GIC 9 : case RTE_SUBQUERY:
5298 tgl 7662 ECB : /* Subselect-in-FROM: examine sub-select's output expr */
7663 : {
5889 tgl 7664 GIC 9 : if (rte->subquery)
6522 tgl 7665 ECB : {
5889 tgl 7666 GIC 6 : TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
7667 : attnum);
5889 tgl 7668 ECB :
5889 tgl 7669 CBC 6 : if (ste == NULL || ste->resjunk)
5889 tgl 7670 UIC 0 : elog(ERROR, "subquery %s does not have attribute %d",
5889 tgl 7671 ECB : rte->eref->aliasname, attnum);
5889 tgl 7672 GIC 6 : expr = (Node *) ste->expr;
7673 6 : if (IsA(expr, Var))
7674 : {
7675 : /*
7676 : * Recurse into the sub-select to see what its Var
7677 : * refers to. We have to build an additional level of
7678 : * namespace to keep in step with varlevelsup in the
7679 : * subselect.
7680 : */
7681 : deparse_namespace mydpns;
7682 : const char *result;
7683 :
3751 7684 6 : set_deparse_for_query(&mydpns, rte->subquery,
7685 : context->namespaces);
7686 :
5889 7687 6 : context->namespaces = lcons(&mydpns,
5889 tgl 7688 ECB : context->namespaces);
6522 tgl 7689 EUB :
5889 tgl 7690 GIC 6 : result = get_name_for_var_field((Var *) expr, fieldno,
5889 tgl 7691 ECB : 0, context);
6522 7692 :
5889 tgl 7693 GBC 6 : context->namespaces =
5889 tgl 7694 GIC 6 : list_delete_first(context->namespaces);
6522 tgl 7695 ECB :
5889 tgl 7696 CBC 6 : return result;
7697 : }
5889 tgl 7698 ECB : /* else fall through to inspect the expression */
7699 : }
7700 : else
7701 : {
7702 : /*
7703 : * We're deparsing a Plan tree so we don't have complete
7704 : * RTE entries (in particular, rte->subquery is NULL). But
5050 bruce 7705 EUB : * the only place we'd see a Var directly referencing a
7706 : * SUBQUERY RTE is in a SubqueryScan plan node, and we can
7707 : * look into the child plan's tlist instead.
5889 tgl 7708 : */
7709 : TargetEntry *tle;
4653 7710 : deparse_namespace save_dpns;
5889 7711 : const char *result;
7712 :
1215 tgl 7713 GIC 3 : if (!dpns->inner_plan)
5889 tgl 7714 UBC 0 : elog(ERROR, "failed to find plan for subquery %s",
5889 tgl 7715 EUB : rte->eref->aliasname);
4198 tgl 7716 GBC 3 : tle = get_tle_by_resno(dpns->inner_tlist, attnum);
5889 tgl 7717 GIC 3 : if (!tle)
5889 tgl 7718 UIC 0 : elog(ERROR, "bogus varattno for subquery var: %d",
5889 tgl 7719 EUB : attnum);
5889 tgl 7720 GBC 3 : Assert(netlevelsup == 0);
1215 tgl 7721 GIC 3 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7722 :
5889 7723 3 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
7724 : levelsup, context);
7725 :
4653 7726 3 : pop_child_plan(dpns, &save_dpns);
6522 tgl 7727 GBC 3 : return result;
6522 tgl 7728 ECB : }
7729 : }
6522 tgl 7730 UIC 0 : break;
6522 tgl 7731 LBC 0 : case RTE_JOIN:
7732 : /* Join RTE --- recursively inspect the alias variable */
5799 tgl 7733 UIC 0 : if (rte->joinaliasvars == NIL)
7734 0 : elog(ERROR, "cannot decompile join alias var in plan tree");
6522 7735 0 : Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
7736 0 : expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
3547 7737 0 : Assert(expr != NULL);
3547 tgl 7738 ECB : /* we intentionally don't strip implicit coercions here */
6522 tgl 7739 LBC 0 : if (IsA(expr, Var))
7740 0 : return get_name_for_var_field((Var *) expr, fieldno,
6522 tgl 7741 UIC 0 : var->varlevelsup + levelsup,
7742 : context);
7743 : /* else fall through to inspect the expression */
7744 0 : break;
7745 0 : case RTE_FUNCTION:
2223 alvherre 7746 ECB : case RTE_TABLEFUNC:
6385 bruce 7747 :
7748 : /*
7749 : * We couldn't get here unless a function is declared with one of
7750 : * its result columns as RECORD, which is not allowed.
6522 tgl 7751 : */
6522 tgl 7752 UIC 0 : break;
5300 tgl 7753 GIC 21 : case RTE_CTE:
5298 tgl 7754 ECB : /* CTE reference: examine subquery's output expr */
7755 : {
5298 tgl 7756 CBC 21 : CommonTableExpr *cte = NULL;
5298 tgl 7757 ECB : Index ctelevelsup;
7758 : ListCell *lc;
7759 :
7760 : /*
5298 tgl 7761 EUB : * Try to find the referenced CTE using the namespace stack.
7762 : */
5298 tgl 7763 CBC 21 : ctelevelsup = rte->ctelevelsup + netlevelsup;
7764 21 : if (ctelevelsup >= list_length(context->namespaces))
5298 tgl 7765 GIC 6 : lc = NULL;
7766 : else
7767 : {
7768 : deparse_namespace *ctedpns;
7769 :
7770 : ctedpns = (deparse_namespace *)
7771 15 : list_nth(context->namespaces, ctelevelsup);
7772 15 : foreach(lc, ctedpns->ctes)
5298 tgl 7773 ECB : {
5298 tgl 7774 GIC 9 : cte = (CommonTableExpr *) lfirst(lc);
7775 9 : if (strcmp(cte->ctename, rte->ctename) == 0)
7776 9 : break;
7777 : }
5298 tgl 7778 ECB : }
5298 tgl 7779 GIC 21 : if (lc != NULL)
7780 : {
5298 tgl 7781 CBC 9 : Query *ctequery = (Query *) cte->ctequery;
4382 bruce 7782 GIC 9 : TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte),
5298 tgl 7783 ECB : attnum);
7784 :
5298 tgl 7785 CBC 9 : if (ste == NULL || ste->resjunk)
5298 tgl 7786 UIC 0 : elog(ERROR, "subquery %s does not have attribute %d",
7787 : rte->eref->aliasname, attnum);
5298 tgl 7788 CBC 9 : expr = (Node *) ste->expr;
5298 tgl 7789 GIC 9 : if (IsA(expr, Var))
5298 tgl 7790 ECB : {
7791 : /*
7792 : * Recurse into the CTE to see what its Var refers to.
7793 : * We have to build an additional level of namespace
7794 : * to keep in step with varlevelsup in the CTE.
7795 : * Furthermore it could be an outer CTE, so we may
7796 : * have to delete some levels of namespace.
7797 : */
5298 tgl 7798 GIC 6 : List *save_nslist = context->namespaces;
7799 : List *new_nslist;
7800 : deparse_namespace mydpns;
7801 : const char *result;
7802 :
3751 7803 6 : set_deparse_for_query(&mydpns, ctequery,
7804 : context->namespaces);
7805 :
5298 7806 6 : new_nslist = list_copy_tail(context->namespaces,
7807 : ctelevelsup);
7808 6 : context->namespaces = lcons(&mydpns, new_nslist);
5298 tgl 7809 ECB :
5298 tgl 7810 GBC 6 : result = get_name_for_var_field((Var *) expr, fieldno,
7811 : 0, context);
5298 tgl 7812 ECB :
5298 tgl 7813 CBC 6 : context->namespaces = save_nslist;
5298 tgl 7814 EUB :
5298 tgl 7815 GIC 6 : return result;
5298 tgl 7816 ECB : }
7817 : /* else fall through to inspect the expression */
7818 : }
7819 : else
7820 : {
7821 : /*
7822 : * We're deparsing a Plan tree so we don't have a CTE
570 7823 : * list. But the only places we'd see a Var directly
7824 : * referencing a CTE RTE are in CteScan or WorkTableScan
7825 : * plan nodes. For those cases, set_deparse_plan arranged
7826 : * for dpns->inner_plan to be the plan node that emits the
7827 : * CTE or RecursiveUnion result, and we can look at its
7828 : * tlist instead.
7829 : */
7830 : TargetEntry *tle;
7831 : deparse_namespace save_dpns;
7832 : const char *result;
5298 7833 :
1215 tgl 7834 GIC 12 : if (!dpns->inner_plan)
5298 tgl 7835 LBC 0 : elog(ERROR, "failed to find plan for CTE %s",
5298 tgl 7836 ECB : rte->eref->aliasname);
4198 tgl 7837 GIC 12 : tle = get_tle_by_resno(dpns->inner_tlist, attnum);
5298 7838 12 : if (!tle)
5298 tgl 7839 UIC 0 : elog(ERROR, "bogus varattno for subquery var: %d",
7840 : attnum);
5298 tgl 7841 GIC 12 : Assert(netlevelsup == 0);
1215 7842 12 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7843 :
5298 7844 12 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
7845 : levelsup, context);
7846 :
4653 7847 12 : pop_child_plan(dpns, &save_dpns);
5298 tgl 7848 CBC 12 : return result;
7849 : }
7850 : }
5300 tgl 7851 GIC 3 : break;
6522 tgl 7852 ECB : }
7853 :
7854 : /*
7855 : * We now have an expression we can't expand any more, so see if
7856 : * get_expr_result_tupdesc() can do anything with it.
7857 : */
1991 tgl 7858 GIC 3 : tupleDesc = get_expr_result_tupdesc(expr, false);
7859 : /* Got the tupdesc, so we can extract the field name */
6522 tgl 7860 CBC 3 : Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
2058 andres 7861 GIC 3 : return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7862 : }
7863 :
7864 : /*
7865 : * Try to find the referenced expression for a PARAM_EXEC Param that might
4232 tgl 7866 ECB : * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
7867 : *
7868 : * If successful, return the expression and set *dpns_p and *ancestor_cell_p
3260 bruce 7869 : * appropriately for calling push_ancestor_plan(). If no referent can be
7870 : * found, return NULL.
4653 tgl 7871 : */
7872 : static Node *
4232 tgl 7873 GIC 2425 : find_param_referent(Param *param, deparse_context *context,
7874 : deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
7875 : {
7876 : /* Initialize output parameters to prevent compiler warnings */
4232 tgl 7877 CBC 2425 : *dpns_p = NULL;
7878 2425 : *ancestor_cell_p = NULL;
7879 :
4653 tgl 7880 ECB : /*
7881 : * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
4232 7882 : * SubPlan argument. This will necessarily be in some ancestor of the
7883 : * current expression's Plan node.
4653 7884 : */
4653 tgl 7885 GIC 2425 : if (param->paramkind == PARAM_EXEC)
4653 tgl 7886 ECB : {
7887 : deparse_namespace *dpns;
7888 : Plan *child_plan;
7889 : ListCell *lc;
7890 :
4653 tgl 7891 GIC 2012 : dpns = (deparse_namespace *) linitial(context->namespaces);
1215 7892 2012 : child_plan = dpns->plan;
7893 :
4653 7894 3811 : foreach(lc, dpns->ancestors)
7895 : {
1215 7896 3195 : Node *ancestor = (Node *) lfirst(lc);
4653 tgl 7897 ECB : ListCell *lc2;
7898 :
7899 : /*
7900 : * NestLoops transmit params to their inner child only.
7901 : */
1215 tgl 7902 GIC 3195 : if (IsA(ancestor, NestLoop) &&
144 tgl 7903 GNC 1287 : child_plan == innerPlan(ancestor))
7904 : {
1215 tgl 7905 CBC 1248 : NestLoop *nl = (NestLoop *) ancestor;
7906 :
4653 tgl 7907 GIC 1528 : foreach(lc2, nl->nestParams)
7908 : {
4382 bruce 7909 1483 : NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
7910 :
4653 tgl 7911 1483 : if (nlp->paramno == param->paramid)
7912 : {
7913 : /* Found a match, so return it */
4232 7914 1203 : *dpns_p = dpns;
4232 tgl 7915 CBC 1203 : *ancestor_cell_p = lc;
4232 tgl 7916 GIC 1203 : return (Node *) nlp->paramval;
7917 : }
4653 tgl 7918 ECB : }
7919 : }
7920 :
7921 : /*
1215 7922 : * If ancestor is a SubPlan, check the arguments it provides.
4653 7923 : */
1215 tgl 7924 CBC 1992 : if (IsA(ancestor, SubPlan))
4653 tgl 7925 GIC 33 : {
1215 7926 226 : SubPlan *subplan = (SubPlan *) ancestor;
4653 tgl 7927 EUB : ListCell *lc3;
7928 : ListCell *lc4;
7929 :
4653 tgl 7930 GIC 254 : forboth(lc3, subplan->parParam, lc4, subplan->args)
7931 : {
4382 bruce 7932 CBC 221 : int paramid = lfirst_int(lc3);
4382 bruce 7933 GIC 221 : Node *arg = (Node *) lfirst(lc4);
7934 :
4653 tgl 7935 221 : if (paramid == param->paramid)
7936 : {
7937 : /*
7938 : * Found a match, so return it. But, since Vars in
7939 : * the arg are to be evaluated in the surrounding
7940 : * context, we have to point to the next ancestor item
1215 tgl 7941 ECB : * that is *not* a SubPlan.
7942 : */
7943 : ListCell *rest;
7944 :
1215 tgl 7945 GIC 193 : for_each_cell(rest, dpns->ancestors,
1215 tgl 7946 ECB : lnext(dpns->ancestors, lc))
7947 : {
1215 tgl 7948 GIC 193 : Node *ancestor2 = (Node *) lfirst(rest);
7949 :
7950 193 : if (!IsA(ancestor2, SubPlan))
7951 : {
7952 193 : *dpns_p = dpns;
1215 tgl 7953 CBC 193 : *ancestor_cell_p = rest;
1215 tgl 7954 GIC 193 : return arg;
7955 : }
7956 : }
1215 tgl 7957 UIC 0 : elog(ERROR, "SubPlan cannot be outermost ancestor");
7958 : }
7959 : }
7960 :
7961 : /* SubPlan isn't a kind of Plan, so skip the rest */
1215 tgl 7962 CBC 33 : continue;
4653 tgl 7963 ECB : }
7964 :
7965 : /*
7966 : * We need not consider the ancestor's initPlan list, since
7967 : * initplans never have any parParams.
7968 : */
7969 :
7970 : /* No luck, crawl up to next ancestor */
1215 tgl 7971 GBC 1766 : child_plan = (Plan *) ancestor;
4653 tgl 7972 ECB : }
4653 tgl 7973 EUB : }
7974 :
4232 tgl 7975 ECB : /* No referent found */
4232 tgl 7976 GIC 1029 : return NULL;
4653 tgl 7977 ECB : }
4653 tgl 7978 EUB :
7979 : /*
4232 tgl 7980 ECB : * Display a Param appropriately.
7981 : */
4653 7982 : static void
4232 tgl 7983 GIC 2419 : get_parameter(Param *param, deparse_context *context)
4653 tgl 7984 ECB : {
7985 : Node *expr;
7986 : deparse_namespace *dpns;
7987 : ListCell *ancestor_cell;
7988 :
7989 : /*
7990 : * If it's a PARAM_EXEC parameter, try to locate the expression from which
3260 bruce 7991 : * the parameter was computed. Note that failing to find a referent isn't
7992 : * an error, since the Param might well be a subplan output rather than an
4232 tgl 7993 : * input.
4653 7994 : */
4232 tgl 7995 CBC 2419 : expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7996 2419 : if (expr)
7997 : {
4232 tgl 7998 ECB : /* Found a match, so print it */
7999 : deparse_namespace save_dpns;
8000 : bool save_varprefix;
8001 : bool need_paren;
4653 8002 :
8003 : /* Switch attention to the ancestor plan node */
4232 tgl 8004 GIC 1390 : push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8005 :
8006 : /*
8007 : * Force prefixing of Vars, since they won't belong to the relation
8008 : * being scanned in the original plan node.
8009 : */
8010 1390 : save_varprefix = context->varprefix;
4232 tgl 8011 CBC 1390 : context->varprefix = true;
8012 :
4232 tgl 8013 ECB : /*
8014 : * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
384 8015 : * upper-level Param, which wouldn't need extra parentheses.
8016 : * Otherwise, insert parens to ensure the expression looks atomic.
4232 8017 : */
4232 tgl 8018 CBC 1393 : need_paren = !(IsA(expr, Var) ||
4232 tgl 8019 GIC 3 : IsA(expr, Aggref) ||
384 8020 3 : IsA(expr, GroupingFunc) ||
4232 tgl 8021 LBC 0 : IsA(expr, Param));
4232 tgl 8022 GIC 1390 : if (need_paren)
4232 tgl 8023 LBC 0 : appendStringInfoChar(context->buf, '(');
4653 tgl 8024 ECB :
4232 tgl 8025 GIC 1390 : get_rule_expr(expr, context, false);
8026 :
4232 tgl 8027 CBC 1390 : if (need_paren)
4232 tgl 8028 LBC 0 : appendStringInfoChar(context->buf, ')');
8029 :
4232 tgl 8030 GIC 1390 : context->varprefix = save_varprefix;
8031 :
8032 1390 : pop_ancestor_plan(dpns, &save_dpns);
8033 :
8034 1390 : return;
8035 : }
4232 tgl 8036 ECB :
8037 : /*
8038 : * If it's an external parameter, see if the outermost namespace provides
8039 : * function argument names.
8040 : */
508 tgl 8041 GIC 1029 : if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8042 : {
8043 413 : dpns = llast(context->namespaces);
8044 413 : if (dpns->argnames &&
8045 33 : param->paramid > 0 &&
508 tgl 8046 CBC 33 : param->paramid <= dpns->numargs)
8047 : {
732 peter 8048 33 : char *argname = dpns->argnames[param->paramid - 1];
8049 :
8050 33 : if (argname)
8051 : {
732 peter 8052 GIC 33 : bool should_qualify = false;
732 peter 8053 ECB : ListCell *lc;
8054 :
8055 : /*
8056 : * Qualify the parameter name if there are any other deparse
8057 : * namespaces with range tables. This avoids qualifying in
8058 : * trivial cases like "RETURN a + b", but makes it safe in all
8059 : * other cases.
8060 : */
732 peter 8061 GBC 75 : foreach(lc, context->namespaces)
8062 : {
186 drowley 8063 GNC 57 : deparse_namespace *depns = lfirst(lc);
8064 :
8065 57 : if (depns->rtable_names != NIL)
8066 : {
732 peter 8067 GIC 15 : should_qualify = true;
8068 15 : break;
8069 : }
8070 : }
8071 33 : if (should_qualify)
732 peter 8072 ECB : {
732 peter 8073 GIC 15 : appendStringInfoString(context->buf, quote_identifier(dpns->funcname));
732 peter 8074 CBC 15 : appendStringInfoChar(context->buf, '.');
732 peter 8075 EUB : }
8076 :
732 peter 8077 CBC 33 : appendStringInfoString(context->buf, quote_identifier(argname));
732 peter 8078 GIC 33 : return;
732 peter 8079 ECB : }
8080 : }
8081 : }
8082 :
8083 : /*
8084 : * Not PARAM_EXEC, or couldn't find referent: just print $N.
8085 : */
4232 tgl 8086 CBC 996 : appendStringInfo(context->buf, "$%d", param->paramid);
8087 : }
7549 tgl 8088 ECB :
8089 : /*
8090 : * get_simple_binary_op_name
8091 : *
8092 : * helper function for isSimpleNode
8093 : * will return single char binary operator name, or NULL if it's not
8094 : */
8095 : static const char *
7184 bruce 8096 GIC 57 : get_simple_binary_op_name(OpExpr *expr)
8097 : {
7193 tgl 8098 57 : List *args = expr->args;
8099 :
6888 neilc 8100 57 : if (list_length(args) == 2)
8101 : {
7193 tgl 8102 ECB : /* binary operator */
6892 neilc 8103 GIC 57 : Node *arg1 = (Node *) linitial(args);
7193 tgl 8104 57 : Node *arg2 = (Node *) lsecond(args);
7193 tgl 8105 EUB : const char *op;
8106 :
7193 tgl 8107 GIC 57 : op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
7193 tgl 8108 CBC 57 : if (strlen(op) == 1)
7188 bruce 8109 GIC 57 : return op;
8110 : }
7193 tgl 8111 UIC 0 : return NULL;
8112 : }
8113 :
7193 tgl 8114 ECB :
8115 : /*
7193 tgl 8116 EUB : * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
8117 : *
8118 : * true : simple in the context of parent node's type
8119 : * false : not simple
8120 : */
8121 : static bool
7193 tgl 8122 GIC 2212 : isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
7193 tgl 8123 EUB : {
7188 bruce 8124 GIC 2212 : if (!node)
7193 tgl 8125 UBC 0 : return false;
8126 :
7188 bruce 8127 CBC 2212 : switch (nodeTag(node))
7188 bruce 8128 ECB : {
7193 tgl 8129 GIC 1852 : case T_Var:
7193 tgl 8130 EUB : case T_Const:
8131 : case T_Param:
8132 : case T_CoerceToDomainValue:
8133 : case T_SetToDefault:
5781 8134 : case T_CurrentOfExpr:
8135 : /* single words: always simple */
7193 tgl 8136 GBC 1852 : return true;
7193 tgl 8137 EUB :
1528 alvherre 8138 GIC 186 : case T_SubscriptingRef:
8139 : case T_ArrayExpr:
6908 tgl 8140 ECB : case T_RowExpr:
8141 : case T_CoalesceExpr:
8142 : case T_MinMaxExpr:
8143 : case T_XmlExpr:
8144 : case T_NextValueExpr:
8145 : case T_NullIfExpr:
8146 : case T_Aggref:
8147 : case T_GroupingFunc:
8148 : case T_WindowFunc:
8149 : case T_FuncExpr:
8150 : case T_JsonConstructorExpr:
8151 : /* function-like: name(..) or name[..] */
7193 tgl 8152 CBC 186 : return true;
7193 tgl 8153 ECB :
7188 bruce 8154 EUB : /* CASE keywords act as parentheses */
7193 tgl 8155 UIC 0 : case T_CaseExpr:
8156 0 : return true;
7193 tgl 8157 ECB :
7193 tgl 8158 CBC 24 : case T_FieldSelect:
7188 bruce 8159 ECB :
7193 tgl 8160 : /*
8161 : * appears simple since . has top precedence, unless parent is
8162 : * T_FieldSelect itself!
8163 : */
578 michael 8164 GBC 24 : return !IsA(parentNode, FieldSelect);
8165 :
6878 tgl 8166 LBC 0 : case T_FieldStore:
6878 tgl 8167 ECB :
8168 : /*
6878 tgl 8169 EUB : * treat like FieldSelect (probably doesn't matter)
8170 : */
578 michael 8171 LBC 0 : return !IsA(parentNode, FieldStore);
6878 tgl 8172 ECB :
7193 tgl 8173 UIC 0 : case T_CoerceToDomain:
7193 tgl 8174 ECB : /* maybe simple, check args */
7188 bruce 8175 LBC 0 : return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8176 : node, prettyFlags);
7193 tgl 8177 GIC 3 : case T_RelabelType:
7188 bruce 8178 3 : return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8179 : node, prettyFlags);
5787 tgl 8180 UIC 0 : case T_CoerceViaIO:
5787 tgl 8181 LBC 0 : return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
5787 tgl 8182 ECB : node, prettyFlags);
5857 tgl 8183 UIC 0 : case T_ArrayCoerceExpr:
5857 tgl 8184 LBC 0 : return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8185 : node, prettyFlags);
6693 tgl 8186 UIC 0 : case T_ConvertRowtypeExpr:
8187 0 : return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8188 : node, prettyFlags);
8189 :
7193 tgl 8190 GIC 126 : case T_OpExpr:
8191 : {
8192 : /* depends on parent node type; needs further checking */
7188 bruce 8193 126 : if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8194 : {
7188 bruce 8195 ECB : const char *op;
8196 : const char *parentOp;
8197 : bool is_lopriop;
8198 : bool is_hipriop;
8199 : bool is_lopriparent;
8200 : bool is_hipriparent;
8201 :
7188 bruce 8202 CBC 30 : op = get_simple_binary_op_name((OpExpr *) node);
8203 30 : if (!op)
7188 bruce 8204 UIC 0 : return false;
7193 tgl 8205 ECB :
7188 bruce 8206 EUB : /* We know only the basic operators + - and * / % */
7188 bruce 8207 GIC 30 : is_lopriop = (strchr("+-", *op) != NULL);
7188 bruce 8208 CBC 30 : is_hipriop = (strchr("*/%", *op) != NULL);
7188 bruce 8209 GIC 30 : if (!(is_lopriop || is_hipriop))
8210 3 : return false;
8211 :
8212 27 : parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8213 27 : if (!parentOp)
7188 bruce 8214 UIC 0 : return false;
8215 :
7188 bruce 8216 GIC 27 : is_lopriparent = (strchr("+-", *parentOp) != NULL);
8217 27 : is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8218 27 : if (!(is_lopriparent || is_hipriparent))
7188 bruce 8219 UIC 0 : return false;
7193 tgl 8220 ECB :
7188 bruce 8221 CBC 27 : if (is_hipriop && is_lopriparent)
8222 6 : return true; /* op binds tighter than parent */
8223 :
7188 bruce 8224 GIC 21 : if (is_lopriop && is_hipriparent)
7188 bruce 8225 CBC 15 : return false;
7193 tgl 8226 ECB :
8227 : /*
6385 bruce 8228 : * Operators are same priority --- can skip parens only if
8229 : * we have (a - b) - c, not a - (b - c).
8230 : */
6892 neilc 8231 GIC 6 : if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
7188 bruce 8232 3 : return true;
8233 :
7188 bruce 8234 CBC 3 : return false;
7188 bruce 8235 ECB : }
8236 : /* else do the same stuff as for T_SubLink et al. */
8237 : }
1804 tgl 8238 : /* FALLTHROUGH */
8239 :
7193 8240 : case T_SubLink:
8241 : case T_NullTest:
7193 tgl 8242 EUB : case T_BooleanTest:
7193 tgl 8243 ECB : case T_DistinctExpr:
8244 : case T_JsonIsPredicate:
7193 tgl 8245 CBC 108 : switch (nodeTag(parentNode))
7193 tgl 8246 EUB : {
7193 tgl 8247 CBC 15 : case T_FuncExpr:
8248 : {
8249 : /* special handling for casts and COERCE_SQL_SYNTAX */
7188 bruce 8250 15 : CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
7193 tgl 8251 EUB :
7188 bruce 8252 GIC 15 : if (type == COERCE_EXPLICIT_CAST ||
129 tgl 8253 3 : type == COERCE_IMPLICIT_CAST ||
129 tgl 8254 EUB : type == COERCE_SQL_SYNTAX)
7188 bruce 8255 GIC 15 : return false;
7188 bruce 8256 UBC 0 : return true; /* own parentheses */
7188 bruce 8257 EUB : }
2118 tgl 8258 GIC 81 : case T_BoolExpr: /* lower precedence */
1528 alvherre 8259 EUB : case T_SubscriptingRef: /* other separators */
2118 tgl 8260 : case T_ArrayExpr: /* other separators */
8261 : case T_RowExpr: /* other separators */
7188 bruce 8262 : case T_CoalesceExpr: /* own parentheses */
8263 : case T_MinMaxExpr: /* own parentheses */
8264 : case T_XmlExpr: /* own parentheses */
8265 : case T_NullIfExpr: /* other separators */
8266 : case T_Aggref: /* own parentheses */
8267 : case T_GroupingFunc: /* own parentheses */
8268 : case T_WindowFunc: /* own parentheses */
8269 : case T_CaseExpr: /* other separators */
7193 tgl 8270 GIC 81 : return true;
8271 12 : default:
8272 12 : return false;
7193 tgl 8273 EUB : }
8274 :
7193 tgl 8275 GBC 9 : case T_BoolExpr:
7193 tgl 8276 GIC 9 : switch (nodeTag(parentNode))
8277 : {
7193 tgl 8278 GBC 9 : case T_BoolExpr:
7193 tgl 8279 GIC 9 : if (prettyFlags & PRETTYFLAG_PAREN)
7193 tgl 8280 EUB : {
8281 : BoolExprType type;
8282 : BoolExprType parentType;
8283 :
7188 bruce 8284 GBC 9 : type = ((BoolExpr *) node)->boolop;
7188 bruce 8285 GIC 9 : parentType = ((BoolExpr *) parentNode)->boolop;
8286 : switch (type)
7193 tgl 8287 EUB : {
7193 tgl 8288 GIC 6 : case NOT_EXPR:
8289 : case AND_EXPR:
8290 6 : if (parentType == AND_EXPR || parentType == OR_EXPR)
8291 6 : return true;
7193 tgl 8292 UIC 0 : break;
7193 tgl 8293 GIC 3 : case OR_EXPR:
8294 3 : if (parentType == OR_EXPR)
7193 tgl 8295 UIC 0 : return true;
7193 tgl 8296 GIC 3 : break;
8297 : }
7193 tgl 8298 ECB : }
7193 tgl 8299 GIC 3 : return false;
7193 tgl 8300 UIC 0 : case T_FuncExpr:
7188 bruce 8301 ECB : {
8302 : /* special handling for casts and COERCE_SQL_SYNTAX */
7188 bruce 8303 LBC 0 : CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8304 :
7188 bruce 8305 UIC 0 : if (type == COERCE_EXPLICIT_CAST ||
129 tgl 8306 0 : type == COERCE_IMPLICIT_CAST ||
129 tgl 8307 ECB : type == COERCE_SQL_SYNTAX)
7188 bruce 8308 UIC 0 : return false;
8309 0 : return true; /* own parentheses */
7188 bruce 8310 ECB : }
1528 alvherre 8311 UIC 0 : case T_SubscriptingRef: /* other separators */
2118 tgl 8312 ECB : case T_ArrayExpr: /* other separators */
8313 : case T_RowExpr: /* other separators */
7188 bruce 8314 : case T_CoalesceExpr: /* own parentheses */
2118 tgl 8315 : case T_MinMaxExpr: /* own parentheses */
8316 : case T_XmlExpr: /* own parentheses */
8317 : case T_NullIfExpr: /* other separators */
8318 : case T_Aggref: /* own parentheses */
8319 : case T_GroupingFunc: /* own parentheses */
8320 : case T_WindowFunc: /* own parentheses */
8321 : case T_CaseExpr: /* other separators */
7193 tgl 8322 UIC 0 : return true;
8323 0 : default:
8324 0 : return false;
8325 : }
8326 :
11 alvherre 8327 UNC 0 : case T_JsonValueExpr:
8328 : /* maybe simple, check args */
8329 0 : return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
8330 : node, prettyFlags);
8331 :
7193 tgl 8332 UBC 0 : default:
8333 0 : break;
8334 : }
7188 bruce 8335 EUB : /* those we don't know: in dubio complexo */
7188 bruce 8336 UIC 0 : return false;
7193 tgl 8337 EUB : }
8338 :
7193 tgl 8339 ECB :
8340 : /*
8341 : * appendContextKeyword - append a keyword to buffer
8342 : *
8343 : * If prettyPrint is enabled, perform a line break, and adjust indentation.
8344 : * Otherwise, just append the keyword.
7193 tgl 8345 EUB : */
8346 : static void
7193 tgl 8347 GIC 8815 : appendContextKeyword(deparse_context *context, const char *str,
7193 tgl 8348 ECB : int indentBefore, int indentAfter, int indentPlus)
8349 : {
3436 tgl 8350 GIC 8815 : StringInfo buf = context->buf;
8351 :
7188 bruce 8352 8815 : if (PRETTY_INDENT(context))
8353 : {
8354 : int indentAmount;
8355 :
7193 tgl 8356 8666 : context->indentLevel += indentBefore;
7193 tgl 8357 ECB :
8358 : /* remove any trailing spaces currently in the buffer ... */
3436 tgl 8359 CBC 8666 : removeStringInfoSpaces(buf);
3436 tgl 8360 ECB : /* ... then add a newline and some spaces */
3436 tgl 8361 CBC 8666 : appendStringInfoChar(buf, '\n');
8362 :
3266 tgl 8363 GIC 8666 : if (context->indentLevel < PRETTYINDENT_LIMIT)
8364 8666 : indentAmount = Max(context->indentLevel, 0) + indentPlus;
8365 : else
8366 : {
8367 : /*
8368 : * If we're indented more than PRETTYINDENT_LIMIT characters, try
8369 : * to conserve horizontal space by reducing the per-level
8370 : * indentation. For best results the scale factor here should
8371 : * divide all the indent amounts that get added to indentLevel
8372 : * (PRETTYINDENT_STD, etc). It's important that the indentation
8373 : * not grow unboundedly, else deeply-nested trees use O(N^2)
8374 : * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8375 : */
3266 tgl 8376 LBC 0 : indentAmount = PRETTYINDENT_LIMIT +
3266 tgl 8377 UIC 0 : (context->indentLevel - PRETTYINDENT_LIMIT) /
8378 : (PRETTYINDENT_STD / 2);
8379 0 : indentAmount %= PRETTYINDENT_LIMIT;
8380 : /* scale/wrap logic affects indentLevel, but not indentPlus */
3266 tgl 8381 LBC 0 : indentAmount += indentPlus;
3266 tgl 8382 ECB : }
3266 tgl 8383 GIC 8666 : appendStringInfoSpaces(buf, indentAmount);
3436 tgl 8384 ECB :
3436 tgl 8385 CBC 8666 : appendStringInfoString(buf, str);
8386 :
7193 8387 8666 : context->indentLevel += indentAfter;
7193 tgl 8388 GIC 8666 : if (context->indentLevel < 0)
7193 tgl 8389 LBC 0 : context->indentLevel = 0;
7188 bruce 8390 ECB : }
6794 tgl 8391 : else
3436 tgl 8392 GIC 149 : appendStringInfoString(buf, str);
7193 8393 8815 : }
8394 :
8395 : /*
8396 : * removeStringInfoSpaces - delete trailing spaces from a buffer.
8397 : *
8398 : * Possibly this should move to stringinfo.c at some point.
8399 : */
8400 : static void
3436 8401 8777 : removeStringInfoSpaces(StringInfo str)
8402 : {
8403 13554 : while (str->len > 0 && str->data[str->len - 1] == ' ')
8404 4777 : str->data[--(str->len)] = '\0';
8405 8777 : }
8406 :
8407 :
7193 tgl 8408 ECB : /*
8409 : * get_rule_expr_paren - deparse expr using get_rule_expr,
8410 : * embracing the string with parentheses if necessary for prettyPrint.
8411 : *
8412 : * Never embrace if prettyFlags=0, because it's done in the calling node.
8413 : *
8414 : * Any node that does *not* embrace its argument node by sql syntax (with
8415 : * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
8416 : * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
8417 : * added.
8418 : */
8419 : static void
7188 bruce 8420 GIC 66059 : get_rule_expr_paren(Node *node, deparse_context *context,
8421 : bool showimplicit, Node *parentNode)
8422 : {
8423 : bool need_paren;
8424 :
7193 tgl 8425 68268 : need_paren = PRETTY_PAREN(context) &&
8426 2209 : !isSimpleNode(node, parentNode, context->prettyFlags);
7193 tgl 8427 ECB :
7193 tgl 8428 GIC 66059 : if (need_paren)
7188 bruce 8429 CBC 51 : appendStringInfoChar(context->buf, '(');
7193 tgl 8430 ECB :
7193 tgl 8431 CBC 66059 : get_rule_expr(node, context, showimplicit);
8432 :
8433 66059 : if (need_paren)
7188 bruce 8434 51 : appendStringInfoChar(context->buf, ')');
7193 tgl 8435 66059 : }
8436 :
402 andrew 8437 ECB :
8994 bruce 8438 : /* ----------
8439 : * get_rule_expr - Parse back an expression
8440 : *
7507 tgl 8441 : * Note: showimplicit determines whether we display any implicit cast that
8442 : * is present at the top of the expression tree. It is a passed argument,
8443 : * not a field of the context struct, because we change the value as we
8444 : * recurse down into the expression. In general we suppress implicit casts
8445 : * when the result type is known with certainty (eg, the arguments of an
8446 : * OR must be boolean). We display implicit casts for arguments of functions
8447 : * and operators, since this is needed to be certain that the same function
8448 : * or operator will be chosen when the expression is re-parsed.
8994 bruce 8449 : * ----------
8450 : */
8590 tgl 8451 : static void
7507 tgl 8452 GIC 131463 : get_rule_expr(Node *node, deparse_context *context,
7507 tgl 8453 ECB : bool showimplicit)
8454 : {
8589 tgl 8455 CBC 131463 : StringInfo buf = context->buf;
8589 tgl 8456 ECB :
8986 bruce 8457 CBC 131463 : if (node == NULL)
8590 tgl 8458 GIC 48 : return;
8994 bruce 8459 ECB :
8460 : /* Guard against excessively long or deeply-nested queries */
3266 tgl 8461 CBC 131415 : CHECK_FOR_INTERRUPTS();
3266 tgl 8462 GIC 131415 : check_stack_depth();
8463 :
8464 : /*
8465 : * Each level of get_rule_expr must emit an indivisible term
8466 : * (parenthesized if necessary) to ensure result is reparsed into the same
8467 : * expression tree. The only exception is that when the input is a List,
8468 : * we emit the component items comma-separated with no surrounding
8469 : * decoration; this is convenient for most callers.
8470 : */
8986 bruce 8471 131415 : switch (nodeTag(node))
8986 bruce 8472 ECB : {
8625 tgl 8473 GIC 58979 : case T_Var:
3999 tgl 8474 GBC 58979 : (void) get_variable((Var *) node, 0, false, context);
8986 bruce 8475 58979 : break;
8476 :
7423 tgl 8477 25743 : case T_Const:
5572 tgl 8478 GIC 25743 : get_const_expr((Const *) node, context, 0);
7423 8479 25743 : break;
8480 :
8481 2419 : case T_Param:
4653 8482 2419 : get_parameter((Param *) node, context);
8986 bruce 8483 2419 : break;
8484 :
8625 tgl 8485 762 : case T_Aggref:
2538 rhaas 8486 CBC 762 : get_agg_expr((Aggref *) node, context, (Aggref *) node);
8625 tgl 8487 762 : break;
8955 bruce 8488 ECB :
2885 andres 8489 CBC 26 : case T_GroupingFunc:
2885 andres 8490 ECB : {
2885 andres 8491 CBC 26 : GroupingFunc *gexpr = (GroupingFunc *) node;
2885 andres 8492 ECB :
2885 andres 8493 GIC 26 : appendStringInfoString(buf, "GROUPING(");
8494 26 : get_rule_expr((Node *) gexpr->args, context, true);
8495 26 : appendStringInfoChar(buf, ')');
8496 : }
8497 26 : break;
8498 :
5215 tgl 8499 117 : case T_WindowFunc:
8500 117 : get_windowfunc_expr((WindowFunc *) node, context);
8501 117 : break;
8502 :
1528 alvherre 8503 CBC 98 : case T_SubscriptingRef:
8504 : {
1528 alvherre 8505 GIC 98 : SubscriptingRef *sbsref = (SubscriptingRef *) node;
8506 : bool need_parens;
8507 :
8508 : /*
8509 : * If the argument is a CaseTestExpr, we must be inside a
8510 : * FieldStore, ie, we are assigning to an element of an array
8511 : * within a composite column. Since we already punted on
8512 : * displaying the FieldStore's target information, just punt
4790 bruce 8513 ECB : * here too, and display only the assignment source
4798 tgl 8514 : * expression.
8515 : */
1528 alvherre 8516 GIC 98 : if (IsA(sbsref->refexpr, CaseTestExpr))
8517 : {
1528 alvherre 8518 UIC 0 : Assert(sbsref->refassgnexpr);
8519 0 : get_rule_expr((Node *) sbsref->refassgnexpr,
4798 tgl 8520 ECB : context, showimplicit);
4798 tgl 8521 UIC 0 : break;
8522 : }
4798 tgl 8523 ECB :
8524 : /*
6797 bruce 8525 : * Parenthesize the argument unless it's a simple Var or a
1528 alvherre 8526 : * FieldSelect. (In particular, if it's another
8527 : * SubscriptingRef, we *must* parenthesize to avoid
8528 : * confusion.)
8275 tgl 8529 : */
1528 alvherre 8530 GIC 154 : need_parens = !IsA(sbsref->refexpr, Var) &&
1528 alvherre 8531 CBC 56 : !IsA(sbsref->refexpr, FieldSelect);
7306 tgl 8532 GIC 98 : if (need_parens)
7306 tgl 8533 CBC 41 : appendStringInfoChar(buf, '(');
1528 alvherre 8534 98 : get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
7306 tgl 8535 GIC 98 : if (need_parens)
7306 tgl 8536 CBC 41 : appendStringInfoChar(buf, ')');
8537 :
6878 tgl 8538 ECB : /*
4790 bruce 8539 : * If there's a refassgnexpr, we want to print the node in the
1528 alvherre 8540 : * format "container[subscripts] := refassgnexpr". This is
8541 : * not legal SQL, so decompilation of INSERT or UPDATE
8542 : * statements should always use processIndirection as part of
8543 : * the statement-level syntax. We should only see this when
4790 bruce 8544 : * EXPLAIN tries to print the targetlist of a plan resulting
8545 : * from such a statement.
6878 tgl 8546 : */
1528 alvherre 8547 CBC 98 : if (sbsref->refassgnexpr)
8548 : {
4790 bruce 8549 ECB : Node *refassgnexpr;
4798 tgl 8550 :
8551 : /*
4790 bruce 8552 : * Use processIndirection to print this node's subscripts
8553 : * as well as any additional field selections or
8554 : * subscripting in immediate descendants. It returns the
8555 : * RHS expr that is actually being "assigned".
8556 : */
2440 tgl 8557 CBC 6 : refassgnexpr = processIndirection(node, context);
4798 tgl 8558 GIC 6 : appendStringInfoString(buf, " := ");
4798 tgl 8559 CBC 6 : get_rule_expr(refassgnexpr, context, showimplicit);
8560 : }
4798 tgl 8561 ECB : else
8562 : {
1528 alvherre 8563 : /* Just an ordinary container fetch, so print subscripts */
1528 alvherre 8564 CBC 92 : printSubscripts(sbsref, context);
4798 tgl 8565 ECB : }
8566 : }
7423 tgl 8567 CBC 98 : break;
8568 :
8569 5662 : case T_FuncExpr:
7423 tgl 8570 GIC 5662 : get_func_expr((FuncExpr *) node, context, showimplicit);
7423 tgl 8571 CBC 5662 : break;
7423 tgl 8572 ECB :
4931 tgl 8573 CBC 9 : case T_NamedArgExpr:
4931 tgl 8574 ECB : {
4931 tgl 8575 GIC 9 : NamedArgExpr *na = (NamedArgExpr *) node;
4931 tgl 8576 ECB :
2900 rhaas 8577 CBC 9 : appendStringInfo(buf, "%s => ", quote_identifier(na->name));
4931 tgl 8578 9 : get_rule_expr((Node *) na->arg, context, showimplicit);
4931 tgl 8579 ECB : }
4931 tgl 8580 GIC 9 : break;
8581 :
7423 8582 24672 : case T_OpExpr:
7423 tgl 8583 CBC 24672 : get_oper_expr((OpExpr *) node, context);
8584 24672 : break;
8585 :
7423 tgl 8586 GIC 9 : case T_DistinctExpr:
8587 : {
8588 9 : DistinctExpr *expr = (DistinctExpr *) node;
8589 9 : List *args = expr->args;
6892 neilc 8590 9 : Node *arg1 = (Node *) linitial(args);
7224 tgl 8591 9 : Node *arg2 = (Node *) lsecond(args);
8592 :
7193 8593 9 : if (!PRETTY_PAREN(context))
7188 bruce 8594 6 : appendStringInfoChar(buf, '(');
7193 tgl 8595 9 : get_rule_expr_paren(arg1, context, true, node);
3447 rhaas 8596 9 : appendStringInfoString(buf, " IS DISTINCT FROM ");
7193 tgl 8597 9 : get_rule_expr_paren(arg2, context, true, node);
7193 tgl 8598 CBC 9 : if (!PRETTY_PAREN(context))
7188 bruce 8599 6 : appendStringInfoChar(buf, ')');
7224 tgl 8600 ECB : }
7224 tgl 8601 GIC 9 : break;
8602 :
4404 tgl 8603 CBC 10 : case T_NullIfExpr:
4404 tgl 8604 ECB : {
4404 tgl 8605 CBC 10 : NullIfExpr *nullifexpr = (NullIfExpr *) node;
8606 :
3447 rhaas 8607 10 : appendStringInfoString(buf, "NULLIF(");
4404 tgl 8608 GIC 10 : get_rule_expr((Node *) nullifexpr->args, context, true);
4404 tgl 8609 CBC 10 : appendStringInfoChar(buf, ')');
8610 : }
8611 10 : break;
4404 tgl 8612 ECB :
7224 tgl 8613 GIC 1186 : case T_ScalarArrayOpExpr:
8614 : {
7224 tgl 8615 CBC 1186 : ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
7224 tgl 8616 GIC 1186 : List *args = expr->args;
6892 neilc 8617 CBC 1186 : Node *arg1 = (Node *) linitial(args);
7224 tgl 8618 1186 : Node *arg2 = (Node *) lsecond(args);
7224 tgl 8619 ECB :
7193 tgl 8620 CBC 1186 : if (!PRETTY_PAREN(context))
7188 bruce 8621 GIC 1180 : appendStringInfoChar(buf, '(');
7193 tgl 8622 CBC 1186 : get_rule_expr_paren(arg1, context, true, node);
7224 tgl 8623 GIC 1186 : appendStringInfo(buf, " %s %s (",
7224 tgl 8624 ECB : generate_operator_name(expr->opno,
8625 : exprType(arg1),
8626 : get_base_element_type(exprType(arg2))),
7224 tgl 8627 GIC 1186 : expr->useOr ? "ANY" : "ALL");
7193 tgl 8628 CBC 1186 : get_rule_expr_paren(arg2, context, true, node);
2544 tgl 8629 ECB :
8630 : /*
8631 : * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
8632 : * a bare sub-SELECT. Since we're here, the sub-SELECT must
8633 : * be meant as a scalar sub-SELECT yielding an array value to
8634 : * be used in ScalarArrayOpExpr; but the grammar will
8635 : * preferentially interpret such a construct as an ANY/ALL
8636 : * SubLink. To prevent misparsing the output that way, insert
8637 : * a dummy coercion (which will be stripped by parse analysis,
8638 : * so no inefficiency is added in dump and reload). This is
8639 : * indeed most likely what the user wrote to get the construct
8640 : * accepted in the first place.
8641 : */
2544 tgl 8642 GIC 1186 : if (IsA(arg2, SubLink) &&
2544 tgl 8643 CBC 3 : ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
8644 3 : appendStringInfo(buf, "::%s",
2544 tgl 8645 ECB : format_type_with_typemod(exprType(arg2),
8646 : exprTypmod(arg2)));
7193 tgl 8647 CBC 1186 : appendStringInfoChar(buf, ')');
8648 1186 : if (!PRETTY_PAREN(context))
7188 bruce 8649 1180 : appendStringInfoChar(buf, ')');
8986 bruce 8650 ECB : }
8986 bruce 8651 CBC 1186 : break;
8652 :
7423 tgl 8653 4632 : case T_BoolExpr:
7423 tgl 8654 ECB : {
7423 tgl 8655 CBC 4632 : BoolExpr *expr = (BoolExpr *) node;
6892 neilc 8656 GIC 4632 : Node *first_arg = linitial(expr->args);
923 tgl 8657 EUB : ListCell *arg;
7423 8658 :
7423 tgl 8659 GIC 4632 : switch (expr->boolop)
8660 : {
8661 3772 : case AND_EXPR:
7193 tgl 8662 CBC 3772 : if (!PRETTY_PAREN(context))
7188 bruce 8663 GIC 3739 : appendStringInfoChar(buf, '(');
6892 neilc 8664 CBC 3772 : get_rule_expr_paren(first_arg, context,
7193 tgl 8665 ECB : false, node);
923 tgl 8666 CBC 8553 : for_each_from(arg, expr->args, 1)
8667 : {
3447 rhaas 8668 4781 : appendStringInfoString(buf, " AND ");
6892 neilc 8669 GIC 4781 : get_rule_expr_paren((Node *) lfirst(arg), context,
7193 tgl 8670 ECB : false, node);
8671 : }
7193 tgl 8672 GIC 3772 : if (!PRETTY_PAREN(context))
7188 bruce 8673 3739 : appendStringInfoChar(buf, ')');
7423 tgl 8674 3772 : break;
8675 :
8676 737 : case OR_EXPR:
7193 8677 737 : if (!PRETTY_PAREN(context))
7188 bruce 8678 CBC 731 : appendStringInfoChar(buf, '(');
6892 neilc 8679 737 : get_rule_expr_paren(first_arg, context,
8680 : false, node);
923 tgl 8681 1759 : for_each_from(arg, expr->args, 1)
8682 : {
3447 rhaas 8683 1022 : appendStringInfoString(buf, " OR ");
6892 neilc 8684 GIC 1022 : get_rule_expr_paren((Node *) lfirst(arg), context,
7193 tgl 8685 EUB : false, node);
8686 : }
7193 tgl 8687 GBC 737 : if (!PRETTY_PAREN(context))
7188 bruce 8688 GIC 731 : appendStringInfoChar(buf, ')');
7423 tgl 8689 737 : break;
8690 :
8691 123 : case NOT_EXPR:
7193 8692 123 : if (!PRETTY_PAREN(context))
7188 bruce 8693 117 : appendStringInfoChar(buf, '(');
3447 rhaas 8694 123 : appendStringInfoString(buf, "NOT ");
6892 neilc 8695 123 : get_rule_expr_paren(first_arg, context,
7193 tgl 8696 EUB : false, node);
7193 tgl 8697 GBC 123 : if (!PRETTY_PAREN(context))
7188 bruce 8698 GIC 117 : appendStringInfoChar(buf, ')');
7423 tgl 8699 GBC 123 : break;
8700 :
7423 tgl 8701 UBC 0 : default:
7196 8702 0 : elog(ERROR, "unrecognized boolop: %d",
8703 : (int) expr->boolop);
7423 tgl 8704 EUB : }
8705 : }
7423 tgl 8706 GBC 4632 : break;
8707 :
8708 191 : case T_SubLink:
7423 tgl 8709 GIC 191 : get_sublink_expr((SubLink *) node, context);
7423 tgl 8710 GBC 191 : break;
8711 :
7421 tgl 8712 CBC 230 : case T_SubPlan:
8713 : {
5050 bruce 8714 230 : SubPlan *subplan = (SubPlan *) node;
5117 tgl 8715 ECB :
7423 8716 : /*
8717 : * We cannot see an already-planned subplan in rule deparsing,
8718 : * only while EXPLAINing a query plan. We don't try to
8719 : * reconstruct the original SQL, just reference the subplan
8720 : * that appears elsewhere in EXPLAIN's result.
8721 : */
5117 tgl 8722 GIC 230 : if (subplan->useHashTable)
8723 58 : appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
8724 : else
8725 172 : appendStringInfo(buf, "(%s)", subplan->plan_name);
7423 tgl 8726 ECB : }
7423 tgl 8727 CBC 230 : break;
7423 tgl 8728 ECB :
5343 tgl 8729 LBC 0 : case T_AlternativeSubPlan:
5117 tgl 8730 ECB : {
5117 tgl 8731 LBC 0 : AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
5117 tgl 8732 ECB : ListCell *lc;
8733 :
8734 : /*
8735 : * This case cannot be reached in normal usage, since no
8736 : * AlternativeSubPlan can appear either in parsetrees or
924 8737 : * finished plan trees. We keep it just in case somebody
8738 : * wants to use this code to print planner data structures.
8739 : */
3447 rhaas 8740 UIC 0 : appendStringInfoString(buf, "(alternatives: ");
5117 tgl 8741 LBC 0 : foreach(lc, asplan->subplans)
8742 : {
2190 8743 0 : SubPlan *splan = lfirst_node(SubPlan, lc);
8744 :
5117 8745 0 : if (splan->useHashTable)
5117 tgl 8746 UIC 0 : appendStringInfo(buf, "hashed %s", splan->plan_name);
8747 : else
3447 rhaas 8748 0 : appendStringInfoString(buf, splan->plan_name);
1364 tgl 8749 0 : if (lnext(asplan->subplans, lc))
3447 rhaas 8750 0 : appendStringInfoString(buf, " or ");
8751 : }
8752 0 : appendStringInfoChar(buf, ')');
8753 : }
5343 tgl 8754 0 : break;
8755 :
8279 tgl 8756 GIC 304 : case T_FieldSelect:
8757 : {
8758 304 : FieldSelect *fselect = (FieldSelect *) node;
6522 8759 304 : Node *arg = (Node *) fselect->arg;
8760 304 : int fno = fselect->fieldnum;
8761 : const char *fieldname;
8762 : bool need_parens;
8763 :
8764 : /*
8765 : * Parenthesize the argument unless it's an SubscriptingRef or
8766 : * another FieldSelect. Note in particular that it would be
6385 bruce 8767 ECB : * WRONG to not parenthesize a Var argument; simplicity is not
8768 : * the issue here, having the right number of names is.
7804 tgl 8769 : */
1528 alvherre 8770 CBC 590 : need_parens = !IsA(arg, SubscriptingRef) &&
8771 286 : !IsA(arg, FieldSelect);
6878 tgl 8772 304 : if (need_parens)
6878 tgl 8773 GIC 286 : appendStringInfoChar(buf, '(');
6522 tgl 8774 CBC 304 : get_rule_expr(arg, context, true);
6878 tgl 8775 GIC 304 : if (need_parens)
6878 tgl 8776 CBC 286 : appendStringInfoChar(buf, ')');
8777 :
6522 tgl 8778 ECB : /*
5889 8779 : * Get and print the field name.
8780 : */
5889 tgl 8781 CBC 304 : fieldname = get_name_for_var_field((Var *) arg, fno,
5889 tgl 8782 ECB : 0, context);
7193 tgl 8783 GIC 304 : appendStringInfo(buf, ".%s", quote_identifier(fieldname));
8784 : }
8279 tgl 8785 CBC 304 : break;
8786 :
6878 tgl 8787 GIC 3 : case T_FieldStore:
8788 : {
4798 tgl 8789 CBC 3 : FieldStore *fstore = (FieldStore *) node;
8790 : bool need_parens;
8791 :
8792 : /*
8793 : * There is no good way to represent a FieldStore as real SQL,
8794 : * so decompilation of INSERT or UPDATE statements should
4798 tgl 8795 ECB : * always use processIndirection as part of the
8796 : * statement-level syntax. We should only get here when
8797 : * EXPLAIN tries to print the targetlist of a plan resulting
8798 : * from such a statement. The plan case is even harder than
8799 : * ordinary rules would be, because the planner tries to
8800 : * collapse multiple assignments to the same field or subfield
8801 : * into one FieldStore; so we can see a list of target fields
8802 : * not just one, and the arguments could be FieldStores
3260 bruce 8803 : * themselves. We don't bother to try to print the target
8804 : * field names; we just print the source arguments, with a
8805 : * ROW() around them if there's more than one. This isn't
4798 tgl 8806 : * terribly complete, but it's probably good enough for
8807 : * EXPLAIN's purposes; especially since anything more would be
8808 : * either hopelessly confusing or an even poorer
8809 : * representation of what the plan is actually doing.
8810 : */
4798 tgl 8811 GIC 3 : need_parens = (list_length(fstore->newvals) != 1);
8812 3 : if (need_parens)
8813 3 : appendStringInfoString(buf, "ROW(");
8814 3 : get_rule_expr((Node *) fstore->newvals, context, showimplicit);
8815 3 : if (need_parens)
4798 tgl 8816 CBC 3 : appendStringInfoChar(buf, ')');
8817 : }
6878 8818 3 : break;
8819 :
8449 8820 1064 : case T_RelabelType:
8449 tgl 8821 ECB : {
8449 tgl 8822 GIC 1064 : RelabelType *relabel = (RelabelType *) node;
7188 bruce 8823 CBC 1064 : Node *arg = (Node *) relabel->arg;
8449 tgl 8824 ECB :
7507 tgl 8825 GIC 1064 : if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
8826 1001 : !showimplicit)
7508 tgl 8827 EUB : {
8828 : /* don't show the implicit cast */
6871 tgl 8829 GIC 30 : get_rule_expr_paren(arg, context, false, node);
8830 : }
7508 tgl 8831 ECB : else
8832 : {
5867 tgl 8833 GIC 1034 : get_coercion_expr(arg, context,
8834 : relabel->resulttype,
8835 : relabel->resulttypmod,
8836 : node);
7508 tgl 8837 ECB : }
8838 : }
8449 tgl 8839 CBC 1064 : break;
8840 :
5787 8841 262 : case T_CoerceViaIO:
5787 tgl 8842 ECB : {
5787 tgl 8843 GIC 262 : CoerceViaIO *iocoerce = (CoerceViaIO *) node;
5787 tgl 8844 CBC 262 : Node *arg = (Node *) iocoerce->arg;
5787 tgl 8845 ECB :
5787 tgl 8846 GIC 262 : if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
8847 6 : !showimplicit)
5787 tgl 8848 ECB : {
8849 : /* don't show the implicit cast */
5787 tgl 8850 GIC 6 : get_rule_expr_paren(arg, context, false, node);
8851 : }
5787 tgl 8852 ECB : else
8853 : {
5787 tgl 8854 GIC 256 : get_coercion_expr(arg, context,
8855 : iocoerce->resulttype,
8856 : -1,
5787 tgl 8857 ECB : node);
8858 : }
8859 : }
5787 tgl 8860 GIC 262 : break;
5787 tgl 8861 ECB :
5857 tgl 8862 CBC 15 : case T_ArrayCoerceExpr:
8863 : {
8864 15 : ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
8865 15 : Node *arg = (Node *) acoerce->arg;
5857 tgl 8866 ECB :
5857 tgl 8867 CBC 15 : if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
5857 tgl 8868 GIC 15 : !showimplicit)
5857 tgl 8869 ECB : {
8870 : /* don't show the implicit cast */
5857 tgl 8871 UIC 0 : get_rule_expr_paren(arg, context, false, node);
5857 tgl 8872 ECB : }
8873 : else
8874 : {
5857 tgl 8875 GIC 15 : get_coercion_expr(arg, context,
5857 tgl 8876 ECB : acoerce->resulttype,
8877 : acoerce->resulttypmod,
8878 : node);
8879 : }
8880 : }
5857 tgl 8881 CBC 15 : break;
8882 :
6693 8883 45 : case T_ConvertRowtypeExpr:
6693 tgl 8884 ECB : {
6693 tgl 8885 GIC 45 : ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
6693 tgl 8886 CBC 45 : Node *arg = (Node *) convert->arg;
8887 :
8888 45 : if (convert->convertformat == COERCE_IMPLICIT_CAST &&
8889 42 : !showimplicit)
8890 : {
6693 tgl 8891 ECB : /* don't show the implicit cast */
6693 tgl 8892 GIC 12 : get_rule_expr_paren(arg, context, false, node);
8893 : }
8894 : else
8895 : {
5867 8896 33 : get_coercion_expr(arg, context,
8897 : convert->resulttype, -1,
8898 : node);
8899 : }
8900 : }
6693 8901 45 : break;
8902 :
4412 8903 48 : case T_CollateExpr:
8904 : {
4412 tgl 8905 CBC 48 : CollateExpr *collate = (CollateExpr *) node;
4412 tgl 8906 GIC 48 : Node *arg = (Node *) collate->arg;
4412 tgl 8907 ECB :
4412 tgl 8908 GIC 48 : if (!PRETTY_PAREN(context))
4412 tgl 8909 CBC 48 : appendStringInfoChar(buf, '(');
8910 48 : get_rule_expr_paren(arg, context, showimplicit, node);
4412 tgl 8911 GIC 48 : appendStringInfo(buf, " COLLATE %s",
4412 tgl 8912 ECB : generate_collation_name(collate->collOid));
4412 tgl 8913 GIC 48 : if (!PRETTY_PAREN(context))
8914 48 : appendStringInfoChar(buf, ')');
8915 : }
4412 tgl 8916 CBC 48 : break;
4412 tgl 8917 ECB :
8625 tgl 8918 CBC 153 : case T_CaseExpr:
8919 : {
8920 153 : CaseExpr *caseexpr = (CaseExpr *) node;
6892 neilc 8921 ECB : ListCell *temp;
8625 tgl 8922 :
7193 tgl 8923 GIC 153 : appendContextKeyword(context, "CASE",
7193 tgl 8924 ECB : 0, PRETTYINDENT_VAR, 0);
6962 tgl 8925 CBC 153 : if (caseexpr->arg)
6962 tgl 8926 ECB : {
6962 tgl 8927 GIC 51 : appendStringInfoChar(buf, ' ');
6962 tgl 8928 CBC 51 : get_rule_expr((Node *) caseexpr->arg, context, true);
6962 tgl 8929 ECB : }
8625 tgl 8930 CBC 632 : foreach(temp, caseexpr->args)
8625 tgl 8931 ECB : {
8625 tgl 8932 GIC 479 : CaseWhen *when = (CaseWhen *) lfirst(temp);
6329 8933 479 : Node *w = (Node *) when->expr;
8625 tgl 8934 ECB :
6962 tgl 8935 GIC 479 : if (caseexpr->arg)
6962 tgl 8936 EUB : {
8937 : /*
8938 : * The parser should have produced WHEN clauses of the
8939 : * form "CaseTestExpr = RHS", possibly with an
8940 : * implicit coercion inserted above the CaseTestExpr.
8941 : * For accurate decompilation of rules it's essential
8942 : * that we show just the RHS. However in an
8943 : * expression that's been through the optimizer, the
8944 : * WHEN clause could be almost anything (since the
4336 8945 : * equality operator could have been expanded into an
8946 : * inline function). If we don't recognize the form
8947 : * of the WHEN clause, just punt and display it as-is.
8948 : */
6329 tgl 8949 CBC 197 : if (IsA(w, OpExpr))
8950 : {
5156 8951 197 : List *args = ((OpExpr *) w)->args;
8952 :
4336 8953 197 : if (list_length(args) == 2 &&
8954 197 : IsA(strip_implicit_coercions(linitial(args)),
4336 tgl 8955 ECB : CaseTestExpr))
4336 tgl 8956 GIC 197 : w = (Node *) lsecond(args);
8957 : }
8958 : }
8959 :
8960 479 : if (!PRETTY_INDENT(context))
8961 41 : appendStringInfoChar(buf, ' ');
4336 tgl 8962 CBC 479 : appendContextKeyword(context, "WHEN ",
4336 tgl 8963 ECB : 0, 0, 0);
4336 tgl 8964 GIC 479 : get_rule_expr(w, context, false);
3447 rhaas 8965 479 : appendStringInfoString(buf, " THEN ");
7423 tgl 8966 CBC 479 : get_rule_expr((Node *) when->result, context, true);
8967 : }
7193 8968 153 : if (!PRETTY_INDENT(context))
7188 bruce 8969 GIC 36 : appendStringInfoChar(buf, ' ');
7193 tgl 8970 CBC 153 : appendContextKeyword(context, "ELSE ",
7193 tgl 8971 ECB : 0, 0, 0);
7423 tgl 8972 GIC 153 : get_rule_expr((Node *) caseexpr->defresult, context, true);
7193 8973 153 : if (!PRETTY_INDENT(context))
7188 bruce 8974 36 : appendStringInfoChar(buf, ' ');
7193 tgl 8975 153 : appendContextKeyword(context, "END",
8976 : -PRETTYINDENT_VAR, 0, 0);
8977 : }
8986 bruce 8978 153 : break;
8979 :
4336 tgl 8980 UIC 0 : case T_CaseTestExpr:
4336 tgl 8981 ECB : {
8982 : /*
8983 : * Normally we should never get here, since for expressions
8984 : * that can contain this node type we attempt to avoid
8985 : * recursing to it. But in an optimized expression we might
8986 : * be unable to avoid that (see comments for CaseExpr). If we
8987 : * do see one, print it as CASE_TEST_EXPR.
8988 : */
3447 rhaas 8989 UIC 0 : appendStringInfoString(buf, "CASE_TEST_EXPR");
8990 : }
4336 tgl 8991 LBC 0 : break;
4336 tgl 8992 ECB :
7306 tgl 8993 CBC 181 : case T_ArrayExpr:
7306 tgl 8994 ECB : {
7188 bruce 8995 GIC 181 : ArrayExpr *arrayexpr = (ArrayExpr *) node;
7306 tgl 8996 ECB :
3447 rhaas 8997 GIC 181 : appendStringInfoString(buf, "ARRAY[");
6758 tgl 8998 CBC 181 : get_rule_expr((Node *) arrayexpr->elements, context, true);
8999 181 : appendStringInfoChar(buf, ']');
9000 :
5224 tgl 9001 ECB : /*
9002 : * If the array isn't empty, we assume its elements are
9003 : * coerced to the desired type. If it's empty, though, we
9004 : * need an explicit coercion to the array type.
9005 : */
5224 tgl 9006 CBC 181 : if (arrayexpr->elements == NIL)
5224 tgl 9007 GIC 3 : appendStringInfo(buf, "::%s",
2118 tgl 9008 ECB : format_type_with_typemod(arrayexpr->array_typeid, -1));
9009 : }
7306 tgl 9010 CBC 181 : break;
9011 :
6908 tgl 9012 GBC 90 : case T_RowExpr:
9013 : {
6797 bruce 9014 90 : RowExpr *rowexpr = (RowExpr *) node;
6809 tgl 9015 90 : TupleDesc tupdesc = NULL;
6892 neilc 9016 EUB : ListCell *arg;
9017 : int i;
6908 tgl 9018 : char *sep;
9019 :
9020 : /*
6385 bruce 9021 ECB : * If it's a named type and not RECORD, we may have to skip
9022 : * dropped columns and/or claim there are NULLs for added
9023 : * columns.
6809 tgl 9024 : */
6809 tgl 9025 CBC 90 : if (rowexpr->row_typeid != RECORDOID)
9026 : {
6809 tgl 9027 GIC 24 : tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
6809 tgl 9028 CBC 24 : Assert(list_length(rowexpr->args) <= tupdesc->natts);
9029 : }
6809 tgl 9030 ECB :
9031 : /*
6385 bruce 9032 : * SQL99 allows "ROW" to be omitted when there is more than
9033 : * one column, but for simplicity we always print it.
9034 : */
3447 rhaas 9035 GIC 90 : appendStringInfoString(buf, "ROW(");
6908 tgl 9036 90 : sep = "";
6809 9037 90 : i = 0;
6908 9038 258 : foreach(arg, rowexpr->args)
9039 : {
6908 tgl 9040 CBC 168 : Node *e = (Node *) lfirst(arg);
6908 tgl 9041 ECB :
6809 tgl 9042 GIC 168 : if (tupdesc == NULL ||
2058 andres 9043 45 : !TupleDescAttr(tupdesc, i)->attisdropped)
9044 : {
6553 neilc 9045 168 : appendStringInfoString(buf, sep);
9046 : /* Whole-row Vars need special treatment here */
2702 tgl 9047 168 : get_rule_expr_toplevel(e, context, true);
6809 9048 168 : sep = ", ";
9049 : }
6809 tgl 9050 CBC 168 : i++;
6809 tgl 9051 ECB : }
6809 tgl 9052 CBC 90 : if (tupdesc != NULL)
6809 tgl 9053 ECB : {
6809 tgl 9054 CBC 24 : while (i < tupdesc->natts)
6809 tgl 9055 ECB : {
2058 andres 9056 UIC 0 : if (!TupleDescAttr(tupdesc, i)->attisdropped)
6809 tgl 9057 ECB : {
6553 neilc 9058 UIC 0 : appendStringInfoString(buf, sep);
3447 rhaas 9059 LBC 0 : appendStringInfoString(buf, "NULL");
6809 tgl 9060 UIC 0 : sep = ", ";
6809 tgl 9061 ECB : }
6809 tgl 9062 UIC 0 : i++;
6809 tgl 9063 ECB : }
6141 9064 :
6141 tgl 9065 CBC 24 : ReleaseTupleDesc(tupdesc);
9066 : }
3447 rhaas 9067 90 : appendStringInfoChar(buf, ')');
6908 tgl 9068 GIC 90 : if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
6908 tgl 9069 CBC 18 : appendStringInfo(buf, "::%s",
9070 : format_type_with_typemod(rowexpr->row_typeid, -1));
6908 tgl 9071 ECB : }
6908 tgl 9072 GIC 90 : break;
6908 tgl 9073 ECB :
6311 tgl 9074 GIC 33 : case T_RowCompareExpr:
6311 tgl 9075 ECB : {
6311 tgl 9076 CBC 33 : RowCompareExpr *rcexpr = (RowCompareExpr *) node;
6311 tgl 9077 ECB :
9078 : /*
9079 : * SQL99 allows "ROW" to be omitted when there is more than
451 9080 : * one column, but for simplicity we always print it. Within
9081 : * a ROW expression, whole-row Vars need special treatment, so
9082 : * use get_rule_list_toplevel.
6311 9083 : */
3447 rhaas 9084 GIC 33 : appendStringInfoString(buf, "(ROW(");
451 tgl 9085 CBC 33 : get_rule_list_toplevel(rcexpr->largs, context, true);
9086 :
6311 tgl 9087 ECB : /*
9088 : * We assume that the name of the first-column operator will
6031 bruce 9089 : * do for all the rest too. This is definitely open to
9090 : * failure, eg if some but not all operators were renamed
9091 : * since the construct was parsed, but there seems no way to
9092 : * be perfect.
9093 : */
6311 tgl 9094 GIC 33 : appendStringInfo(buf, ") %s ROW(",
2118 tgl 9095 CBC 33 : generate_operator_name(linitial_oid(rcexpr->opnos),
2118 tgl 9096 GIC 33 : exprType(linitial(rcexpr->largs)),
2118 tgl 9097 CBC 33 : exprType(linitial(rcexpr->rargs))));
451 9098 33 : get_rule_list_toplevel(rcexpr->rargs, context, true);
3447 rhaas 9099 33 : appendStringInfoString(buf, "))");
6311 tgl 9100 ECB : }
6311 tgl 9101 CBC 33 : break;
6311 tgl 9102 ECB :
7357 tgl 9103 CBC 489 : case T_CoalesceExpr:
7357 tgl 9104 ECB : {
7357 tgl 9105 CBC 489 : CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
7357 tgl 9106 ECB :
3447 rhaas 9107 CBC 489 : appendStringInfoString(buf, "COALESCE(");
6758 tgl 9108 489 : get_rule_expr((Node *) coalesceexpr->args, context, true);
9109 489 : appendStringInfoChar(buf, ')');
7357 tgl 9110 ECB : }
7357 tgl 9111 CBC 489 : break;
7188 bruce 9112 ECB :
6496 tgl 9113 CBC 18 : case T_MinMaxExpr:
6496 tgl 9114 ECB : {
6496 tgl 9115 CBC 18 : MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
6496 tgl 9116 ECB :
6496 tgl 9117 CBC 18 : switch (minmaxexpr->op)
6496 tgl 9118 EUB : {
6496 tgl 9119 GBC 3 : case IS_GREATEST:
3447 rhaas 9120 GIC 3 : appendStringInfoString(buf, "GREATEST(");
6496 tgl 9121 CBC 3 : break;
6496 tgl 9122 GIC 15 : case IS_LEAST:
3447 rhaas 9123 CBC 15 : appendStringInfoString(buf, "LEAST(");
6496 tgl 9124 GBC 15 : break;
9125 : }
6496 tgl 9126 CBC 18 : get_rule_expr((Node *) minmaxexpr->args, context, true);
6496 tgl 9127 GIC 18 : appendStringInfoChar(buf, ')');
6496 tgl 9128 ECB : }
6496 tgl 9129 GIC 18 : break;
6496 tgl 9130 ECB :
5950 tgl 9131 GIC 72 : case T_XmlExpr:
5950 tgl 9132 ECB : {
5624 bruce 9133 CBC 72 : XmlExpr *xexpr = (XmlExpr *) node;
9134 72 : bool needcomma = false;
5950 tgl 9135 ECB : ListCell *arg;
9136 : ListCell *narg;
9137 : Const *con;
5950 tgl 9138 EUB :
5950 tgl 9139 GIC 72 : switch (xexpr->op)
5950 tgl 9140 ECB : {
5950 tgl 9141 CBC 8 : case IS_XMLCONCAT:
5950 tgl 9142 GIC 8 : appendStringInfoString(buf, "XMLCONCAT(");
9143 8 : break;
9144 16 : case IS_XMLELEMENT:
5950 tgl 9145 CBC 16 : appendStringInfoString(buf, "XMLELEMENT(");
5950 tgl 9146 GIC 16 : break;
5950 tgl 9147 CBC 8 : case IS_XMLFOREST:
9148 8 : appendStringInfoString(buf, "XMLFOREST(");
5950 tgl 9149 GIC 8 : break;
5950 tgl 9150 CBC 8 : case IS_XMLPARSE:
5950 tgl 9151 GBC 8 : appendStringInfoString(buf, "XMLPARSE(");
9152 8 : break;
5950 tgl 9153 GIC 8 : case IS_XMLPI:
5950 tgl 9154 GBC 8 : appendStringInfoString(buf, "XMLPI(");
9155 8 : break;
9156 8 : case IS_XMLROOT:
5950 tgl 9157 GIC 8 : appendStringInfoString(buf, "XMLROOT(");
5950 tgl 9158 GBC 8 : break;
5909 peter_e 9159 16 : case IS_XMLSERIALIZE:
9160 16 : appendStringInfoString(buf, "XMLSERIALIZE(");
5909 peter_e 9161 GIC 16 : break;
5929 peter_e 9162 UIC 0 : case IS_DOCUMENT:
5929 peter_e 9163 LBC 0 : break;
5950 tgl 9164 EUB : }
5909 peter_e 9165 GBC 72 : if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
5909 peter_e 9166 EUB : {
5909 peter_e 9167 GIC 24 : if (xexpr->xmloption == XMLOPTION_DOCUMENT)
5909 peter_e 9168 UIC 0 : appendStringInfoString(buf, "DOCUMENT ");
5909 peter_e 9169 ECB : else
5909 peter_e 9170 CBC 24 : appendStringInfoString(buf, "CONTENT ");
9171 : }
5950 tgl 9172 GIC 72 : if (xexpr->name)
5950 tgl 9173 ECB : {
5950 tgl 9174 GBC 24 : appendStringInfo(buf, "NAME %s",
5945 peter_e 9175 GIC 24 : quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
5950 tgl 9176 CBC 24 : needcomma = true;
9177 : }
9178 72 : if (xexpr->named_args)
9179 : {
9180 16 : if (xexpr->op != IS_XMLFOREST)
9181 : {
9182 8 : if (needcomma)
5950 tgl 9183 GIC 8 : appendStringInfoString(buf, ", ");
5950 tgl 9184 CBC 8 : appendStringInfoString(buf, "XMLATTRIBUTES(");
9185 8 : needcomma = false;
5950 tgl 9186 ECB : }
5950 tgl 9187 GIC 56 : forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
9188 : {
5624 bruce 9189 40 : Node *e = (Node *) lfirst(arg);
9190 40 : char *argname = strVal(lfirst(narg));
9191 :
5950 tgl 9192 40 : if (needcomma)
9193 24 : appendStringInfoString(buf, ", ");
5950 tgl 9194 CBC 40 : get_rule_expr((Node *) e, context, true);
9195 40 : appendStringInfo(buf, " AS %s",
5945 peter_e 9196 GIC 40 : quote_identifier(map_xml_name_to_sql_identifier(argname)));
5950 tgl 9197 CBC 40 : needcomma = true;
9198 : }
9199 16 : if (xexpr->op != IS_XMLFOREST)
9200 8 : appendStringInfoChar(buf, ')');
5950 tgl 9201 ECB : }
5950 tgl 9202 CBC 72 : if (xexpr->args)
5950 tgl 9203 ECB : {
5950 tgl 9204 CBC 64 : if (needcomma)
5950 tgl 9205 GBC 24 : appendStringInfoString(buf, ", ");
9206 64 : switch (xexpr->op)
9207 : {
5950 tgl 9208 GIC 48 : case IS_XMLCONCAT:
9209 : case IS_XMLELEMENT:
9210 : case IS_XMLFOREST:
9211 : case IS_XMLPI:
5909 peter_e 9212 ECB : case IS_XMLSERIALIZE:
9213 : /* no extra decoration needed */
5950 tgl 9214 CBC 48 : get_rule_expr((Node *) xexpr->args, context, true);
9215 48 : break;
9216 8 : case IS_XMLPARSE:
5909 peter_e 9217 8 : Assert(list_length(xexpr->args) == 2);
5950 tgl 9218 ECB :
5950 tgl 9219 CBC 8 : get_rule_expr((Node *) linitial(xexpr->args),
5950 tgl 9220 EUB : context, true);
9221 :
2190 tgl 9222 GIC 8 : con = lsecond_node(Const, xexpr->args);
5950 9223 8 : Assert(!con->constisnull);
9224 8 : if (DatumGetBool(con->constvalue))
5950 tgl 9225 LBC 0 : appendStringInfoString(buf,
2118 tgl 9226 ECB : " PRESERVE WHITESPACE");
9227 : else
5950 tgl 9228 CBC 8 : appendStringInfoString(buf,
9229 : " STRIP WHITESPACE");
9230 8 : break;
5950 tgl 9231 GIC 8 : case IS_XMLROOT:
5950 tgl 9232 CBC 8 : Assert(list_length(xexpr->args) == 3);
9233 :
9234 8 : get_rule_expr((Node *) linitial(xexpr->args),
5950 tgl 9235 ECB : context, true);
9236 :
5950 tgl 9237 CBC 8 : appendStringInfoString(buf, ", VERSION ");
5950 tgl 9238 GIC 8 : con = (Const *) lsecond(xexpr->args);
5950 tgl 9239 CBC 8 : if (IsA(con, Const) &&
9240 8 : con->constisnull)
9241 8 : appendStringInfoString(buf, "NO VALUE");
5950 tgl 9242 ECB : else
5950 tgl 9243 LBC 0 : get_rule_expr((Node *) con, context, false);
5950 tgl 9244 ECB :
2190 tgl 9245 GBC 8 : con = lthird_node(Const, xexpr->args);
5950 9246 8 : if (con->constisnull)
5624 bruce 9247 EUB : /* suppress STANDALONE NO VALUE */ ;
5950 tgl 9248 : else
5909 peter_e 9249 : {
5909 peter_e 9250 GBC 8 : switch (DatumGetInt32(con->constvalue))
5909 peter_e 9251 ECB : {
5909 peter_e 9252 CBC 8 : case XML_STANDALONE_YES:
9253 8 : appendStringInfoString(buf,
2118 tgl 9254 ECB : ", STANDALONE YES");
5909 peter_e 9255 CBC 8 : break;
5909 peter_e 9256 LBC 0 : case XML_STANDALONE_NO:
5909 peter_e 9257 UBC 0 : appendStringInfoString(buf,
2118 tgl 9258 EUB : ", STANDALONE NO");
5909 peter_e 9259 UIC 0 : break;
9260 0 : case XML_STANDALONE_NO_VALUE:
5909 peter_e 9261 LBC 0 : appendStringInfoString(buf,
2118 tgl 9262 ECB : ", STANDALONE NO VALUE");
5909 peter_e 9263 UIC 0 : break;
5909 peter_e 9264 LBC 0 : default:
5909 peter_e 9265 UIC 0 : break;
5909 peter_e 9266 ECB : }
9267 : }
5950 tgl 9268 CBC 8 : break;
5929 peter_e 9269 LBC 0 : case IS_DOCUMENT:
5929 peter_e 9270 UIC 0 : get_rule_expr_paren((Node *) xexpr->args, context, false, node);
5929 peter_e 9271 LBC 0 : break;
5950 tgl 9272 ECB : }
9273 : }
5909 peter_e 9274 GIC 72 : if (xexpr->op == IS_XMLSERIALIZE)
4404 tgl 9275 CBC 16 : appendStringInfo(buf, " AS %s",
9276 : format_type_with_typemod(xexpr->type,
9277 : xexpr->typmod));
5929 peter_e 9278 GIC 72 : if (xexpr->op == IS_DOCUMENT)
5929 peter_e 9279 LBC 0 : appendStringInfoString(buf, " IS DOCUMENT");
9280 : else
5929 peter_e 9281 GIC 72 : appendStringInfoChar(buf, ')');
9282 : }
5950 tgl 9283 72 : break;
9284 :
7964 tgl 9285 CBC 897 : case T_NullTest:
9286 : {
7836 bruce 9287 897 : NullTest *ntest = (NullTest *) node;
7964 tgl 9288 ECB :
7193 tgl 9289 CBC 897 : if (!PRETTY_PAREN(context))
7188 bruce 9290 GIC 873 : appendStringInfoChar(buf, '(');
7193 tgl 9291 CBC 897 : get_rule_expr_paren((Node *) ntest->arg, context, true, node);
2446 tgl 9292 ECB :
9293 : /*
9294 : * For scalar inputs, we prefer to print as IS [NOT] NULL,
9295 : * which is shorter and traditional. If it's a rowtype input
9296 : * but we're applying a scalar test, must print IS [NOT]
9297 : * DISTINCT FROM NULL to be semantically correct.
9298 : */
2446 tgl 9299 CBC 897 : if (ntest->argisrow ||
9300 888 : !type_is_rowtype(exprType((Node *) ntest->arg)))
7836 bruce 9301 ECB : {
2446 tgl 9302 GIC 1776 : switch (ntest->nulltesttype)
2446 tgl 9303 EUB : {
2446 tgl 9304 GIC 264 : case IS_NULL:
9305 264 : appendStringInfoString(buf, " IS NULL");
2446 tgl 9306 CBC 264 : break;
2446 tgl 9307 GIC 624 : case IS_NOT_NULL:
2446 tgl 9308 GBC 624 : appendStringInfoString(buf, " IS NOT NULL");
2446 tgl 9309 GIC 624 : break;
2446 tgl 9310 UBC 0 : default:
2446 tgl 9311 UIC 0 : elog(ERROR, "unrecognized nulltesttype: %d",
9312 : (int) ntest->nulltesttype);
9313 : }
9314 : }
9315 : else
2446 tgl 9316 EUB : {
2446 tgl 9317 GBC 9 : switch (ntest->nulltesttype)
2446 tgl 9318 EUB : {
2446 tgl 9319 GIC 3 : case IS_NULL:
2446 tgl 9320 GBC 3 : appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
2446 tgl 9321 GIC 3 : break;
2446 tgl 9322 GBC 6 : case IS_NOT_NULL:
2446 tgl 9323 GIC 6 : appendStringInfoString(buf, " IS DISTINCT FROM NULL");
2446 tgl 9324 CBC 6 : break;
2446 tgl 9325 UIC 0 : default:
2446 tgl 9326 LBC 0 : elog(ERROR, "unrecognized nulltesttype: %d",
9327 : (int) ntest->nulltesttype);
9328 : }
9329 : }
7193 tgl 9330 GIC 897 : if (!PRETTY_PAREN(context))
7188 bruce 9331 873 : appendStringInfoChar(buf, ')');
9332 : }
7964 tgl 9333 897 : break;
7964 tgl 9334 ECB :
7964 tgl 9335 CBC 36 : case T_BooleanTest:
9336 : {
7836 bruce 9337 GIC 36 : BooleanTest *btest = (BooleanTest *) node;
9338 :
7193 tgl 9339 36 : if (!PRETTY_PAREN(context))
7188 bruce 9340 36 : appendStringInfoChar(buf, '(');
7193 tgl 9341 CBC 36 : get_rule_expr_paren((Node *) btest->arg, context, false, node);
7836 bruce 9342 36 : switch (btest->booltesttype)
7836 bruce 9343 EUB : {
7836 bruce 9344 GIC 6 : case IS_TRUE:
3447 rhaas 9345 GBC 6 : appendStringInfoString(buf, " IS TRUE");
7964 tgl 9346 GIC 6 : break;
7836 bruce 9347 CBC 12 : case IS_NOT_TRUE:
3447 rhaas 9348 GBC 12 : appendStringInfoString(buf, " IS NOT TRUE");
7964 tgl 9349 CBC 12 : break;
7836 bruce 9350 UIC 0 : case IS_FALSE:
3447 rhaas 9351 LBC 0 : appendStringInfoString(buf, " IS FALSE");
7964 tgl 9352 UBC 0 : break;
7836 bruce 9353 UIC 0 : case IS_NOT_FALSE:
3447 rhaas 9354 LBC 0 : appendStringInfoString(buf, " IS NOT FALSE");
7964 tgl 9355 UIC 0 : break;
7836 bruce 9356 CBC 9 : case IS_UNKNOWN:
3447 rhaas 9357 9 : appendStringInfoString(buf, " IS UNKNOWN");
7964 tgl 9358 GIC 9 : break;
7836 bruce 9359 9 : case IS_NOT_UNKNOWN:
3447 rhaas 9360 9 : appendStringInfoString(buf, " IS NOT UNKNOWN");
7964 tgl 9361 CBC 9 : break;
7836 bruce 9362 UIC 0 : default:
7196 tgl 9363 LBC 0 : elog(ERROR, "unrecognized booltesttype: %d",
7836 bruce 9364 ECB : (int) btest->booltesttype);
9365 : }
7193 tgl 9366 CBC 36 : if (!PRETTY_PAREN(context))
7188 bruce 9367 GIC 36 : appendStringInfoChar(buf, ')');
9368 : }
7964 tgl 9369 CBC 36 : break;
9370 :
7370 9371 16 : case T_CoerceToDomain:
9372 : {
9373 16 : CoerceToDomain *ctest = (CoerceToDomain *) node;
7188 bruce 9374 GIC 16 : Node *arg = (Node *) ctest->arg;
9375 :
7370 tgl 9376 16 : if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
7370 tgl 9377 CBC 11 : !showimplicit)
9378 : {
7370 tgl 9379 ECB : /* don't show the implicit cast */
7370 tgl 9380 CBC 11 : get_rule_expr(arg, context, false);
9381 : }
9382 : else
7370 tgl 9383 ECB : {
5867 tgl 9384 GIC 5 : get_coercion_expr(arg, context,
5867 tgl 9385 ECB : ctest->resulttype,
9386 : ctest->resulttypmod,
9387 : node);
9388 : }
7526 9389 : }
7526 tgl 9390 CBC 16 : break;
9391 :
7370 9392 140 : case T_CoerceToDomainValue:
3447 rhaas 9393 GIC 140 : appendStringInfoString(buf, "VALUE");
7698 tgl 9394 CBC 140 : break;
7698 tgl 9395 ECB :
7220 tgl 9396 GIC 32 : case T_SetToDefault:
3447 rhaas 9397 CBC 32 : appendStringInfoString(buf, "DEFAULT");
7220 tgl 9398 32 : break;
7220 tgl 9399 ECB :
5781 tgl 9400 GIC 9 : case T_CurrentOfExpr:
5781 tgl 9401 ECB : {
5781 tgl 9402 GIC 9 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
5781 tgl 9403 ECB :
5781 tgl 9404 CBC 9 : if (cexpr->cursor_name)
9405 9 : appendStringInfo(buf, "CURRENT OF %s",
5781 tgl 9406 GIC 9 : quote_identifier(cexpr->cursor_name));
9407 : else
5781 tgl 9408 LBC 0 : appendStringInfo(buf, "CURRENT OF $%d",
5781 tgl 9409 ECB : cexpr->cursor_param);
9410 : }
5781 tgl 9411 CBC 9 : break;
5781 tgl 9412 ECB :
2095 tgl 9413 UIC 0 : case T_NextValueExpr:
9414 : {
9415 0 : NextValueExpr *nvexpr = (NextValueExpr *) node;
9416 :
2095 tgl 9417 ECB : /*
9418 : * This isn't exactly nextval(), but that seems close enough
9419 : * for EXPLAIN's purposes.
9420 : */
2095 tgl 9421 UIC 0 : appendStringInfoString(buf, "nextval(");
2095 tgl 9422 UBC 0 : simple_quote_literal(buf,
9423 0 : generate_relation_name(nvexpr->seqid,
9424 : NIL));
2095 tgl 9425 UIC 0 : appendStringInfoChar(buf, ')');
9426 : }
9427 0 : break;
2095 tgl 9428 ECB :
2882 andres 9429 GIC 12 : case T_InferenceElem:
2882 andres 9430 ECB : {
2878 bruce 9431 GIC 12 : InferenceElem *iexpr = (InferenceElem *) node;
2618 tgl 9432 ECB : bool save_varprefix;
9433 : bool need_parens;
2882 andres 9434 :
9435 : /*
9436 : * InferenceElem can only refer to target relation, so a
2618 tgl 9437 : * prefix is not useful, and indeed would cause parse errors.
9438 : */
2618 tgl 9439 CBC 12 : save_varprefix = context->varprefix;
2882 andres 9440 12 : context->varprefix = false;
2882 andres 9441 ECB :
9442 : /*
9443 : * Parenthesize the element unless it's a simple Var or a bare
9444 : * function call. Follows pg_get_indexdef_worker().
9445 : */
2882 andres 9446 GIC 12 : need_parens = !IsA(iexpr->expr, Var);
2882 andres 9447 CBC 12 : if (IsA(iexpr->expr, FuncExpr) &&
2882 andres 9448 LBC 0 : ((FuncExpr *) iexpr->expr)->funcformat ==
9449 : COERCE_EXPLICIT_CALL)
9450 0 : need_parens = false;
9451 :
2882 andres 9452 CBC 12 : if (need_parens)
2882 andres 9453 UIC 0 : appendStringInfoChar(buf, '(');
2882 andres 9454 GIC 12 : get_rule_expr((Node *) iexpr->expr,
9455 : context, false);
2882 andres 9456 CBC 12 : if (need_parens)
2882 andres 9457 UIC 0 : appendStringInfoChar(buf, ')');
2882 andres 9458 ECB :
2618 tgl 9459 CBC 12 : context->varprefix = save_varprefix;
2882 andres 9460 ECB :
2882 andres 9461 CBC 12 : if (iexpr->infercollid)
9462 6 : appendStringInfo(buf, " COLLATE %s",
2118 tgl 9463 ECB : generate_collation_name(iexpr->infercollid));
2882 andres 9464 :
9465 : /* Add the operator class name, if not default */
2882 andres 9466 CBC 12 : if (iexpr->inferopclass)
2882 andres 9467 ECB : {
2878 bruce 9468 CBC 6 : Oid inferopclass = iexpr->inferopclass;
2878 bruce 9469 GIC 6 : Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
9470 :
2882 andres 9471 CBC 6 : get_opclass_name(inferopclass, inferopcinputtype, buf);
2882 andres 9472 ECB : }
9473 : }
2882 andres 9474 CBC 12 : break;
2882 andres 9475 ECB :
2314 rhaas 9476 GIC 1715 : case T_PartitionBoundSpec:
2314 rhaas 9477 ECB : {
2314 rhaas 9478 GIC 1715 : PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
2266 rhaas 9479 ECB : ListCell *cell;
9480 : char *sep;
9481 :
2039 rhaas 9482 GIC 1715 : if (spec->is_default)
9483 : {
2039 rhaas 9484 CBC 76 : appendStringInfoString(buf, "DEFAULT");
9485 76 : break;
9486 : }
2039 rhaas 9487 ECB :
2314 rhaas 9488 CBC 1639 : switch (spec->strategy)
2314 rhaas 9489 ECB : {
1977 rhaas 9490 GIC 91 : case PARTITION_STRATEGY_HASH:
9491 91 : Assert(spec->modulus > 0 && spec->remainder >= 0);
1977 rhaas 9492 CBC 91 : Assert(spec->modulus > spec->remainder);
9493 :
9494 91 : appendStringInfoString(buf, "FOR VALUES");
9495 91 : appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
1977 rhaas 9496 ECB : spec->modulus, spec->remainder);
1977 rhaas 9497 GIC 91 : break;
1977 rhaas 9498 EUB :
2314 rhaas 9499 GBC 537 : case PARTITION_STRATEGY_LIST:
2314 rhaas 9500 GIC 537 : Assert(spec->listdatums != NIL);
9501 :
2142 tgl 9502 537 : appendStringInfoString(buf, "FOR VALUES IN (");
2314 rhaas 9503 537 : sep = "";
2266 9504 1483 : foreach(cell, spec->listdatums)
9505 : {
629 peter 9506 946 : Const *val = lfirst_node(Const, cell);
9507 :
2314 rhaas 9508 946 : appendStringInfoString(buf, sep);
9509 946 : get_const_expr(val, context, -1);
9510 946 : sep = ", ";
9511 : }
9512 :
2063 peter_e 9513 537 : appendStringInfoChar(buf, ')');
2314 rhaas 9514 537 : break;
9515 :
2314 rhaas 9516 CBC 1011 : case PARTITION_STRATEGY_RANGE:
2314 rhaas 9517 GIC 1011 : Assert(spec->lowerdatums != NIL &&
9518 : spec->upperdatums != NIL &&
2314 rhaas 9519 ECB : list_length(spec->lowerdatums) ==
9520 : list_length(spec->upperdatums));
9521 :
2068 rhaas 9522 CBC 1011 : appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
2064 tgl 9523 ECB : get_range_partbound_string(spec->lowerdatums),
9524 : get_range_partbound_string(spec->upperdatums));
2314 rhaas 9525 GIC 1011 : break;
9526 :
2314 rhaas 9527 UIC 0 : default:
9528 0 : elog(ERROR, "unrecognized partition strategy: %d",
9529 : (int) spec->strategy);
9530 : break;
9531 : }
9532 : }
2314 rhaas 9533 GIC 1639 : break;
2314 rhaas 9534 ECB :
11 alvherre 9535 GNC 24 : case T_JsonValueExpr:
9536 : {
9537 24 : JsonValueExpr *jve = (JsonValueExpr *) node;
9538 :
9539 24 : get_rule_expr((Node *) jve->raw_expr, context, false);
9540 24 : get_json_format(jve->format, context->buf);
9541 : }
9542 24 : break;
9543 :
9544 36 : case T_JsonConstructorExpr:
9545 36 : get_json_constructor((JsonConstructorExpr *) node, context, false);
9546 36 : break;
9547 :
9 9548 24 : case T_JsonIsPredicate:
9549 : {
9550 24 : JsonIsPredicate *pred = (JsonIsPredicate *) node;
9551 :
9552 24 : if (!PRETTY_PAREN(context))
9553 12 : appendStringInfoChar(context->buf, '(');
9554 :
9555 24 : get_rule_expr_paren(pred->expr, context, true, node);
9556 :
9557 24 : appendStringInfoString(context->buf, " IS JSON");
9558 :
9559 : /* TODO: handle FORMAT clause */
9560 :
9561 24 : switch (pred->item_type)
9562 : {
9563 6 : case JS_TYPE_SCALAR:
9564 6 : appendStringInfoString(context->buf, " SCALAR");
9565 6 : break;
9566 6 : case JS_TYPE_ARRAY:
9567 6 : appendStringInfoString(context->buf, " ARRAY");
9568 6 : break;
9569 6 : case JS_TYPE_OBJECT:
9570 6 : appendStringInfoString(context->buf, " OBJECT");
9571 6 : break;
9572 6 : default:
9573 6 : break;
9574 : }
9575 :
9576 24 : if (pred->unique_keys)
9577 6 : appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
9578 :
9579 24 : if (!PRETTY_PAREN(context))
9580 12 : appendStringInfoChar(context->buf, ')');
9581 : }
9582 24 : break;
9583 :
6758 tgl 9584 GIC 940 : case T_List:
9585 : {
9586 : char *sep;
9587 : ListCell *l;
9588 :
6758 tgl 9589 CBC 940 : sep = "";
9590 2658 : foreach(l, (List *) node)
9591 : {
6553 neilc 9592 1718 : appendStringInfoString(buf, sep);
6758 tgl 9593 GIC 1718 : get_rule_expr((Node *) lfirst(l), context, showimplicit);
6758 tgl 9594 CBC 1718 : sep = ", ";
6758 tgl 9595 ECB : }
9596 : }
6758 tgl 9597 GIC 940 : break;
6758 tgl 9598 ECB :
2223 alvherre 9599 GIC 12 : case T_TableFunc:
9600 12 : get_tablefunc((TableFunc *) node, context, showimplicit);
9601 12 : break;
9602 :
8986 bruce 9603 UIC 0 : default:
7196 tgl 9604 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
9605 : break;
9606 : }
9607 : }
9608 :
9609 : /*
9610 : * get_rule_expr_toplevel - Parse back a toplevel expression
9611 : *
9612 : * Same as get_rule_expr(), except that if the expr is just a Var, we pass
2702 tgl 9613 ECB : * istoplevel = true not false to get_variable(). This causes whole-row Vars
9614 : * to get printed with decoration that will prevent expansion of "*".
9615 : * We need to use this in contexts such as ROW() and VALUES(), where the
9616 : * parser would expand "foo.*" appearing at top level. (In principle we'd
9617 : * use this in get_target_list() too, but that has additional worries about
9618 : * whether to print AS, so it needs to invoke get_variable() directly anyway.)
9619 : */
9620 : static void
2702 tgl 9621 GIC 1351 : get_rule_expr_toplevel(Node *node, deparse_context *context,
2702 tgl 9622 ECB : bool showimplicit)
9623 : {
2702 tgl 9624 CBC 1351 : if (node && IsA(node, Var))
9625 514 : (void) get_variable((Var *) node, 0, true, context);
9626 : else
2702 tgl 9627 GIC 837 : get_rule_expr(node, context, showimplicit);
9628 1351 : }
2702 tgl 9629 ECB :
9630 : /*
9631 : * get_rule_list_toplevel - Parse back a list of toplevel expressions
9632 : *
9633 : * Apply get_rule_expr_toplevel() to each element of a List.
9634 : *
9635 : * This adds commas between the expressions, but caller is responsible
451 9636 : * for printing surrounding decoration.
9637 : */
9638 : static void
451 tgl 9639 GBC 186 : get_rule_list_toplevel(List *lst, deparse_context *context,
451 tgl 9640 ECB : bool showimplicit)
9641 : {
9642 : const char *sep;
9643 : ListCell *lc;
9644 :
451 tgl 9645 CBC 186 : sep = "";
9646 658 : foreach(lc, lst)
9647 : {
451 tgl 9648 GIC 472 : Node *e = (Node *) lfirst(lc);
9649 :
9650 472 : appendStringInfoString(context->buf, sep);
451 tgl 9651 CBC 472 : get_rule_expr_toplevel(e, context, showimplicit);
9652 472 : sep = ", ";
451 tgl 9653 ECB : }
451 tgl 9654 GIC 186 : }
451 tgl 9655 ECB :
9656 : /*
9657 : * get_rule_expr_funccall - Parse back a function-call expression
9658 : *
9659 : * Same as get_rule_expr(), except that we guarantee that the output will
9660 : * look like a function call, or like one of the things the grammar treats as
9661 : * equivalent to a function call (see the func_expr_windowless production).
9662 : * This is needed in places where the grammar uses func_expr_windowless and
2096 9663 : * you can't substitute a parenthesized a_expr. If what we have isn't going
9664 : * to look like a function call, wrap it in a dummy CAST() expression, which
9665 : * will satisfy the grammar --- and, indeed, is likely what the user wrote to
9666 : * produce such a thing.
9667 : */
9668 : static void
2096 tgl 9669 CBC 276 : get_rule_expr_funccall(Node *node, deparse_context *context,
2096 tgl 9670 ECB : bool showimplicit)
9671 : {
2096 tgl 9672 GIC 276 : if (looks_like_function(node))
9673 270 : get_rule_expr(node, context, showimplicit);
2096 tgl 9674 ECB : else
9675 : {
2096 tgl 9676 GIC 6 : StringInfo buf = context->buf;
2096 tgl 9677 ECB :
2096 tgl 9678 CBC 6 : appendStringInfoString(buf, "CAST(");
9679 : /* no point in showing any top-level implicit cast */
2096 tgl 9680 GIC 6 : get_rule_expr(node, context, false);
9681 6 : appendStringInfo(buf, " AS %s)",
2096 tgl 9682 ECB : format_type_with_typemod(exprType(node),
9683 : exprTypmod(node)));
9684 : }
2096 tgl 9685 GIC 276 : }
9686 :
2096 tgl 9687 ECB : /*
9688 : * Helper function to identify node types that satisfy func_expr_windowless.
9689 : * If in doubt, "false" is always a safe answer.
9690 : */
9691 : static bool
2096 tgl 9692 GIC 818 : looks_like_function(Node *node)
2096 tgl 9693 ECB : {
2096 tgl 9694 GIC 818 : if (node == NULL)
2096 tgl 9695 LBC 0 : return false; /* probably shouldn't happen */
2096 tgl 9696 CBC 818 : switch (nodeTag(node))
2096 tgl 9697 ECB : {
2096 tgl 9698 GIC 341 : case T_FuncExpr:
9699 : /* OK, unless it's going to deparse as a cast */
886 9700 401 : return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
9701 60 : ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
2096 9702 3 : case T_NullIfExpr:
2096 tgl 9703 ECB : case T_CoalesceExpr:
9704 : case T_MinMaxExpr:
9705 : case T_XmlExpr:
9706 : /* these are all accepted by func_expr_common_subexpr */
2096 tgl 9707 GIC 3 : return true;
9708 474 : default:
9709 474 : break;
9710 : }
9711 474 : return false;
9712 : }
9713 :
9714 :
9715 : /*
9716 : * get_oper_expr - Parse back an OpExpr node
7646 tgl 9717 ECB : */
9718 : static void
7184 bruce 9719 CBC 24672 : get_oper_expr(OpExpr *expr, deparse_context *context)
9720 : {
7646 tgl 9721 24672 : StringInfo buf = context->buf;
7423 tgl 9722 GIC 24672 : Oid opno = expr->opno;
7646 9723 24672 : List *args = expr->args;
9724 :
7193 9725 24672 : if (!PRETTY_PAREN(context))
7188 bruce 9726 23770 : appendStringInfoChar(buf, '(');
6888 neilc 9727 24672 : if (list_length(args) == 2)
7646 tgl 9728 ECB : {
9729 : /* binary operator */
6892 neilc 9730 GIC 24657 : Node *arg1 = (Node *) linitial(args);
7522 bruce 9731 CBC 24657 : Node *arg2 = (Node *) lsecond(args);
7188 bruce 9732 ECB :
7188 bruce 9733 GIC 24657 : get_rule_expr_paren(arg1, context, true, (Node *) expr);
7646 tgl 9734 24657 : appendStringInfo(buf, " %s ",
9735 : generate_operator_name(opno,
7646 tgl 9736 ECB : exprType(arg1),
9737 : exprType(arg2)));
7188 bruce 9738 CBC 24657 : get_rule_expr_paren(arg2, context, true, (Node *) expr);
9739 : }
9740 : else
9741 : {
934 tgl 9742 ECB : /* prefix operator */
6892 neilc 9743 GIC 15 : Node *arg = (Node *) linitial(args);
9744 :
934 tgl 9745 15 : appendStringInfo(buf, "%s ",
9746 : generate_operator_name(opno,
9747 : InvalidOid,
9748 : exprType(arg)));
9749 15 : get_rule_expr_paren(arg, context, true, (Node *) expr);
7646 tgl 9750 ECB : }
7193 tgl 9751 GIC 24672 : if (!PRETTY_PAREN(context))
7188 bruce 9752 CBC 23770 : appendStringInfoChar(buf, ')');
7646 tgl 9753 24672 : }
9754 :
9755 : /*
9756 : * get_func_expr - Parse back a FuncExpr node
9757 : */
9758 : static void
7184 bruce 9759 GIC 5662 : get_func_expr(FuncExpr *expr, deparse_context *context,
7507 tgl 9760 ECB : bool showimplicit)
8994 bruce 9761 EUB : {
8589 tgl 9762 GIC 5662 : StringInfo buf = context->buf;
7423 9763 5662 : Oid funcoid = expr->funcid;
7646 tgl 9764 ECB : Oid argtypes[FUNC_MAX_ARGS];
9765 : int nargs;
4931 9766 : List *argnames;
9767 : bool use_variadic;
6892 neilc 9768 : ListCell *l;
9769 :
8443 tgl 9770 : /*
6385 bruce 9771 : * If the function call came from an implicit coercion, then just show the
9772 : * first argument --- unless caller wants to see implicit coercions.
7508 tgl 9773 : */
7423 tgl 9774 GIC 5662 : if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
9775 : {
6892 neilc 9776 CBC 847 : get_rule_expr_paren((Node *) linitial(expr->args), context,
9777 : false, (Node *) expr);
7508 tgl 9778 GIC 2125 : return;
7508 tgl 9779 ECB : }
9780 :
9781 : /*
7188 bruce 9782 : * If the function call came from a cast, then show the first argument
9783 : * plus an explicit cast operation.
9784 : */
7423 tgl 9785 CBC 4815 : if (expr->funcformat == COERCE_EXPLICIT_CAST ||
9786 4560 : expr->funcformat == COERCE_IMPLICIT_CAST)
8443 tgl 9787 ECB : {
6892 neilc 9788 CBC 656 : Node *arg = linitial(expr->args);
7423 tgl 9789 656 : Oid rettype = expr->funcresulttype;
9790 : int32 coercedTypmod;
7508 tgl 9791 ECB :
9792 : /* Get the typmod if this is a length-coercion function */
7508 tgl 9793 GIC 656 : (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
9794 :
5867 9795 656 : get_coercion_expr(arg, context,
9796 : rettype, coercedTypmod,
9797 : (Node *) expr);
8179 tgl 9798 ECB :
8443 tgl 9799 GIC 656 : return;
9800 : }
8443 tgl 9801 ECB :
9802 : /*
886 9803 : * If the function was called using one of the SQL spec's random special
9804 : * syntaxes, try to reproduce that. If we don't recognize the function,
9805 : * fall through.
9806 : */
886 tgl 9807 GIC 4159 : if (expr->funcformat == COERCE_SQL_SYNTAX)
9808 : {
9809 625 : if (get_func_sql_syntax(expr, context))
886 tgl 9810 CBC 622 : return;
9811 : }
9812 :
9813 : /*
6385 bruce 9814 ECB : * Normal function: display as proname(args). First we need to extract
9815 : * the argument datatypes.
9816 : */
5215 tgl 9817 CBC 3537 : if (list_length(expr->args) > FUNC_MAX_ARGS)
5215 tgl 9818 UIC 0 : ereport(ERROR,
9819 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
9820 : errmsg("too many arguments")));
7646 tgl 9821 GIC 3537 : nargs = 0;
4931 9822 3537 : argnames = NIL;
7646 9823 7563 : foreach(l, expr->args)
9824 : {
4790 bruce 9825 4026 : Node *arg = (Node *) lfirst(l);
4931 tgl 9826 ECB :
4931 tgl 9827 GIC 4026 : if (IsA(arg, NamedArgExpr))
9828 9 : argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
9829 4026 : argtypes[nargs] = exprType(arg);
7646 tgl 9830 CBC 4026 : nargs++;
7646 tgl 9831 ECB : }
7522 bruce 9832 :
7646 tgl 9833 GIC 3537 : appendStringInfo(buf, "%s(",
4931 tgl 9834 ECB : generate_function_name(funcoid, nargs,
9835 : argnames, argtypes,
3730 tgl 9836 GIC 3537 : expr->funcvariadic,
9837 : &use_variadic,
9838 : context->special_exprkind));
5380 9839 3537 : nargs = 0;
9840 7563 : foreach(l, expr->args)
5380 tgl 9841 ECB : {
5380 tgl 9842 CBC 4026 : if (nargs++ > 0)
5380 tgl 9843 GIC 809 : appendStringInfoString(buf, ", ");
1364 9844 4026 : if (use_variadic && lnext(expr->args, l) == NULL)
5380 tgl 9845 CBC 3 : appendStringInfoString(buf, "VARIADIC ");
5380 tgl 9846 GIC 4026 : get_rule_expr((Node *) lfirst(l), context, true);
5380 tgl 9847 ECB : }
8449 tgl 9848 CBC 3537 : appendStringInfoChar(buf, ')');
8994 bruce 9849 ECB : }
9850 :
9851 : /*
9852 : * get_agg_expr - Parse back an Aggref node
9853 : */
7668 tgl 9854 : static void
220 andrew 9855 CBC 892 : get_agg_expr(Aggref *aggref, deparse_context *context,
9856 : Aggref *original_aggref)
9857 : {
11 alvherre 9858 GNC 892 : get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
9859 : false);
9860 892 : }
9861 :
9862 : /*
9863 : * get_agg_expr_helper - subroutine for get_agg_expr and
9864 : * get_json_agg_constructor
9865 : */
9866 : static void
9867 910 : get_agg_expr_helper(Aggref *aggref, deparse_context *context,
9868 : Aggref *original_aggref, const char *funcname,
9869 : const char *options, bool is_json_objectagg)
7668 tgl 9870 ECB : {
7668 tgl 9871 GIC 910 : StringInfo buf = context->buf;
9872 : Oid argtypes[FUNC_MAX_ARGS];
9873 : int nargs;
11 alvherre 9874 GNC 910 : bool use_variadic = false;
9875 :
9876 : /*
2538 rhaas 9877 ECB : * For a combining aggregate, we look up and deparse the corresponding
9878 : * partial aggregate instead. This is necessary because our input
9879 : * argument list has been replaced; the new argument list always has just
9880 : * one element, which will point to a partial Aggref that supplies us with
9881 : * transition states to combine.
9882 : */
2478 tgl 9883 GIC 910 : if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
9884 : {
9885 : TargetEntry *tle;
2538 rhaas 9886 ECB :
2538 rhaas 9887 CBC 130 : Assert(list_length(aggref->args) == 1);
1215 tgl 9888 GIC 130 : tle = linitial_node(TargetEntry, aggref->args);
9889 130 : resolve_special_varno((Node *) tle->expr, context,
9890 : get_agg_combine_expr, original_aggref);
2538 rhaas 9891 130 : return;
9892 : }
2538 rhaas 9893 ECB :
2478 tgl 9894 : /*
9895 : * Mark as PARTIAL, if appropriate. We look to the original aggref so as
9896 : * to avoid printing this when recursing from the code just above.
9897 : */
2478 tgl 9898 GIC 780 : if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
2538 rhaas 9899 CBC 30 : appendStringInfoString(buf, "PARTIAL ");
2538 rhaas 9900 ECB :
3394 tgl 9901 : /* Extract the argument types as seen by the parser */
3394 tgl 9902 CBC 780 : nargs = get_aggregate_argtypes(aggref, argtypes);
9903 :
11 alvherre 9904 GNC 780 : if (!funcname)
9905 762 : funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
9906 762 : argtypes, aggref->aggvariadic,
9907 : &use_variadic,
9908 : context->special_exprkind);
9909 :
3394 tgl 9910 ECB : /* Print the aggregate name, schema-qualified if needed */
11 alvherre 9911 GNC 780 : appendStringInfo(buf, "%s(%s", funcname,
4863 tgl 9912 GBC 780 : (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
9913 :
3394 tgl 9914 CBC 780 : if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
9915 : {
9916 : /*
3394 tgl 9917 ECB : * Ordered-set aggregates do not use "*" syntax. Also, we needn't
9918 : * worry about inserting VARIADIC. So we can just dump the direct
9919 : * args as-is.
9920 : */
3394 tgl 9921 CBC 14 : Assert(!aggref->aggvariadic);
3394 tgl 9922 GIC 14 : get_rule_expr((Node *) aggref->aggdirectargs, context, true);
9923 14 : Assert(aggref->aggorder != NIL);
9924 14 : appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
3394 tgl 9925 CBC 14 : get_rule_orderby(aggref->aggorder, aggref->args, false, context);
9926 : }
7668 tgl 9927 ECB : else
3505 9928 : {
9929 : /* aggstar can be set only in zero-argument aggregates */
3394 tgl 9930 GIC 766 : if (aggref->aggstar)
9931 112 : appendStringInfoChar(buf, '*');
3394 tgl 9932 ECB : else
3505 9933 : {
9934 : ListCell *l;
3394 9935 : int i;
9936 :
3394 tgl 9937 CBC 654 : i = 0;
9938 1387 : foreach(l, aggref->args)
9939 : {
3394 tgl 9940 GIC 733 : TargetEntry *tle = (TargetEntry *) lfirst(l);
3394 tgl 9941 CBC 733 : Node *arg = (Node *) tle->expr;
9942 :
3394 tgl 9943 GIC 733 : Assert(!IsA(arg, NamedArgExpr));
9944 733 : if (tle->resjunk)
9945 19 : continue;
9946 714 : if (i++ > 0)
9947 : {
11 alvherre 9948 GNC 60 : if (is_json_objectagg)
9949 : {
9950 : /*
9951 : * the ABSENT ON NULL and WITH UNIQUE args are printed
9952 : * separately, so ignore them here
9953 : */
9954 6 : if (i > 2)
11 alvherre 9955 UNC 0 : break;
9956 :
11 alvherre 9957 GNC 6 : appendStringInfoString(buf, " : ");
9958 : }
9959 : else
9960 54 : appendStringInfoString(buf, ", ");
9961 : }
3394 tgl 9962 GIC 714 : if (use_variadic && i == nargs)
9963 4 : appendStringInfoString(buf, "VARIADIC ");
3394 tgl 9964 CBC 714 : get_rule_expr(arg, context, true);
9965 : }
9966 : }
3505 tgl 9967 ECB :
3394 tgl 9968 GIC 766 : if (aggref->aggorder != NIL)
3394 tgl 9969 ECB : {
3394 tgl 9970 GBC 35 : appendStringInfoString(buf, " ORDER BY ");
3394 tgl 9971 GIC 35 : get_rule_orderby(aggref->aggorder, aggref->args, false, context);
3394 tgl 9972 ECB : }
4863 9973 : }
3554 noah 9974 :
11 alvherre 9975 GNC 780 : if (options)
9976 18 : appendStringInfoString(buf, options);
9977 :
3554 noah 9978 GIC 780 : if (aggref->aggfilter != NULL)
9979 : {
9980 23 : appendStringInfoString(buf, ") FILTER (WHERE ");
9981 23 : get_rule_expr((Node *) aggref->aggfilter, context, false);
9982 : }
3554 noah 9983 ECB :
7668 tgl 9984 GIC 780 : appendStringInfoChar(buf, ')');
7668 tgl 9985 ECB : }
9986 :
9987 : /*
9988 : * This is a helper function for get_agg_expr(). It's used when we deparse
9989 : * a combining Aggref; resolve_special_varno locates the corresponding partial
9990 : * Aggref and then calls this.
9991 : */
9992 : static void
1215 tgl 9993 GIC 130 : get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
2538 rhaas 9994 ECB : {
9995 : Aggref *aggref;
1215 tgl 9996 GIC 130 : Aggref *original_aggref = callback_arg;
9997 :
2538 rhaas 9998 CBC 130 : if (!IsA(node, Aggref))
2538 rhaas 9999 UIC 0 : elog(ERROR, "combining Aggref does not point to an Aggref");
10000 :
2538 rhaas 10001 GIC 130 : aggref = (Aggref *) node;
10002 130 : get_agg_expr(aggref, context, original_aggref);
10003 130 : }
2538 rhaas 10004 ECB :
5215 tgl 10005 EUB : /*
10006 : * get_windowfunc_expr - Parse back a WindowFunc node
10007 : */
5215 tgl 10008 ECB : static void
220 andrew 10009 CBC 117 : get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
10010 : {
11 alvherre 10011 GNC 117 : get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
10012 117 : }
10013 :
10014 :
10015 : /*
10016 : * get_windowfunc_expr_helper - subroutine for get_windowfunc_expr and
10017 : * get_json_agg_constructor
10018 : */
10019 : static void
10020 123 : get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
10021 : const char *funcname, const char *options,
10022 : bool is_json_objectagg)
5215 tgl 10023 ECB : {
5215 tgl 10024 GIC 123 : StringInfo buf = context->buf;
5215 tgl 10025 ECB : Oid argtypes[FUNC_MAX_ARGS];
10026 : int nargs;
3441 10027 : List *argnames;
5215 tgl 10028 EUB : ListCell *l;
5215 tgl 10029 ECB :
5215 tgl 10030 CBC 123 : if (list_length(wfunc->args) > FUNC_MAX_ARGS)
5215 tgl 10031 UIC 0 : ereport(ERROR,
10032 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5215 tgl 10033 ECB : errmsg("too many arguments")));
5215 tgl 10034 CBC 123 : nargs = 0;
3441 tgl 10035 GIC 123 : argnames = NIL;
5215 10036 192 : foreach(l, wfunc->args)
10037 : {
4790 bruce 10038 CBC 69 : Node *arg = (Node *) lfirst(l);
10039 :
3441 tgl 10040 GIC 69 : if (IsA(arg, NamedArgExpr))
3441 tgl 10041 LBC 0 : argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
4931 tgl 10042 CBC 69 : argtypes[nargs] = exprType(arg);
5215 tgl 10043 GIC 69 : nargs++;
10044 : }
5215 tgl 10045 ECB :
11 alvherre 10046 GNC 123 : if (!funcname)
10047 117 : funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
10048 : argtypes, false, NULL,
10049 : context->special_exprkind);
10050 :
10051 123 : appendStringInfo(buf, "%s(", funcname);
10052 :
10053 : /* winstar can be set only in zero-argument aggregates */
5215 tgl 10054 CBC 123 : if (wfunc->winstar)
5215 tgl 10055 GIC 12 : appendStringInfoChar(buf, '*');
10056 : else
10057 : {
11 alvherre 10058 GNC 111 : if (is_json_objectagg)
10059 : {
10060 3 : get_rule_expr((Node *) linitial(wfunc->args), context, false);
10061 3 : appendStringInfoString(buf, " : ");
10062 3 : get_rule_expr((Node *) lsecond(wfunc->args), context, false);
10063 : }
10064 : else
10065 108 : get_rule_expr((Node *) wfunc->args, context, true);
10066 : }
10067 :
10068 123 : if (options)
10069 6 : appendStringInfoString(buf, options);
3554 noah 10070 ECB :
3554 noah 10071 GIC 123 : if (wfunc->aggfilter != NULL)
3554 noah 10072 ECB : {
3554 noah 10073 UIC 0 : appendStringInfoString(buf, ") FILTER (WHERE ");
3554 noah 10074 UBC 0 : get_rule_expr((Node *) wfunc->aggfilter, context, false);
3554 noah 10075 EUB : }
10076 :
5215 tgl 10077 GIC 123 : appendStringInfoString(buf, ") OVER ");
5215 tgl 10078 ECB :
5215 tgl 10079 GIC 123 : foreach(l, context->windowClause)
5215 tgl 10080 ECB : {
5215 tgl 10081 GIC 21 : WindowClause *wc = (WindowClause *) lfirst(l);
5215 tgl 10082 ECB :
5215 tgl 10083 GIC 21 : if (wc->winref == wfunc->winref)
5215 tgl 10084 ECB : {
5215 tgl 10085 GIC 21 : if (wc->name)
5215 tgl 10086 LBC 0 : appendStringInfoString(buf, quote_identifier(wc->name));
5215 tgl 10087 EUB : else
5215 tgl 10088 GIC 21 : get_rule_windowspec(wc, context->windowTList, context);
5215 tgl 10089 CBC 21 : break;
5215 tgl 10090 ECB : }
10091 : }
5215 tgl 10092 GIC 123 : if (l == NULL)
5215 tgl 10093 ECB : {
5215 tgl 10094 GIC 102 : if (context->windowClause)
5215 tgl 10095 LBC 0 : elog(ERROR, "could not find window clause for winref %u",
5215 tgl 10096 EUB : wfunc->winref);
10097 :
10098 : /*
10099 : * In EXPLAIN, we don't have window context information available, so
10100 : * we have to settle for this:
10101 : */
5215 tgl 10102 GIC 102 : appendStringInfoString(buf, "(?)");
5215 tgl 10103 ECB : }
5215 tgl 10104 GIC 123 : }
5215 tgl 10105 ECB :
10106 : /*
10107 : * get_func_sql_syntax_time
10108 : *
10109 : * Parse back argument of SQL-syntax function call related to a time or a
10110 : * timestamp. These require a specific handling when their typmod is given
10111 : * by the function caller through their SQL keyword.
10112 : */
10113 : static void
139 michael 10114 GNC 366 : get_func_sql_syntax_time(List *args, deparse_context *context)
10115 : {
10116 366 : StringInfo buf = context->buf;
10117 : Const *cons;
10118 :
10119 366 : if (list_length(args) != 1)
10120 24 : return;
10121 :
10122 342 : cons = (Const *) linitial(args);
10123 342 : Assert(IsA(cons, Const));
10124 :
10125 342 : if (!cons->constisnull)
10126 : {
10127 333 : appendStringInfoString(buf, "(");
10128 333 : get_rule_expr((Node *) cons, context, false);
10129 333 : appendStringInfoString(buf, ")");
10130 : }
10131 : }
10132 :
10133 : /*
10134 : * get_func_sql_syntax - Parse back a SQL-syntax function call
10135 : *
10136 : * Returns true if we successfully deparsed, false if we did not
10137 : * recognize the function.
10138 : */
10139 : static bool
886 tgl 10140 GIC 625 : get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
10141 : {
886 tgl 10142 CBC 625 : StringInfo buf = context->buf;
886 tgl 10143 GIC 625 : Oid funcoid = expr->funcid;
886 tgl 10144 ECB :
886 tgl 10145 GIC 625 : switch (funcoid)
10146 : {
886 tgl 10147 CBC 6 : case F_TIMEZONE_INTERVAL_TIMESTAMP:
886 tgl 10148 ECB : case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
10149 : case F_TIMEZONE_INTERVAL_TIMETZ:
10150 : case F_TIMEZONE_TEXT_TIMESTAMP:
10151 : case F_TIMEZONE_TEXT_TIMESTAMPTZ:
10152 : case F_TIMEZONE_TEXT_TIMETZ:
10153 : /* AT TIME ZONE ... note reversed argument order */
886 tgl 10154 GIC 6 : appendStringInfoChar(buf, '(');
129 tgl 10155 CBC 6 : get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
129 tgl 10156 ECB : (Node *) expr);
886 tgl 10157 CBC 6 : appendStringInfoString(buf, " AT TIME ZONE ");
129 tgl 10158 GIC 6 : get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10159 : (Node *) expr);
886 10160 6 : appendStringInfoChar(buf, ')');
10161 6 : return true;
10162 :
10163 3 : case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
10164 : case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
10165 : case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
10166 : case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
10167 : case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
886 tgl 10168 ECB : case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
10169 : case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
10170 : case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
10171 : case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
10172 : case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
10173 : case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
10174 : case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
10175 : case F_OVERLAPS_TIME_TIME_TIME_TIME:
10176 : /* (x1, x2) OVERLAPS (y1, y2) */
886 tgl 10177 GIC 3 : appendStringInfoString(buf, "((");
10178 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
10179 3 : appendStringInfoString(buf, ", ");
10180 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10181 3 : appendStringInfoString(buf, ") OVERLAPS (");
886 tgl 10182 CBC 3 : get_rule_expr((Node *) lthird(expr->args), context, false);
10183 3 : appendStringInfoString(buf, ", ");
886 tgl 10184 GIC 3 : get_rule_expr((Node *) lfourth(expr->args), context, false);
886 tgl 10185 CBC 3 : appendStringInfoString(buf, "))");
10186 3 : return true;
10187 :
733 peter 10188 3 : case F_EXTRACT_TEXT_DATE:
733 peter 10189 ECB : case F_EXTRACT_TEXT_TIME:
10190 : case F_EXTRACT_TEXT_TIMETZ:
10191 : case F_EXTRACT_TEXT_TIMESTAMP:
10192 : case F_EXTRACT_TEXT_TIMESTAMPTZ:
10193 : case F_EXTRACT_TEXT_INTERVAL:
10194 : /* EXTRACT (x FROM y) */
733 peter 10195 GIC 3 : appendStringInfoString(buf, "EXTRACT(");
10196 : {
10197 3 : Const *con = (Const *) linitial(expr->args);
10198 :
10199 3 : Assert(IsA(con, Const) &&
10200 : con->consttype == TEXTOID &&
10201 : !con->constisnull);
10202 3 : appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
10203 : }
10204 3 : appendStringInfoString(buf, " FROM ");
733 peter 10205 CBC 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10206 3 : appendStringInfoChar(buf, ')');
10207 3 : return true;
733 peter 10208 ECB :
886 tgl 10209 CBC 6 : case F_IS_NORMALIZED:
886 tgl 10210 ECB : /* IS xxx NORMALIZED */
129 tgl 10211 CBC 6 : appendStringInfoString(buf, "(");
10212 6 : get_rule_expr_paren((Node *) linitial(expr->args), context, false,
129 tgl 10213 ECB : (Node *) expr);
129 tgl 10214 CBC 6 : appendStringInfoString(buf, " IS");
886 tgl 10215 GIC 6 : if (list_length(expr->args) == 2)
886 tgl 10216 ECB : {
886 tgl 10217 GIC 3 : Const *con = (Const *) lsecond(expr->args);
10218 :
10219 3 : Assert(IsA(con, Const) &&
10220 : con->consttype == TEXTOID &&
10221 : !con->constisnull);
10222 3 : appendStringInfo(buf, " %s",
886 tgl 10223 CBC 3 : TextDatumGetCString(con->constvalue));
10224 : }
10225 6 : appendStringInfoString(buf, " NORMALIZED)");
886 tgl 10226 GIC 6 : return true;
886 tgl 10227 ECB :
886 tgl 10228 GIC 3 : case F_PG_COLLATION_FOR:
10229 : /* COLLATION FOR */
886 tgl 10230 CBC 3 : appendStringInfoString(buf, "COLLATION FOR (");
886 tgl 10231 GIC 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
886 tgl 10232 CBC 3 : appendStringInfoChar(buf, ')');
10233 3 : return true;
886 tgl 10234 ECB :
886 tgl 10235 CBC 6 : case F_NORMALIZE:
10236 : /* NORMALIZE() */
10237 6 : appendStringInfoString(buf, "NORMALIZE(");
886 tgl 10238 GIC 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
886 tgl 10239 CBC 6 : if (list_length(expr->args) == 2)
886 tgl 10240 ECB : {
886 tgl 10241 GIC 3 : Const *con = (Const *) lsecond(expr->args);
886 tgl 10242 ECB :
886 tgl 10243 CBC 3 : Assert(IsA(con, Const) &&
10244 : con->consttype == TEXTOID &&
886 tgl 10245 ECB : !con->constisnull);
886 tgl 10246 GIC 3 : appendStringInfo(buf, ", %s",
886 tgl 10247 CBC 3 : TextDatumGetCString(con->constvalue));
10248 : }
886 tgl 10249 GIC 6 : appendStringInfoChar(buf, ')');
886 tgl 10250 CBC 6 : return true;
886 tgl 10251 ECB :
886 tgl 10252 GIC 6 : case F_OVERLAY_BIT_BIT_INT4:
886 tgl 10253 ECB : case F_OVERLAY_BIT_BIT_INT4_INT4:
10254 : case F_OVERLAY_BYTEA_BYTEA_INT4:
10255 : case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
10256 : case F_OVERLAY_TEXT_TEXT_INT4:
10257 : case F_OVERLAY_TEXT_TEXT_INT4_INT4:
10258 : /* OVERLAY() */
886 tgl 10259 CBC 6 : appendStringInfoString(buf, "OVERLAY(");
10260 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
10261 6 : appendStringInfoString(buf, " PLACING ");
886 tgl 10262 GIC 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
886 tgl 10263 CBC 6 : appendStringInfoString(buf, " FROM ");
886 tgl 10264 GIC 6 : get_rule_expr((Node *) lthird(expr->args), context, false);
886 tgl 10265 CBC 6 : if (list_length(expr->args) == 4)
886 tgl 10266 ECB : {
886 tgl 10267 CBC 3 : appendStringInfoString(buf, " FOR ");
886 tgl 10268 GIC 3 : get_rule_expr((Node *) lfourth(expr->args), context, false);
886 tgl 10269 ECB : }
886 tgl 10270 GIC 6 : appendStringInfoChar(buf, ')');
886 tgl 10271 CBC 6 : return true;
10272 :
886 tgl 10273 GIC 3 : case F_POSITION_BIT_BIT:
886 tgl 10274 ECB : case F_POSITION_BYTEA_BYTEA:
10275 : case F_POSITION_TEXT_TEXT:
10276 : /* POSITION() ... extra parens since args are b_expr not a_expr */
886 tgl 10277 CBC 3 : appendStringInfoString(buf, "POSITION((");
10278 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
886 tgl 10279 GIC 3 : appendStringInfoString(buf, ") IN (");
886 tgl 10280 CBC 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
886 tgl 10281 GIC 3 : appendStringInfoString(buf, "))");
10282 3 : return true;
10283 :
10284 3 : case F_SUBSTRING_BIT_INT4:
10285 : case F_SUBSTRING_BIT_INT4_INT4:
10286 : case F_SUBSTRING_BYTEA_INT4:
886 tgl 10287 ECB : case F_SUBSTRING_BYTEA_INT4_INT4:
10288 : case F_SUBSTRING_TEXT_INT4:
10289 : case F_SUBSTRING_TEXT_INT4_INT4:
10290 : /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
886 tgl 10291 CBC 3 : appendStringInfoString(buf, "SUBSTRING(");
10292 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
10293 3 : appendStringInfoString(buf, " FROM ");
886 tgl 10294 GIC 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
886 tgl 10295 CBC 3 : if (list_length(expr->args) == 3)
886 tgl 10296 ECB : {
886 tgl 10297 GIC 3 : appendStringInfoString(buf, " FOR ");
886 tgl 10298 CBC 3 : get_rule_expr((Node *) lthird(expr->args), context, false);
886 tgl 10299 ECB : }
886 tgl 10300 GIC 3 : appendStringInfoChar(buf, ')');
886 tgl 10301 CBC 3 : return true;
10302 :
886 tgl 10303 GIC 3 : case F_SUBSTRING_TEXT_TEXT_TEXT:
10304 : /* SUBSTRING SIMILAR/ESCAPE */
886 tgl 10305 CBC 3 : appendStringInfoString(buf, "SUBSTRING(");
10306 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
10307 3 : appendStringInfoString(buf, " SIMILAR ");
10308 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10309 3 : appendStringInfoString(buf, " ESCAPE ");
10310 3 : get_rule_expr((Node *) lthird(expr->args), context, false);
886 tgl 10311 GIC 3 : appendStringInfoChar(buf, ')');
886 tgl 10312 CBC 3 : return true;
10313 :
886 tgl 10314 GIC 6 : case F_BTRIM_BYTEA_BYTEA:
10315 : case F_BTRIM_TEXT:
10316 : case F_BTRIM_TEXT_TEXT:
10317 : /* TRIM() */
10318 6 : appendStringInfoString(buf, "TRIM(BOTH");
886 tgl 10319 CBC 6 : if (list_length(expr->args) == 2)
886 tgl 10320 ECB : {
886 tgl 10321 CBC 6 : appendStringInfoChar(buf, ' ');
10322 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
886 tgl 10323 ECB : }
886 tgl 10324 GIC 6 : appendStringInfoString(buf, " FROM ");
886 tgl 10325 CBC 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
10326 6 : appendStringInfoChar(buf, ')');
886 tgl 10327 GIC 6 : return true;
886 tgl 10328 ECB :
811 tgl 10329 CBC 6 : case F_LTRIM_BYTEA_BYTEA:
10330 : case F_LTRIM_TEXT:
886 tgl 10331 ECB : case F_LTRIM_TEXT_TEXT:
10332 : /* TRIM() */
886 tgl 10333 CBC 6 : appendStringInfoString(buf, "TRIM(LEADING");
10334 6 : if (list_length(expr->args) == 2)
886 tgl 10335 ECB : {
886 tgl 10336 CBC 6 : appendStringInfoChar(buf, ' ');
10337 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
886 tgl 10338 ECB : }
886 tgl 10339 CBC 6 : appendStringInfoString(buf, " FROM ");
10340 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
886 tgl 10341 GIC 6 : appendStringInfoChar(buf, ')');
886 tgl 10342 CBC 6 : return true;
10343 :
811 tgl 10344 GIC 6 : case F_RTRIM_BYTEA_BYTEA:
10345 : case F_RTRIM_TEXT:
886 tgl 10346 ECB : case F_RTRIM_TEXT_TEXT:
10347 : /* TRIM() */
886 tgl 10348 GIC 6 : appendStringInfoString(buf, "TRIM(TRAILING");
886 tgl 10349 CBC 6 : if (list_length(expr->args) == 2)
886 tgl 10350 ECB : {
886 tgl 10351 GIC 3 : appendStringInfoChar(buf, ' ');
886 tgl 10352 CBC 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
886 tgl 10353 ECB : }
886 tgl 10354 CBC 6 : appendStringInfoString(buf, " FROM ");
10355 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
886 tgl 10356 GIC 6 : appendStringInfoChar(buf, ')');
886 tgl 10357 CBC 6 : return true;
10358 :
140 michael 10359 GNC 6 : case F_CURRENT_CATALOG:
10360 6 : appendStringInfoString(buf, "CURRENT_CATALOG");
10361 6 : return true;
10362 6 : case F_CURRENT_ROLE:
10363 6 : appendStringInfoString(buf, "CURRENT_ROLE");
10364 6 : return true;
10365 6 : case F_CURRENT_SCHEMA:
10366 6 : appendStringInfoString(buf, "CURRENT_SCHEMA");
10367 6 : return true;
10368 141 : case F_CURRENT_USER:
10369 141 : appendStringInfoString(buf, "CURRENT_USER");
10370 141 : return true;
10371 6 : case F_USER:
10372 6 : appendStringInfoString(buf, "USER");
10373 6 : return true;
10374 16 : case F_SESSION_USER:
10375 16 : appendStringInfoString(buf, "SESSION_USER");
10376 16 : return true;
192 10377 6 : case F_SYSTEM_USER:
10378 6 : appendStringInfoString(buf, "SYSTEM_USER");
10379 6 : return true;
10380 :
139 10381 9 : case F_CURRENT_DATE:
10382 9 : appendStringInfoString(buf, "CURRENT_DATE");
10383 9 : return true;
10384 12 : case F_CURRENT_TIME:
10385 12 : appendStringInfoString(buf, "CURRENT_TIME");
10386 12 : get_func_sql_syntax_time(expr->args, context);
10387 12 : return true;
10388 318 : case F_CURRENT_TIMESTAMP:
10389 318 : appendStringInfoString(buf, "CURRENT_TIMESTAMP");
10390 318 : get_func_sql_syntax_time(expr->args, context);
10391 318 : return true;
10392 12 : case F_LOCALTIME:
10393 12 : appendStringInfoString(buf, "LOCALTIME");
10394 12 : get_func_sql_syntax_time(expr->args, context);
10395 12 : return true;
10396 24 : case F_LOCALTIMESTAMP:
10397 24 : appendStringInfoString(buf, "LOCALTIMESTAMP");
10398 24 : get_func_sql_syntax_time(expr->args, context);
10399 24 : return true;
10400 :
886 tgl 10401 UIC 0 : case F_XMLEXISTS:
10402 : /* XMLEXISTS ... extra parens because args are c_expr */
886 tgl 10403 LBC 0 : appendStringInfoString(buf, "XMLEXISTS((");
10404 0 : get_rule_expr((Node *) linitial(expr->args), context, false);
886 tgl 10405 UIC 0 : appendStringInfoString(buf, ") PASSING (");
886 tgl 10406 LBC 0 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10407 0 : appendStringInfoString(buf, "))");
886 tgl 10408 UIC 0 : return true;
886 tgl 10409 ECB : }
886 tgl 10410 CBC 3 : return false;
886 tgl 10411 ECB : }
10412 :
10413 : /* ----------
5867 10414 : * get_coercion_expr
10415 : *
10416 : * Make a string representation of a value coerced to a specific type
10417 : * ----------
10418 : */
10419 : static void
5867 tgl 10420 GIC 1999 : get_coercion_expr(Node *arg, deparse_context *context,
5867 tgl 10421 ECB : Oid resulttype, int32 resulttypmod,
10422 : Node *parentNode)
10423 : {
5867 tgl 10424 CBC 1999 : StringInfo buf = context->buf;
5867 tgl 10425 ECB :
10426 : /*
10427 : * Since parse_coerce.c doesn't immediately collapse application of
10428 : * length-coercion functions to constants, what we'll typically see in
5624 bruce 10429 : * such cases is a Const with typmod -1 and a length-coercion function
3260 10430 : * right above it. Avoid generating redundant output. However, beware of
5624 10431 : * suppressing casts when the user actually wrote something like
10432 : * 'foo'::text::char(3).
2932 tgl 10433 : *
10434 : * Note: it might seem that we are missing the possibility of needing to
10435 : * print a COLLATE clause for such a Const. However, a Const could only
10436 : * have nondefault collation in a post-constant-folding tree, in which the
10437 : * length coercion would have been folded too. See also the special
10438 : * handling of CollateExpr in coerce_to_target_type(): any collation
10439 : * marking will be above the coercion node, not below it.
5867 10440 : */
5867 tgl 10441 CBC 1999 : if (arg && IsA(arg, Const) &&
10442 225 : ((Const *) arg)->consttype == resulttype &&
10443 12 : ((Const *) arg)->consttypmod == -1)
5867 tgl 10444 ECB : {
10445 : /* Show the constant without normal ::typename decoration */
5572 tgl 10446 CBC 12 : get_const_expr((Const *) arg, context, -1);
5867 tgl 10447 ECB : }
10448 : else
10449 : {
5867 tgl 10450 GIC 1987 : if (!PRETTY_PAREN(context))
5867 tgl 10451 CBC 1823 : appendStringInfoChar(buf, '(');
10452 1987 : get_rule_expr_paren(arg, context, false, parentNode);
10453 1987 : if (!PRETTY_PAREN(context))
10454 1823 : appendStringInfoChar(buf, ')');
5867 tgl 10455 ECB : }
1343 noah 10456 :
10457 : /*
10458 : * Never emit resulttype(arg) functional notation. A pg_proc entry could
10459 : * take precedence, and a resulttype in pg_temp would require schema
10460 : * qualification that format_type_with_typemod() would usually omit. We've
10461 : * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
10462 : * would work fine.
10463 : */
5867 tgl 10464 CBC 1999 : appendStringInfo(buf, "::%s",
5867 tgl 10465 ECB : format_type_with_typemod(resulttype, resulttypmod));
5867 tgl 10466 CBC 1999 : }
8994 bruce 10467 ECB :
10468 : /* ----------
8590 tgl 10469 : * get_const_expr
10470 : *
8588 tgl 10471 EUB : * Make a string representation of a Const
10472 : *
5572 10473 : * showtype can be -1 to never show "::typename" decoration, or +1 to always
10474 : * show it, or 0 to show it only if the constant wouldn't be assumed to be
10475 : * the right type by default.
4412 10476 : *
10477 : * If the Const's collation isn't default for its type, show that too.
2932 10478 : * We mustn't do this when showtype is -1 (since that means the caller will
10479 : * print "::typename", and we can't put a COLLATE clause in between). It's
2932 tgl 10480 ECB : * caller's responsibility that collation isn't missed in such cases.
10481 : * ----------
10482 : */
10483 : static void
5572 tgl 10484 GIC 28960 : get_const_expr(Const *constval, deparse_context *context, int showtype)
10485 : {
8589 10486 28960 : StringInfo buf = context->buf;
10487 : Oid typoutput;
10488 : bool typIsVarlena;
10489 : char *extval;
2932 tgl 10490 CBC 28960 : bool needlabel = false;
10491 :
8507 tgl 10492 GIC 28960 : if (constval->constisnull)
10493 : {
8507 tgl 10494 ECB : /*
10495 : * Always label the type of a NULL constant to prevent misdecisions
10496 : * about type when reparsing.
10497 : */
3447 rhaas 10498 GIC 360 : appendStringInfoString(buf, "NULL");
5572 tgl 10499 360 : if (showtype >= 0)
10500 : {
5867 10501 338 : appendStringInfo(buf, "::%s",
10502 : format_type_with_typemod(constval->consttype,
10503 : constval->consttypmod));
4412 10504 338 : get_const_collation(constval, context);
10505 : }
8507 10506 3555 : return;
10507 : }
10508 :
6881 10509 28600 : getTypeOutputInfo(constval->consttype,
10510 : &typoutput, &typIsVarlena);
7651 tgl 10511 ECB :
6214 tgl 10512 CBC 28600 : extval = OidOutputFunctionCall(typoutput, constval->constvalue);
8994 bruce 10513 ECB :
8588 tgl 10514 GIC 28600 : switch (constval->consttype)
10515 : {
8588 tgl 10516 CBC 16499 : case INT4OID:
10517 :
10518 : /*
10519 : * INT4 can be printed without any decoration, unless it is
2932 tgl 10520 ECB : * negative; in that case print it as '-nnn'::integer to ensure
10521 : * that the output will re-parse as a constant, not as a constant
10522 : * plus operator. In most cases we could get away with printing
10523 : * (-nnn) instead, because of the way that gram.y handles negative
10524 : * literals; but that doesn't work for INT_MIN, and it doesn't
10525 : * seem that much prettier anyway.
10526 : */
2932 tgl 10527 GIC 16499 : if (extval[0] != '-')
10528 16243 : appendStringInfoString(buf, extval);
10529 : else
10530 : {
10531 256 : appendStringInfo(buf, "'%s'", extval);
2118 10532 256 : needlabel = true; /* we must attach a cast */
10533 : }
2932 tgl 10534 CBC 16499 : break;
10535 :
7539 peter_e 10536 508 : case NUMERICOID:
10537 :
10538 : /*
10539 : * NUMERIC can be printed without quotes if it looks like a float
10540 : * constant (not an integer, and not Infinity or NaN) and doesn't
10541 : * have a leading sign (for the same reason as for INT4).
10542 : */
2932 tgl 10543 GIC 508 : if (isdigit((unsigned char) extval[0]) &&
10544 508 : strcspn(extval, "eE.") != strlen(extval))
10545 : {
10546 180 : appendStringInfoString(buf, extval);
10547 : }
10548 : else
10549 : {
10550 328 : appendStringInfo(buf, "'%s'", extval);
2118 10551 328 : needlabel = true; /* we must attach a cast */
10552 : }
7522 bruce 10553 508 : break;
7539 peter_e 10554 ECB :
7539 peter_e 10555 GIC 669 : case BOOLOID:
7522 bruce 10556 CBC 669 : if (strcmp(extval, "t") == 0)
3447 rhaas 10557 GIC 354 : appendStringInfoString(buf, "true");
10558 : else
10559 315 : appendStringInfoString(buf, "false");
7539 peter_e 10560 CBC 669 : break;
10561 :
10562 10924 : default:
5328 tgl 10563 GIC 10924 : simple_quote_literal(buf, extval);
8588 10564 10924 : break;
10565 : }
10566 :
8590 10567 28600 : pfree(extval);
8588 tgl 10568 ECB :
5572 tgl 10569 CBC 28600 : if (showtype < 0)
5867 tgl 10570 GIC 3195 : return;
5867 tgl 10571 ECB :
10572 : /*
10573 : * For showtype == 0, append ::typename unless the constant will be
5572 10574 : * implicitly typed as the right type when it is read in.
10575 : *
10576 : * XXX this code has to be kept in sync with the behavior of the parser,
10577 : * especially make_const.
10578 : */
8588 tgl 10579 CBC 25405 : switch (constval->consttype)
10580 : {
7539 peter_e 10581 GIC 685 : case BOOLOID:
8588 tgl 10582 ECB : case UNKNOWNOID:
10583 : /* These types can be left unlabeled */
7508 tgl 10584 CBC 685 : needlabel = false;
7508 tgl 10585 GIC 685 : break;
2932 tgl 10586 CBC 14466 : case INT4OID:
10587 : /* We determined above whether a label is needed */
2932 tgl 10588 GIC 14466 : break;
7508 10589 508 : case NUMERICOID:
10590 :
10591 : /*
10592 : * Float-looking constants will be typed as numeric, which we
10593 : * checked above; but if there's a nondefault typmod we need to
10594 : * show it.
10595 : */
2932 10596 508 : needlabel |= (constval->consttypmod >= 0);
8588 tgl 10597 CBC 508 : break;
10598 9746 : default:
7508 tgl 10599 GIC 9746 : needlabel = true;
8588 10600 9746 : break;
8588 tgl 10601 ECB : }
5572 tgl 10602 CBC 25405 : if (needlabel || showtype > 0)
7508 tgl 10603 GIC 10323 : appendStringInfo(buf, "::%s",
5867 tgl 10604 ECB : format_type_with_typemod(constval->consttype,
10605 : constval->consttypmod));
4412 10606 :
4412 tgl 10607 GIC 25405 : get_const_collation(constval, context);
10608 : }
10609 :
10610 : /*
10611 : * helper for get_const_expr: append COLLATE if needed
10612 : */
4412 tgl 10613 ECB : static void
4412 tgl 10614 CBC 25743 : get_const_collation(Const *constval, deparse_context *context)
10615 : {
10616 25743 : StringInfo buf = context->buf;
10617 :
4412 tgl 10618 GIC 25743 : if (OidIsValid(constval->constcollid))
10619 : {
4382 bruce 10620 CBC 3672 : Oid typcollation = get_typcollation(constval->consttype);
4412 tgl 10621 ECB :
4412 tgl 10622 GIC 3672 : if (constval->constcollid != typcollation)
4412 tgl 10623 ECB : {
4412 tgl 10624 GIC 35 : appendStringInfo(buf, " COLLATE %s",
4412 tgl 10625 ECB : generate_collation_name(constval->constcollid));
10626 : }
10627 : }
8955 bruce 10628 GIC 25743 : }
8955 bruce 10629 ECB :
10630 : /*
10631 : * get_json_format - Parse back a JsonFormat node
10632 : */
10633 : static void
11 alvherre 10634 GNC 24 : get_json_format(JsonFormat *format, StringInfo buf)
10635 : {
10636 24 : if (format->format_type == JS_FORMAT_DEFAULT)
11 alvherre 10637 UNC 0 : return;
10638 :
11 alvherre 10639 GNC 24 : appendStringInfoString(buf,
10640 24 : format->format_type == JS_FORMAT_JSONB ?
10641 : " FORMAT JSONB" : " FORMAT JSON");
10642 :
10643 24 : if (format->encoding != JS_ENC_DEFAULT)
10644 : {
10645 : const char *encoding;
10646 :
11 alvherre 10647 UNC 0 : encoding =
10648 0 : format->encoding == JS_ENC_UTF16 ? "UTF16" :
10649 0 : format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
10650 :
10651 0 : appendStringInfo(buf, " ENCODING %s", encoding);
10652 : }
10653 : }
10654 :
10655 : /*
10656 : * get_json_returning - Parse back a JsonReturning structure
10657 : */
10658 : static void
11 alvherre 10659 GNC 36 : get_json_returning(JsonReturning *returning, StringInfo buf,
10660 : bool json_format_by_default)
10661 : {
10662 36 : if (!OidIsValid(returning->typid))
11 alvherre 10663 UNC 0 : return;
10664 :
11 alvherre 10665 GNC 36 : appendStringInfo(buf, " RETURNING %s",
10666 : format_type_with_typemod(returning->typid,
10667 : returning->typmod));
10668 :
10669 72 : if (!json_format_by_default ||
10670 36 : returning->format->format_type !=
10671 36 : (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
11 alvherre 10672 UNC 0 : get_json_format(returning->format, buf);
10673 : }
10674 :
10675 : /*
10676 : * get_json_constructor - Parse back a JsonConstructorExpr node
10677 : */
10678 : static void
11 alvherre 10679 GNC 36 : get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context,
10680 : bool showimplicit)
10681 : {
10682 36 : StringInfo buf = context->buf;
10683 : const char *funcname;
10684 : bool is_json_object;
10685 : int curridx;
10686 : ListCell *lc;
10687 :
10688 36 : if (ctor->type == JSCTOR_JSON_OBJECTAGG)
10689 : {
10690 9 : get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
10691 9 : return;
10692 : }
10693 27 : else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
10694 : {
10695 15 : get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
10696 15 : return;
10697 : }
10698 :
10699 12 : switch (ctor->type)
10700 : {
10701 6 : case JSCTOR_JSON_OBJECT:
10702 6 : funcname = "JSON_OBJECT";
10703 6 : break;
10704 6 : case JSCTOR_JSON_ARRAY:
10705 6 : funcname = "JSON_ARRAY";
10706 6 : break;
11 alvherre 10707 UNC 0 : default:
10 10708 0 : elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
10709 : }
10710 :
11 alvherre 10711 GNC 12 : appendStringInfo(buf, "%s(", funcname);
10712 :
10713 12 : is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
10714 48 : foreach(lc, ctor->args)
10715 : {
10716 36 : curridx = foreach_current_index(lc);
10717 36 : if (curridx > 0)
10718 : {
10719 : const char *sep;
10720 :
10721 24 : sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
10722 24 : appendStringInfoString(buf, sep);
10723 : }
10724 :
10725 36 : get_rule_expr((Node *) lfirst(lc), context, true);
10726 : }
10727 :
10728 12 : get_json_constructor_options(ctor, buf);
10729 12 : appendStringInfo(buf, ")");
10730 : }
10731 :
10732 : /*
10733 : * Append options, if any, to the JSON constructor being deparsed
10734 : */
10735 : static void
10736 36 : get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
10737 : {
10738 36 : if (ctor->absent_on_null)
10739 : {
10740 12 : if (ctor->type == JSCTOR_JSON_OBJECT ||
10741 12 : ctor->type == JSCTOR_JSON_OBJECTAGG)
11 alvherre 10742 UNC 0 : appendStringInfoString(buf, " ABSENT ON NULL");
10743 : }
10744 : else
10745 : {
11 alvherre 10746 GNC 24 : if (ctor->type == JSCTOR_JSON_ARRAY ||
10747 24 : ctor->type == JSCTOR_JSON_ARRAYAGG)
10748 9 : appendStringInfoString(buf, " NULL ON NULL");
10749 : }
10750 :
10751 36 : if (ctor->unique)
10752 9 : appendStringInfoString(buf, " WITH UNIQUE KEYS");
10753 :
10754 36 : get_json_returning(ctor->returning, buf, true);
10755 36 : }
10756 :
10757 : /*
10758 : * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
10759 : */
10760 : static void
10761 24 : get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context,
10762 : const char *funcname, bool is_json_objectagg)
10763 : {
10764 : StringInfoData options;
10765 :
10766 24 : initStringInfo(&options);
10767 24 : get_json_constructor_options(ctor, &options);
10768 :
10769 24 : if (IsA(ctor->func, Aggref))
10770 18 : get_agg_expr_helper((Aggref *) ctor->func, context,
10771 18 : (Aggref *) ctor->func,
10772 18 : funcname, options.data, is_json_objectagg);
10773 6 : else if (IsA(ctor->func, WindowFunc))
10774 6 : get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
10775 6 : funcname, options.data,
10776 : is_json_objectagg);
10777 : else
11 alvherre 10778 UNC 0 : elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
10779 : nodeTag(ctor->func));
11 alvherre 10780 GNC 24 : }
10781 :
5328 tgl 10782 ECB : /*
10783 : * simple_quote_literal - Format a string as a SQL literal, append to buf
10784 : */
10785 : static void
5328 tgl 10786 CBC 11451 : simple_quote_literal(StringInfo buf, const char *val)
10787 : {
10788 : const char *valptr;
5328 tgl 10789 ECB :
10790 : /*
5050 bruce 10791 : * We form the string literal according to the prevailing setting of
10792 : * standard_conforming_strings; we never use E''. User is responsible for
10793 : * making sure result is used correctly.
10794 : */
5328 tgl 10795 GIC 11451 : appendStringInfoChar(buf, '\'');
10796 118056 : for (valptr = val; *valptr; valptr++)
10797 : {
10798 106605 : char ch = *valptr;
10799 :
10800 106605 : if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
5328 tgl 10801 CBC 153 : appendStringInfoChar(buf, ch);
5328 tgl 10802 GIC 106605 : appendStringInfoChar(buf, ch);
5328 tgl 10803 ECB : }
5328 tgl 10804 GIC 11451 : appendStringInfoChar(buf, '\'');
10805 11451 : }
5328 tgl 10806 ECB :
8955 bruce 10807 :
10808 : /* ----------
10809 : * get_sublink_expr - Parse back a sublink
10810 : * ----------
10811 : */
10812 : static void
7423 tgl 10813 GIC 191 : get_sublink_expr(SubLink *sublink, deparse_context *context)
10814 : {
8589 10815 191 : StringInfo buf = context->buf;
8955 bruce 10816 191 : Query *query = (Query *) (sublink->subselect);
6311 tgl 10817 191 : char *opname = NULL;
8546 tgl 10818 ECB : bool need_paren;
8955 bruce 10819 :
7306 tgl 10820 CBC 191 : if (sublink->subLinkType == ARRAY_SUBLINK)
3447 rhaas 10821 6 : appendStringInfoString(buf, "ARRAY(");
7306 tgl 10822 ECB : else
7306 tgl 10823 GIC 185 : appendStringInfoChar(buf, '(');
8625 tgl 10824 ECB :
6311 10825 : /*
10826 : * Note that we print the name of only the first operator, when there are
10827 : * multiple combining operators. This is an approximation that could go
10828 : * wrong in various scenarios (operators in different schemas, renamed
6031 bruce 10829 : * operators, etc) but there is not a whole lot we can do about it, since
10830 : * the syntax allows only one operator to be shown.
10831 : */
6311 tgl 10832 GIC 191 : if (sublink->testexpr)
10833 : {
10834 9 : if (IsA(sublink->testexpr, OpExpr))
10835 : {
6311 tgl 10836 ECB : /* single combining operator */
6031 bruce 10837 GIC 3 : OpExpr *opexpr = (OpExpr *) sublink->testexpr;
6311 tgl 10838 ECB :
6311 tgl 10839 GIC 3 : get_rule_expr(linitial(opexpr->args), context, true);
6311 tgl 10840 CBC 3 : opname = generate_operator_name(opexpr->opno,
6311 tgl 10841 GIC 3 : exprType(linitial(opexpr->args)),
6311 tgl 10842 CBC 3 : exprType(lsecond(opexpr->args)));
10843 : }
10844 6 : else if (IsA(sublink->testexpr, BoolExpr))
10845 : {
6311 tgl 10846 ECB : /* multiple combining operators, = or <> cases */
10847 : char *sep;
10848 : ListCell *l;
10849 :
8449 tgl 10850 CBC 3 : appendStringInfoChar(buf, '(');
6311 tgl 10851 GIC 3 : sep = "";
10852 9 : foreach(l, ((BoolExpr *) sublink->testexpr)->args)
10853 : {
2190 10854 6 : OpExpr *opexpr = lfirst_node(OpExpr, l);
10855 :
6311 tgl 10856 CBC 6 : appendStringInfoString(buf, sep);
6311 tgl 10857 GIC 6 : get_rule_expr(linitial(opexpr->args), context, true);
6311 tgl 10858 CBC 6 : if (!opname)
6311 tgl 10859 GBC 3 : opname = generate_operator_name(opexpr->opno,
2118 tgl 10860 GIC 3 : exprType(linitial(opexpr->args)),
2118 tgl 10861 CBC 3 : exprType(lsecond(opexpr->args)));
6311 10862 6 : sep = ", ";
10863 : }
6758 tgl 10864 GIC 3 : appendStringInfoChar(buf, ')');
6311 tgl 10865 ECB : }
6311 tgl 10866 GIC 3 : else if (IsA(sublink->testexpr, RowCompareExpr))
10867 : {
10868 : /* multiple combining operators, < <= > >= cases */
6311 tgl 10869 GBC 3 : RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
6311 tgl 10870 EUB :
6311 tgl 10871 GBC 3 : appendStringInfoChar(buf, '(');
6311 tgl 10872 GIC 3 : get_rule_expr((Node *) rcexpr->largs, context, true);
6311 tgl 10873 GBC 3 : opname = generate_operator_name(linitial_oid(rcexpr->opnos),
6311 tgl 10874 GIC 3 : exprType(linitial(rcexpr->largs)),
2118 10875 3 : exprType(linitial(rcexpr->rargs)));
6311 10876 3 : appendStringInfoChar(buf, ')');
10877 : }
10878 : else
6311 tgl 10879 UIC 0 : elog(ERROR, "unrecognized testexpr type: %d",
10880 : (int) nodeTag(sublink->testexpr));
8955 bruce 10881 ECB : }
10882 :
8546 tgl 10883 GIC 191 : need_paren = true;
8546 tgl 10884 ECB :
8720 bruce 10885 GBC 191 : switch (sublink->subLinkType)
10886 : {
8955 bruce 10887 CBC 85 : case EXISTS_SUBLINK:
3447 rhaas 10888 GIC 85 : appendStringInfoString(buf, "EXISTS ");
8955 bruce 10889 85 : break;
10890 :
8955 bruce 10891 CBC 6 : case ANY_SUBLINK:
2118 tgl 10892 6 : if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
3447 rhaas 10893 3 : appendStringInfoString(buf, " IN ");
7395 tgl 10894 EUB : else
6311 tgl 10895 GIC 3 : appendStringInfo(buf, " %s ANY ", opname);
8955 bruce 10896 6 : break;
10897 :
10898 3 : case ALL_SUBLINK:
6311 tgl 10899 3 : appendStringInfo(buf, " %s ALL ", opname);
8955 bruce 10900 3 : break;
8955 bruce 10901 ECB :
6311 tgl 10902 UIC 0 : case ROWCOMPARE_SUBLINK:
10903 0 : appendStringInfo(buf, " %s ", opname);
8955 bruce 10904 LBC 0 : break;
10905 :
8546 tgl 10906 GIC 97 : case EXPR_SUBLINK:
10907 : case MULTIEXPR_SUBLINK:
10908 : case ARRAY_SUBLINK:
10909 97 : need_paren = false;
8546 tgl 10910 CBC 97 : break;
10911 :
5300 tgl 10912 LBC 0 : case CTE_SUBLINK: /* shouldn't occur in a SubLink */
8955 bruce 10913 ECB : default:
7196 tgl 10914 UIC 0 : elog(ERROR, "unrecognized sublink type: %d",
7196 tgl 10915 ECB : (int) sublink->subLinkType);
10916 : break;
8955 bruce 10917 : }
10918 :
8546 tgl 10919 GIC 191 : if (need_paren)
8449 10920 94 : appendStringInfoChar(buf, '(');
8546 tgl 10921 ECB :
323 tgl 10922 GIC 191 : get_query_def(query, buf, context->namespaces, NULL, false,
3758 tgl 10923 ECB : context->prettyFlags, context->wrapColumn,
10924 : context->indentLevel);
8546 10925 :
8546 tgl 10926 CBC 191 : if (need_paren)
3447 rhaas 10927 94 : appendStringInfoString(buf, "))");
8546 tgl 10928 ECB : else
8449 tgl 10929 GBC 97 : appendStringInfoChar(buf, ')');
8994 bruce 10930 191 : }
10931 :
10932 :
2223 alvherre 10933 ECB : /* ----------
10934 : * get_tablefunc - Parse back a table function
10935 : * ----------
10936 : */
10937 : static void
220 andrew 10938 CBC 25 : get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
2223 alvherre 10939 ECB : {
2223 alvherre 10940 GIC 25 : StringInfo buf = context->buf;
10941 :
10942 : /* XMLTABLE is the only existing implementation. */
220 andrew 10943 ECB :
2223 alvherre 10944 CBC 25 : appendStringInfoString(buf, "XMLTABLE(");
10945 :
2223 alvherre 10946 GIC 25 : if (tf->ns_uris != NIL)
2223 alvherre 10947 ECB : {
10948 : ListCell *lc1,
10949 : *lc2;
2223 alvherre 10950 CBC 5 : bool first = true;
2223 alvherre 10951 ECB :
2223 alvherre 10952 GIC 5 : appendStringInfoString(buf, "XMLNAMESPACES (");
10953 10 : forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
10954 : {
10955 5 : Node *expr = (Node *) lfirst(lc1);
577 peter 10956 5 : String *ns_node = lfirst_node(String, lc2);
10957 :
2223 alvherre 10958 CBC 5 : if (!first)
2223 alvherre 10959 UIC 0 : appendStringInfoString(buf, ", ");
2223 alvherre 10960 ECB : else
2223 alvherre 10961 GIC 5 : first = false;
2223 alvherre 10962 ECB :
1665 tgl 10963 CBC 5 : if (ns_node != NULL)
2223 alvherre 10964 EUB : {
2223 alvherre 10965 GIC 5 : get_rule_expr(expr, context, showimplicit);
1665 tgl 10966 5 : appendStringInfo(buf, " AS %s", strVal(ns_node));
10967 : }
2223 alvherre 10968 ECB : else
10969 : {
2223 alvherre 10970 LBC 0 : appendStringInfoString(buf, "DEFAULT ");
2223 alvherre 10971 UIC 0 : get_rule_expr(expr, context, showimplicit);
10972 : }
2223 alvherre 10973 ECB : }
2223 alvherre 10974 CBC 5 : appendStringInfoString(buf, "), ");
10975 : }
2223 alvherre 10976 ECB :
2223 alvherre 10977 CBC 25 : appendStringInfoChar(buf, '(');
2223 alvherre 10978 GIC 25 : get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
10979 25 : appendStringInfoString(buf, ") PASSING (");
10980 25 : get_rule_expr((Node *) tf->docexpr, context, showimplicit);
10981 25 : appendStringInfoChar(buf, ')');
10982 :
2223 alvherre 10983 CBC 25 : if (tf->colexprs != NIL)
10984 : {
10985 : ListCell *l1;
10986 : ListCell *l2;
10987 : ListCell *l3;
2223 alvherre 10988 ECB : ListCell *l4;
10989 : ListCell *l5;
2223 alvherre 10990 GIC 25 : int colnum = 0;
2223 alvherre 10991 ECB :
2223 alvherre 10992 CBC 25 : appendStringInfoString(buf, " COLUMNS ");
1501 tgl 10993 172 : forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
1501 tgl 10994 ECB : l4, tf->colexprs, l5, tf->coldefexprs)
2223 alvherre 10995 : {
2223 alvherre 10996 CBC 147 : char *colname = strVal(lfirst(l1));
1501 tgl 10997 147 : Oid typid = lfirst_oid(l2);
1501 tgl 10998 GIC 147 : int32 typmod = lfirst_int(l3);
10999 147 : Node *colexpr = (Node *) lfirst(l4);
1501 tgl 11000 GBC 147 : Node *coldefexpr = (Node *) lfirst(l5);
1501 tgl 11001 GIC 147 : bool ordinality = (tf->ordinalitycol == colnum);
2223 alvherre 11002 CBC 147 : bool notnull = bms_is_member(colnum, tf->notnulls);
11003 :
2223 alvherre 11004 GIC 147 : if (colnum > 0)
11005 122 : appendStringInfoString(buf, ", ");
11006 147 : colnum++;
11007 :
2223 alvherre 11008 CBC 277 : appendStringInfo(buf, "%s %s", quote_identifier(colname),
11009 : ordinality ? "FOR ORDINALITY" :
2223 alvherre 11010 GIC 130 : format_type_with_typemod(typid, typmod));
11011 147 : if (ordinality)
11012 17 : continue;
11013 :
11014 130 : if (coldefexpr != NULL)
11015 : {
11016 17 : appendStringInfoString(buf, " DEFAULT (");
2223 alvherre 11017 CBC 17 : get_rule_expr((Node *) coldefexpr, context, showimplicit);
11018 17 : appendStringInfoChar(buf, ')');
11019 : }
11020 130 : if (colexpr != NULL)
11021 : {
11022 124 : appendStringInfoString(buf, " PATH (");
11023 124 : get_rule_expr((Node *) colexpr, context, showimplicit);
11024 124 : appendStringInfoChar(buf, ')');
11025 : }
11026 130 : if (notnull)
11027 17 : appendStringInfoString(buf, " NOT NULL");
11028 : }
11029 : }
11030 :
2223 alvherre 11031 GIC 25 : appendStringInfoChar(buf, ')');
11032 25 : }
11033 :
11034 : /* ----------
8244 tgl 11035 ECB : * get_from_clause - Parse back a FROM clause
11036 : *
6576 neilc 11037 : * "prefix" is the keyword that denotes the start of the list of FROM
11038 : * elements. It is FROM when used to parse back SELECT and UPDATE, but
11039 : * is USING when parsing back DELETE.
11040 : * ----------
11041 : */
8244 tgl 11042 : static void
6576 neilc 11043 CBC 1932 : get_from_clause(Query *query, const char *prefix, deparse_context *context)
11044 : {
8244 tgl 11045 1932 : StringInfo buf = context->buf;
7193 tgl 11046 GIC 1932 : bool first = true;
11047 : ListCell *l;
11048 :
11049 : /*
11050 : * We use the query's jointree as a guide to what to print. However, we
11051 : * must ignore auto-added RTEs that are marked not inFromCl. (These can
11052 : * only appear at the top level of the jointree, so it's sufficient to
11053 : * check here.) This check also ensures we ignore the rule pseudo-RTEs
6385 bruce 11054 ECB : * for NEW and OLD.
11055 : */
8227 tgl 11056 CBC 3860 : foreach(l, query->jointree->fromlist)
11057 : {
8053 bruce 11058 GIC 1928 : Node *jtnode = (Node *) lfirst(l);
8244 tgl 11059 ECB :
8244 tgl 11060 GIC 1928 : if (IsA(jtnode, RangeTblRef))
8244 tgl 11061 ECB : {
8244 tgl 11062 CBC 1593 : int varno = ((RangeTblRef *) jtnode)->rtindex;
11063 1593 : RangeTblEntry *rte = rt_fetch(varno, query->rtable);
8244 tgl 11064 ECB :
8244 tgl 11065 GIC 1593 : if (!rte->inFromCl)
8244 tgl 11066 CBC 185 : continue;
11067 : }
11068 :
7193 tgl 11069 GIC 1743 : if (first)
11070 : {
6576 neilc 11071 1591 : appendContextKeyword(context, prefix,
7193 tgl 11072 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7193 tgl 11073 CBC 1591 : first = false;
4067 andrew 11074 ECB :
4067 andrew 11075 GIC 1591 : get_from_clause_item(jtnode, query, context);
7193 tgl 11076 ECB : }
11077 : else
4067 andrew 11078 : {
3758 tgl 11079 : StringInfoData itembuf;
4067 andrew 11080 :
7188 bruce 11081 CBC 152 : appendStringInfoString(buf, ", ");
3955 bruce 11082 ECB :
3758 tgl 11083 : /*
11084 : * Put the new FROM item's text into itembuf so we can decide
11085 : * after we've got it whether or not it needs to go on a new line.
11086 : */
3758 tgl 11087 GIC 152 : initStringInfo(&itembuf);
3758 tgl 11088 CBC 152 : context->buf = &itembuf;
11089 :
4067 andrew 11090 GIC 152 : get_from_clause_item(jtnode, query, context);
4067 andrew 11091 ECB :
11092 : /* Restore context's output buffer */
4067 andrew 11093 CBC 152 : context->buf = buf;
4067 andrew 11094 ECB :
3758 tgl 11095 : /* Consider line-wrapping if enabled */
3758 tgl 11096 CBC 152 : if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
3758 tgl 11097 ECB : {
3436 11098 : /* Does the new item start with a new line? */
3436 tgl 11099 GIC 152 : if (itembuf.len > 0 && itembuf.data[0] == '\n')
11100 : {
3436 tgl 11101 EUB : /* If so, we shouldn't add anything */
11102 : /* instead, remove any trailing spaces currently in buf */
3436 tgl 11103 UIC 0 : removeStringInfoSpaces(buf);
11104 : }
3758 tgl 11105 ECB : else
11106 : {
3436 11107 : char *trailing_nl;
11108 :
11109 : /* Locate the start of the current line in the buffer */
3436 tgl 11110 CBC 152 : trailing_nl = strrchr(buf->data, '\n');
11111 152 : if (trailing_nl == NULL)
3436 tgl 11112 UIC 0 : trailing_nl = buf->data;
3436 tgl 11113 ECB : else
3436 tgl 11114 CBC 152 : trailing_nl++;
3436 tgl 11115 ECB :
11116 : /*
11117 : * Add a newline, plus some indentation, if the new item
11118 : * would cause an overflow.
11119 : */
3436 tgl 11120 CBC 152 : if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
11121 152 : appendContextKeyword(context, "", -PRETTYINDENT_STD,
3436 tgl 11122 ECB : PRETTYINDENT_STD,
11123 : PRETTYINDENT_VAR);
3436 tgl 11124 EUB : }
4067 andrew 11125 : }
11126 :
11127 : /* Add the new item */
1356 drowley 11128 CBC 152 : appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
11129 :
11130 : /* clean up */
3758 tgl 11131 152 : pfree(itembuf.data);
4067 andrew 11132 ECB : }
11133 : }
8244 tgl 11134 GBC 1932 : }
11135 :
8244 tgl 11136 EUB : static void
8244 tgl 11137 GIC 2743 : get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
11138 : {
11139 2743 : StringInfo buf = context->buf;
3751 11140 2743 : deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
8244 tgl 11141 ECB :
8244 tgl 11142 CBC 2743 : if (IsA(jtnode, RangeTblRef))
11143 : {
11144 2243 : int varno = ((RangeTblRef *) jtnode)->rtindex;
8244 tgl 11145 GIC 2243 : RangeTblEntry *rte = rt_fetch(varno, query->rtable);
3751 11146 2243 : deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
3426 11147 2243 : RangeTblFunction *rtfunc1 = NULL;
8244 tgl 11148 ECB :
3897 tgl 11149 CBC 2243 : if (rte->lateral)
3897 tgl 11150 GIC 32 : appendStringInfoString(buf, "LATERAL ");
3897 tgl 11151 ECB :
3831 11152 : /* Print the FROM item proper */
7688 tgl 11153 GIC 2243 : switch (rte->rtekind)
11154 : {
11155 1752 : case RTE_RELATION:
11156 : /* Normal relation RTE */
11157 3504 : appendStringInfo(buf, "%s%s",
11158 1752 : only_marker(rte),
11159 : generate_relation_name(rte->relid,
5298 tgl 11160 ECB : context->namespaces));
7688 tgl 11161 GIC 1752 : break;
7688 tgl 11162 CBC 119 : case RTE_SUBQUERY:
11163 : /* Subquery RTE */
7688 tgl 11164 GIC 119 : appendStringInfoChar(buf, '(');
7188 bruce 11165 119 : get_query_def(rte->subquery, buf, context->namespaces, NULL,
323 tgl 11166 ECB : true,
11167 : context->prettyFlags, context->wrapColumn,
3758 11168 : context->indentLevel);
7688 tgl 11169 GIC 119 : appendStringInfoChar(buf, ')');
11170 119 : break;
7637 11171 267 : case RTE_FUNCTION:
7637 tgl 11172 ECB : /* Function RTE */
3426 tgl 11173 GIC 267 : rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
3426 tgl 11174 ECB :
11175 : /*
11176 : * Omit ROWS FROM() syntax for just one function, unless it
11177 : * has both a coldeflist and WITH ORDINALITY. If it has both,
3407 noah 11178 : * we must use ROWS FROM() syntax to avoid ambiguity about
11179 : * whether the coldeflist includes the ordinality column.
3426 tgl 11180 : */
3426 tgl 11181 GBC 267 : if (list_length(rte->functions) == 1 &&
3426 tgl 11182 GIC 252 : (rtfunc1->funccolnames == NIL || !rte->funcordinality))
3426 tgl 11183 ECB : {
2096 tgl 11184 GIC 252 : get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
3426 tgl 11185 ECB : /* we'll print the coldeflist below, if it has one */
11186 : }
11187 : else
11188 : {
11189 : bool all_unnest;
11190 : ListCell *lc;
11191 :
3426 tgl 11192 EUB : /*
11193 : * If all the function calls in the list are to unnest,
11194 : * and none need a coldeflist, then collapse the list back
11195 : * down to UNNEST(args). (If we had more than one
3426 tgl 11196 ECB : * built-in unnest function, this would get more
11197 : * difficult.)
11198 : *
11199 : * XXX This is pretty ugly, since it makes not-terribly-
11200 : * future-proof assumptions about what the parser would do
11201 : * with the output; but the alternative is to emit our
3407 noah 11202 : * nonstandard ROWS FROM() notation for what might have
11203 : * been a perfectly spec-compliant multi-argument
11204 : * UNNEST().
3426 tgl 11205 : */
3426 tgl 11206 GIC 15 : all_unnest = true;
11207 39 : foreach(lc, rte->functions)
11208 : {
11209 33 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11210 :
11211 33 : if (!IsA(rtfunc->funcexpr, FuncExpr) ||
888 tgl 11212 CBC 33 : ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
3426 tgl 11213 GIC 24 : rtfunc->funccolnames != NIL)
3426 tgl 11214 ECB : {
3426 tgl 11215 CBC 9 : all_unnest = false;
3426 tgl 11216 GIC 9 : break;
11217 : }
3426 tgl 11218 ECB : }
11219 :
3426 tgl 11220 CBC 15 : if (all_unnest)
3426 tgl 11221 ECB : {
3426 tgl 11222 CBC 6 : List *allargs = NIL;
3426 tgl 11223 ECB :
3426 tgl 11224 CBC 24 : foreach(lc, rte->functions)
11225 : {
11226 18 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11227 18 : List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
3426 tgl 11228 ECB :
1336 tgl 11229 GIC 18 : allargs = list_concat(allargs, args);
3426 tgl 11230 ECB : }
11231 :
3426 tgl 11232 CBC 6 : appendStringInfoString(buf, "UNNEST(");
11233 6 : get_rule_expr((Node *) allargs, context, true);
11234 6 : appendStringInfoChar(buf, ')');
11235 : }
3426 tgl 11236 ECB : else
11237 : {
3426 tgl 11238 CBC 9 : int funcno = 0;
3426 tgl 11239 ECB :
3407 noah 11240 CBC 9 : appendStringInfoString(buf, "ROWS FROM(");
3426 tgl 11241 GIC 33 : foreach(lc, rte->functions)
3426 tgl 11242 ECB : {
3426 tgl 11243 GIC 24 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
3426 tgl 11244 ECB :
3426 tgl 11245 CBC 24 : if (funcno > 0)
11246 15 : appendStringInfoString(buf, ", ");
2096 tgl 11247 GIC 24 : get_rule_expr_funccall(rtfunc->funcexpr, context, true);
3426 tgl 11248 CBC 24 : if (rtfunc->funccolnames != NIL)
3426 tgl 11249 ECB : {
11250 : /* Reconstruct the column definition list */
3426 tgl 11251 GIC 3 : appendStringInfoString(buf, " AS ");
11252 3 : get_from_clause_coldeflist(rtfunc,
3426 tgl 11253 ECB : NULL,
11254 : context);
11255 : }
3426 tgl 11256 GIC 24 : funcno++;
11257 : }
11258 9 : appendStringInfoChar(buf, ')');
11259 : }
11260 : /* prevent printing duplicate coldeflist below */
11261 15 : rtfunc1 = NULL;
11262 : }
3541 stark 11263 267 : if (rte->funcordinality)
11264 9 : appendStringInfoString(buf, " WITH ORDINALITY");
7637 tgl 11265 CBC 267 : break;
2223 alvherre 11266 GIC 13 : case RTE_TABLEFUNC:
2223 alvherre 11267 CBC 13 : get_tablefunc(rte->tablefunc, context, true);
11268 13 : break;
6094 mail 11269 GIC 6 : case RTE_VALUES:
11270 : /* Values list RTE */
2965 tgl 11271 6 : appendStringInfoChar(buf, '(');
6094 mail 11272 6 : get_values_def(rte->values_lists, context);
2965 tgl 11273 6 : appendStringInfoChar(buf, ')');
6094 mail 11274 6 : break;
5300 tgl 11275 86 : case RTE_CTE:
11276 86 : appendStringInfoString(buf, quote_identifier(rte->ctename));
11277 86 : break;
7688 tgl 11278 LBC 0 : default:
7196 tgl 11279 UIC 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
7688 tgl 11280 ECB : break;
11281 : }
6394 11282 :
11283 : /* Print the relation alias, if needed */
51 tgl 11284 CBC 2243 : get_rte_alias(rte, varno, false, context);
6394 tgl 11285 ECB :
11286 : /* Print the column definitions or aliases, if needed */
3426 tgl 11287 CBC 2243 : if (rtfunc1 && rtfunc1->funccolnames != NIL)
7528 tgl 11288 ECB : {
11289 : /* Reconstruct the columndef list, which is also the aliases */
3426 tgl 11290 UIC 0 : get_from_clause_coldeflist(rtfunc1, colinfo, context);
7549 tgl 11291 ECB : }
11292 : else
6394 11293 : {
11294 : /* Else print column aliases as needed */
3751 tgl 11295 CBC 2243 : get_column_alias_list(colinfo, context);
11296 : }
2815 tgl 11297 ECB :
11298 : /* Tablesample clause must go after any alias */
2815 tgl 11299 GIC 2243 : if (rte->rtekind == RTE_RELATION && rte->tablesample)
11300 16 : get_tablesample_def(rte->tablesample, context);
11301 : }
8244 11302 500 : else if (IsA(jtnode, JoinExpr))
8244 tgl 11303 ECB : {
8244 tgl 11304 GIC 500 : JoinExpr *j = (JoinExpr *) jtnode;
3751 11305 500 : deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
11306 : bool need_paren_on_right;
11307 :
7193 11308 1219 : need_paren_on_right = PRETTY_PAREN(context) &&
6496 tgl 11309 CBC 500 : !IsA(j->rarg, RangeTblRef) &&
1058 tgl 11310 LBC 0 : !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
11311 :
7193 tgl 11312 CBC 500 : if (!PRETTY_PAREN(context) || j->alias != NULL)
7188 bruce 11313 GIC 335 : appendStringInfoChar(buf, '(');
11314 :
8244 tgl 11315 CBC 500 : get_from_clause_item(j->larg, query, context);
11316 :
3751 tgl 11317 GIC 500 : switch (j->jointype)
7193 tgl 11318 ECB : {
3751 tgl 11319 GIC 302 : case JOIN_INNER:
11320 302 : if (j->quals)
3751 tgl 11321 CBC 281 : appendContextKeyword(context, " JOIN ",
11322 : -PRETTYINDENT_STD,
11323 : PRETTYINDENT_STD,
11324 : PRETTYINDENT_JOIN);
3751 tgl 11325 EUB : else
3751 tgl 11326 GIC 21 : appendContextKeyword(context, " CROSS JOIN ",
11327 : -PRETTYINDENT_STD,
11328 : PRETTYINDENT_STD,
11329 : PRETTYINDENT_JOIN);
11330 302 : break;
11331 147 : case JOIN_LEFT:
3751 tgl 11332 CBC 147 : appendContextKeyword(context, " LEFT JOIN ",
3266 tgl 11333 ECB : -PRETTYINDENT_STD,
3266 tgl 11334 EUB : PRETTYINDENT_STD,
11335 : PRETTYINDENT_JOIN);
3751 tgl 11336 CBC 147 : break;
3751 tgl 11337 GIC 51 : case JOIN_FULL:
11338 51 : appendContextKeyword(context, " FULL JOIN ",
11339 : -PRETTYINDENT_STD,
11340 : PRETTYINDENT_STD,
11341 : PRETTYINDENT_JOIN);
3751 tgl 11342 CBC 51 : break;
3751 tgl 11343 LBC 0 : case JOIN_RIGHT:
3751 tgl 11344 UIC 0 : appendContextKeyword(context, " RIGHT JOIN ",
11345 : -PRETTYINDENT_STD,
11346 : PRETTYINDENT_STD,
11347 : PRETTYINDENT_JOIN);
11348 0 : break;
11349 0 : default:
3751 tgl 11350 LBC 0 : elog(ERROR, "unrecognized join type: %d",
11351 : (int) j->jointype);
11352 : }
7193 tgl 11353 ECB :
7193 tgl 11354 GIC 500 : if (need_paren_on_right)
7188 bruce 11355 UIC 0 : appendStringInfoChar(buf, '(');
8244 tgl 11356 CBC 500 : get_from_clause_item(j->rarg, query, context);
7193 tgl 11357 GIC 500 : if (need_paren_on_right)
7188 bruce 11358 UIC 0 : appendStringInfoChar(buf, ')');
7193 tgl 11359 ECB :
3751 tgl 11360 GIC 500 : if (j->usingClause)
8244 tgl 11361 ECB : {
3751 11362 : ListCell *lc;
3751 tgl 11363 GIC 212 : bool first = true;
8244 tgl 11364 ECB :
3447 rhaas 11365 GIC 212 : appendStringInfoString(buf, " USING (");
3751 tgl 11366 ECB : /* Use the assigned names, not what's in usingClause */
3751 tgl 11367 CBC 502 : foreach(lc, colinfo->usingNames)
8244 tgl 11368 ECB : {
3751 tgl 11369 CBC 290 : char *colname = (char *) lfirst(lc);
11370 :
11371 290 : if (first)
11372 212 : first = false;
11373 : else
3447 rhaas 11374 GIC 78 : appendStringInfoString(buf, ", ");
3751 tgl 11375 CBC 290 : appendStringInfoString(buf, quote_identifier(colname));
11376 : }
11377 212 : appendStringInfoChar(buf, ')');
11378 :
739 peter 11379 212 : if (j->join_using_alias)
11380 6 : appendStringInfo(buf, " AS %s",
739 peter 11381 GIC 6 : quote_identifier(j->join_using_alias->aliasname));
11382 : }
3751 tgl 11383 CBC 288 : else if (j->quals)
3751 tgl 11384 ECB : {
3447 rhaas 11385 GIC 264 : appendStringInfoString(buf, " ON ");
3751 tgl 11386 CBC 264 : if (!PRETTY_PAREN(context))
11387 261 : appendStringInfoChar(buf, '(');
3751 tgl 11388 GIC 264 : get_rule_expr(j->quals, context, false);
11389 264 : if (!PRETTY_PAREN(context))
11390 261 : appendStringInfoChar(buf, ')');
8244 tgl 11391 ECB : }
2089 tgl 11392 CBC 24 : else if (j->jointype != JOIN_INNER)
2089 tgl 11393 ECB : {
11394 : /* If we didn't say CROSS JOIN above, we must provide an ON */
2089 tgl 11395 CBC 3 : appendStringInfoString(buf, " ON TRUE");
11396 : }
11397 :
7193 tgl 11398 GIC 500 : if (!PRETTY_PAREN(context) || j->alias != NULL)
7188 bruce 11399 335 : appendStringInfoChar(buf, ')');
11400 :
11401 : /* Yes, it's correct to put alias after the right paren ... */
8244 tgl 11402 500 : if (j->alias != NULL)
8244 tgl 11403 ECB : {
1397 11404 : /*
11405 : * Note that it's correct to emit an alias clause if and only if
11406 : * there was one originally. Otherwise we'd be converting a named
11407 : * join to unnamed or vice versa, which creates semantic
11408 : * subtleties we don't want. However, we might print a different
11409 : * alias name than was there originally.
11410 : */
8244 tgl 11411 GIC 54 : appendStringInfo(buf, " %s",
1397 11412 54 : quote_identifier(get_rtable_name(j->rtindex,
11413 : context)));
3751 11414 54 : get_column_alias_list(colinfo, context);
11415 : }
11416 : }
11417 : else
7196 tgl 11418 UIC 0 : elog(ERROR, "unrecognized node type: %d",
11419 : (int) nodeTag(jtnode));
8244 tgl 11420 GIC 2743 : }
11421 :
11422 : /*
11423 : * get_rte_alias - print the relation's alias, if needed
11424 : *
11425 : * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
11426 : */
11427 : static void
51 tgl 11428 CBC 2507 : get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
51 tgl 11429 ECB : deparse_context *context)
11430 : {
51 tgl 11431 CBC 2507 : deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
51 tgl 11432 GIC 2507 : char *refname = get_rtable_name(varno, context);
51 tgl 11433 CBC 2507 : deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
11434 2507 : bool printalias = false;
51 tgl 11435 ECB :
51 tgl 11436 GIC 2507 : if (rte->alias != NULL)
51 tgl 11437 ECB : {
11438 : /* Always print alias if user provided one */
51 tgl 11439 GIC 1007 : printalias = true;
11440 : }
11441 1500 : else if (colinfo->printaliases)
51 tgl 11442 ECB : {
11443 : /* Always print alias if we need to print column aliases */
51 tgl 11444 CBC 126 : printalias = true;
11445 : }
11446 1374 : else if (rte->rtekind == RTE_RELATION)
11447 : {
51 tgl 11448 ECB : /*
11449 : * No need to print alias if it's same as relation name (this would
11450 : * normally be the case, but not if set_rtable_names had to resolve a
11451 : * conflict).
11452 : */
51 tgl 11453 GIC 1274 : if (strcmp(refname, get_relation_name(rte->relid)) != 0)
51 tgl 11454 CBC 19 : printalias = true;
51 tgl 11455 ECB : }
51 tgl 11456 CBC 100 : else if (rte->rtekind == RTE_FUNCTION)
11457 : {
11458 : /*
11459 : * For a function RTE, always print alias. This covers possible
51 tgl 11460 ECB : * renaming of the function and/or instability of the FigureColname
11461 : * rules for things that aren't simple functions. Note we'd need to
11462 : * force it anyway for the columndef list case.
11463 : */
51 tgl 11464 UIC 0 : printalias = true;
51 tgl 11465 ECB : }
51 tgl 11466 GIC 100 : else if (rte->rtekind == RTE_SUBQUERY ||
51 tgl 11467 CBC 88 : rte->rtekind == RTE_VALUES)
51 tgl 11468 ECB : {
11469 : /*
11470 : * For a subquery, always print alias. This makes the output
11471 : * SQL-spec-compliant, even though we allow such aliases to be omitted
11472 : * on input.
11473 : */
51 tgl 11474 CBC 18 : printalias = true;
11475 : }
51 tgl 11476 GIC 82 : else if (rte->rtekind == RTE_CTE)
51 tgl 11477 ECB : {
11478 : /*
11479 : * No need to print alias if it's same as CTE name (this would
11480 : * normally be the case, but not if set_rtable_names had to resolve a
11481 : * conflict).
11482 : */
51 tgl 11483 GIC 69 : if (strcmp(refname, rte->ctename) != 0)
51 tgl 11484 CBC 11 : printalias = true;
11485 : }
11486 :
11487 2507 : if (printalias)
51 tgl 11488 GIC 1181 : appendStringInfo(context->buf, "%s%s",
51 tgl 11489 ECB : use_as ? " AS " : " ",
11490 : quote_identifier(refname));
51 tgl 11491 CBC 2507 : }
51 tgl 11492 ECB :
6807 11493 : /*
3751 11494 : * get_column_alias_list - print column alias list for an RTE
6807 11495 : *
11496 : * Caller must already have printed the relation's alias name.
11497 : */
11498 : static void
3751 tgl 11499 CBC 2297 : get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
6807 tgl 11500 ECB : {
6807 tgl 11501 CBC 2297 : StringInfo buf = context->buf;
3751 tgl 11502 ECB : int i;
6807 tgl 11503 CBC 2297 : bool first = true;
6807 tgl 11504 EUB :
3751 11505 : /* Don't print aliases if not needed */
3751 tgl 11506 GIC 2297 : if (!colinfo->printaliases)
11507 1853 : return;
11508 :
11509 2898 : for (i = 0; i < colinfo->num_new_cols; i++)
6807 tgl 11510 ECB : {
3751 tgl 11511 GIC 2454 : char *colname = colinfo->new_colnames[i];
11512 :
6807 tgl 11513 CBC 2454 : if (first)
11514 : {
6807 tgl 11515 GIC 444 : appendStringInfoChar(buf, '(');
6807 tgl 11516 GBC 444 : first = false;
11517 : }
11518 : else
3447 rhaas 11519 GIC 2010 : appendStringInfoString(buf, ", ");
3751 tgl 11520 2454 : appendStringInfoString(buf, quote_identifier(colname));
6807 tgl 11521 ECB : }
6807 tgl 11522 GIC 444 : if (!first)
11523 444 : appendStringInfoChar(buf, ')');
11524 : }
6807 tgl 11525 ECB :
7528 11526 : /*
11527 : * get_from_clause_coldeflist - reproduce FROM clause coldeflist
11528 : *
11529 : * When printing a top-level coldeflist (which is syntactically also the
3426 11530 : * relation's column alias list), use column names from colinfo. But when
3407 noah 11531 : * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
11532 : * original coldeflist's names, which are available in rtfunc->funccolnames.
11533 : * Pass NULL for colinfo to select the latter behavior.
3426 tgl 11534 : *
7528 11535 : * The coldeflist is appended immediately (no space) to buf. Caller is
7528 tgl 11536 EUB : * responsible for ensuring that an alias or AS is present before it.
11537 : */
7528 tgl 11538 ECB : static void
3426 tgl 11539 CBC 3 : get_from_clause_coldeflist(RangeTblFunction *rtfunc,
11540 : deparse_columns *colinfo,
6233 tgl 11541 ECB : deparse_context *context)
11542 : {
7528 tgl 11543 CBC 3 : StringInfo buf = context->buf;
11544 : ListCell *l1;
6233 tgl 11545 ECB : ListCell *l2;
11546 : ListCell *l3;
3426 11547 : ListCell *l4;
11548 : int i;
11549 :
7528 tgl 11550 GIC 3 : appendStringInfoChar(buf, '(');
11551 :
3751 tgl 11552 CBC 3 : i = 0;
1501 tgl 11553 GIC 12 : forfour(l1, rtfunc->funccoltypes,
11554 : l2, rtfunc->funccoltypmods,
11555 : l3, rtfunc->funccolcollations,
1501 tgl 11556 ECB : l4, rtfunc->funccolnames)
3751 11557 : {
3751 tgl 11558 CBC 9 : Oid atttypid = lfirst_oid(l1);
3751 tgl 11559 GIC 9 : int32 atttypmod = lfirst_int(l2);
11560 9 : Oid attcollation = lfirst_oid(l3);
11561 : char *attname;
3426 tgl 11562 ECB :
3426 tgl 11563 CBC 9 : if (colinfo)
3426 tgl 11564 LBC 0 : attname = colinfo->colnames[i];
11565 : else
3426 tgl 11566 GIC 9 : attname = strVal(lfirst(l4));
11567 :
3751 tgl 11568 CBC 9 : Assert(attname); /* shouldn't be any dropped columns here */
7528 tgl 11569 EUB :
7528 tgl 11570 GBC 9 : if (i > 0)
3447 rhaas 11571 GIC 6 : appendStringInfoString(buf, ", ");
7528 tgl 11572 9 : appendStringInfo(buf, "%s %s",
11573 : quote_identifier(attname),
6233 tgl 11574 EUB : format_type_with_typemod(atttypid, atttypmod));
4370 tgl 11575 GBC 12 : if (OidIsValid(attcollation) &&
11576 3 : attcollation != get_typcollation(atttypid))
4399 tgl 11577 UIC 0 : appendStringInfo(buf, " COLLATE %s",
11578 : generate_collation_name(attcollation));
11579 :
7528 tgl 11580 CBC 9 : i++;
7528 tgl 11581 EUB : }
7528 tgl 11582 ECB :
7528 tgl 11583 CBC 3 : appendStringInfoChar(buf, ')');
7528 tgl 11584 GBC 3 : }
11585 :
2815 tgl 11586 ECB : /*
11587 : * get_tablesample_def - print a TableSampleClause
11588 : */
11589 : static void
2815 tgl 11590 GIC 16 : get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
2815 tgl 11591 ECB : {
2815 tgl 11592 GIC 16 : StringInfo buf = context->buf;
2815 tgl 11593 ECB : Oid argtypes[1];
11594 : int nargs;
11595 : ListCell *l;
11596 :
11597 : /*
11598 : * We should qualify the handler's function name if it wouldn't be
11599 : * resolved by lookup in the current search path.
11600 : */
2815 tgl 11601 CBC 16 : argtypes[0] = INTERNALOID;
2815 tgl 11602 GIC 16 : appendStringInfo(buf, " TABLESAMPLE %s (",
2815 tgl 11603 ECB : generate_function_name(tablesample->tsmhandler, 1,
11604 : NIL, argtypes,
11605 : false, NULL, EXPR_KIND_NONE));
11606 :
2815 tgl 11607 CBC 16 : nargs = 0;
2815 tgl 11608 GIC 32 : foreach(l, tablesample->args)
2815 tgl 11609 ECB : {
2815 tgl 11610 GIC 16 : if (nargs++ > 0)
2815 tgl 11611 LBC 0 : appendStringInfoString(buf, ", ");
2815 tgl 11612 CBC 16 : get_rule_expr((Node *) lfirst(l), context, false);
2815 tgl 11613 ECB : }
2815 tgl 11614 CBC 16 : appendStringInfoChar(buf, ')');
2815 tgl 11615 ECB :
2815 tgl 11616 CBC 16 : if (tablesample->repeatable != NULL)
11617 : {
11618 8 : appendStringInfoString(buf, " REPEATABLE (");
2815 tgl 11619 GIC 8 : get_rule_expr((Node *) tablesample->repeatable, context, false);
11620 8 : appendStringInfoChar(buf, ')');
2815 tgl 11621 ECB : }
2815 tgl 11622 GIC 16 : }
11623 :
7646 tgl 11624 ECB : /*
7860 11625 : * get_opclass_name - fetch name of an index operator class
11626 : *
11627 : * The opclass name is appended (after a space) to buf.
7857 11628 : *
11629 : * Output is suppressed if the opclass is the default for the given
11630 : * actual_datatype. (If you don't want this behavior, just pass
11631 : * InvalidOid for actual_datatype.)
11632 : */
11633 : static void
7857 tgl 11634 GIC 4810 : get_opclass_name(Oid opclass, Oid actual_datatype,
11635 : StringInfo buf)
11636 : {
7860 tgl 11637 ECB : HeapTuple ht_opc;
11638 : Form_pg_opclass opcrec;
11639 : char *opcname;
7646 11640 : char *nspname;
11641 :
4802 rhaas 11642 GIC 4810 : ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
7860 tgl 11643 4810 : if (!HeapTupleIsValid(ht_opc))
7860 tgl 11644 UBC 0 : elog(ERROR, "cache lookup failed for opclass %u", opclass);
7860 tgl 11645 GIC 4810 : opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
7175 tgl 11646 ECB :
5951 tgl 11647 GIC 9602 : if (!OidIsValid(actual_datatype) ||
11648 4792 : GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
11649 : {
11650 : /* Okay, we need the opclass name. Do we need to qualify it? */
7646 11651 277 : opcname = NameStr(opcrec->opcname);
5951 11652 277 : if (OpclassIsVisible(opclass))
7646 11653 277 : appendStringInfo(buf, " %s", quote_identifier(opcname));
7646 tgl 11654 ECB : else
11655 : {
621 tgl 11656 UIC 0 : nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
7646 tgl 11657 LBC 0 : appendStringInfo(buf, " %s.%s",
7646 tgl 11658 ECB : quote_identifier(nspname),
11659 : quote_identifier(opcname));
11660 : }
11661 : }
7860 tgl 11662 CBC 4810 : ReleaseSysCache(ht_opc);
7860 tgl 11663 GIC 4810 : }
11664 :
1105 akorotkov 11665 ECB : /*
11666 : * generate_opclass_name
96 michael 11667 : * Compute the name to display for an opclass specified by OID
11668 : *
11669 : * The result includes all necessary quoting and schema-prefixing.
1105 akorotkov 11670 : */
11671 : char *
1105 akorotkov 11672 CBC 3 : generate_opclass_name(Oid opclass)
11673 : {
11674 : StringInfoData buf;
11675 :
1105 akorotkov 11676 GIC 3 : initStringInfo(&buf);
11677 3 : get_opclass_name(opclass, InvalidOid, &buf);
11678 :
1060 tgl 11679 CBC 3 : return &buf.data[1]; /* get_opclass_name() prepends space */
1105 akorotkov 11680 ECB : }
11681 :
7646 tgl 11682 : /*
11683 : * processIndirection - take care of array and subfield assignment
11684 : *
11685 : * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
11686 : * appear in the input, printing them as decoration for the base column
11687 : * name (which we assume the caller just printed). We might also need to
11688 : * strip CoerceToDomain nodes, but only ones that appear above assignment
11689 : * nodes.
2097 tgl 11690 EUB : *
11691 : * Returns the subexpression that's to be assigned.
8275 tgl 11692 ECB : */
6878 11693 : static Node *
2440 tgl 11694 GIC 558 : processIndirection(Node *node, deparse_context *context)
11695 : {
6878 11696 558 : StringInfo buf = context->buf;
2097 11697 558 : CoerceToDomain *cdomain = NULL;
11698 :
11699 : for (;;)
6878 tgl 11700 ECB : {
6878 tgl 11701 GIC 645 : if (node == NULL)
6878 tgl 11702 LBC 0 : break;
6878 tgl 11703 GIC 645 : if (IsA(node, FieldStore))
11704 : {
11705 36 : FieldStore *fstore = (FieldStore *) node;
11706 : Oid typrelid;
11707 : char *fieldname;
11708 :
6878 tgl 11709 ECB : /* lookup tuple type */
6878 tgl 11710 CBC 36 : typrelid = get_typ_typrelid(fstore->resulttype);
6878 tgl 11711 GIC 36 : if (!OidIsValid(typrelid))
6878 tgl 11712 UIC 0 : elog(ERROR, "argument type %s of FieldStore is not a tuple type",
6878 tgl 11713 ECB : format_type_be(fstore->resulttype));
6797 bruce 11714 :
11715 : /*
11716 : * Print the field name. There should only be one target field in
4790 11717 : * stored rules. There could be more than that in executable
11718 : * target lists, but this function cannot be used for that case.
11719 : */
4798 tgl 11720 GIC 36 : Assert(list_length(fstore->fieldnums) == 1);
1882 alvherre 11721 36 : fieldname = get_attname(typrelid,
11722 36 : linitial_int(fstore->fieldnums), false);
2440 tgl 11723 36 : appendStringInfo(buf, ".%s", quote_identifier(fieldname));
11724 :
6878 tgl 11725 ECB : /*
11726 : * We ignore arg since it should be an uninteresting reference to
6385 bruce 11727 : * the target column or subcolumn.
11728 : */
6878 tgl 11729 CBC 36 : node = (Node *) linitial(fstore->newvals);
11730 : }
1528 alvherre 11731 GIC 609 : else if (IsA(node, SubscriptingRef))
6878 tgl 11732 ECB : {
1528 alvherre 11733 CBC 39 : SubscriptingRef *sbsref = (SubscriptingRef *) node;
11734 :
11735 39 : if (sbsref->refassgnexpr == NULL)
6878 tgl 11736 UIC 0 : break;
1528 alvherre 11737 ECB :
1528 alvherre 11738 GIC 39 : printSubscripts(sbsref, context);
6797 bruce 11739 ECB :
11740 : /*
6385 11741 : * We ignore refexpr since it should be an uninteresting reference
11742 : * to the target column or subcolumn.
11743 : */
1528 alvherre 11744 GIC 39 : node = (Node *) sbsref->refassgnexpr;
6878 tgl 11745 ECB : }
2097 tgl 11746 CBC 570 : else if (IsA(node, CoerceToDomain))
11747 : {
11748 12 : cdomain = (CoerceToDomain *) node;
2097 tgl 11749 ECB : /* If it's an explicit domain coercion, we're done */
2097 tgl 11750 GIC 12 : if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
2097 tgl 11751 UIC 0 : break;
11752 : /* Tentatively descend past the CoerceToDomain */
2097 tgl 11753 GIC 12 : node = (Node *) cdomain->arg;
11754 : }
11755 : else
6878 11756 558 : break;
11757 : }
11758 :
11759 : /*
11760 : * If we descended past a CoerceToDomain whose argument turned out not to
11761 : * be a FieldStore or array assignment, back up to the CoerceToDomain.
11762 : * (This is not enough to be fully correct if there are nested implicit
11763 : * CoerceToDomains, but such cases shouldn't ever occur.)
11764 : */
2097 tgl 11765 CBC 558 : if (cdomain && node == (Node *) cdomain->arg)
2097 tgl 11766 UIC 0 : node = (Node *) cdomain;
11767 :
6878 tgl 11768 GIC 558 : return node;
6878 tgl 11769 ECB : }
11770 :
11771 : static void
1528 alvherre 11772 GIC 131 : printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
11773 : {
6878 tgl 11774 131 : StringInfo buf = context->buf;
11775 : ListCell *lowlist_item;
6878 tgl 11776 ECB : ListCell *uplist_item;
11777 :
1528 alvherre 11778 CBC 131 : lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
11779 262 : foreach(uplist_item, sbsref->refupperindexpr)
11780 : {
6878 tgl 11781 GIC 131 : appendStringInfoChar(buf, '[');
11782 131 : if (lowlist_item)
11783 : {
2665 tgl 11784 ECB : /* If subexpression is NULL, get_rule_expr prints nothing */
6878 tgl 11785 LBC 0 : get_rule_expr((Node *) lfirst(lowlist_item), context, false);
11786 0 : appendStringInfoChar(buf, ':');
1364 tgl 11787 UIC 0 : lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
11788 : }
2665 tgl 11789 ECB : /* If subexpression is NULL, get_rule_expr prints nothing */
6878 tgl 11790 GBC 131 : get_rule_expr((Node *) lfirst(uplist_item), context, false);
6878 tgl 11791 GIC 131 : appendStringInfoChar(buf, ']');
6878 tgl 11792 ECB : }
8275 tgl 11793 GIC 131 : }
8275 tgl 11794 ECB :
11795 : /*
8588 11796 : * quote_identifier - Quote an identifier only if needed
11797 : *
11798 : * When quotes are needed, we palloc the required space; slightly
11799 : * space-wasteful but well worth it for notational simplicity.
11800 : */
7654 11801 : const char *
7654 tgl 11802 CBC 1056314 : quote_identifier(const char *ident)
8588 tgl 11803 EUB : {
11804 : /*
11805 : * Can avoid quoting if ident starts with a lowercase letter or underscore
6385 bruce 11806 ECB : * and contains only lowercase letters, digits, and underscores, *and* is
11807 : * not any SQL keyword. Otherwise, supply quotes.
11808 : */
7632 tgl 11809 CBC 1056314 : int nquotes = 0;
8588 tgl 11810 ECB : bool safe;
11811 : const char *ptr;
11812 : char *result;
11813 : char *optr;
11814 :
11815 : /*
6385 bruce 11816 : * would like to use <ctype.h> macros here, but they might yield unwanted
11817 : * locale-specific results...
8588 tgl 11818 : */
7651 tgl 11819 GIC 1056314 : safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
11820 :
7632 11821 8625457 : for (ptr = ident; *ptr; ptr++)
11822 : {
11823 7569143 : char ch = *ptr;
11824 :
11825 7569143 : if ((ch >= 'a' && ch <= 'z') ||
11826 843761 : (ch >= '0' && ch <= '9') ||
7632 tgl 11827 ECB : (ch == '_'))
8588 11828 : {
11829 : /* okay */
11830 : }
11831 : else
11832 : {
7632 tgl 11833 CBC 23897 : safe = false;
11834 23897 : if (ch == '"')
7632 tgl 11835 GIC 6 : nquotes++;
8588 tgl 11836 ECB : }
8588 tgl 11837 EUB : }
8588 tgl 11838 ECB :
4644 rhaas 11839 GIC 1056314 : if (quote_all_identifiers)
4644 rhaas 11840 CBC 5564 : safe = false;
11841 :
8525 tgl 11842 1056314 : if (safe)
11843 : {
8525 tgl 11844 ECB : /*
5774 11845 : * Check for keyword. We quote keywords except for unreserved ones.
11846 : * (In some cases we could avoid quoting a col_name or type_func_name
11847 : * keyword, but it seems much harder than it's worth to tell that.)
8525 11848 : *
11849 : * Note: ScanKeywordLookup() does case-insensitive comparison, but
11850 : * that's fine, since we already know we have all-lower-case.
11851 : */
1554 tgl 11852 GIC 1041297 : int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
11853 :
11854 1041297 : if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
8525 11855 1046 : safe = false;
11856 : }
11857 :
8588 11858 1056314 : if (safe)
11859 1040251 : return ident; /* no change needed */
8588 tgl 11860 ECB :
7632 tgl 11861 GIC 16063 : result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
11862 :
11863 16063 : optr = result;
11864 16063 : *optr++ = '"';
11865 97533 : for (ptr = ident; *ptr; ptr++)
11866 : {
11867 81470 : char ch = *ptr;
7632 tgl 11868 ECB :
7632 tgl 11869 CBC 81470 : if (ch == '"')
7632 tgl 11870 GBC 6 : *optr++ = '"';
7632 tgl 11871 CBC 81470 : *optr++ = ch;
11872 : }
11873 16063 : *optr++ = '"';
11874 16063 : *optr = '\0';
11875 :
8588 tgl 11876 GIC 16063 : return result;
8588 tgl 11877 ECB : }
8994 bruce 11878 :
7646 tgl 11879 : /*
11880 : * quote_qualified_identifier - Quote a possibly-qualified identifier
11881 : *
5015 peter_e 11882 EUB : * Return a name of the form qualifier.ident, or just ident if qualifier
7654 tgl 11883 : * is NULL, quoting each component if necessary. The result is palloc'd.
11884 : */
11885 : char *
5015 peter_e 11886 GIC 488282 : quote_qualified_identifier(const char *qualifier,
11887 : const char *ident)
7654 tgl 11888 ECB : {
11889 : StringInfoData buf;
11890 :
7654 tgl 11891 GIC 488282 : initStringInfo(&buf);
5015 peter_e 11892 488282 : if (qualifier)
11893 200798 : appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
7008 neilc 11894 488282 : appendStringInfoString(&buf, quote_identifier(ident));
7654 tgl 11895 488282 : return buf.data;
11896 : }
11897 :
4541 tgl 11898 ECB : /*
11899 : * get_relation_name
11900 : * Get the unqualified name of a relation specified by OID
11901 : *
11902 : * This differs from the underlying get_rel_name() function in that it will
11903 : * throw error instead of silently returning NULL if the OID is bad.
11904 : */
11905 : static char *
4541 tgl 11906 GIC 6844 : get_relation_name(Oid relid)
11907 : {
11908 6844 : char *relname = get_rel_name(relid);
11909 :
11910 6844 : if (!relname)
4541 tgl 11911 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
4541 tgl 11912 GIC 6844 : return relname;
11913 : }
11914 :
11915 : /*
11916 : * generate_relation_name
11917 : * Compute the name to display for a relation specified by OID
11918 : *
11919 : * The result includes all necessary quoting and schema-prefixing.
5298 tgl 11920 ECB : *
11921 : * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
11922 : * We will forcibly qualify the relation name if it equals any CTE name
11923 : * visible in the namespace list.
11924 : */
11925 : static char *
5298 tgl 11926 GIC 3210 : generate_relation_name(Oid relid, List *namespaces)
7646 tgl 11927 ECB : {
7646 tgl 11928 EUB : HeapTuple tp;
7646 tgl 11929 ECB : Form_pg_class reltup;
11930 : bool need_qual;
5298 11931 : ListCell *nslist;
11932 : char *relname;
11933 : char *nspname;
11934 : char *result;
11935 :
4802 rhaas 11936 CBC 3210 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
7646 tgl 11937 3210 : if (!HeapTupleIsValid(tp))
7196 tgl 11938 UBC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
7646 tgl 11939 GIC 3210 : reltup = (Form_pg_class) GETSTRUCT(tp);
5298 11940 3210 : relname = NameStr(reltup->relname);
11941 :
11942 : /* Check for conflicting CTE name */
11943 3210 : need_qual = false;
11944 5383 : foreach(nslist, namespaces)
11945 : {
5298 tgl 11946 CBC 2173 : deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
5298 tgl 11947 ECB : ListCell *ctlist;
11948 :
5298 tgl 11949 CBC 2203 : foreach(ctlist, dpns->ctes)
11950 : {
5298 tgl 11951 GIC 30 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
11952 :
11953 30 : if (strcmp(cte->ctename, relname) == 0)
11954 : {
5298 tgl 11955 LBC 0 : need_qual = true;
5298 tgl 11956 UIC 0 : break;
5298 tgl 11957 ECB : }
11958 : }
5298 tgl 11959 CBC 2173 : if (need_qual)
5298 tgl 11960 UIC 0 : break;
5298 tgl 11961 ECB : }
5298 tgl 11962 EUB :
11963 : /* Otherwise, qualify the name if not visible in search path */
5298 tgl 11964 CBC 3210 : if (!need_qual)
5298 tgl 11965 GIC 3210 : need_qual = !RelationIsVisible(relid);
11966 :
11967 3210 : if (need_qual)
621 11968 1079 : nspname = get_namespace_name_or_temp(reltup->relnamespace);
11969 : else
5298 tgl 11970 CBC 2131 : nspname = NULL;
11971 :
11972 3210 : result = quote_qualified_identifier(nspname, relname);
11973 :
7646 11974 3210 : ReleaseSysCache(tp);
11975 :
11976 3210 : return result;
7646 tgl 11977 EUB : }
11978 :
2697 tgl 11979 ECB : /*
11980 : * generate_qualified_relation_name
11981 : * Compute the name to display for a relation specified by OID
11982 : *
11983 : * As above, but unconditionally schema-qualify the name.
11984 : */
11985 : static char *
2697 tgl 11986 GIC 3205 : generate_qualified_relation_name(Oid relid)
11987 : {
11988 : HeapTuple tp;
11989 : Form_pg_class reltup;
11990 : char *relname;
2697 tgl 11991 ECB : char *nspname;
2697 tgl 11992 EUB : char *result;
11993 :
2697 tgl 11994 CBC 3205 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2697 tgl 11995 GIC 3205 : if (!HeapTupleIsValid(tp))
2697 tgl 11996 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
2697 tgl 11997 GIC 3205 : reltup = (Form_pg_class) GETSTRUCT(tp);
2697 tgl 11998 CBC 3205 : relname = NameStr(reltup->relname);
11999 :
621 12000 3205 : nspname = get_namespace_name_or_temp(reltup->relnamespace);
2697 tgl 12001 GIC 3205 : if (!nspname)
2697 tgl 12002 UIC 0 : elog(ERROR, "cache lookup failed for namespace %u",
12003 : reltup->relnamespace);
2697 tgl 12004 ECB :
2697 tgl 12005 CBC 3205 : result = quote_qualified_identifier(nspname, relname);
12006 :
12007 3205 : ReleaseSysCache(tp);
2697 tgl 12008 ECB :
2697 tgl 12009 GIC 3205 : return result;
12010 : }
2697 tgl 12011 EUB :
7646 12012 : /*
12013 : * generate_function_name
12014 : * Compute the name to display for a function specified by OID,
12015 : * given that it is being called with the specified actual arg names and
3260 bruce 12016 ECB : * types. (Those matter because of ambiguous-function resolution rules.)
7646 tgl 12017 : *
12018 : * If we're dealing with a potentially variadic function (in practice, this
3505 12019 : * means a FuncExpr or Aggref, not some other way of calling a function), then
12020 : * has_variadic must specify whether variadic arguments have been merged,
12021 : * and *use_variadic_p will be set to indicate whether to print VARIADIC in
12022 : * the output. For non-FuncExpr cases, has_variadic should be false and
12023 : * use_variadic_p can be NULL.
12024 : *
12025 : * The result includes all necessary quoting and schema-prefixing.
12026 : */
12027 : static char *
3730 tgl 12028 CBC 5107 : generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
12029 : bool has_variadic, bool *use_variadic_p,
12030 : ParseExprKind special_exprkind)
12031 : {
12032 : char *result;
12033 : HeapTuple proctup;
12034 : Form_pg_proc procform;
7646 tgl 12035 ECB : char *proname;
12036 : bool use_variadic;
12037 : char *nspname;
12038 : FuncDetailCode p_result;
12039 : Oid p_funcid;
12040 : Oid p_rettype;
12041 : bool p_retset;
12042 : int p_nvargs;
12043 : Oid p_vatype;
12044 : Oid *p_true_typeids;
2885 andres 12045 CBC 5107 : bool force_qualify = false;
12046 :
4802 rhaas 12047 5107 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
7646 tgl 12048 GIC 5107 : if (!HeapTupleIsValid(proctup))
7196 tgl 12049 LBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
7646 tgl 12050 GIC 5107 : procform = (Form_pg_proc) GETSTRUCT(proctup);
7646 tgl 12051 CBC 5107 : proname = NameStr(procform->proname);
7646 tgl 12052 ECB :
12053 : /*
12054 : * Due to parser hacks to avoid needing to reserve CUBE, we need to force
12055 : * qualification in some special cases.
12056 : */
2885 andres 12057 GIC 5107 : if (special_exprkind == EXPR_KIND_GROUP_BY)
12058 : {
2885 andres 12059 LBC 0 : if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
12060 0 : force_qualify = true;
2885 andres 12061 ECB : }
12062 :
12063 : /*
12064 : * Determine whether VARIADIC should be printed. We must do this first
3730 tgl 12065 : * since it affects the lookup rules in func_get_detail().
12066 : *
12067 : * We always print VARIADIC if the function has a merged variadic-array
1716 noah 12068 : * argument. Note that this is always the case for functions taking a
12069 : * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
12070 : * and printed the array elements as separate arguments, the call could
12071 : * match a newer non-VARIADIC function.
12072 : */
3730 tgl 12073 GIC 5107 : if (use_variadic_p)
12074 : {
12075 : /* Parser should not have set funcvariadic unless fn is variadic */
3293 12076 4299 : Assert(!has_variadic || OidIsValid(procform->provariadic));
12077 4299 : use_variadic = has_variadic;
3730 tgl 12078 CBC 4299 : *use_variadic_p = use_variadic;
12079 : }
3730 tgl 12080 ECB : else
12081 : {
3293 tgl 12082 GIC 808 : Assert(!has_variadic);
3730 12083 808 : use_variadic = false;
3730 tgl 12084 ECB : }
12085 :
12086 : /*
7646 12087 : * The idea here is to schema-qualify only if the parser would fail to
12088 : * resolve the correct function given the unqualified func name with the
2885 andres 12089 : * specified argtypes and VARIADIC flag. But if we already decided to
12090 : * force qualification, then we can skip the lookup and pretend we didn't
12091 : * find it.
12092 : */
2885 andres 12093 CBC 5107 : if (!force_qualify)
2885 andres 12094 GIC 5107 : p_result = func_get_detail(list_make1(makeString(proname)),
2885 andres 12095 ECB : NIL, argnames, nargs, argtypes,
668 tgl 12096 CBC 5107 : !use_variadic, true, false,
2885 andres 12097 ECB : &p_funcid, &p_rettype,
12098 : &p_retset, &p_nvargs, &p_vatype,
2885 andres 12099 CBC 5107 : &p_true_typeids, NULL);
2885 andres 12100 ECB : else
12101 : {
2885 andres 12102 LBC 0 : p_result = FUNCDETAIL_NOTFOUND;
2885 andres 12103 UIC 0 : p_funcid = InvalidOid;
12104 : }
12105 :
5215 tgl 12106 GIC 5107 : if ((p_result == FUNCDETAIL_NORMAL ||
12107 589 : p_result == FUNCDETAIL_AGGREGATE ||
12108 4569 : p_result == FUNCDETAIL_WINDOWFUNC) &&
7219 12109 4569 : p_funcid == funcid)
7646 12110 4569 : nspname = NULL;
12111 : else
621 tgl 12112 CBC 538 : nspname = get_namespace_name_or_temp(procform->pronamespace);
12113 :
7646 tgl 12114 GIC 5107 : result = quote_qualified_identifier(nspname, proname);
12115 :
12116 5107 : ReleaseSysCache(proctup);
7646 tgl 12117 ECB :
7646 tgl 12118 CBC 5107 : return result;
7646 tgl 12119 ECB : }
12120 :
12121 : /*
12122 : * generate_operator_name
12123 : * Compute the name to display for an operator specified by OID,
12124 : * given that it is being called with the specified actual arg types.
12125 : * (Arg types matter because of ambiguous-operator resolution rules.
12126 : * Pass InvalidOid for unused arg of a unary operator.)
12127 : *
12128 : * The result includes all necessary quoting and schema-prefixing,
12129 : * plus the OPERATOR() decoration needed to use a qualified operator name
12130 : * in an expression.
12131 : */
12132 : static char *
7646 tgl 12133 GIC 26028 : generate_operator_name(Oid operid, Oid arg1, Oid arg2)
7646 tgl 12134 ECB : {
12135 : StringInfoData buf;
12136 : HeapTuple opertup;
7646 tgl 12137 EUB : Form_pg_operator operform;
7646 tgl 12138 ECB : char *oprname;
12139 : char *nspname;
12140 : Operator p_result;
12141 :
7646 tgl 12142 GIC 26028 : initStringInfo(&buf);
12143 :
4802 rhaas 12144 26028 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
7646 tgl 12145 26028 : if (!HeapTupleIsValid(opertup))
7196 tgl 12146 UIC 0 : elog(ERROR, "cache lookup failed for operator %u", operid);
7646 tgl 12147 GIC 26028 : operform = (Form_pg_operator) GETSTRUCT(opertup);
12148 26028 : oprname = NameStr(operform->oprname);
12149 :
12150 : /*
12151 : * The idea here is to schema-qualify only if the parser would fail to
7522 bruce 12152 ECB : * resolve the correct operator given the unqualified op name with the
12153 : * specified argtypes.
12154 : */
7646 tgl 12155 GIC 26028 : switch (operform->oprkind)
12156 : {
12157 26013 : case 'b':
6235 12158 26013 : p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
12159 : true, -1);
7646 12160 26013 : break;
12161 15 : case 'l':
6235 tgl 12162 CBC 15 : p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
6235 tgl 12163 ECB : true, -1);
7646 tgl 12164 GBC 15 : break;
7646 tgl 12165 LBC 0 : default:
7196 12166 0 : elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
12167 : p_result = NULL; /* keep compiler quiet */
12168 : break;
7646 tgl 12169 ECB : }
12170 :
7646 tgl 12171 GIC 26028 : if (p_result != NULL && oprid(p_result) == operid)
7646 tgl 12172 CBC 26023 : nspname = NULL;
12173 : else
12174 : {
621 12175 5 : nspname = get_namespace_name_or_temp(operform->oprnamespace);
7646 tgl 12176 GIC 5 : appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
7646 tgl 12177 ECB : }
12178 :
7008 neilc 12179 CBC 26028 : appendStringInfoString(&buf, oprname);
12180 :
7646 tgl 12181 GBC 26028 : if (nspname)
12182 5 : appendStringInfoChar(&buf, ')');
12183 :
7646 tgl 12184 GIC 26028 : if (p_result != NULL)
7646 tgl 12185 CBC 26023 : ReleaseSysCache(p_result);
7646 tgl 12186 EUB :
7646 tgl 12187 GIC 26028 : ReleaseSysCache(opertup);
12188 :
12189 26028 : return buf.data;
7646 tgl 12190 ECB : }
12191 :
12192 : /*
1847 12193 : * generate_operator_clause --- generate a binary-operator WHERE clause
12194 : *
12195 : * This is used for internally-generated-and-executed SQL queries, where
12196 : * precision is essential and readability is secondary. The basic
12197 : * requirement is to append "leftop op rightop" to buf, where leftop and
12198 : * rightop are given as strings and are assumed to yield types leftoptype
12199 : * and rightoptype; the operator is identified by OID. The complexity
12200 : * comes from needing to be sure that the parser will select the desired
12201 : * operator when the query is parsed. We always name the operator using
12202 : * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
12203 : * We have to emit casts too, if either input isn't already the input type
12204 : * of the operator; else we are at the mercy of the parser's heuristics for
12205 : * ambiguous-operator resolution. The caller must ensure that leftop and
12206 : * rightop are suitable arguments for a cast operation; it's best to insert
12207 : * parentheses if they aren't just variables or parameters.
12208 : */
12209 : void
1847 tgl 12210 GIC 2508 : generate_operator_clause(StringInfo buf,
12211 : const char *leftop, Oid leftoptype,
1847 tgl 12212 ECB : Oid opoid,
12213 : const char *rightop, Oid rightoptype)
12214 : {
12215 : HeapTuple opertup;
12216 : Form_pg_operator operform;
12217 : char *oprname;
12218 : char *nspname;
12219 :
1847 tgl 12220 CBC 2508 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
12221 2508 : if (!HeapTupleIsValid(opertup))
1847 tgl 12222 UBC 0 : elog(ERROR, "cache lookup failed for operator %u", opoid);
1847 tgl 12223 CBC 2508 : operform = (Form_pg_operator) GETSTRUCT(opertup);
12224 2508 : Assert(operform->oprkind == 'b');
1847 tgl 12225 GIC 2508 : oprname = NameStr(operform->oprname);
1847 tgl 12226 ECB :
1847 tgl 12227 CBC 2508 : nspname = get_namespace_name(operform->oprnamespace);
1847 tgl 12228 EUB :
1847 tgl 12229 GIC 2508 : appendStringInfoString(buf, leftop);
12230 2508 : if (leftoptype != operform->oprleft)
1847 tgl 12231 CBC 21 : add_cast_to(buf, operform->oprleft);
1847 tgl 12232 GIC 2508 : appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
1847 tgl 12233 CBC 2508 : appendStringInfoString(buf, oprname);
1847 tgl 12234 GIC 2508 : appendStringInfo(buf, ") %s", rightop);
1847 tgl 12235 CBC 2508 : if (rightoptype != operform->oprright)
1847 tgl 12236 GIC 30 : add_cast_to(buf, operform->oprright);
12237 :
12238 2508 : ReleaseSysCache(opertup);
12239 2508 : }
12240 :
12241 : /*
12242 : * Add a cast specification to buf. We spell out the type name the hard way,
12243 : * intentionally not using format_type_be(). This is to avoid corner cases
12244 : * for CHARACTER, BIT, and perhaps other types, where specifying the type
12245 : * using SQL-standard syntax results in undesirable data truncation. By
12246 : * doing it this way we can be certain that the cast will have default (-1)
12247 : * target typmod.
12248 : */
12249 : static void
12250 51 : add_cast_to(StringInfo buf, Oid typid)
12251 : {
12252 : HeapTuple typetup;
12253 : Form_pg_type typform;
1847 tgl 12254 ECB : char *typname;
12255 : char *nspname;
12256 :
1847 tgl 12257 GIC 51 : typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
12258 51 : if (!HeapTupleIsValid(typetup))
1847 tgl 12259 UIC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
1847 tgl 12260 GIC 51 : typform = (Form_pg_type) GETSTRUCT(typetup);
12261 :
12262 51 : typname = NameStr(typform->typname);
621 12263 51 : nspname = get_namespace_name_or_temp(typform->typnamespace);
12264 :
1847 12265 51 : appendStringInfo(buf, "::%s.%s",
12266 : quote_identifier(nspname), quote_identifier(typname));
12267 :
12268 51 : ReleaseSysCache(typetup);
12269 51 : }
12270 :
1985 tgl 12271 ECB : /*
12272 : * generate_qualified_type_name
12273 : * Compute the name to display for a type specified by OID
12274 : *
1985 tgl 12275 EUB : * This is different from format_type_be() in that we unconditionally
1985 tgl 12276 ECB : * schema-qualify the name. That also means no special syntax for
12277 : * SQL-standard type names ... although in current usage, this should
12278 : * only get used for domains, so such cases wouldn't occur anyway.
12279 : */
12280 : static char *
1985 tgl 12281 GIC 7 : generate_qualified_type_name(Oid typid)
12282 : {
1985 tgl 12283 ECB : HeapTuple tp;
12284 : Form_pg_type typtup;
1985 tgl 12285 EUB : char *typname;
12286 : char *nspname;
12287 : char *result;
12288 :
1985 tgl 12289 GIC 7 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
12290 7 : if (!HeapTupleIsValid(tp))
1985 tgl 12291 UIC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
1985 tgl 12292 GIC 7 : typtup = (Form_pg_type) GETSTRUCT(tp);
12293 7 : typname = NameStr(typtup->typname);
12294 :
621 12295 7 : nspname = get_namespace_name_or_temp(typtup->typnamespace);
1985 12296 7 : if (!nspname)
1985 tgl 12297 UIC 0 : elog(ERROR, "cache lookup failed for namespace %u",
12298 : typtup->typnamespace);
1985 tgl 12299 ECB :
1985 tgl 12300 GIC 7 : result = quote_qualified_identifier(nspname, typname);
12301 :
1985 tgl 12302 CBC 7 : ReleaseSysCache(tp);
1985 tgl 12303 ECB :
1985 tgl 12304 CBC 7 : return result;
12305 : }
12306 :
12307 : /*
4443 peter_e 12308 ECB : * generate_collation_name
12309 : * Compute the name to display for a collation specified by OID
12310 : *
12311 : * The result includes all necessary quoting and schema-prefixing.
12312 : */
12313 : char *
4443 peter_e 12314 GIC 155 : generate_collation_name(Oid collid)
12315 : {
12316 : HeapTuple tp;
12317 : Form_pg_collation colltup;
12318 : char *collname;
4443 peter_e 12319 ECB : char *nspname;
12320 : char *result;
12321 :
4443 peter_e 12322 CBC 155 : tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
4443 peter_e 12323 GIC 155 : if (!HeapTupleIsValid(tp))
4443 peter_e 12324 UIC 0 : elog(ERROR, "cache lookup failed for collation %u", collid);
4443 peter_e 12325 CBC 155 : colltup = (Form_pg_collation) GETSTRUCT(tp);
4443 peter_e 12326 GIC 155 : collname = NameStr(colltup->collname);
12327 :
4443 peter_e 12328 GBC 155 : if (!CollationIsVisible(collid))
621 tgl 12329 UBC 0 : nspname = get_namespace_name_or_temp(colltup->collnamespace);
12330 : else
4443 peter_e 12331 GIC 155 : nspname = NULL;
4443 peter_e 12332 ECB :
4443 peter_e 12333 CBC 155 : result = quote_qualified_identifier(nspname, collname);
4443 peter_e 12334 ECB :
4443 peter_e 12335 CBC 155 : ReleaseSysCache(tp);
4443 peter_e 12336 ECB :
4443 peter_e 12337 GIC 155 : return result;
4443 peter_e 12338 ECB : }
12339 :
6913 tgl 12340 : /*
12341 : * Given a C string, produce a TEXT datum.
12342 : *
12343 : * We assume that the input was palloc'd and may be freed.
12344 : */
12345 : static text *
6913 tgl 12346 GIC 18304 : string_to_text(char *str)
12347 : {
12348 : text *result;
12349 :
5493 12350 18304 : result = cstring_to_text(str);
6913 12351 18304 : pfree(str);
12352 18304 : return result;
12353 : }
12354 :
12355 : /*
12356 : * Generate a C string representing a relation options from text[] datum.
12357 : */
12358 : static void
1105 akorotkov 12359 CBC 120 : get_reloptions(StringInfo buf, Datum reloptions)
12360 : {
12361 : Datum *options;
12362 : int noptions;
12363 : int i;
12364 :
282 peter 12365 GNC 120 : deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
12366 : &options, NULL, &noptions);
1105 akorotkov 12367 ECB :
1105 akorotkov 12368 GIC 250 : for (i = 0; i < noptions; i++)
1105 akorotkov 12369 ECB : {
1105 akorotkov 12370 CBC 130 : char *option = TextDatumGetCString(options[i]);
1105 akorotkov 12371 EUB : char *name;
1105 akorotkov 12372 ECB : char *separator;
12373 : char *value;
12374 :
12375 : /*
12376 : * Each array element should have the form name=value. If the "=" is
12377 : * missing for some reason, treat it like an empty value.
12378 : */
1105 akorotkov 12379 GIC 130 : name = option;
1105 akorotkov 12380 CBC 130 : separator = strchr(option, '=');
1105 akorotkov 12381 GIC 130 : if (separator)
1105 akorotkov 12382 ECB : {
1105 akorotkov 12383 CBC 130 : *separator = '\0';
1105 akorotkov 12384 GIC 130 : value = separator + 1;
1105 akorotkov 12385 ECB : }
12386 : else
1105 akorotkov 12387 LBC 0 : value = "";
12388 :
1105 akorotkov 12389 CBC 130 : if (i > 0)
1105 akorotkov 12390 GBC 10 : appendStringInfoString(buf, ", ");
12391 130 : appendStringInfo(buf, "%s=", quote_identifier(name));
12392 :
12393 : /*
12394 : * In general we need to quote the value; but to avoid unnecessary
12395 : * clutter, do not quote if it is an identifier that would not need
1060 tgl 12396 ECB : * quoting. (We could also allow numbers, but that is a bit trickier
12397 : * than it looks --- for example, are leading zeroes significant? We
12398 : * don't want to assume very much here about what custom reloptions
12399 : * might mean.)
1105 akorotkov 12400 : */
1105 akorotkov 12401 CBC 130 : if (quote_identifier(value) == value)
1105 akorotkov 12402 GIC 4 : appendStringInfoString(buf, value);
12403 : else
1105 akorotkov 12404 CBC 126 : simple_quote_literal(buf, value);
12405 :
12406 130 : pfree(option);
1105 akorotkov 12407 ECB : }
1105 akorotkov 12408 GIC 120 : }
1105 akorotkov 12409 ECB :
6124 tgl 12410 : /*
12411 : * Generate a C string representing a relation's reloptions, or NULL if none.
12412 : */
12413 : static char *
6125 bruce 12414 CBC 2949 : flatten_reloptions(Oid relid)
12415 : {
6125 bruce 12416 GIC 2949 : char *result = NULL;
12417 : HeapTuple tuple;
12418 : Datum reloptions;
12419 : bool isnull;
12420 :
4802 rhaas 12421 2949 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
6124 tgl 12422 2949 : if (!HeapTupleIsValid(tuple))
6124 tgl 12423 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
12424 :
6124 tgl 12425 GIC 2949 : reloptions = SysCacheGetAttr(RELOID, tuple,
12426 : Anum_pg_class_reloptions, &isnull);
12427 2949 : if (!isnull)
12428 : {
12429 : StringInfoData buf;
12430 :
2655 12431 105 : initStringInfo(&buf);
1105 akorotkov 12432 105 : get_reloptions(&buf, reloptions);
12433 :
2655 tgl 12434 105 : result = buf.data;
6125 bruce 12435 ECB : }
12436 :
6124 tgl 12437 GIC 2949 : ReleaseSysCache(tuple);
12438 :
6125 bruce 12439 2949 : return result;
12440 : }
12441 :
12442 : /*
12443 : * get_range_partbound_string
12444 : * A C string representation of one range partition bound
2068 rhaas 12445 ECB : */
12446 : char *
2068 rhaas 12447 GBC 2034 : get_range_partbound_string(List *bound_datums)
2068 rhaas 12448 ECB : {
12449 : deparse_context context;
2068 rhaas 12450 CBC 2034 : StringInfo buf = makeStringInfo();
12451 : ListCell *cell;
2068 rhaas 12452 ECB : char *sep;
12453 :
2068 rhaas 12454 CBC 2034 : memset(&context, 0, sizeof(deparse_context));
12455 2034 : context.buf = buf;
2068 rhaas 12456 ECB :
906 drowley 12457 CBC 2034 : appendStringInfoChar(buf, '(');
2068 rhaas 12458 2034 : sep = "";
12459 4464 : foreach(cell, bound_datums)
2068 rhaas 12460 ECB : {
12461 : PartitionRangeDatum *datum =
629 peter 12462 GIC 2430 : lfirst_node(PartitionRangeDatum, cell);
2068 rhaas 12463 ECB :
2068 rhaas 12464 CBC 2430 : appendStringInfoString(buf, sep);
2068 rhaas 12465 GIC 2430 : if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
12466 111 : appendStringInfoString(buf, "MINVALUE");
12467 2319 : else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
12468 60 : appendStringInfoString(buf, "MAXVALUE");
12469 : else
12470 : {
12471 2259 : Const *val = castNode(Const, datum->value);
12472 :
12473 2259 : get_const_expr(val, &context, -1);
12474 : }
2068 rhaas 12475 CBC 2430 : sep = ", ";
12476 : }
2063 peter_e 12477 GIC 2034 : appendStringInfoChar(buf, ')');
12478 :
2068 rhaas 12479 2034 : return buf->data;
12480 : }
|