At update of non-LP_NORMAL TID, fail instead of corrupting page header.
[pgsql.git] / src / backend / utils / adt / ruleutils.c
blob54dad975553d2a6614a611c7dd4eedb81f22ea80
1 /*-------------------------------------------------------------------------
3 * ruleutils.c
4 * Functions to convert stored expressions/querytrees back to
5 * source text
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * IDENTIFICATION
12 * src/backend/utils/adt/ruleutils.c
14 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include <ctype.h>
19 #include <unistd.h>
20 #include <fcntl.h>
22 #include "access/amapi.h"
23 #include "access/htup_details.h"
24 #include "access/relation.h"
25 #include "access/table.h"
26 #include "catalog/pg_aggregate.h"
27 #include "catalog/pg_am.h"
28 #include "catalog/pg_authid.h"
29 #include "catalog/pg_collation.h"
30 #include "catalog/pg_constraint.h"
31 #include "catalog/pg_depend.h"
32 #include "catalog/pg_language.h"
33 #include "catalog/pg_opclass.h"
34 #include "catalog/pg_operator.h"
35 #include "catalog/pg_partitioned_table.h"
36 #include "catalog/pg_proc.h"
37 #include "catalog/pg_statistic_ext.h"
38 #include "catalog/pg_trigger.h"
39 #include "catalog/pg_type.h"
40 #include "commands/defrem.h"
41 #include "commands/tablespace.h"
42 #include "common/keywords.h"
43 #include "executor/spi.h"
44 #include "funcapi.h"
45 #include "mb/pg_wchar.h"
46 #include "miscadmin.h"
47 #include "nodes/makefuncs.h"
48 #include "nodes/nodeFuncs.h"
49 #include "nodes/pathnodes.h"
50 #include "optimizer/optimizer.h"
51 #include "parser/parse_agg.h"
52 #include "parser/parse_func.h"
53 #include "parser/parse_oper.h"
54 #include "parser/parse_relation.h"
55 #include "parser/parser.h"
56 #include "parser/parsetree.h"
57 #include "rewrite/rewriteHandler.h"
58 #include "rewrite/rewriteManip.h"
59 #include "rewrite/rewriteSupport.h"
60 #include "utils/array.h"
61 #include "utils/builtins.h"
62 #include "utils/fmgroids.h"
63 #include "utils/guc.h"
64 #include "utils/hsearch.h"
65 #include "utils/lsyscache.h"
66 #include "utils/partcache.h"
67 #include "utils/rel.h"
68 #include "utils/ruleutils.h"
69 #include "utils/snapmgr.h"
70 #include "utils/syscache.h"
71 #include "utils/typcache.h"
72 #include "utils/varlena.h"
73 #include "utils/xml.h"
75 /* ----------
76 * Pretty formatting constants
77 * ----------
80 /* Indent counts */
81 #define PRETTYINDENT_STD 8
82 #define PRETTYINDENT_JOIN 4
83 #define PRETTYINDENT_VAR 4
85 #define PRETTYINDENT_LIMIT 40 /* wrap limit */
87 /* Pretty flags */
88 #define PRETTYFLAG_PAREN 0x0001
89 #define PRETTYFLAG_INDENT 0x0002
90 #define PRETTYFLAG_SCHEMA 0x0004
92 /* Standard conversion of a "bool pretty" option to detailed flags */
93 #define GET_PRETTY_FLAGS(pretty) \
94 ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
95 : PRETTYFLAG_INDENT)
97 /* Default line length for pretty-print wrapping: 0 means wrap always */
98 #define WRAP_COLUMN_DEFAULT 0
100 /* macros to test if pretty action needed */
101 #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
102 #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
103 #define PRETTY_SCHEMA(context) ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
106 /* ----------
107 * Local data types
108 * ----------
111 /* Context info needed for invoking a recursive querytree display routine */
112 typedef struct
114 StringInfo buf; /* output buffer to append to */
115 List *namespaces; /* List of deparse_namespace nodes */
116 TupleDesc resultDesc; /* if top level of a view, the view's tupdesc */
117 List *targetList; /* Current query level's SELECT targetlist */
118 List *windowClause; /* Current query level's WINDOW clause */
119 int prettyFlags; /* enabling of pretty-print functions */
120 int wrapColumn; /* max line length, or -1 for no limit */
121 int indentLevel; /* current indent level for pretty-print */
122 bool varprefix; /* true to print prefixes on Vars */
123 bool colNamesVisible; /* do we care about output column names? */
124 bool inGroupBy; /* deparsing GROUP BY clause? */
125 bool varInOrderBy; /* deparsing simple Var in ORDER BY? */
126 Bitmapset *appendparents; /* if not null, map child Vars of these relids
127 * back to the parent rel */
128 } deparse_context;
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.
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.
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.
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.
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.)
162 typedef struct
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 char *ret_old_alias; /* alias for OLD in RETURNING list */
171 char *ret_new_alias; /* alias for NEW in RETURNING list */
172 /* Workspace for column alias assignment: */
173 bool unique_using; /* Are we making USING names globally unique */
174 List *using_names; /* List of assigned names for USING columns */
175 /* Remaining fields are used only when deparsing a Plan tree: */
176 Plan *plan; /* immediate parent of current expression */
177 List *ancestors; /* ancestors of plan */
178 Plan *outer_plan; /* outer subnode, or NULL if none */
179 Plan *inner_plan; /* inner subnode, or NULL if none */
180 List *outer_tlist; /* referent for OUTER_VAR Vars */
181 List *inner_tlist; /* referent for INNER_VAR Vars */
182 List *index_tlist; /* referent for INDEX_VAR Vars */
183 /* Special namespace representing a function signature: */
184 char *funcname;
185 int numargs;
186 char **argnames;
187 } deparse_namespace;
190 * Per-relation data about column alias names.
192 * Selecting aliases is unreasonably complicated because of the need to dump
193 * rules/views whose underlying tables may have had columns added, deleted, or
194 * renamed since the query was parsed. We must nonetheless print the rule/view
195 * in a form that can be reloaded and will produce the same results as before.
197 * For each RTE used in the query, we must assign column aliases that are
198 * unique within that RTE. SQL does not require this of the original query,
199 * but due to factors such as *-expansion we need to be able to uniquely
200 * reference every column in a decompiled query. As long as we qualify all
201 * column references, per-RTE uniqueness is sufficient for that.
203 * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
204 * since they just inherit column names from their input RTEs, and we can't
205 * rename the columns at the join level. Most of the time this isn't an issue
206 * because we don't need to reference the join's output columns as such; we
207 * can reference the input columns instead. That approach can fail for merged
208 * JOIN USING columns, however, so when we have one of those in an unnamed
209 * join, we have to make that column's alias globally unique across the whole
210 * query to ensure it can be referenced unambiguously.
212 * Another problem is that a JOIN USING clause requires the columns to be
213 * merged to have the same aliases in both input RTEs, and that no other
214 * columns in those RTEs or their children conflict with the USING names.
215 * To handle that, we do USING-column alias assignment in a recursive
216 * traversal of the query's jointree. When descending through a JOIN with
217 * USING, we preassign the USING column names to the child columns, overriding
218 * other rules for column alias assignment. We also mark each RTE with a list
219 * of all USING column names selected for joins containing that RTE, so that
220 * when we assign other columns' aliases later, we can avoid conflicts.
222 * Another problem is that if a JOIN's input tables have had columns added or
223 * deleted since the query was parsed, we must generate a column alias list
224 * for the join that matches the current set of input columns --- otherwise, a
225 * change in the number of columns in the left input would throw off matching
226 * of aliases to columns of the right input. Thus, positions in the printable
227 * column alias list are not necessarily one-for-one with varattnos of the
228 * JOIN, so we need a separate new_colnames[] array for printing purposes.
230 * Finally, when dealing with wide tables we risk O(N^2) costs in assigning
231 * non-duplicate column names. We ameliorate that by using a hash table that
232 * holds all the strings appearing in colnames, new_colnames, and parentUsing.
234 typedef struct
237 * colnames is an array containing column aliases to use for columns that
238 * existed when the query was parsed. Dropped columns have NULL entries.
239 * This array can be directly indexed by varattno to get a Var's name.
241 * Non-NULL entries are guaranteed unique within the RTE, *except* when
242 * this is for an unnamed JOIN RTE. In that case we merely copy up names
243 * from the two input RTEs.
245 * During the recursive descent in set_using_names(), forcible assignment
246 * of a child RTE's column name is represented by pre-setting that element
247 * of the child's colnames array. So at that stage, NULL entries in this
248 * array just mean that no name has been preassigned, not necessarily that
249 * the column is dropped.
251 int num_cols; /* length of colnames[] array */
252 char **colnames; /* array of C strings and NULLs */
255 * new_colnames is an array containing column aliases to use for columns
256 * that would exist if the query was re-parsed against the current
257 * definitions of its base tables. This is what to print as the column
258 * alias list for the RTE. This array does not include dropped columns,
259 * but it will include columns added since original parsing. Indexes in
260 * it therefore have little to do with current varattno values. As above,
261 * entries are unique unless this is for an unnamed JOIN RTE. (In such an
262 * RTE, we never actually print this array, but we must compute it anyway
263 * for possible use in computing column names of upper joins.) The
264 * parallel array is_new_col marks which of these columns are new since
265 * original parsing. Entries with is_new_col false must match the
266 * non-NULL colnames entries one-for-one.
268 int num_new_cols; /* length of new_colnames[] array */
269 char **new_colnames; /* array of C strings */
270 bool *is_new_col; /* array of bool flags */
272 /* This flag tells whether we should actually print a column alias list */
273 bool printaliases;
275 /* This list has all names used as USING names in joins above this RTE */
276 List *parentUsing; /* names assigned to parent merged columns */
279 * If this struct is for a JOIN RTE, we fill these fields during the
280 * set_using_names() pass to describe its relationship to its child RTEs.
282 * leftattnos and rightattnos are arrays with one entry per existing
283 * output column of the join (hence, indexable by join varattno). For a
284 * simple reference to a column of the left child, leftattnos[i] is the
285 * child RTE's attno and rightattnos[i] is zero; and conversely for a
286 * column of the right child. But for merged columns produced by JOIN
287 * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
288 * Note that a simple reference might be to a child RTE column that's been
289 * dropped; but that's OK since the column could not be used in the query.
291 * If it's a JOIN USING, usingNames holds the alias names selected for the
292 * merged columns (these might be different from the original USING list,
293 * if we had to modify names to achieve uniqueness).
295 int leftrti; /* rangetable index of left child */
296 int rightrti; /* rangetable index of right child */
297 int *leftattnos; /* left-child varattnos of join cols, or 0 */
298 int *rightattnos; /* right-child varattnos of join cols, or 0 */
299 List *usingNames; /* names assigned to merged columns */
302 * Hash table holding copies of all the strings appearing in this struct's
303 * colnames, new_colnames, and parentUsing. We use a hash table only for
304 * sufficiently wide relations, and only during the colname-assignment
305 * functions set_relation_column_names and set_join_column_names;
306 * otherwise, names_hash is NULL.
308 HTAB *names_hash; /* entries are just strings */
309 } deparse_columns;
311 /* This macro is analogous to rt_fetch(), but for deparse_columns structs */
312 #define deparse_columns_fetch(rangetable_index, dpns) \
313 ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
316 * Entry in set_rtable_names' hash table
318 typedef struct
320 char name[NAMEDATALEN]; /* Hash key --- must be first */
321 int counter; /* Largest addition used so far for name */
322 } NameHashEntry;
324 /* Callback signature for resolve_special_varno() */
325 typedef void (*rsv_callback) (Node *node, deparse_context *context,
326 void *callback_arg);
329 /* ----------
330 * Global data
331 * ----------
333 static SPIPlanPtr plan_getrulebyoid = NULL;
334 static const char *const query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
335 static SPIPlanPtr plan_getviewrule = NULL;
336 static const char *const query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
338 /* GUC parameters */
339 bool quote_all_identifiers = false;
342 /* ----------
343 * Local functions
345 * Most of these functions used to use fixed-size buffers to build their
346 * results. Now, they take an (already initialized) StringInfo object
347 * as a parameter, and append their text output to its contents.
348 * ----------
350 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
351 bool forceprefix, bool showimplicit,
352 int prettyFlags, int startIndent);
353 static char *pg_get_viewdef_worker(Oid viewoid,
354 int prettyFlags, int wrapColumn);
355 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
356 static int decompile_column_index_array(Datum column_index_array, Oid relId,
357 bool withPeriod, StringInfo buf);
358 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
359 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
360 const Oid *excludeOps,
361 bool attrsOnly, bool keysOnly,
362 bool showTblSpc, bool inherits,
363 int prettyFlags, bool missing_ok);
364 static char *pg_get_statisticsobj_worker(Oid statextid, bool columns_only,
365 bool missing_ok);
366 static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
367 bool attrsOnly, bool missing_ok);
368 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
369 int prettyFlags, bool missing_ok);
370 static text *pg_get_expr_worker(text *expr, Oid relid, int prettyFlags);
371 static int print_function_arguments(StringInfo buf, HeapTuple proctup,
372 bool print_table_args, bool print_defaults);
373 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
374 static void print_function_trftypes(StringInfo buf, HeapTuple proctup);
375 static void print_function_sqlbody(StringInfo buf, HeapTuple proctup);
376 static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
377 Bitmapset *rels_used);
378 static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
379 List *parent_namespaces);
380 static void set_simple_column_names(deparse_namespace *dpns);
381 static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode);
382 static void set_using_names(deparse_namespace *dpns, Node *jtnode,
383 List *parentUsing);
384 static void set_relation_column_names(deparse_namespace *dpns,
385 RangeTblEntry *rte,
386 deparse_columns *colinfo);
387 static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
388 deparse_columns *colinfo);
389 static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
390 deparse_columns *colinfo);
391 static char *make_colname_unique(char *colname, deparse_namespace *dpns,
392 deparse_columns *colinfo);
393 static void expand_colnames_array_to(deparse_columns *colinfo, int n);
394 static void build_colinfo_names_hash(deparse_columns *colinfo);
395 static void add_to_names_hash(deparse_columns *colinfo, const char *name);
396 static void destroy_colinfo_names_hash(deparse_columns *colinfo);
397 static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
398 deparse_columns *colinfo);
399 static char *get_rtable_name(int rtindex, deparse_context *context);
400 static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
401 static Plan *find_recursive_union(deparse_namespace *dpns,
402 WorkTableScan *wtscan);
403 static void push_child_plan(deparse_namespace *dpns, Plan *plan,
404 deparse_namespace *save_dpns);
405 static void pop_child_plan(deparse_namespace *dpns,
406 deparse_namespace *save_dpns);
407 static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
408 deparse_namespace *save_dpns);
409 static void pop_ancestor_plan(deparse_namespace *dpns,
410 deparse_namespace *save_dpns);
411 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
412 int prettyFlags);
413 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
414 int prettyFlags, int wrapColumn);
415 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
416 TupleDesc resultDesc, bool colNamesVisible,
417 int prettyFlags, int wrapColumn, int startIndent);
418 static void get_values_def(List *values_lists, deparse_context *context);
419 static void get_with_clause(Query *query, deparse_context *context);
420 static void get_select_query_def(Query *query, deparse_context *context);
421 static void get_insert_query_def(Query *query, deparse_context *context);
422 static void get_update_query_def(Query *query, deparse_context *context);
423 static void get_update_query_targetlist_def(Query *query, List *targetList,
424 deparse_context *context,
425 RangeTblEntry *rte);
426 static void get_delete_query_def(Query *query, deparse_context *context);
427 static void get_merge_query_def(Query *query, deparse_context *context);
428 static void get_utility_query_def(Query *query, deparse_context *context);
429 static void get_basic_select_query(Query *query, deparse_context *context);
430 static void get_target_list(List *targetList, deparse_context *context);
431 static void get_returning_clause(Query *query, deparse_context *context);
432 static void get_setop_query(Node *setOp, Query *query,
433 deparse_context *context);
434 static Node *get_rule_sortgroupclause(Index ref, List *tlist,
435 bool force_colno,
436 deparse_context *context);
437 static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
438 bool omit_parens, deparse_context *context);
439 static void get_rule_orderby(List *orderList, List *targetList,
440 bool force_colno, deparse_context *context);
441 static void get_rule_windowclause(Query *query, deparse_context *context);
442 static void get_rule_windowspec(WindowClause *wc, List *targetList,
443 deparse_context *context);
444 static char *get_variable(Var *var, int levelsup, bool istoplevel,
445 deparse_context *context);
446 static void get_special_variable(Node *node, deparse_context *context,
447 void *callback_arg);
448 static void resolve_special_varno(Node *node, deparse_context *context,
449 rsv_callback callback, void *callback_arg);
450 static Node *find_param_referent(Param *param, deparse_context *context,
451 deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
452 static SubPlan *find_param_generator(Param *param, deparse_context *context,
453 int *column_p);
454 static SubPlan *find_param_generator_initplan(Param *param, Plan *plan,
455 int *column_p);
456 static void get_parameter(Param *param, deparse_context *context);
457 static const char *get_simple_binary_op_name(OpExpr *expr);
458 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
459 static void appendContextKeyword(deparse_context *context, const char *str,
460 int indentBefore, int indentAfter, int indentPlus);
461 static void removeStringInfoSpaces(StringInfo str);
462 static void get_rule_expr(Node *node, deparse_context *context,
463 bool showimplicit);
464 static void get_rule_expr_toplevel(Node *node, deparse_context *context,
465 bool showimplicit);
466 static void get_rule_list_toplevel(List *lst, deparse_context *context,
467 bool showimplicit);
468 static void get_rule_expr_funccall(Node *node, deparse_context *context,
469 bool showimplicit);
470 static bool looks_like_function(Node *node);
471 static void get_oper_expr(OpExpr *expr, deparse_context *context);
472 static void get_func_expr(FuncExpr *expr, deparse_context *context,
473 bool showimplicit);
474 static void get_agg_expr(Aggref *aggref, deparse_context *context,
475 Aggref *original_aggref);
476 static void get_agg_expr_helper(Aggref *aggref, deparse_context *context,
477 Aggref *original_aggref, const char *funcname,
478 const char *options, bool is_json_objectagg);
479 static void get_agg_combine_expr(Node *node, deparse_context *context,
480 void *callback_arg);
481 static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
482 static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
483 const char *funcname, const char *options,
484 bool is_json_objectagg);
485 static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context);
486 static void get_coercion_expr(Node *arg, deparse_context *context,
487 Oid resulttype, int32 resulttypmod,
488 Node *parentNode);
489 static void get_const_expr(Const *constval, deparse_context *context,
490 int showtype);
491 static void get_const_collation(Const *constval, deparse_context *context);
492 static void get_json_format(JsonFormat *format, StringInfo buf);
493 static void get_json_returning(JsonReturning *returning, StringInfo buf,
494 bool json_format_by_default);
495 static void get_json_constructor(JsonConstructorExpr *ctor,
496 deparse_context *context, bool showimplicit);
497 static void get_json_constructor_options(JsonConstructorExpr *ctor,
498 StringInfo buf);
499 static void get_json_agg_constructor(JsonConstructorExpr *ctor,
500 deparse_context *context,
501 const char *funcname,
502 bool is_json_objectagg);
503 static void simple_quote_literal(StringInfo buf, const char *val);
504 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
505 static void get_tablefunc(TableFunc *tf, deparse_context *context,
506 bool showimplicit);
507 static void get_from_clause(Query *query, const char *prefix,
508 deparse_context *context);
509 static void get_from_clause_item(Node *jtnode, Query *query,
510 deparse_context *context);
511 static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
512 deparse_context *context);
513 static void get_column_alias_list(deparse_columns *colinfo,
514 deparse_context *context);
515 static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
516 deparse_columns *colinfo,
517 deparse_context *context);
518 static void get_tablesample_def(TableSampleClause *tablesample,
519 deparse_context *context);
520 static void get_opclass_name(Oid opclass, Oid actual_datatype,
521 StringInfo buf);
522 static Node *processIndirection(Node *node, deparse_context *context);
523 static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
524 static char *get_relation_name(Oid relid);
525 static char *generate_relation_name(Oid relid, List *namespaces);
526 static char *generate_qualified_relation_name(Oid relid);
527 static char *generate_function_name(Oid funcid, int nargs,
528 List *argnames, Oid *argtypes,
529 bool has_variadic, bool *use_variadic_p,
530 bool inGroupBy);
531 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
532 static void add_cast_to(StringInfo buf, Oid typid);
533 static char *generate_qualified_type_name(Oid typid);
534 static text *string_to_text(char *str);
535 static char *flatten_reloptions(Oid relid);
536 static void get_reloptions(StringInfo buf, Datum reloptions);
537 static void get_json_path_spec(Node *path_spec, deparse_context *context,
538 bool showimplicit);
539 static void get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan,
540 deparse_context *context,
541 bool showimplicit);
542 static void get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan,
543 deparse_context *context,
544 bool showimplicit,
545 bool needcomma);
547 #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
550 /* ----------
551 * pg_get_ruledef - Do it all and return a text
552 * that could be used as a statement
553 * to recreate the rule
554 * ----------
556 Datum
557 pg_get_ruledef(PG_FUNCTION_ARGS)
559 Oid ruleoid = PG_GETARG_OID(0);
560 int prettyFlags;
561 char *res;
563 prettyFlags = PRETTYFLAG_INDENT;
565 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
567 if (res == NULL)
568 PG_RETURN_NULL();
570 PG_RETURN_TEXT_P(string_to_text(res));
574 Datum
575 pg_get_ruledef_ext(PG_FUNCTION_ARGS)
577 Oid ruleoid = PG_GETARG_OID(0);
578 bool pretty = PG_GETARG_BOOL(1);
579 int prettyFlags;
580 char *res;
582 prettyFlags = GET_PRETTY_FLAGS(pretty);
584 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
586 if (res == NULL)
587 PG_RETURN_NULL();
589 PG_RETURN_TEXT_P(string_to_text(res));
593 static char *
594 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
596 Datum args[1];
597 char nulls[1];
598 int spirc;
599 HeapTuple ruletup;
600 TupleDesc rulettc;
601 StringInfoData buf;
604 * Do this first so that string is alloc'd in outer context not SPI's.
606 initStringInfo(&buf);
609 * Connect to SPI manager
611 SPI_connect();
614 * On the first call prepare the plan to lookup pg_rewrite. We read
615 * pg_rewrite over the SPI manager instead of using the syscache to be
616 * checked for read access on pg_rewrite.
618 if (plan_getrulebyoid == NULL)
620 Oid argtypes[1];
621 SPIPlanPtr plan;
623 argtypes[0] = OIDOID;
624 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
625 if (plan == NULL)
626 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
627 SPI_keepplan(plan);
628 plan_getrulebyoid = plan;
632 * Get the pg_rewrite tuple for this rule
634 args[0] = ObjectIdGetDatum(ruleoid);
635 nulls[0] = ' ';
636 spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
637 if (spirc != SPI_OK_SELECT)
638 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
639 if (SPI_processed != 1)
642 * There is no tuple data available here, just keep the output buffer
643 * empty.
646 else
649 * Get the rule's definition and put it into executor's memory
651 ruletup = SPI_tuptable->vals[0];
652 rulettc = SPI_tuptable->tupdesc;
653 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
657 * Disconnect from SPI manager
659 if (SPI_finish() != SPI_OK_FINISH)
660 elog(ERROR, "SPI_finish failed");
662 if (buf.len == 0)
663 return NULL;
665 return buf.data;
669 /* ----------
670 * pg_get_viewdef - Mainly the same thing, but we
671 * only return the SELECT part of a view
672 * ----------
674 Datum
675 pg_get_viewdef(PG_FUNCTION_ARGS)
677 /* By OID */
678 Oid viewoid = PG_GETARG_OID(0);
679 int prettyFlags;
680 char *res;
682 prettyFlags = PRETTYFLAG_INDENT;
684 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
686 if (res == NULL)
687 PG_RETURN_NULL();
689 PG_RETURN_TEXT_P(string_to_text(res));
693 Datum
694 pg_get_viewdef_ext(PG_FUNCTION_ARGS)
696 /* By OID */
697 Oid viewoid = PG_GETARG_OID(0);
698 bool pretty = PG_GETARG_BOOL(1);
699 int prettyFlags;
700 char *res;
702 prettyFlags = GET_PRETTY_FLAGS(pretty);
704 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
706 if (res == NULL)
707 PG_RETURN_NULL();
709 PG_RETURN_TEXT_P(string_to_text(res));
712 Datum
713 pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
715 /* By OID */
716 Oid viewoid = PG_GETARG_OID(0);
717 int wrap = PG_GETARG_INT32(1);
718 int prettyFlags;
719 char *res;
721 /* calling this implies we want pretty printing */
722 prettyFlags = GET_PRETTY_FLAGS(true);
724 res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
726 if (res == NULL)
727 PG_RETURN_NULL();
729 PG_RETURN_TEXT_P(string_to_text(res));
732 Datum
733 pg_get_viewdef_name(PG_FUNCTION_ARGS)
735 /* By qualified name */
736 text *viewname = PG_GETARG_TEXT_PP(0);
737 int prettyFlags;
738 RangeVar *viewrel;
739 Oid viewoid;
740 char *res;
742 prettyFlags = PRETTYFLAG_INDENT;
744 /* Look up view name. Can't lock it - we might not have privileges. */
745 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
746 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
748 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
750 if (res == NULL)
751 PG_RETURN_NULL();
753 PG_RETURN_TEXT_P(string_to_text(res));
757 Datum
758 pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
760 /* By qualified name */
761 text *viewname = PG_GETARG_TEXT_PP(0);
762 bool pretty = PG_GETARG_BOOL(1);
763 int prettyFlags;
764 RangeVar *viewrel;
765 Oid viewoid;
766 char *res;
768 prettyFlags = GET_PRETTY_FLAGS(pretty);
770 /* Look up view name. Can't lock it - we might not have privileges. */
771 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
772 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
774 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
776 if (res == NULL)
777 PG_RETURN_NULL();
779 PG_RETURN_TEXT_P(string_to_text(res));
783 * Common code for by-OID and by-name variants of pg_get_viewdef
785 static char *
786 pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
788 Datum args[2];
789 char nulls[2];
790 int spirc;
791 HeapTuple ruletup;
792 TupleDesc rulettc;
793 StringInfoData buf;
796 * Do this first so that string is alloc'd in outer context not SPI's.
798 initStringInfo(&buf);
801 * Connect to SPI manager
803 SPI_connect();
806 * On the first call prepare the plan to lookup pg_rewrite. We read
807 * pg_rewrite over the SPI manager instead of using the syscache to be
808 * checked for read access on pg_rewrite.
810 if (plan_getviewrule == NULL)
812 Oid argtypes[2];
813 SPIPlanPtr plan;
815 argtypes[0] = OIDOID;
816 argtypes[1] = NAMEOID;
817 plan = SPI_prepare(query_getviewrule, 2, argtypes);
818 if (plan == NULL)
819 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
820 SPI_keepplan(plan);
821 plan_getviewrule = plan;
825 * Get the pg_rewrite tuple for the view's SELECT rule
827 args[0] = ObjectIdGetDatum(viewoid);
828 args[1] = DirectFunctionCall1(namein, CStringGetDatum(ViewSelectRuleName));
829 nulls[0] = ' ';
830 nulls[1] = ' ';
831 spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
832 if (spirc != SPI_OK_SELECT)
833 elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
834 if (SPI_processed != 1)
837 * There is no tuple data available here, just keep the output buffer
838 * empty.
841 else
844 * Get the rule's definition and put it into executor's memory
846 ruletup = SPI_tuptable->vals[0];
847 rulettc = SPI_tuptable->tupdesc;
848 make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
852 * Disconnect from SPI manager
854 if (SPI_finish() != SPI_OK_FINISH)
855 elog(ERROR, "SPI_finish failed");
857 if (buf.len == 0)
858 return NULL;
860 return buf.data;
863 /* ----------
864 * pg_get_triggerdef - Get the definition of a trigger
865 * ----------
867 Datum
868 pg_get_triggerdef(PG_FUNCTION_ARGS)
870 Oid trigid = PG_GETARG_OID(0);
871 char *res;
873 res = pg_get_triggerdef_worker(trigid, false);
875 if (res == NULL)
876 PG_RETURN_NULL();
878 PG_RETURN_TEXT_P(string_to_text(res));
881 Datum
882 pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
884 Oid trigid = PG_GETARG_OID(0);
885 bool pretty = PG_GETARG_BOOL(1);
886 char *res;
888 res = pg_get_triggerdef_worker(trigid, pretty);
890 if (res == NULL)
891 PG_RETURN_NULL();
893 PG_RETURN_TEXT_P(string_to_text(res));
896 static char *
897 pg_get_triggerdef_worker(Oid trigid, bool pretty)
899 HeapTuple ht_trig;
900 Form_pg_trigger trigrec;
901 StringInfoData buf;
902 Relation tgrel;
903 ScanKeyData skey[1];
904 SysScanDesc tgscan;
905 int findx = 0;
906 char *tgname;
907 char *tgoldtable;
908 char *tgnewtable;
909 Datum value;
910 bool isnull;
913 * Fetch the pg_trigger tuple by the Oid of the trigger
915 tgrel = table_open(TriggerRelationId, AccessShareLock);
917 ScanKeyInit(&skey[0],
918 Anum_pg_trigger_oid,
919 BTEqualStrategyNumber, F_OIDEQ,
920 ObjectIdGetDatum(trigid));
922 tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
923 NULL, 1, skey);
925 ht_trig = systable_getnext(tgscan);
927 if (!HeapTupleIsValid(ht_trig))
929 systable_endscan(tgscan);
930 table_close(tgrel, AccessShareLock);
931 return NULL;
934 trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
937 * Start the trigger definition. Note that the trigger's name should never
938 * be schema-qualified, but the trigger rel's name may be.
940 initStringInfo(&buf);
942 tgname = NameStr(trigrec->tgname);
943 appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
944 OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
945 quote_identifier(tgname));
947 if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
948 appendStringInfoString(&buf, "BEFORE");
949 else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
950 appendStringInfoString(&buf, "AFTER");
951 else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
952 appendStringInfoString(&buf, "INSTEAD OF");
953 else
954 elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
956 if (TRIGGER_FOR_INSERT(trigrec->tgtype))
958 appendStringInfoString(&buf, " INSERT");
959 findx++;
961 if (TRIGGER_FOR_DELETE(trigrec->tgtype))
963 if (findx > 0)
964 appendStringInfoString(&buf, " OR DELETE");
965 else
966 appendStringInfoString(&buf, " DELETE");
967 findx++;
969 if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
971 if (findx > 0)
972 appendStringInfoString(&buf, " OR UPDATE");
973 else
974 appendStringInfoString(&buf, " UPDATE");
975 findx++;
976 /* tgattr is first var-width field, so OK to access directly */
977 if (trigrec->tgattr.dim1 > 0)
979 int i;
981 appendStringInfoString(&buf, " OF ");
982 for (i = 0; i < trigrec->tgattr.dim1; i++)
984 char *attname;
986 if (i > 0)
987 appendStringInfoString(&buf, ", ");
988 attname = get_attname(trigrec->tgrelid,
989 trigrec->tgattr.values[i], false);
990 appendStringInfoString(&buf, quote_identifier(attname));
994 if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
996 if (findx > 0)
997 appendStringInfoString(&buf, " OR TRUNCATE");
998 else
999 appendStringInfoString(&buf, " TRUNCATE");
1000 findx++;
1004 * In non-pretty mode, always schema-qualify the target table name for
1005 * safety. In pretty mode, schema-qualify only if not visible.
1007 appendStringInfo(&buf, " ON %s ",
1008 pretty ?
1009 generate_relation_name(trigrec->tgrelid, NIL) :
1010 generate_qualified_relation_name(trigrec->tgrelid));
1012 if (OidIsValid(trigrec->tgconstraint))
1014 if (OidIsValid(trigrec->tgconstrrelid))
1015 appendStringInfo(&buf, "FROM %s ",
1016 generate_relation_name(trigrec->tgconstrrelid, NIL));
1017 if (!trigrec->tgdeferrable)
1018 appendStringInfoString(&buf, "NOT ");
1019 appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
1020 if (trigrec->tginitdeferred)
1021 appendStringInfoString(&buf, "DEFERRED ");
1022 else
1023 appendStringInfoString(&buf, "IMMEDIATE ");
1026 value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
1027 tgrel->rd_att, &isnull);
1028 if (!isnull)
1029 tgoldtable = NameStr(*DatumGetName(value));
1030 else
1031 tgoldtable = NULL;
1032 value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
1033 tgrel->rd_att, &isnull);
1034 if (!isnull)
1035 tgnewtable = NameStr(*DatumGetName(value));
1036 else
1037 tgnewtable = NULL;
1038 if (tgoldtable != NULL || tgnewtable != NULL)
1040 appendStringInfoString(&buf, "REFERENCING ");
1041 if (tgoldtable != NULL)
1042 appendStringInfo(&buf, "OLD TABLE AS %s ",
1043 quote_identifier(tgoldtable));
1044 if (tgnewtable != NULL)
1045 appendStringInfo(&buf, "NEW TABLE AS %s ",
1046 quote_identifier(tgnewtable));
1049 if (TRIGGER_FOR_ROW(trigrec->tgtype))
1050 appendStringInfoString(&buf, "FOR EACH ROW ");
1051 else
1052 appendStringInfoString(&buf, "FOR EACH STATEMENT ");
1054 /* If the trigger has a WHEN qualification, add that */
1055 value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
1056 tgrel->rd_att, &isnull);
1057 if (!isnull)
1059 Node *qual;
1060 char relkind;
1061 deparse_context context;
1062 deparse_namespace dpns;
1063 RangeTblEntry *oldrte;
1064 RangeTblEntry *newrte;
1066 appendStringInfoString(&buf, "WHEN (");
1068 qual = stringToNode(TextDatumGetCString(value));
1070 relkind = get_rel_relkind(trigrec->tgrelid);
1072 /* Build minimal OLD and NEW RTEs for the rel */
1073 oldrte = makeNode(RangeTblEntry);
1074 oldrte->rtekind = RTE_RELATION;
1075 oldrte->relid = trigrec->tgrelid;
1076 oldrte->relkind = relkind;
1077 oldrte->rellockmode = AccessShareLock;
1078 oldrte->alias = makeAlias("old", NIL);
1079 oldrte->eref = oldrte->alias;
1080 oldrte->lateral = false;
1081 oldrte->inh = false;
1082 oldrte->inFromCl = true;
1084 newrte = makeNode(RangeTblEntry);
1085 newrte->rtekind = RTE_RELATION;
1086 newrte->relid = trigrec->tgrelid;
1087 newrte->relkind = relkind;
1088 newrte->rellockmode = AccessShareLock;
1089 newrte->alias = makeAlias("new", NIL);
1090 newrte->eref = newrte->alias;
1091 newrte->lateral = false;
1092 newrte->inh = false;
1093 newrte->inFromCl = true;
1095 /* Build two-element rtable */
1096 memset(&dpns, 0, sizeof(dpns));
1097 dpns.rtable = list_make2(oldrte, newrte);
1098 dpns.subplans = NIL;
1099 dpns.ctes = NIL;
1100 dpns.appendrels = NULL;
1101 set_rtable_names(&dpns, NIL, NULL);
1102 set_simple_column_names(&dpns);
1104 /* Set up context with one-deep namespace stack */
1105 context.buf = &buf;
1106 context.namespaces = list_make1(&dpns);
1107 context.resultDesc = NULL;
1108 context.targetList = NIL;
1109 context.windowClause = NIL;
1110 context.varprefix = true;
1111 context.prettyFlags = GET_PRETTY_FLAGS(pretty);
1112 context.wrapColumn = WRAP_COLUMN_DEFAULT;
1113 context.indentLevel = PRETTYINDENT_STD;
1114 context.colNamesVisible = true;
1115 context.inGroupBy = false;
1116 context.varInOrderBy = false;
1117 context.appendparents = NULL;
1119 get_rule_expr(qual, &context, false);
1121 appendStringInfoString(&buf, ") ");
1124 appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
1125 generate_function_name(trigrec->tgfoid, 0,
1126 NIL, NULL,
1127 false, NULL, false));
1129 if (trigrec->tgnargs > 0)
1131 char *p;
1132 int i;
1134 value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
1135 tgrel->rd_att, &isnull);
1136 if (isnull)
1137 elog(ERROR, "tgargs is null for trigger %u", trigid);
1138 p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1139 for (i = 0; i < trigrec->tgnargs; i++)
1141 if (i > 0)
1142 appendStringInfoString(&buf, ", ");
1143 simple_quote_literal(&buf, p);
1144 /* advance p to next string embedded in tgargs */
1145 while (*p)
1146 p++;
1147 p++;
1151 /* We deliberately do not put semi-colon at end */
1152 appendStringInfoChar(&buf, ')');
1154 /* Clean up */
1155 systable_endscan(tgscan);
1157 table_close(tgrel, AccessShareLock);
1159 return buf.data;
1162 /* ----------
1163 * pg_get_indexdef - Get the definition of an index
1165 * In the extended version, there is a colno argument as well as pretty bool.
1166 * if colno == 0, we want a complete index definition.
1167 * if colno > 0, we only want the Nth index key's variable or expression.
1169 * Note that the SQL-function versions of this omit any info about the
1170 * index tablespace; this is intentional because pg_dump wants it that way.
1171 * However pg_get_indexdef_string() includes the index tablespace.
1172 * ----------
1174 Datum
1175 pg_get_indexdef(PG_FUNCTION_ARGS)
1177 Oid indexrelid = PG_GETARG_OID(0);
1178 int prettyFlags;
1179 char *res;
1181 prettyFlags = PRETTYFLAG_INDENT;
1183 res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1184 false, false,
1185 false, false,
1186 prettyFlags, true);
1188 if (res == NULL)
1189 PG_RETURN_NULL();
1191 PG_RETURN_TEXT_P(string_to_text(res));
1194 Datum
1195 pg_get_indexdef_ext(PG_FUNCTION_ARGS)
1197 Oid indexrelid = PG_GETARG_OID(0);
1198 int32 colno = PG_GETARG_INT32(1);
1199 bool pretty = PG_GETARG_BOOL(2);
1200 int prettyFlags;
1201 char *res;
1203 prettyFlags = GET_PRETTY_FLAGS(pretty);
1205 res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1206 colno != 0, false,
1207 false, false,
1208 prettyFlags, true);
1210 if (res == NULL)
1211 PG_RETURN_NULL();
1213 PG_RETURN_TEXT_P(string_to_text(res));
1217 * Internal version for use by ALTER TABLE.
1218 * Includes a tablespace clause in the result.
1219 * Returns a palloc'd C string; no pretty-printing.
1221 char *
1222 pg_get_indexdef_string(Oid indexrelid)
1224 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1225 false, false,
1226 true, true,
1227 0, false);
1230 /* Internal version that just reports the key-column definitions */
1231 char *
1232 pg_get_indexdef_columns(Oid indexrelid, bool pretty)
1234 int prettyFlags;
1236 prettyFlags = GET_PRETTY_FLAGS(pretty);
1238 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1239 true, true,
1240 false, false,
1241 prettyFlags, false);
1244 /* Internal version, extensible with flags to control its behavior */
1245 char *
1246 pg_get_indexdef_columns_extended(Oid indexrelid, bits16 flags)
1248 bool pretty = ((flags & RULE_INDEXDEF_PRETTY) != 0);
1249 bool keys_only = ((flags & RULE_INDEXDEF_KEYS_ONLY) != 0);
1250 int prettyFlags;
1252 prettyFlags = GET_PRETTY_FLAGS(pretty);
1254 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1255 true, keys_only,
1256 false, false,
1257 prettyFlags, false);
1261 * Internal workhorse to decompile an index definition.
1263 * This is now used for exclusion constraints as well: if excludeOps is not
1264 * NULL then it points to an array of exclusion operator OIDs.
1266 static char *
1267 pg_get_indexdef_worker(Oid indexrelid, int colno,
1268 const Oid *excludeOps,
1269 bool attrsOnly, bool keysOnly,
1270 bool showTblSpc, bool inherits,
1271 int prettyFlags, bool missing_ok)
1273 /* might want a separate isConstraint parameter later */
1274 bool isConstraint = (excludeOps != NULL);
1275 HeapTuple ht_idx;
1276 HeapTuple ht_idxrel;
1277 HeapTuple ht_am;
1278 Form_pg_index idxrec;
1279 Form_pg_class idxrelrec;
1280 Form_pg_am amrec;
1281 IndexAmRoutine *amroutine;
1282 List *indexprs;
1283 ListCell *indexpr_item;
1284 List *context;
1285 Oid indrelid;
1286 int keyno;
1287 Datum indcollDatum;
1288 Datum indclassDatum;
1289 Datum indoptionDatum;
1290 oidvector *indcollation;
1291 oidvector *indclass;
1292 int2vector *indoption;
1293 StringInfoData buf;
1294 char *str;
1295 char *sep;
1298 * Fetch the pg_index tuple by the Oid of the index
1300 ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
1301 if (!HeapTupleIsValid(ht_idx))
1303 if (missing_ok)
1304 return NULL;
1305 elog(ERROR, "cache lookup failed for index %u", indexrelid);
1307 idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1309 indrelid = idxrec->indrelid;
1310 Assert(indexrelid == idxrec->indexrelid);
1312 /* Must get indcollation, indclass, and indoption the hard way */
1313 indcollDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1314 Anum_pg_index_indcollation);
1315 indcollation = (oidvector *) DatumGetPointer(indcollDatum);
1317 indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1318 Anum_pg_index_indclass);
1319 indclass = (oidvector *) DatumGetPointer(indclassDatum);
1321 indoptionDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1322 Anum_pg_index_indoption);
1323 indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1326 * Fetch the pg_class tuple of the index relation
1328 ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
1329 if (!HeapTupleIsValid(ht_idxrel))
1330 elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1331 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1334 * Fetch the pg_am tuple of the index' access method
1336 ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1337 if (!HeapTupleIsValid(ht_am))
1338 elog(ERROR, "cache lookup failed for access method %u",
1339 idxrelrec->relam);
1340 amrec = (Form_pg_am) GETSTRUCT(ht_am);
1342 /* Fetch the index AM's API struct */
1343 amroutine = GetIndexAmRoutine(amrec->amhandler);
1346 * Get the index expressions, if any. (NOTE: we do not use the relcache
1347 * versions of the expressions and predicate, because we want to display
1348 * non-const-folded expressions.)
1350 if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
1352 Datum exprsDatum;
1353 char *exprsString;
1355 exprsDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1356 Anum_pg_index_indexprs);
1357 exprsString = TextDatumGetCString(exprsDatum);
1358 indexprs = (List *) stringToNode(exprsString);
1359 pfree(exprsString);
1361 else
1362 indexprs = NIL;
1364 indexpr_item = list_head(indexprs);
1366 context = deparse_context_for(get_relation_name(indrelid), indrelid);
1369 * Start the index definition. Note that the index's name should never be
1370 * schema-qualified, but the indexed rel's name may be.
1372 initStringInfo(&buf);
1374 if (!attrsOnly)
1376 if (!isConstraint)
1377 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
1378 idxrec->indisunique ? "UNIQUE " : "",
1379 quote_identifier(NameStr(idxrelrec->relname)),
1380 idxrelrec->relkind == RELKIND_PARTITIONED_INDEX
1381 && !inherits ? "ONLY " : "",
1382 (prettyFlags & PRETTYFLAG_SCHEMA) ?
1383 generate_relation_name(indrelid, NIL) :
1384 generate_qualified_relation_name(indrelid),
1385 quote_identifier(NameStr(amrec->amname)));
1386 else /* currently, must be EXCLUDE constraint */
1387 appendStringInfo(&buf, "EXCLUDE USING %s (",
1388 quote_identifier(NameStr(amrec->amname)));
1392 * Report the indexed attributes
1394 sep = "";
1395 for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1397 AttrNumber attnum = idxrec->indkey.values[keyno];
1398 Oid keycoltype;
1399 Oid keycolcollation;
1402 * Ignore non-key attributes if told to.
1404 if (keysOnly && keyno >= idxrec->indnkeyatts)
1405 break;
1407 /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1408 if (!colno && keyno == idxrec->indnkeyatts)
1410 appendStringInfoString(&buf, ") INCLUDE (");
1411 sep = "";
1414 if (!colno)
1415 appendStringInfoString(&buf, sep);
1416 sep = ", ";
1418 if (attnum != 0)
1420 /* Simple index column */
1421 char *attname;
1422 int32 keycoltypmod;
1424 attname = get_attname(indrelid, attnum, false);
1425 if (!colno || colno == keyno + 1)
1426 appendStringInfoString(&buf, quote_identifier(attname));
1427 get_atttypetypmodcoll(indrelid, attnum,
1428 &keycoltype, &keycoltypmod,
1429 &keycolcollation);
1431 else
1433 /* expressional index */
1434 Node *indexkey;
1436 if (indexpr_item == NULL)
1437 elog(ERROR, "too few entries in indexprs list");
1438 indexkey = (Node *) lfirst(indexpr_item);
1439 indexpr_item = lnext(indexprs, indexpr_item);
1440 /* Deparse */
1441 str = deparse_expression_pretty(indexkey, context, false, false,
1442 prettyFlags, 0);
1443 if (!colno || colno == keyno + 1)
1445 /* Need parens if it's not a bare function call */
1446 if (looks_like_function(indexkey))
1447 appendStringInfoString(&buf, str);
1448 else
1449 appendStringInfo(&buf, "(%s)", str);
1451 keycoltype = exprType(indexkey);
1452 keycolcollation = exprCollation(indexkey);
1455 /* Print additional decoration for (selected) key columns */
1456 if (!attrsOnly && keyno < idxrec->indnkeyatts &&
1457 (!colno || colno == keyno + 1))
1459 int16 opt = indoption->values[keyno];
1460 Oid indcoll = indcollation->values[keyno];
1461 Datum attoptions = get_attoptions(indexrelid, keyno + 1);
1462 bool has_options = attoptions != (Datum) 0;
1464 /* Add collation, if not default for column */
1465 if (OidIsValid(indcoll) && indcoll != keycolcollation)
1466 appendStringInfo(&buf, " COLLATE %s",
1467 generate_collation_name((indcoll)));
1469 /* Add the operator class name, if not default */
1470 get_opclass_name(indclass->values[keyno],
1471 has_options ? InvalidOid : keycoltype, &buf);
1473 if (has_options)
1475 appendStringInfoString(&buf, " (");
1476 get_reloptions(&buf, attoptions);
1477 appendStringInfoChar(&buf, ')');
1480 /* Add options if relevant */
1481 if (amroutine->amcanorder)
1483 /* if it supports sort ordering, report DESC and NULLS opts */
1484 if (opt & INDOPTION_DESC)
1486 appendStringInfoString(&buf, " DESC");
1487 /* NULLS FIRST is the default in this case */
1488 if (!(opt & INDOPTION_NULLS_FIRST))
1489 appendStringInfoString(&buf, " NULLS LAST");
1491 else
1493 if (opt & INDOPTION_NULLS_FIRST)
1494 appendStringInfoString(&buf, " NULLS FIRST");
1498 /* Add the exclusion operator if relevant */
1499 if (excludeOps != NULL)
1500 appendStringInfo(&buf, " WITH %s",
1501 generate_operator_name(excludeOps[keyno],
1502 keycoltype,
1503 keycoltype));
1507 if (!attrsOnly)
1509 appendStringInfoChar(&buf, ')');
1511 if (idxrec->indnullsnotdistinct)
1512 appendStringInfoString(&buf, " NULLS NOT DISTINCT");
1515 * If it has options, append "WITH (options)"
1517 str = flatten_reloptions(indexrelid);
1518 if (str)
1520 appendStringInfo(&buf, " WITH (%s)", str);
1521 pfree(str);
1525 * Print tablespace, but only if requested
1527 if (showTblSpc)
1529 Oid tblspc;
1531 tblspc = get_rel_tablespace(indexrelid);
1532 if (OidIsValid(tblspc))
1534 if (isConstraint)
1535 appendStringInfoString(&buf, " USING INDEX");
1536 appendStringInfo(&buf, " TABLESPACE %s",
1537 quote_identifier(get_tablespace_name(tblspc)));
1542 * If it's a partial index, decompile and append the predicate
1544 if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
1546 Node *node;
1547 Datum predDatum;
1548 char *predString;
1550 /* Convert text string to node tree */
1551 predDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1552 Anum_pg_index_indpred);
1553 predString = TextDatumGetCString(predDatum);
1554 node = (Node *) stringToNode(predString);
1555 pfree(predString);
1557 /* Deparse */
1558 str = deparse_expression_pretty(node, context, false, false,
1559 prettyFlags, 0);
1560 if (isConstraint)
1561 appendStringInfo(&buf, " WHERE (%s)", str);
1562 else
1563 appendStringInfo(&buf, " WHERE %s", str);
1567 /* Clean up */
1568 ReleaseSysCache(ht_idx);
1569 ReleaseSysCache(ht_idxrel);
1570 ReleaseSysCache(ht_am);
1572 return buf.data;
1575 /* ----------
1576 * pg_get_querydef
1578 * Public entry point to deparse one query parsetree.
1579 * The pretty flags are determined by GET_PRETTY_FLAGS(pretty).
1581 * The result is a palloc'd C string.
1582 * ----------
1584 char *
1585 pg_get_querydef(Query *query, bool pretty)
1587 StringInfoData buf;
1588 int prettyFlags;
1590 prettyFlags = GET_PRETTY_FLAGS(pretty);
1592 initStringInfo(&buf);
1594 get_query_def(query, &buf, NIL, NULL, true,
1595 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1597 return buf.data;
1601 * pg_get_statisticsobjdef
1602 * Get the definition of an extended statistics object
1604 Datum
1605 pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
1607 Oid statextid = PG_GETARG_OID(0);
1608 char *res;
1610 res = pg_get_statisticsobj_worker(statextid, false, true);
1612 if (res == NULL)
1613 PG_RETURN_NULL();
1615 PG_RETURN_TEXT_P(string_to_text(res));
1619 * Internal version for use by ALTER TABLE.
1620 * Includes a tablespace clause in the result.
1621 * Returns a palloc'd C string; no pretty-printing.
1623 char *
1624 pg_get_statisticsobjdef_string(Oid statextid)
1626 return pg_get_statisticsobj_worker(statextid, false, false);
1630 * pg_get_statisticsobjdef_columns
1631 * Get columns and expressions for an extended statistics object
1633 Datum
1634 pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)
1636 Oid statextid = PG_GETARG_OID(0);
1637 char *res;
1639 res = pg_get_statisticsobj_worker(statextid, true, true);
1641 if (res == NULL)
1642 PG_RETURN_NULL();
1644 PG_RETURN_TEXT_P(string_to_text(res));
1648 * Internal workhorse to decompile an extended statistics object.
1650 static char *
1651 pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
1653 Form_pg_statistic_ext statextrec;
1654 HeapTuple statexttup;
1655 StringInfoData buf;
1656 int colno;
1657 char *nsp;
1658 ArrayType *arr;
1659 char *enabled;
1660 Datum datum;
1661 bool ndistinct_enabled;
1662 bool dependencies_enabled;
1663 bool mcv_enabled;
1664 int i;
1665 List *context;
1666 ListCell *lc;
1667 List *exprs = NIL;
1668 bool has_exprs;
1669 int ncolumns;
1671 statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1673 if (!HeapTupleIsValid(statexttup))
1675 if (missing_ok)
1676 return NULL;
1677 elog(ERROR, "cache lookup failed for statistics object %u", statextid);
1680 /* has the statistics expressions? */
1681 has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1683 statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1686 * Get the statistics expressions, if any. (NOTE: we do not use the
1687 * relcache versions of the expressions, because we want to display
1688 * non-const-folded expressions.)
1690 if (has_exprs)
1692 Datum exprsDatum;
1693 char *exprsString;
1695 exprsDatum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1696 Anum_pg_statistic_ext_stxexprs);
1697 exprsString = TextDatumGetCString(exprsDatum);
1698 exprs = (List *) stringToNode(exprsString);
1699 pfree(exprsString);
1701 else
1702 exprs = NIL;
1704 /* count the number of columns (attributes and expressions) */
1705 ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
1707 initStringInfo(&buf);
1709 if (!columns_only)
1711 nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
1712 appendStringInfo(&buf, "CREATE STATISTICS %s",
1713 quote_qualified_identifier(nsp,
1714 NameStr(statextrec->stxname)));
1717 * Decode the stxkind column so that we know which stats types to
1718 * print.
1720 datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1721 Anum_pg_statistic_ext_stxkind);
1722 arr = DatumGetArrayTypeP(datum);
1723 if (ARR_NDIM(arr) != 1 ||
1724 ARR_HASNULL(arr) ||
1725 ARR_ELEMTYPE(arr) != CHAROID)
1726 elog(ERROR, "stxkind is not a 1-D char array");
1727 enabled = (char *) ARR_DATA_PTR(arr);
1729 ndistinct_enabled = false;
1730 dependencies_enabled = false;
1731 mcv_enabled = false;
1733 for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1735 if (enabled[i] == STATS_EXT_NDISTINCT)
1736 ndistinct_enabled = true;
1737 else if (enabled[i] == STATS_EXT_DEPENDENCIES)
1738 dependencies_enabled = true;
1739 else if (enabled[i] == STATS_EXT_MCV)
1740 mcv_enabled = true;
1742 /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
1746 * If any option is disabled, then we'll need to append the types
1747 * clause to show which options are enabled. We omit the types clause
1748 * on purpose when all options are enabled, so a pg_dump/pg_restore
1749 * will create all statistics types on a newer postgres version, if
1750 * the statistics had all options enabled on the original version.
1752 * But if the statistics is defined on just a single column, it has to
1753 * be an expression statistics. In that case we don't need to specify
1754 * kinds.
1756 if ((!ndistinct_enabled || !dependencies_enabled || !mcv_enabled) &&
1757 (ncolumns > 1))
1759 bool gotone = false;
1761 appendStringInfoString(&buf, " (");
1763 if (ndistinct_enabled)
1765 appendStringInfoString(&buf, "ndistinct");
1766 gotone = true;
1769 if (dependencies_enabled)
1771 appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
1772 gotone = true;
1775 if (mcv_enabled)
1776 appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
1778 appendStringInfoChar(&buf, ')');
1781 appendStringInfoString(&buf, " ON ");
1784 /* decode simple column references */
1785 for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
1787 AttrNumber attnum = statextrec->stxkeys.values[colno];
1788 char *attname;
1790 if (colno > 0)
1791 appendStringInfoString(&buf, ", ");
1793 attname = get_attname(statextrec->stxrelid, attnum, false);
1795 appendStringInfoString(&buf, quote_identifier(attname));
1798 context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1799 statextrec->stxrelid);
1801 foreach(lc, exprs)
1803 Node *expr = (Node *) lfirst(lc);
1804 char *str;
1805 int prettyFlags = PRETTYFLAG_PAREN;
1807 str = deparse_expression_pretty(expr, context, false, false,
1808 prettyFlags, 0);
1810 if (colno > 0)
1811 appendStringInfoString(&buf, ", ");
1813 /* Need parens if it's not a bare function call */
1814 if (looks_like_function(expr))
1815 appendStringInfoString(&buf, str);
1816 else
1817 appendStringInfo(&buf, "(%s)", str);
1819 colno++;
1822 if (!columns_only)
1823 appendStringInfo(&buf, " FROM %s",
1824 generate_relation_name(statextrec->stxrelid, NIL));
1826 ReleaseSysCache(statexttup);
1828 return buf.data;
1832 * Generate text array of expressions for statistics object.
1834 Datum
1835 pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
1837 Oid statextid = PG_GETARG_OID(0);
1838 Form_pg_statistic_ext statextrec;
1839 HeapTuple statexttup;
1840 Datum datum;
1841 List *context;
1842 ListCell *lc;
1843 List *exprs = NIL;
1844 bool has_exprs;
1845 char *tmp;
1846 ArrayBuildState *astate = NULL;
1848 statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1850 if (!HeapTupleIsValid(statexttup))
1851 PG_RETURN_NULL();
1853 /* Does the stats object have expressions? */
1854 has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1856 /* no expressions? we're done */
1857 if (!has_exprs)
1859 ReleaseSysCache(statexttup);
1860 PG_RETURN_NULL();
1863 statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1866 * Get the statistics expressions, and deparse them into text values.
1868 datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1869 Anum_pg_statistic_ext_stxexprs);
1870 tmp = TextDatumGetCString(datum);
1871 exprs = (List *) stringToNode(tmp);
1872 pfree(tmp);
1874 context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1875 statextrec->stxrelid);
1877 foreach(lc, exprs)
1879 Node *expr = (Node *) lfirst(lc);
1880 char *str;
1881 int prettyFlags = PRETTYFLAG_INDENT;
1883 str = deparse_expression_pretty(expr, context, false, false,
1884 prettyFlags, 0);
1886 astate = accumArrayResult(astate,
1887 PointerGetDatum(cstring_to_text(str)),
1888 false,
1889 TEXTOID,
1890 CurrentMemoryContext);
1893 ReleaseSysCache(statexttup);
1895 PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
1899 * pg_get_partkeydef
1901 * Returns the partition key specification, ie, the following:
1903 * { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
1905 Datum
1906 pg_get_partkeydef(PG_FUNCTION_ARGS)
1908 Oid relid = PG_GETARG_OID(0);
1909 char *res;
1911 res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1913 if (res == NULL)
1914 PG_RETURN_NULL();
1916 PG_RETURN_TEXT_P(string_to_text(res));
1919 /* Internal version that just reports the column definitions */
1920 char *
1921 pg_get_partkeydef_columns(Oid relid, bool pretty)
1923 int prettyFlags;
1925 prettyFlags = GET_PRETTY_FLAGS(pretty);
1927 return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1931 * Internal workhorse to decompile a partition key definition.
1933 static char *
1934 pg_get_partkeydef_worker(Oid relid, int prettyFlags,
1935 bool attrsOnly, bool missing_ok)
1937 Form_pg_partitioned_table form;
1938 HeapTuple tuple;
1939 oidvector *partclass;
1940 oidvector *partcollation;
1941 List *partexprs;
1942 ListCell *partexpr_item;
1943 List *context;
1944 Datum datum;
1945 StringInfoData buf;
1946 int keyno;
1947 char *str;
1948 char *sep;
1950 tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
1951 if (!HeapTupleIsValid(tuple))
1953 if (missing_ok)
1954 return NULL;
1955 elog(ERROR, "cache lookup failed for partition key of %u", relid);
1958 form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
1960 Assert(form->partrelid == relid);
1962 /* Must get partclass and partcollation the hard way */
1963 datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1964 Anum_pg_partitioned_table_partclass);
1965 partclass = (oidvector *) DatumGetPointer(datum);
1967 datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1968 Anum_pg_partitioned_table_partcollation);
1969 partcollation = (oidvector *) DatumGetPointer(datum);
1973 * Get the expressions, if any. (NOTE: we do not use the relcache
1974 * versions of the expressions, because we want to display
1975 * non-const-folded expressions.)
1977 if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
1979 Datum exprsDatum;
1980 char *exprsString;
1982 exprsDatum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1983 Anum_pg_partitioned_table_partexprs);
1984 exprsString = TextDatumGetCString(exprsDatum);
1985 partexprs = (List *) stringToNode(exprsString);
1987 if (!IsA(partexprs, List))
1988 elog(ERROR, "unexpected node type found in partexprs: %d",
1989 (int) nodeTag(partexprs));
1991 pfree(exprsString);
1993 else
1994 partexprs = NIL;
1996 partexpr_item = list_head(partexprs);
1997 context = deparse_context_for(get_relation_name(relid), relid);
1999 initStringInfo(&buf);
2001 switch (form->partstrat)
2003 case PARTITION_STRATEGY_HASH:
2004 if (!attrsOnly)
2005 appendStringInfoString(&buf, "HASH");
2006 break;
2007 case PARTITION_STRATEGY_LIST:
2008 if (!attrsOnly)
2009 appendStringInfoString(&buf, "LIST");
2010 break;
2011 case PARTITION_STRATEGY_RANGE:
2012 if (!attrsOnly)
2013 appendStringInfoString(&buf, "RANGE");
2014 break;
2015 default:
2016 elog(ERROR, "unexpected partition strategy: %d",
2017 (int) form->partstrat);
2020 if (!attrsOnly)
2021 appendStringInfoString(&buf, " (");
2022 sep = "";
2023 for (keyno = 0; keyno < form->partnatts; keyno++)
2025 AttrNumber attnum = form->partattrs.values[keyno];
2026 Oid keycoltype;
2027 Oid keycolcollation;
2028 Oid partcoll;
2030 appendStringInfoString(&buf, sep);
2031 sep = ", ";
2032 if (attnum != 0)
2034 /* Simple attribute reference */
2035 char *attname;
2036 int32 keycoltypmod;
2038 attname = get_attname(relid, attnum, false);
2039 appendStringInfoString(&buf, quote_identifier(attname));
2040 get_atttypetypmodcoll(relid, attnum,
2041 &keycoltype, &keycoltypmod,
2042 &keycolcollation);
2044 else
2046 /* Expression */
2047 Node *partkey;
2049 if (partexpr_item == NULL)
2050 elog(ERROR, "too few entries in partexprs list");
2051 partkey = (Node *) lfirst(partexpr_item);
2052 partexpr_item = lnext(partexprs, partexpr_item);
2054 /* Deparse */
2055 str = deparse_expression_pretty(partkey, context, false, false,
2056 prettyFlags, 0);
2057 /* Need parens if it's not a bare function call */
2058 if (looks_like_function(partkey))
2059 appendStringInfoString(&buf, str);
2060 else
2061 appendStringInfo(&buf, "(%s)", str);
2063 keycoltype = exprType(partkey);
2064 keycolcollation = exprCollation(partkey);
2067 /* Add collation, if not default for column */
2068 partcoll = partcollation->values[keyno];
2069 if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
2070 appendStringInfo(&buf, " COLLATE %s",
2071 generate_collation_name((partcoll)));
2073 /* Add the operator class name, if not default */
2074 if (!attrsOnly)
2075 get_opclass_name(partclass->values[keyno], keycoltype, &buf);
2078 if (!attrsOnly)
2079 appendStringInfoChar(&buf, ')');
2081 /* Clean up */
2082 ReleaseSysCache(tuple);
2084 return buf.data;
2088 * pg_get_partition_constraintdef
2090 * Returns partition constraint expression as a string for the input relation
2092 Datum
2093 pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
2095 Oid relationId = PG_GETARG_OID(0);
2096 Expr *constr_expr;
2097 int prettyFlags;
2098 List *context;
2099 char *consrc;
2101 constr_expr = get_partition_qual_relid(relationId);
2103 /* Quick exit if no partition constraint */
2104 if (constr_expr == NULL)
2105 PG_RETURN_NULL();
2108 * Deparse and return the constraint expression.
2110 prettyFlags = PRETTYFLAG_INDENT;
2111 context = deparse_context_for(get_relation_name(relationId), relationId);
2112 consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2113 false, prettyFlags, 0);
2115 PG_RETURN_TEXT_P(string_to_text(consrc));
2119 * pg_get_partconstrdef_string
2121 * Returns the partition constraint as a C-string for the input relation, with
2122 * the given alias. No pretty-printing.
2124 char *
2125 pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
2127 Expr *constr_expr;
2128 List *context;
2130 constr_expr = get_partition_qual_relid(partitionId);
2131 context = deparse_context_for(aliasname, partitionId);
2133 return deparse_expression((Node *) constr_expr, context, true, false);
2137 * pg_get_constraintdef
2139 * Returns the definition for the constraint, ie, everything that needs to
2140 * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
2142 Datum
2143 pg_get_constraintdef(PG_FUNCTION_ARGS)
2145 Oid constraintId = PG_GETARG_OID(0);
2146 int prettyFlags;
2147 char *res;
2149 prettyFlags = PRETTYFLAG_INDENT;
2151 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2153 if (res == NULL)
2154 PG_RETURN_NULL();
2156 PG_RETURN_TEXT_P(string_to_text(res));
2159 Datum
2160 pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
2162 Oid constraintId = PG_GETARG_OID(0);
2163 bool pretty = PG_GETARG_BOOL(1);
2164 int prettyFlags;
2165 char *res;
2167 prettyFlags = GET_PRETTY_FLAGS(pretty);
2169 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2171 if (res == NULL)
2172 PG_RETURN_NULL();
2174 PG_RETURN_TEXT_P(string_to_text(res));
2178 * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
2180 char *
2181 pg_get_constraintdef_command(Oid constraintId)
2183 return pg_get_constraintdef_worker(constraintId, true, 0, false);
2187 * As of 9.4, we now use an MVCC snapshot for this.
2189 static char *
2190 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
2191 int prettyFlags, bool missing_ok)
2193 HeapTuple tup;
2194 Form_pg_constraint conForm;
2195 StringInfoData buf;
2196 SysScanDesc scandesc;
2197 ScanKeyData scankey[1];
2198 Snapshot snapshot = RegisterSnapshot(GetTransactionSnapshot());
2199 Relation relation = table_open(ConstraintRelationId, AccessShareLock);
2201 ScanKeyInit(&scankey[0],
2202 Anum_pg_constraint_oid,
2203 BTEqualStrategyNumber, F_OIDEQ,
2204 ObjectIdGetDatum(constraintId));
2206 scandesc = systable_beginscan(relation,
2207 ConstraintOidIndexId,
2208 true,
2209 snapshot,
2211 scankey);
2214 * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2215 * via SearchSysCache, which works fine.
2217 tup = systable_getnext(scandesc);
2219 UnregisterSnapshot(snapshot);
2221 if (!HeapTupleIsValid(tup))
2223 if (missing_ok)
2225 systable_endscan(scandesc);
2226 table_close(relation, AccessShareLock);
2227 return NULL;
2229 elog(ERROR, "could not find tuple for constraint %u", constraintId);
2232 conForm = (Form_pg_constraint) GETSTRUCT(tup);
2234 initStringInfo(&buf);
2236 if (fullCommand)
2238 if (OidIsValid(conForm->conrelid))
2241 * Currently, callers want ALTER TABLE (without ONLY) for CHECK
2242 * constraints, and other types of constraints don't inherit
2243 * anyway so it doesn't matter whether we say ONLY or not. Someday
2244 * we might need to let callers specify whether to put ONLY in the
2245 * command.
2247 appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2248 generate_qualified_relation_name(conForm->conrelid),
2249 quote_identifier(NameStr(conForm->conname)));
2251 else
2253 /* Must be a domain constraint */
2254 Assert(OidIsValid(conForm->contypid));
2255 appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
2256 generate_qualified_type_name(conForm->contypid),
2257 quote_identifier(NameStr(conForm->conname)));
2261 switch (conForm->contype)
2263 case CONSTRAINT_FOREIGN:
2265 Datum val;
2266 bool isnull;
2267 const char *string;
2269 /* Start off the constraint definition */
2270 appendStringInfoString(&buf, "FOREIGN KEY (");
2272 /* Fetch and build referencing-column list */
2273 val = SysCacheGetAttrNotNull(CONSTROID, tup,
2274 Anum_pg_constraint_conkey);
2276 /* If it is a temporal foreign key then it uses PERIOD. */
2277 decompile_column_index_array(val, conForm->conrelid, conForm->conperiod, &buf);
2279 /* add foreign relation name */
2280 appendStringInfo(&buf, ") REFERENCES %s(",
2281 generate_relation_name(conForm->confrelid,
2282 NIL));
2284 /* Fetch and build referenced-column list */
2285 val = SysCacheGetAttrNotNull(CONSTROID, tup,
2286 Anum_pg_constraint_confkey);
2288 decompile_column_index_array(val, conForm->confrelid, conForm->conperiod, &buf);
2290 appendStringInfoChar(&buf, ')');
2292 /* Add match type */
2293 switch (conForm->confmatchtype)
2295 case FKCONSTR_MATCH_FULL:
2296 string = " MATCH FULL";
2297 break;
2298 case FKCONSTR_MATCH_PARTIAL:
2299 string = " MATCH PARTIAL";
2300 break;
2301 case FKCONSTR_MATCH_SIMPLE:
2302 string = "";
2303 break;
2304 default:
2305 elog(ERROR, "unrecognized confmatchtype: %d",
2306 conForm->confmatchtype);
2307 string = ""; /* keep compiler quiet */
2308 break;
2310 appendStringInfoString(&buf, string);
2312 /* Add ON UPDATE and ON DELETE clauses, if needed */
2313 switch (conForm->confupdtype)
2315 case FKCONSTR_ACTION_NOACTION:
2316 string = NULL; /* suppress default */
2317 break;
2318 case FKCONSTR_ACTION_RESTRICT:
2319 string = "RESTRICT";
2320 break;
2321 case FKCONSTR_ACTION_CASCADE:
2322 string = "CASCADE";
2323 break;
2324 case FKCONSTR_ACTION_SETNULL:
2325 string = "SET NULL";
2326 break;
2327 case FKCONSTR_ACTION_SETDEFAULT:
2328 string = "SET DEFAULT";
2329 break;
2330 default:
2331 elog(ERROR, "unrecognized confupdtype: %d",
2332 conForm->confupdtype);
2333 string = NULL; /* keep compiler quiet */
2334 break;
2336 if (string)
2337 appendStringInfo(&buf, " ON UPDATE %s", string);
2339 switch (conForm->confdeltype)
2341 case FKCONSTR_ACTION_NOACTION:
2342 string = NULL; /* suppress default */
2343 break;
2344 case FKCONSTR_ACTION_RESTRICT:
2345 string = "RESTRICT";
2346 break;
2347 case FKCONSTR_ACTION_CASCADE:
2348 string = "CASCADE";
2349 break;
2350 case FKCONSTR_ACTION_SETNULL:
2351 string = "SET NULL";
2352 break;
2353 case FKCONSTR_ACTION_SETDEFAULT:
2354 string = "SET DEFAULT";
2355 break;
2356 default:
2357 elog(ERROR, "unrecognized confdeltype: %d",
2358 conForm->confdeltype);
2359 string = NULL; /* keep compiler quiet */
2360 break;
2362 if (string)
2363 appendStringInfo(&buf, " ON DELETE %s", string);
2366 * Add columns specified to SET NULL or SET DEFAULT if
2367 * provided.
2369 val = SysCacheGetAttr(CONSTROID, tup,
2370 Anum_pg_constraint_confdelsetcols, &isnull);
2371 if (!isnull)
2373 appendStringInfoString(&buf, " (");
2374 decompile_column_index_array(val, conForm->conrelid, false, &buf);
2375 appendStringInfoChar(&buf, ')');
2378 break;
2380 case CONSTRAINT_PRIMARY:
2381 case CONSTRAINT_UNIQUE:
2383 Datum val;
2384 Oid indexId;
2385 int keyatts;
2386 HeapTuple indtup;
2388 /* Start off the constraint definition */
2389 if (conForm->contype == CONSTRAINT_PRIMARY)
2390 appendStringInfoString(&buf, "PRIMARY KEY ");
2391 else
2392 appendStringInfoString(&buf, "UNIQUE ");
2394 indexId = conForm->conindid;
2396 indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2397 if (!HeapTupleIsValid(indtup))
2398 elog(ERROR, "cache lookup failed for index %u", indexId);
2399 if (conForm->contype == CONSTRAINT_UNIQUE &&
2400 ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
2401 appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
2403 appendStringInfoChar(&buf, '(');
2405 /* Fetch and build target column list */
2406 val = SysCacheGetAttrNotNull(CONSTROID, tup,
2407 Anum_pg_constraint_conkey);
2409 keyatts = decompile_column_index_array(val, conForm->conrelid, false, &buf);
2410 if (conForm->conperiod)
2411 appendStringInfoString(&buf, " WITHOUT OVERLAPS");
2413 appendStringInfoChar(&buf, ')');
2415 /* Build including column list (from pg_index.indkeys) */
2416 val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2417 Anum_pg_index_indnatts);
2418 if (DatumGetInt32(val) > keyatts)
2420 Datum cols;
2421 Datum *keys;
2422 int nKeys;
2423 int j;
2425 appendStringInfoString(&buf, " INCLUDE (");
2427 cols = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2428 Anum_pg_index_indkey);
2430 deconstruct_array_builtin(DatumGetArrayTypeP(cols), INT2OID,
2431 &keys, NULL, &nKeys);
2433 for (j = keyatts; j < nKeys; j++)
2435 char *colName;
2437 colName = get_attname(conForm->conrelid,
2438 DatumGetInt16(keys[j]), false);
2439 if (j > keyatts)
2440 appendStringInfoString(&buf, ", ");
2441 appendStringInfoString(&buf, quote_identifier(colName));
2444 appendStringInfoChar(&buf, ')');
2446 ReleaseSysCache(indtup);
2448 /* XXX why do we only print these bits if fullCommand? */
2449 if (fullCommand && OidIsValid(indexId))
2451 char *options = flatten_reloptions(indexId);
2452 Oid tblspc;
2454 if (options)
2456 appendStringInfo(&buf, " WITH (%s)", options);
2457 pfree(options);
2461 * Print the tablespace, unless it's the database default.
2462 * This is to help ALTER TABLE usage of this facility,
2463 * which needs this behavior to recreate exact catalog
2464 * state.
2466 tblspc = get_rel_tablespace(indexId);
2467 if (OidIsValid(tblspc))
2468 appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2469 quote_identifier(get_tablespace_name(tblspc)));
2472 break;
2474 case CONSTRAINT_CHECK:
2476 Datum val;
2477 char *conbin;
2478 char *consrc;
2479 Node *expr;
2480 List *context;
2482 /* Fetch constraint expression in parsetree form */
2483 val = SysCacheGetAttrNotNull(CONSTROID, tup,
2484 Anum_pg_constraint_conbin);
2486 conbin = TextDatumGetCString(val);
2487 expr = stringToNode(conbin);
2489 /* Set up deparsing context for Var nodes in constraint */
2490 if (conForm->conrelid != InvalidOid)
2492 /* relation constraint */
2493 context = deparse_context_for(get_relation_name(conForm->conrelid),
2494 conForm->conrelid);
2496 else
2498 /* domain constraint --- can't have Vars */
2499 context = NIL;
2502 consrc = deparse_expression_pretty(expr, context, false, false,
2503 prettyFlags, 0);
2506 * Now emit the constraint definition, adding NO INHERIT if
2507 * necessary.
2509 * There are cases where the constraint expression will be
2510 * fully parenthesized and we don't need the outer parens ...
2511 * but there are other cases where we do need 'em. Be
2512 * conservative for now.
2514 * Note that simply checking for leading '(' and trailing ')'
2515 * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2517 appendStringInfo(&buf, "CHECK (%s)%s",
2518 consrc,
2519 conForm->connoinherit ? " NO INHERIT" : "");
2520 break;
2522 case CONSTRAINT_NOTNULL:
2524 if (conForm->conrelid)
2526 AttrNumber attnum;
2528 attnum = extractNotNullColumn(tup);
2530 appendStringInfo(&buf, "NOT NULL %s",
2531 quote_identifier(get_attname(conForm->conrelid,
2532 attnum, false)));
2533 if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
2534 appendStringInfoString(&buf, " NO INHERIT");
2536 else if (conForm->contypid)
2538 /* conkey is null for domain not-null constraints */
2539 appendStringInfoString(&buf, "NOT NULL");
2541 break;
2544 case CONSTRAINT_TRIGGER:
2547 * There isn't an ALTER TABLE syntax for creating a user-defined
2548 * constraint trigger, but it seems better to print something than
2549 * throw an error; if we throw error then this function couldn't
2550 * safely be applied to all rows of pg_constraint.
2552 appendStringInfoString(&buf, "TRIGGER");
2553 break;
2554 case CONSTRAINT_EXCLUSION:
2556 Oid indexOid = conForm->conindid;
2557 Datum val;
2558 Datum *elems;
2559 int nElems;
2560 int i;
2561 Oid *operators;
2563 /* Extract operator OIDs from the pg_constraint tuple */
2564 val = SysCacheGetAttrNotNull(CONSTROID, tup,
2565 Anum_pg_constraint_conexclop);
2567 deconstruct_array_builtin(DatumGetArrayTypeP(val), OIDOID,
2568 &elems, NULL, &nElems);
2570 operators = (Oid *) palloc(nElems * sizeof(Oid));
2571 for (i = 0; i < nElems; i++)
2572 operators[i] = DatumGetObjectId(elems[i]);
2574 /* pg_get_indexdef_worker does the rest */
2575 /* suppress tablespace because pg_dump wants it that way */
2576 appendStringInfoString(&buf,
2577 pg_get_indexdef_worker(indexOid,
2579 operators,
2580 false,
2581 false,
2582 false,
2583 false,
2584 prettyFlags,
2585 false));
2586 break;
2588 default:
2589 elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2590 break;
2593 if (conForm->condeferrable)
2594 appendStringInfoString(&buf, " DEFERRABLE");
2595 if (conForm->condeferred)
2596 appendStringInfoString(&buf, " INITIALLY DEFERRED");
2598 /* Validated status is irrelevant when the constraint is NOT ENFORCED. */
2599 if (!conForm->conenforced)
2600 appendStringInfoString(&buf, " NOT ENFORCED");
2601 else if (!conForm->convalidated)
2602 appendStringInfoString(&buf, " NOT VALID");
2604 /* Cleanup */
2605 systable_endscan(scandesc);
2606 table_close(relation, AccessShareLock);
2608 return buf.data;
2613 * Convert an int16[] Datum into a comma-separated list of column names
2614 * for the indicated relation; append the list to buf. Returns the number
2615 * of keys.
2617 static int
2618 decompile_column_index_array(Datum column_index_array, Oid relId,
2619 bool withPeriod, StringInfo buf)
2621 Datum *keys;
2622 int nKeys;
2623 int j;
2625 /* Extract data from array of int16 */
2626 deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2627 &keys, NULL, &nKeys);
2629 for (j = 0; j < nKeys; j++)
2631 char *colName;
2633 colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2635 if (j == 0)
2636 appendStringInfoString(buf, quote_identifier(colName));
2637 else
2638 appendStringInfo(buf, ", %s%s",
2639 (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
2640 quote_identifier(colName));
2643 return nKeys;
2647 /* ----------
2648 * pg_get_expr - Decompile an expression tree
2650 * Input: an expression tree in nodeToString form, and a relation OID
2652 * Output: reverse-listed expression
2654 * Currently, the expression can only refer to a single relation, namely
2655 * the one specified by the second parameter. This is sufficient for
2656 * partial indexes, column default expressions, etc. We also support
2657 * Var-free expressions, for which the OID can be InvalidOid.
2659 * If the OID is nonzero but not actually valid, don't throw an error,
2660 * just return NULL. This is a bit questionable, but it's what we've
2661 * done historically, and it can help avoid unwanted failures when
2662 * examining catalog entries for just-deleted relations.
2664 * We expect this function to work, or throw a reasonably clean error,
2665 * for any node tree that can appear in a catalog pg_node_tree column.
2666 * Query trees, such as those appearing in pg_rewrite.ev_action, are
2667 * not supported. Nor are expressions in more than one relation, which
2668 * can appear in places like pg_rewrite.ev_qual.
2669 * ----------
2671 Datum
2672 pg_get_expr(PG_FUNCTION_ARGS)
2674 text *expr = PG_GETARG_TEXT_PP(0);
2675 Oid relid = PG_GETARG_OID(1);
2676 text *result;
2677 int prettyFlags;
2679 prettyFlags = PRETTYFLAG_INDENT;
2681 result = pg_get_expr_worker(expr, relid, prettyFlags);
2682 if (result)
2683 PG_RETURN_TEXT_P(result);
2684 else
2685 PG_RETURN_NULL();
2688 Datum
2689 pg_get_expr_ext(PG_FUNCTION_ARGS)
2691 text *expr = PG_GETARG_TEXT_PP(0);
2692 Oid relid = PG_GETARG_OID(1);
2693 bool pretty = PG_GETARG_BOOL(2);
2694 text *result;
2695 int prettyFlags;
2697 prettyFlags = GET_PRETTY_FLAGS(pretty);
2699 result = pg_get_expr_worker(expr, relid, prettyFlags);
2700 if (result)
2701 PG_RETURN_TEXT_P(result);
2702 else
2703 PG_RETURN_NULL();
2706 static text *
2707 pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
2709 Node *node;
2710 Node *tst;
2711 Relids relids;
2712 List *context;
2713 char *exprstr;
2714 Relation rel = NULL;
2715 char *str;
2717 /* Convert input pg_node_tree (really TEXT) object to C string */
2718 exprstr = text_to_cstring(expr);
2720 /* Convert expression to node tree */
2721 node = (Node *) stringToNode(exprstr);
2723 pfree(exprstr);
2726 * Throw error if the input is a querytree rather than an expression tree.
2727 * While we could support queries here, there seems no very good reason
2728 * to. In most such catalog columns, we'll see a List of Query nodes, or
2729 * even nested Lists, so drill down to a non-List node before checking.
2731 tst = node;
2732 while (tst && IsA(tst, List))
2733 tst = linitial((List *) tst);
2734 if (tst && IsA(tst, Query))
2735 ereport(ERROR,
2736 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2737 errmsg("input is a query, not an expression")));
2740 * Throw error if the expression contains Vars we won't be able to
2741 * deparse.
2743 relids = pull_varnos(NULL, node);
2744 if (OidIsValid(relid))
2746 if (!bms_is_subset(relids, bms_make_singleton(1)))
2747 ereport(ERROR,
2748 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2749 errmsg("expression contains variables of more than one relation")));
2751 else
2753 if (!bms_is_empty(relids))
2754 ereport(ERROR,
2755 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2756 errmsg("expression contains variables")));
2760 * Prepare deparse context if needed. If we are deparsing with a relid,
2761 * we need to transiently open and lock the rel, to make sure it won't go
2762 * away underneath us. (set_relation_column_names would lock it anyway,
2763 * so this isn't really introducing any new behavior.)
2765 if (OidIsValid(relid))
2767 rel = try_relation_open(relid, AccessShareLock);
2768 if (rel == NULL)
2769 return NULL;
2770 context = deparse_context_for(RelationGetRelationName(rel), relid);
2772 else
2773 context = NIL;
2775 /* Deparse */
2776 str = deparse_expression_pretty(node, context, false, false,
2777 prettyFlags, 0);
2779 if (rel != NULL)
2780 relation_close(rel, AccessShareLock);
2782 return string_to_text(str);
2786 /* ----------
2787 * pg_get_userbyid - Get a user name by roleid and
2788 * fallback to 'unknown (OID=n)'
2789 * ----------
2791 Datum
2792 pg_get_userbyid(PG_FUNCTION_ARGS)
2794 Oid roleid = PG_GETARG_OID(0);
2795 Name result;
2796 HeapTuple roletup;
2797 Form_pg_authid role_rec;
2800 * Allocate space for the result
2802 result = (Name) palloc(NAMEDATALEN);
2803 memset(NameStr(*result), 0, NAMEDATALEN);
2806 * Get the pg_authid entry and print the result
2808 roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2809 if (HeapTupleIsValid(roletup))
2811 role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2812 *result = role_rec->rolname;
2813 ReleaseSysCache(roletup);
2815 else
2816 sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2818 PG_RETURN_NAME(result);
2823 * pg_get_serial_sequence
2824 * Get the name of the sequence used by an identity or serial column,
2825 * formatted suitably for passing to setval, nextval or currval.
2826 * First parameter is not treated as double-quoted, second parameter
2827 * is --- see documentation for reason.
2829 Datum
2830 pg_get_serial_sequence(PG_FUNCTION_ARGS)
2832 text *tablename = PG_GETARG_TEXT_PP(0);
2833 text *columnname = PG_GETARG_TEXT_PP(1);
2834 RangeVar *tablerv;
2835 Oid tableOid;
2836 char *column;
2837 AttrNumber attnum;
2838 Oid sequenceId = InvalidOid;
2839 Relation depRel;
2840 ScanKeyData key[3];
2841 SysScanDesc scan;
2842 HeapTuple tup;
2844 /* Look up table name. Can't lock it - we might not have privileges. */
2845 tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2846 tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2848 /* Get the number of the column */
2849 column = text_to_cstring(columnname);
2851 attnum = get_attnum(tableOid, column);
2852 if (attnum == InvalidAttrNumber)
2853 ereport(ERROR,
2854 (errcode(ERRCODE_UNDEFINED_COLUMN),
2855 errmsg("column \"%s\" of relation \"%s\" does not exist",
2856 column, tablerv->relname)));
2858 /* Search the dependency table for the dependent sequence */
2859 depRel = table_open(DependRelationId, AccessShareLock);
2861 ScanKeyInit(&key[0],
2862 Anum_pg_depend_refclassid,
2863 BTEqualStrategyNumber, F_OIDEQ,
2864 ObjectIdGetDatum(RelationRelationId));
2865 ScanKeyInit(&key[1],
2866 Anum_pg_depend_refobjid,
2867 BTEqualStrategyNumber, F_OIDEQ,
2868 ObjectIdGetDatum(tableOid));
2869 ScanKeyInit(&key[2],
2870 Anum_pg_depend_refobjsubid,
2871 BTEqualStrategyNumber, F_INT4EQ,
2872 Int32GetDatum(attnum));
2874 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2875 NULL, 3, key);
2877 while (HeapTupleIsValid(tup = systable_getnext(scan)))
2879 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2882 * Look for an auto dependency (serial column) or internal dependency
2883 * (identity column) of a sequence on a column. (We need the relkind
2884 * test because indexes can also have auto dependencies on columns.)
2886 if (deprec->classid == RelationRelationId &&
2887 deprec->objsubid == 0 &&
2888 (deprec->deptype == DEPENDENCY_AUTO ||
2889 deprec->deptype == DEPENDENCY_INTERNAL) &&
2890 get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2892 sequenceId = deprec->objid;
2893 break;
2897 systable_endscan(scan);
2898 table_close(depRel, AccessShareLock);
2900 if (OidIsValid(sequenceId))
2902 char *result;
2904 result = generate_qualified_relation_name(sequenceId);
2906 PG_RETURN_TEXT_P(string_to_text(result));
2909 PG_RETURN_NULL();
2914 * pg_get_functiondef
2915 * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
2916 * the specified function.
2918 * Note: if you change the output format of this function, be careful not
2919 * to break psql's rules (in \ef and \sf) for identifying the start of the
2920 * function body. To wit: the function body starts on a line that begins with
2921 * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
2923 Datum
2924 pg_get_functiondef(PG_FUNCTION_ARGS)
2926 Oid funcid = PG_GETARG_OID(0);
2927 StringInfoData buf;
2928 StringInfoData dq;
2929 HeapTuple proctup;
2930 Form_pg_proc proc;
2931 bool isfunction;
2932 Datum tmp;
2933 bool isnull;
2934 const char *prosrc;
2935 const char *name;
2936 const char *nsp;
2937 float4 procost;
2938 int oldlen;
2940 initStringInfo(&buf);
2942 /* Look up the function */
2943 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2944 if (!HeapTupleIsValid(proctup))
2945 PG_RETURN_NULL();
2947 proc = (Form_pg_proc) GETSTRUCT(proctup);
2948 name = NameStr(proc->proname);
2950 if (proc->prokind == PROKIND_AGGREGATE)
2951 ereport(ERROR,
2952 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2953 errmsg("\"%s\" is an aggregate function", name)));
2955 isfunction = (proc->prokind != PROKIND_PROCEDURE);
2958 * We always qualify the function name, to ensure the right function gets
2959 * replaced.
2961 nsp = get_namespace_name_or_temp(proc->pronamespace);
2962 appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
2963 isfunction ? "FUNCTION" : "PROCEDURE",
2964 quote_qualified_identifier(nsp, name));
2965 (void) print_function_arguments(&buf, proctup, false, true);
2966 appendStringInfoString(&buf, ")\n");
2967 if (isfunction)
2969 appendStringInfoString(&buf, " RETURNS ");
2970 print_function_rettype(&buf, proctup);
2971 appendStringInfoChar(&buf, '\n');
2974 print_function_trftypes(&buf, proctup);
2976 appendStringInfo(&buf, " LANGUAGE %s\n",
2977 quote_identifier(get_language_name(proc->prolang, false)));
2979 /* Emit some miscellaneous options on one line */
2980 oldlen = buf.len;
2982 if (proc->prokind == PROKIND_WINDOW)
2983 appendStringInfoString(&buf, " WINDOW");
2984 switch (proc->provolatile)
2986 case PROVOLATILE_IMMUTABLE:
2987 appendStringInfoString(&buf, " IMMUTABLE");
2988 break;
2989 case PROVOLATILE_STABLE:
2990 appendStringInfoString(&buf, " STABLE");
2991 break;
2992 case PROVOLATILE_VOLATILE:
2993 break;
2996 switch (proc->proparallel)
2998 case PROPARALLEL_SAFE:
2999 appendStringInfoString(&buf, " PARALLEL SAFE");
3000 break;
3001 case PROPARALLEL_RESTRICTED:
3002 appendStringInfoString(&buf, " PARALLEL RESTRICTED");
3003 break;
3004 case PROPARALLEL_UNSAFE:
3005 break;
3008 if (proc->proisstrict)
3009 appendStringInfoString(&buf, " STRICT");
3010 if (proc->prosecdef)
3011 appendStringInfoString(&buf, " SECURITY DEFINER");
3012 if (proc->proleakproof)
3013 appendStringInfoString(&buf, " LEAKPROOF");
3015 /* This code for the default cost and rows should match functioncmds.c */
3016 if (proc->prolang == INTERNALlanguageId ||
3017 proc->prolang == ClanguageId)
3018 procost = 1;
3019 else
3020 procost = 100;
3021 if (proc->procost != procost)
3022 appendStringInfo(&buf, " COST %g", proc->procost);
3024 if (proc->prorows > 0 && proc->prorows != 1000)
3025 appendStringInfo(&buf, " ROWS %g", proc->prorows);
3027 if (proc->prosupport)
3029 Oid argtypes[1];
3032 * We should qualify the support function's name if it wouldn't be
3033 * resolved by lookup in the current search path.
3035 argtypes[0] = INTERNALOID;
3036 appendStringInfo(&buf, " SUPPORT %s",
3037 generate_function_name(proc->prosupport, 1,
3038 NIL, argtypes,
3039 false, NULL, false));
3042 if (oldlen != buf.len)
3043 appendStringInfoChar(&buf, '\n');
3045 /* Emit any proconfig options, one per line */
3046 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
3047 if (!isnull)
3049 ArrayType *a = DatumGetArrayTypeP(tmp);
3050 int i;
3052 Assert(ARR_ELEMTYPE(a) == TEXTOID);
3053 Assert(ARR_NDIM(a) == 1);
3054 Assert(ARR_LBOUND(a)[0] == 1);
3056 for (i = 1; i <= ARR_DIMS(a)[0]; i++)
3058 Datum d;
3060 d = array_ref(a, 1, &i,
3061 -1 /* varlenarray */ ,
3062 -1 /* TEXT's typlen */ ,
3063 false /* TEXT's typbyval */ ,
3064 TYPALIGN_INT /* TEXT's typalign */ ,
3065 &isnull);
3066 if (!isnull)
3068 char *configitem = TextDatumGetCString(d);
3069 char *pos;
3071 pos = strchr(configitem, '=');
3072 if (pos == NULL)
3073 continue;
3074 *pos++ = '\0';
3076 appendStringInfo(&buf, " SET %s TO ",
3077 quote_identifier(configitem));
3080 * Variables that are marked GUC_LIST_QUOTE were already fully
3081 * quoted by flatten_set_variable_args() before they were put
3082 * into the proconfig array. However, because the quoting
3083 * rules used there aren't exactly like SQL's, we have to
3084 * break the list value apart and then quote the elements as
3085 * string literals. (The elements may be double-quoted as-is,
3086 * but we can't just feed them to the SQL parser; it would do
3087 * the wrong thing with elements that are zero-length or
3088 * longer than NAMEDATALEN.)
3090 * Variables that are not so marked should just be emitted as
3091 * simple string literals. If the variable is not known to
3092 * guc.c, we'll do that; this makes it unsafe to use
3093 * GUC_LIST_QUOTE for extension variables.
3095 if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
3097 List *namelist;
3098 ListCell *lc;
3100 /* Parse string into list of identifiers */
3101 if (!SplitGUCList(pos, ',', &namelist))
3103 /* this shouldn't fail really */
3104 elog(ERROR, "invalid list syntax in proconfig item");
3106 foreach(lc, namelist)
3108 char *curname = (char *) lfirst(lc);
3110 simple_quote_literal(&buf, curname);
3111 if (lnext(namelist, lc))
3112 appendStringInfoString(&buf, ", ");
3115 else
3116 simple_quote_literal(&buf, pos);
3117 appendStringInfoChar(&buf, '\n');
3122 /* And finally the function definition ... */
3123 (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3124 if (proc->prolang == SQLlanguageId && !isnull)
3126 print_function_sqlbody(&buf, proctup);
3128 else
3130 appendStringInfoString(&buf, "AS ");
3132 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
3133 if (!isnull)
3135 simple_quote_literal(&buf, TextDatumGetCString(tmp));
3136 appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
3139 tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosrc);
3140 prosrc = TextDatumGetCString(tmp);
3143 * We always use dollar quoting. Figure out a suitable delimiter.
3145 * Since the user is likely to be editing the function body string, we
3146 * shouldn't use a short delimiter that he might easily create a
3147 * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3148 * if needed.
3150 initStringInfo(&dq);
3151 appendStringInfoChar(&dq, '$');
3152 appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3153 while (strstr(prosrc, dq.data) != NULL)
3154 appendStringInfoChar(&dq, 'x');
3155 appendStringInfoChar(&dq, '$');
3157 appendBinaryStringInfo(&buf, dq.data, dq.len);
3158 appendStringInfoString(&buf, prosrc);
3159 appendBinaryStringInfo(&buf, dq.data, dq.len);
3162 appendStringInfoChar(&buf, '\n');
3164 ReleaseSysCache(proctup);
3166 PG_RETURN_TEXT_P(string_to_text(buf.data));
3170 * pg_get_function_arguments
3171 * Get a nicely-formatted list of arguments for a function.
3172 * This is everything that would go between the parentheses in
3173 * CREATE FUNCTION.
3175 Datum
3176 pg_get_function_arguments(PG_FUNCTION_ARGS)
3178 Oid funcid = PG_GETARG_OID(0);
3179 StringInfoData buf;
3180 HeapTuple proctup;
3182 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3183 if (!HeapTupleIsValid(proctup))
3184 PG_RETURN_NULL();
3186 initStringInfo(&buf);
3188 (void) print_function_arguments(&buf, proctup, false, true);
3190 ReleaseSysCache(proctup);
3192 PG_RETURN_TEXT_P(string_to_text(buf.data));
3196 * pg_get_function_identity_arguments
3197 * Get a formatted list of arguments for a function.
3198 * This is everything that would go between the parentheses in
3199 * ALTER FUNCTION, etc. In particular, don't print defaults.
3201 Datum
3202 pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
3204 Oid funcid = PG_GETARG_OID(0);
3205 StringInfoData buf;
3206 HeapTuple proctup;
3208 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3209 if (!HeapTupleIsValid(proctup))
3210 PG_RETURN_NULL();
3212 initStringInfo(&buf);
3214 (void) print_function_arguments(&buf, proctup, false, false);
3216 ReleaseSysCache(proctup);
3218 PG_RETURN_TEXT_P(string_to_text(buf.data));
3222 * pg_get_function_result
3223 * Get a nicely-formatted version of the result type of a function.
3224 * This is what would appear after RETURNS in CREATE FUNCTION.
3226 Datum
3227 pg_get_function_result(PG_FUNCTION_ARGS)
3229 Oid funcid = PG_GETARG_OID(0);
3230 StringInfoData buf;
3231 HeapTuple proctup;
3233 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3234 if (!HeapTupleIsValid(proctup))
3235 PG_RETURN_NULL();
3237 if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3239 ReleaseSysCache(proctup);
3240 PG_RETURN_NULL();
3243 initStringInfo(&buf);
3245 print_function_rettype(&buf, proctup);
3247 ReleaseSysCache(proctup);
3249 PG_RETURN_TEXT_P(string_to_text(buf.data));
3253 * Guts of pg_get_function_result: append the function's return type
3254 * to the specified buffer.
3256 static void
3257 print_function_rettype(StringInfo buf, HeapTuple proctup)
3259 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3260 int ntabargs = 0;
3261 StringInfoData rbuf;
3263 initStringInfo(&rbuf);
3265 if (proc->proretset)
3267 /* It might be a table function; try to print the arguments */
3268 appendStringInfoString(&rbuf, "TABLE(");
3269 ntabargs = print_function_arguments(&rbuf, proctup, true, false);
3270 if (ntabargs > 0)
3271 appendStringInfoChar(&rbuf, ')');
3272 else
3273 resetStringInfo(&rbuf);
3276 if (ntabargs == 0)
3278 /* Not a table function, so do the normal thing */
3279 if (proc->proretset)
3280 appendStringInfoString(&rbuf, "SETOF ");
3281 appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3284 appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3288 * Common code for pg_get_function_arguments and pg_get_function_result:
3289 * append the desired subset of arguments to buf. We print only TABLE
3290 * arguments when print_table_args is true, and all the others when it's false.
3291 * We print argument defaults only if print_defaults is true.
3292 * Function return value is the number of arguments printed.
3294 static int
3295 print_function_arguments(StringInfo buf, HeapTuple proctup,
3296 bool print_table_args, bool print_defaults)
3298 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3299 int numargs;
3300 Oid *argtypes;
3301 char **argnames;
3302 char *argmodes;
3303 int insertorderbyat = -1;
3304 int argsprinted;
3305 int inputargno;
3306 int nlackdefaults;
3307 List *argdefaults = NIL;
3308 ListCell *nextargdefault = NULL;
3309 int i;
3311 numargs = get_func_arg_info(proctup,
3312 &argtypes, &argnames, &argmodes);
3314 nlackdefaults = numargs;
3315 if (print_defaults && proc->pronargdefaults > 0)
3317 Datum proargdefaults;
3318 bool isnull;
3320 proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3321 Anum_pg_proc_proargdefaults,
3322 &isnull);
3323 if (!isnull)
3325 char *str;
3327 str = TextDatumGetCString(proargdefaults);
3328 argdefaults = castNode(List, stringToNode(str));
3329 pfree(str);
3330 nextargdefault = list_head(argdefaults);
3331 /* nlackdefaults counts only *input* arguments lacking defaults */
3332 nlackdefaults = proc->pronargs - list_length(argdefaults);
3336 /* Check for special treatment of ordered-set aggregates */
3337 if (proc->prokind == PROKIND_AGGREGATE)
3339 HeapTuple aggtup;
3340 Form_pg_aggregate agg;
3342 aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(proc->oid));
3343 if (!HeapTupleIsValid(aggtup))
3344 elog(ERROR, "cache lookup failed for aggregate %u",
3345 proc->oid);
3346 agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
3347 if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3348 insertorderbyat = agg->aggnumdirectargs;
3349 ReleaseSysCache(aggtup);
3352 argsprinted = 0;
3353 inputargno = 0;
3354 for (i = 0; i < numargs; i++)
3356 Oid argtype = argtypes[i];
3357 char *argname = argnames ? argnames[i] : NULL;
3358 char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
3359 const char *modename;
3360 bool isinput;
3362 switch (argmode)
3364 case PROARGMODE_IN:
3367 * For procedures, explicitly mark all argument modes, so as
3368 * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3370 if (proc->prokind == PROKIND_PROCEDURE)
3371 modename = "IN ";
3372 else
3373 modename = "";
3374 isinput = true;
3375 break;
3376 case PROARGMODE_INOUT:
3377 modename = "INOUT ";
3378 isinput = true;
3379 break;
3380 case PROARGMODE_OUT:
3381 modename = "OUT ";
3382 isinput = false;
3383 break;
3384 case PROARGMODE_VARIADIC:
3385 modename = "VARIADIC ";
3386 isinput = true;
3387 break;
3388 case PROARGMODE_TABLE:
3389 modename = "";
3390 isinput = false;
3391 break;
3392 default:
3393 elog(ERROR, "invalid parameter mode '%c'", argmode);
3394 modename = NULL; /* keep compiler quiet */
3395 isinput = false;
3396 break;
3398 if (isinput)
3399 inputargno++; /* this is a 1-based counter */
3401 if (print_table_args != (argmode == PROARGMODE_TABLE))
3402 continue;
3404 if (argsprinted == insertorderbyat)
3406 if (argsprinted)
3407 appendStringInfoChar(buf, ' ');
3408 appendStringInfoString(buf, "ORDER BY ");
3410 else if (argsprinted)
3411 appendStringInfoString(buf, ", ");
3413 appendStringInfoString(buf, modename);
3414 if (argname && argname[0])
3415 appendStringInfo(buf, "%s ", quote_identifier(argname));
3416 appendStringInfoString(buf, format_type_be(argtype));
3417 if (print_defaults && isinput && inputargno > nlackdefaults)
3419 Node *expr;
3421 Assert(nextargdefault != NULL);
3422 expr = (Node *) lfirst(nextargdefault);
3423 nextargdefault = lnext(argdefaults, nextargdefault);
3425 appendStringInfo(buf, " DEFAULT %s",
3426 deparse_expression(expr, NIL, false, false));
3428 argsprinted++;
3430 /* nasty hack: print the last arg twice for variadic ordered-set agg */
3431 if (argsprinted == insertorderbyat && i == numargs - 1)
3433 i--;
3434 /* aggs shouldn't have defaults anyway, but just to be sure ... */
3435 print_defaults = false;
3439 return argsprinted;
3442 static bool
3443 is_input_argument(int nth, const char *argmodes)
3445 return (!argmodes
3446 || argmodes[nth] == PROARGMODE_IN
3447 || argmodes[nth] == PROARGMODE_INOUT
3448 || argmodes[nth] == PROARGMODE_VARIADIC);
3452 * Append used transformed types to specified buffer
3454 static void
3455 print_function_trftypes(StringInfo buf, HeapTuple proctup)
3457 Oid *trftypes;
3458 int ntypes;
3460 ntypes = get_func_trftypes(proctup, &trftypes);
3461 if (ntypes > 0)
3463 int i;
3465 appendStringInfoString(buf, " TRANSFORM ");
3466 for (i = 0; i < ntypes; i++)
3468 if (i != 0)
3469 appendStringInfoString(buf, ", ");
3470 appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3472 appendStringInfoChar(buf, '\n');
3477 * Get textual representation of a function argument's default value. The
3478 * second argument of this function is the argument number among all arguments
3479 * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3480 * how information_schema.sql uses it.
3482 Datum
3483 pg_get_function_arg_default(PG_FUNCTION_ARGS)
3485 Oid funcid = PG_GETARG_OID(0);
3486 int32 nth_arg = PG_GETARG_INT32(1);
3487 HeapTuple proctup;
3488 Form_pg_proc proc;
3489 int numargs;
3490 Oid *argtypes;
3491 char **argnames;
3492 char *argmodes;
3493 int i;
3494 List *argdefaults;
3495 Node *node;
3496 char *str;
3497 int nth_inputarg;
3498 Datum proargdefaults;
3499 bool isnull;
3500 int nth_default;
3502 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3503 if (!HeapTupleIsValid(proctup))
3504 PG_RETURN_NULL();
3506 numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3507 if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3509 ReleaseSysCache(proctup);
3510 PG_RETURN_NULL();
3513 nth_inputarg = 0;
3514 for (i = 0; i < nth_arg; i++)
3515 if (is_input_argument(i, argmodes))
3516 nth_inputarg++;
3518 proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3519 Anum_pg_proc_proargdefaults,
3520 &isnull);
3521 if (isnull)
3523 ReleaseSysCache(proctup);
3524 PG_RETURN_NULL();
3527 str = TextDatumGetCString(proargdefaults);
3528 argdefaults = castNode(List, stringToNode(str));
3529 pfree(str);
3531 proc = (Form_pg_proc) GETSTRUCT(proctup);
3534 * Calculate index into proargdefaults: proargdefaults corresponds to the
3535 * last N input arguments, where N = pronargdefaults.
3537 nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3539 if (nth_default < 0 || nth_default >= list_length(argdefaults))
3541 ReleaseSysCache(proctup);
3542 PG_RETURN_NULL();
3544 node = list_nth(argdefaults, nth_default);
3545 str = deparse_expression(node, NIL, false, false);
3547 ReleaseSysCache(proctup);
3549 PG_RETURN_TEXT_P(string_to_text(str));
3552 static void
3553 print_function_sqlbody(StringInfo buf, HeapTuple proctup)
3555 int numargs;
3556 Oid *argtypes;
3557 char **argnames;
3558 char *argmodes;
3559 deparse_namespace dpns = {0};
3560 Datum tmp;
3561 Node *n;
3563 dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
3564 numargs = get_func_arg_info(proctup,
3565 &argtypes, &argnames, &argmodes);
3566 dpns.numargs = numargs;
3567 dpns.argnames = argnames;
3569 tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
3570 n = stringToNode(TextDatumGetCString(tmp));
3572 if (IsA(n, List))
3574 List *stmts;
3575 ListCell *lc;
3577 stmts = linitial(castNode(List, n));
3579 appendStringInfoString(buf, "BEGIN ATOMIC\n");
3581 foreach(lc, stmts)
3583 Query *query = lfirst_node(Query, lc);
3585 /* It seems advisable to get at least AccessShareLock on rels */
3586 AcquireRewriteLocks(query, false, false);
3587 get_query_def(query, buf, list_make1(&dpns), NULL, false,
3588 PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 1);
3589 appendStringInfoChar(buf, ';');
3590 appendStringInfoChar(buf, '\n');
3593 appendStringInfoString(buf, "END");
3595 else
3597 Query *query = castNode(Query, n);
3599 /* It seems advisable to get at least AccessShareLock on rels */
3600 AcquireRewriteLocks(query, false, false);
3601 get_query_def(query, buf, list_make1(&dpns), NULL, false,
3602 0, WRAP_COLUMN_DEFAULT, 0);
3606 Datum
3607 pg_get_function_sqlbody(PG_FUNCTION_ARGS)
3609 Oid funcid = PG_GETARG_OID(0);
3610 StringInfoData buf;
3611 HeapTuple proctup;
3612 bool isnull;
3614 initStringInfo(&buf);
3616 /* Look up the function */
3617 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3618 if (!HeapTupleIsValid(proctup))
3619 PG_RETURN_NULL();
3621 (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3622 if (isnull)
3624 ReleaseSysCache(proctup);
3625 PG_RETURN_NULL();
3628 print_function_sqlbody(&buf, proctup);
3630 ReleaseSysCache(proctup);
3632 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf.data, buf.len));
3637 * deparse_expression - General utility for deparsing expressions
3639 * calls deparse_expression_pretty with all prettyPrinting disabled
3641 char *
3642 deparse_expression(Node *expr, List *dpcontext,
3643 bool forceprefix, bool showimplicit)
3645 return deparse_expression_pretty(expr, dpcontext, forceprefix,
3646 showimplicit, 0, 0);
3649 /* ----------
3650 * deparse_expression_pretty - General utility for deparsing expressions
3652 * expr is the node tree to be deparsed. It must be a transformed expression
3653 * tree (ie, not the raw output of gram.y).
3655 * dpcontext is a list of deparse_namespace nodes representing the context
3656 * for interpreting Vars in the node tree. It can be NIL if no Vars are
3657 * expected.
3659 * forceprefix is true to force all Vars to be prefixed with their table names.
3661 * showimplicit is true to force all implicit casts to be shown explicitly.
3663 * Tries to pretty up the output according to prettyFlags and startIndent.
3665 * The result is a palloc'd string.
3666 * ----------
3668 static char *
3669 deparse_expression_pretty(Node *expr, List *dpcontext,
3670 bool forceprefix, bool showimplicit,
3671 int prettyFlags, int startIndent)
3673 StringInfoData buf;
3674 deparse_context context;
3676 initStringInfo(&buf);
3677 context.buf = &buf;
3678 context.namespaces = dpcontext;
3679 context.resultDesc = NULL;
3680 context.targetList = NIL;
3681 context.windowClause = NIL;
3682 context.varprefix = forceprefix;
3683 context.prettyFlags = prettyFlags;
3684 context.wrapColumn = WRAP_COLUMN_DEFAULT;
3685 context.indentLevel = startIndent;
3686 context.colNamesVisible = true;
3687 context.inGroupBy = false;
3688 context.varInOrderBy = false;
3689 context.appendparents = NULL;
3691 get_rule_expr(expr, &context, showimplicit);
3693 return buf.data;
3696 /* ----------
3697 * deparse_context_for - Build deparse context for a single relation
3699 * Given the reference name (alias) and OID of a relation, build deparsing
3700 * context for an expression referencing only that relation (as varno 1,
3701 * varlevelsup 0). This is sufficient for many uses of deparse_expression.
3702 * ----------
3704 List *
3705 deparse_context_for(const char *aliasname, Oid relid)
3707 deparse_namespace *dpns;
3708 RangeTblEntry *rte;
3710 dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3712 /* Build a minimal RTE for the rel */
3713 rte = makeNode(RangeTblEntry);
3714 rte->rtekind = RTE_RELATION;
3715 rte->relid = relid;
3716 rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3717 rte->rellockmode = AccessShareLock;
3718 rte->alias = makeAlias(aliasname, NIL);
3719 rte->eref = rte->alias;
3720 rte->lateral = false;
3721 rte->inh = false;
3722 rte->inFromCl = true;
3724 /* Build one-element rtable */
3725 dpns->rtable = list_make1(rte);
3726 dpns->subplans = NIL;
3727 dpns->ctes = NIL;
3728 dpns->appendrels = NULL;
3729 set_rtable_names(dpns, NIL, NULL);
3730 set_simple_column_names(dpns);
3732 /* Return a one-deep namespace stack */
3733 return list_make1(dpns);
3737 * deparse_context_for_plan_tree - Build deparse context for a Plan tree
3739 * When deparsing an expression in a Plan tree, we use the plan's rangetable
3740 * to resolve names of simple Vars. The initialization of column names for
3741 * this is rather expensive if the rangetable is large, and it'll be the same
3742 * for every expression in the Plan tree; so we do it just once and re-use
3743 * the result of this function for each expression. (Note that the result
3744 * is not usable until set_deparse_context_plan() is applied to it.)
3746 * In addition to the PlannedStmt, pass the per-RTE alias names
3747 * assigned by a previous call to select_rtable_names_for_explain.
3749 List *
3750 deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
3752 deparse_namespace *dpns;
3754 dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3756 /* Initialize fields that stay the same across the whole plan tree */
3757 dpns->rtable = pstmt->rtable;
3758 dpns->rtable_names = rtable_names;
3759 dpns->subplans = pstmt->subplans;
3760 dpns->ctes = NIL;
3761 if (pstmt->appendRelations)
3763 /* Set up the array, indexed by child relid */
3764 int ntables = list_length(dpns->rtable);
3765 ListCell *lc;
3767 dpns->appendrels = (AppendRelInfo **)
3768 palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3769 foreach(lc, pstmt->appendRelations)
3771 AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3772 Index crelid = appinfo->child_relid;
3774 Assert(crelid > 0 && crelid <= ntables);
3775 Assert(dpns->appendrels[crelid] == NULL);
3776 dpns->appendrels[crelid] = appinfo;
3779 else
3780 dpns->appendrels = NULL; /* don't need it */
3783 * Set up column name aliases, ignoring any join RTEs; they don't matter
3784 * because plan trees don't contain any join alias Vars.
3786 set_simple_column_names(dpns);
3788 /* Return a one-deep namespace stack */
3789 return list_make1(dpns);
3793 * set_deparse_context_plan - Specify Plan node containing expression
3795 * When deparsing an expression in a Plan tree, we might have to resolve
3796 * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
3797 * provide the parent Plan node. Then OUTER_VAR and INNER_VAR references
3798 * can be resolved by drilling down into the left and right child plans.
3799 * Similarly, INDEX_VAR references can be resolved by reference to the
3800 * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
3801 * ForeignScan and CustomScan nodes. (Note that we don't currently support
3802 * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
3803 * for those, we can only deparse the indexqualorig fields, which won't
3804 * contain INDEX_VAR Vars.)
3806 * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
3807 * the most-closely-nested first. This is needed to resolve PARAM_EXEC
3808 * Params. Note we assume that all the Plan nodes share the same rtable.
3810 * For a ModifyTable plan, we might also need to resolve references to OLD/NEW
3811 * variables in the RETURNING list, so we copy the alias names of the OLD and
3812 * NEW rows from the ModifyTable plan node.
3814 * Once this function has been called, deparse_expression() can be called on
3815 * subsidiary expression(s) of the specified Plan node. To deparse
3816 * expressions of a different Plan node in the same Plan tree, re-call this
3817 * function to identify the new parent Plan node.
3819 * The result is the same List passed in; this is a notational convenience.
3821 List *
3822 set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
3824 deparse_namespace *dpns;
3826 /* Should always have one-entry namespace list for Plan deparsing */
3827 Assert(list_length(dpcontext) == 1);
3828 dpns = (deparse_namespace *) linitial(dpcontext);
3830 /* Set our attention on the specific plan node passed in */
3831 dpns->ancestors = ancestors;
3832 set_deparse_plan(dpns, plan);
3834 /* For ModifyTable, set aliases for OLD and NEW in RETURNING */
3835 if (IsA(plan, ModifyTable))
3837 dpns->ret_old_alias = ((ModifyTable *) plan)->returningOldAlias;
3838 dpns->ret_new_alias = ((ModifyTable *) plan)->returningNewAlias;
3841 return dpcontext;
3845 * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
3847 * Determine the relation aliases we'll use during an EXPLAIN operation.
3848 * This is just a frontend to set_rtable_names. We have to expose the aliases
3849 * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
3851 List *
3852 select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
3854 deparse_namespace dpns;
3856 memset(&dpns, 0, sizeof(dpns));
3857 dpns.rtable = rtable;
3858 dpns.subplans = NIL;
3859 dpns.ctes = NIL;
3860 dpns.appendrels = NULL;
3861 set_rtable_names(&dpns, NIL, rels_used);
3862 /* We needn't bother computing column aliases yet */
3864 return dpns.rtable_names;
3868 * set_rtable_names: select RTE aliases to be used in printing a query
3870 * We fill in dpns->rtable_names with a list of names that is one-for-one with
3871 * the already-filled dpns->rtable list. Each RTE name is unique among those
3872 * in the new namespace plus any ancestor namespaces listed in
3873 * parent_namespaces.
3875 * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
3877 * Note that this function is only concerned with relation names, not column
3878 * names.
3880 static void
3881 set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
3882 Bitmapset *rels_used)
3884 HASHCTL hash_ctl;
3885 HTAB *names_hash;
3886 NameHashEntry *hentry;
3887 bool found;
3888 int rtindex;
3889 ListCell *lc;
3891 dpns->rtable_names = NIL;
3892 /* nothing more to do if empty rtable */
3893 if (dpns->rtable == NIL)
3894 return;
3897 * We use a hash table to hold known names, so that this process is O(N)
3898 * not O(N^2) for N names.
3900 hash_ctl.keysize = NAMEDATALEN;
3901 hash_ctl.entrysize = sizeof(NameHashEntry);
3902 hash_ctl.hcxt = CurrentMemoryContext;
3903 names_hash = hash_create("set_rtable_names names",
3904 list_length(dpns->rtable),
3905 &hash_ctl,
3906 HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
3908 /* Preload the hash table with names appearing in parent_namespaces */
3909 foreach(lc, parent_namespaces)
3911 deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3912 ListCell *lc2;
3914 foreach(lc2, olddpns->rtable_names)
3916 char *oldname = (char *) lfirst(lc2);
3918 if (oldname == NULL)
3919 continue;
3920 hentry = (NameHashEntry *) hash_search(names_hash,
3921 oldname,
3922 HASH_ENTER,
3923 &found);
3924 /* we do not complain about duplicate names in parent namespaces */
3925 hentry->counter = 0;
3929 /* Now we can scan the rtable */
3930 rtindex = 1;
3931 foreach(lc, dpns->rtable)
3933 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3934 char *refname;
3936 /* Just in case this takes an unreasonable amount of time ... */
3937 CHECK_FOR_INTERRUPTS();
3939 if (rels_used && !bms_is_member(rtindex, rels_used))
3941 /* Ignore unreferenced RTE */
3942 refname = NULL;
3944 else if (rte->alias)
3946 /* If RTE has a user-defined alias, prefer that */
3947 refname = rte->alias->aliasname;
3949 else if (rte->rtekind == RTE_RELATION)
3951 /* Use the current actual name of the relation */
3952 refname = get_rel_name(rte->relid);
3954 else if (rte->rtekind == RTE_JOIN)
3956 /* Unnamed join has no refname */
3957 refname = NULL;
3959 else
3961 /* Otherwise use whatever the parser assigned */
3962 refname = rte->eref->aliasname;
3966 * If the selected name isn't unique, append digits to make it so, and
3967 * make a new hash entry for it once we've got a unique name. For a
3968 * very long input name, we might have to truncate to stay within
3969 * NAMEDATALEN.
3971 if (refname)
3973 hentry = (NameHashEntry *) hash_search(names_hash,
3974 refname,
3975 HASH_ENTER,
3976 &found);
3977 if (found)
3979 /* Name already in use, must choose a new one */
3980 int refnamelen = strlen(refname);
3981 char *modname = (char *) palloc(refnamelen + 16);
3982 NameHashEntry *hentry2;
3986 hentry->counter++;
3987 for (;;)
3989 memcpy(modname, refname, refnamelen);
3990 sprintf(modname + refnamelen, "_%d", hentry->counter);
3991 if (strlen(modname) < NAMEDATALEN)
3992 break;
3993 /* drop chars from refname to keep all the digits */
3994 refnamelen = pg_mbcliplen(refname, refnamelen,
3995 refnamelen - 1);
3997 hentry2 = (NameHashEntry *) hash_search(names_hash,
3998 modname,
3999 HASH_ENTER,
4000 &found);
4001 } while (found);
4002 hentry2->counter = 0; /* init new hash entry */
4003 refname = modname;
4005 else
4007 /* Name not previously used, need only initialize hentry */
4008 hentry->counter = 0;
4012 dpns->rtable_names = lappend(dpns->rtable_names, refname);
4013 rtindex++;
4016 hash_destroy(names_hash);
4020 * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
4022 * For convenience, this is defined to initialize the deparse_namespace struct
4023 * from scratch.
4025 static void
4026 set_deparse_for_query(deparse_namespace *dpns, Query *query,
4027 List *parent_namespaces)
4029 ListCell *lc;
4030 ListCell *lc2;
4032 /* Initialize *dpns and fill rtable/ctes links */
4033 memset(dpns, 0, sizeof(deparse_namespace));
4034 dpns->rtable = query->rtable;
4035 dpns->subplans = NIL;
4036 dpns->ctes = query->cteList;
4037 dpns->appendrels = NULL;
4038 dpns->ret_old_alias = query->returningOldAlias;
4039 dpns->ret_new_alias = query->returningNewAlias;
4041 /* Assign a unique relation alias to each RTE */
4042 set_rtable_names(dpns, parent_namespaces, NULL);
4044 /* Initialize dpns->rtable_columns to contain zeroed structs */
4045 dpns->rtable_columns = NIL;
4046 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4047 dpns->rtable_columns = lappend(dpns->rtable_columns,
4048 palloc0(sizeof(deparse_columns)));
4050 /* If it's a utility query, it won't have a jointree */
4051 if (query->jointree)
4053 /* Detect whether global uniqueness of USING names is needed */
4054 dpns->unique_using =
4055 has_dangerous_join_using(dpns, (Node *) query->jointree);
4058 * Select names for columns merged by USING, via a recursive pass over
4059 * the query jointree.
4061 set_using_names(dpns, (Node *) query->jointree, NIL);
4065 * Now assign remaining column aliases for each RTE. We do this in a
4066 * linear scan of the rtable, so as to process RTEs whether or not they
4067 * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
4068 * etc). JOIN RTEs must be processed after their children, but this is
4069 * okay because they appear later in the rtable list than their children
4070 * (cf Asserts in identify_join_columns()).
4072 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4074 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4075 deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4077 if (rte->rtekind == RTE_JOIN)
4078 set_join_column_names(dpns, rte, colinfo);
4079 else
4080 set_relation_column_names(dpns, rte, colinfo);
4085 * set_simple_column_names: fill in column aliases for non-query situations
4087 * This handles EXPLAIN and cases where we only have relation RTEs. Without
4088 * a join tree, we can't do anything smart about join RTEs, but we don't
4089 * need to, because EXPLAIN should never see join alias Vars anyway.
4090 * If we find a join RTE we'll just skip it, leaving its deparse_columns
4091 * struct all-zero. If somehow we try to deparse a join alias Var, we'll
4092 * error out cleanly because the struct's num_cols will be zero.
4094 static void
4095 set_simple_column_names(deparse_namespace *dpns)
4097 ListCell *lc;
4098 ListCell *lc2;
4100 /* Initialize dpns->rtable_columns to contain zeroed structs */
4101 dpns->rtable_columns = NIL;
4102 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4103 dpns->rtable_columns = lappend(dpns->rtable_columns,
4104 palloc0(sizeof(deparse_columns)));
4106 /* Assign unique column aliases within each non-join RTE */
4107 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4109 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4110 deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4112 if (rte->rtekind != RTE_JOIN)
4113 set_relation_column_names(dpns, rte, colinfo);
4118 * has_dangerous_join_using: search jointree for unnamed JOIN USING
4120 * Merged columns of a JOIN USING may act differently from either of the input
4121 * columns, either because they are merged with COALESCE (in a FULL JOIN) or
4122 * because an implicit coercion of the underlying input column is required.
4123 * In such a case the column must be referenced as a column of the JOIN not as
4124 * a column of either input. And this is problematic if the join is unnamed
4125 * (alias-less): we cannot qualify the column's name with an RTE name, since
4126 * there is none. (Forcibly assigning an alias to the join is not a solution,
4127 * since that will prevent legal references to tables below the join.)
4128 * To ensure that every column in the query is unambiguously referenceable,
4129 * we must assign such merged columns names that are globally unique across
4130 * the whole query, aliasing other columns out of the way as necessary.
4132 * Because the ensuing re-aliasing is fairly damaging to the readability of
4133 * the query, we don't do this unless we have to. So, we must pre-scan
4134 * the join tree to see if we have to, before starting set_using_names().
4136 static bool
4137 has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
4139 if (IsA(jtnode, RangeTblRef))
4141 /* nothing to do here */
4143 else if (IsA(jtnode, FromExpr))
4145 FromExpr *f = (FromExpr *) jtnode;
4146 ListCell *lc;
4148 foreach(lc, f->fromlist)
4150 if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
4151 return true;
4154 else if (IsA(jtnode, JoinExpr))
4156 JoinExpr *j = (JoinExpr *) jtnode;
4158 /* Is it an unnamed JOIN with USING? */
4159 if (j->alias == NULL && j->usingClause)
4162 * Yes, so check each join alias var to see if any of them are not
4163 * simple references to underlying columns. If so, we have a
4164 * dangerous situation and must pick unique aliases.
4166 RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4168 /* We need only examine the merged columns */
4169 for (int i = 0; i < jrte->joinmergedcols; i++)
4171 Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4173 if (!IsA(aliasvar, Var))
4174 return true;
4178 /* Nope, but inspect children */
4179 if (has_dangerous_join_using(dpns, j->larg))
4180 return true;
4181 if (has_dangerous_join_using(dpns, j->rarg))
4182 return true;
4184 else
4185 elog(ERROR, "unrecognized node type: %d",
4186 (int) nodeTag(jtnode));
4187 return false;
4191 * set_using_names: select column aliases to be used for merged USING columns
4193 * We do this during a recursive descent of the query jointree.
4194 * dpns->unique_using must already be set to determine the global strategy.
4196 * Column alias info is saved in the dpns->rtable_columns list, which is
4197 * assumed to be filled with pre-zeroed deparse_columns structs.
4199 * parentUsing is a list of all USING aliases assigned in parent joins of
4200 * the current jointree node. (The passed-in list must not be modified.)
4202 * Note that we do not use per-deparse_columns hash tables in this function.
4203 * The number of names that need to be assigned should be small enough that
4204 * we don't need to trouble with that.
4206 static void
4207 set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
4209 if (IsA(jtnode, RangeTblRef))
4211 /* nothing to do now */
4213 else if (IsA(jtnode, FromExpr))
4215 FromExpr *f = (FromExpr *) jtnode;
4216 ListCell *lc;
4218 foreach(lc, f->fromlist)
4219 set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4221 else if (IsA(jtnode, JoinExpr))
4223 JoinExpr *j = (JoinExpr *) jtnode;
4224 RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4225 deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
4226 int *leftattnos;
4227 int *rightattnos;
4228 deparse_columns *leftcolinfo;
4229 deparse_columns *rightcolinfo;
4230 int i;
4231 ListCell *lc;
4233 /* Get info about the shape of the join */
4234 identify_join_columns(j, rte, colinfo);
4235 leftattnos = colinfo->leftattnos;
4236 rightattnos = colinfo->rightattnos;
4238 /* Look up the not-yet-filled-in child deparse_columns structs */
4239 leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4240 rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4243 * If this join is unnamed, then we cannot substitute new aliases at
4244 * this level, so any name requirements pushed down to here must be
4245 * pushed down again to the children.
4247 if (rte->alias == NULL)
4249 for (i = 0; i < colinfo->num_cols; i++)
4251 char *colname = colinfo->colnames[i];
4253 if (colname == NULL)
4254 continue;
4256 /* Push down to left column, unless it's a system column */
4257 if (leftattnos[i] > 0)
4259 expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4260 leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4263 /* Same on the righthand side */
4264 if (rightattnos[i] > 0)
4266 expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4267 rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4273 * If there's a USING clause, select the USING column names and push
4274 * those names down to the children. We have two strategies:
4276 * If dpns->unique_using is true, we force all USING names to be
4277 * unique across the whole query level. In principle we'd only need
4278 * the names of dangerous USING columns to be globally unique, but to
4279 * safely assign all USING names in a single pass, we have to enforce
4280 * the same uniqueness rule for all of them. However, if a USING
4281 * column's name has been pushed down from the parent, we should use
4282 * it as-is rather than making a uniqueness adjustment. This is
4283 * necessary when we're at an unnamed join, and it creates no risk of
4284 * ambiguity. Also, if there's a user-written output alias for a
4285 * merged column, we prefer to use that rather than the input name;
4286 * this simplifies the logic and seems likely to lead to less aliasing
4287 * overall.
4289 * If dpns->unique_using is false, we only need USING names to be
4290 * unique within their own join RTE. We still need to honor
4291 * pushed-down names, though.
4293 * Though significantly different in results, these two strategies are
4294 * implemented by the same code, with only the difference of whether
4295 * to put assigned names into dpns->using_names.
4297 if (j->usingClause)
4299 /* Copy the input parentUsing list so we don't modify it */
4300 parentUsing = list_copy(parentUsing);
4302 /* USING names must correspond to the first join output columns */
4303 expand_colnames_array_to(colinfo, list_length(j->usingClause));
4304 i = 0;
4305 foreach(lc, j->usingClause)
4307 char *colname = strVal(lfirst(lc));
4309 /* Assert it's a merged column */
4310 Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4312 /* Adopt passed-down name if any, else select unique name */
4313 if (colinfo->colnames[i] != NULL)
4314 colname = colinfo->colnames[i];
4315 else
4317 /* Prefer user-written output alias if any */
4318 if (rte->alias && i < list_length(rte->alias->colnames))
4319 colname = strVal(list_nth(rte->alias->colnames, i));
4320 /* Make it appropriately unique */
4321 colname = make_colname_unique(colname, dpns, colinfo);
4322 if (dpns->unique_using)
4323 dpns->using_names = lappend(dpns->using_names,
4324 colname);
4325 /* Save it as output column name, too */
4326 colinfo->colnames[i] = colname;
4329 /* Remember selected names for use later */
4330 colinfo->usingNames = lappend(colinfo->usingNames, colname);
4331 parentUsing = lappend(parentUsing, colname);
4333 /* Push down to left column, unless it's a system column */
4334 if (leftattnos[i] > 0)
4336 expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4337 leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4340 /* Same on the righthand side */
4341 if (rightattnos[i] > 0)
4343 expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4344 rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4347 i++;
4351 /* Mark child deparse_columns structs with correct parentUsing info */
4352 leftcolinfo->parentUsing = parentUsing;
4353 rightcolinfo->parentUsing = parentUsing;
4355 /* Now recursively assign USING column names in children */
4356 set_using_names(dpns, j->larg, parentUsing);
4357 set_using_names(dpns, j->rarg, parentUsing);
4359 else
4360 elog(ERROR, "unrecognized node type: %d",
4361 (int) nodeTag(jtnode));
4365 * set_relation_column_names: select column aliases for a non-join RTE
4367 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4368 * If any colnames entries are already filled in, those override local
4369 * choices.
4371 static void
4372 set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4373 deparse_columns *colinfo)
4375 int ncolumns;
4376 char **real_colnames;
4377 bool changed_any;
4378 int noldcolumns;
4379 int i;
4380 int j;
4383 * Construct an array of the current "real" column names of the RTE.
4384 * real_colnames[] will be indexed by physical column number, with NULL
4385 * entries for dropped columns.
4387 if (rte->rtekind == RTE_RELATION)
4389 /* Relation --- look to the system catalogs for up-to-date info */
4390 Relation rel;
4391 TupleDesc tupdesc;
4393 rel = relation_open(rte->relid, AccessShareLock);
4394 tupdesc = RelationGetDescr(rel);
4396 ncolumns = tupdesc->natts;
4397 real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4399 for (i = 0; i < ncolumns; i++)
4401 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4403 if (attr->attisdropped)
4404 real_colnames[i] = NULL;
4405 else
4406 real_colnames[i] = pstrdup(NameStr(attr->attname));
4408 relation_close(rel, AccessShareLock);
4410 else
4412 /* Otherwise get the column names from eref or expandRTE() */
4413 List *colnames;
4414 ListCell *lc;
4417 * Functions returning composites have the annoying property that some
4418 * of the composite type's columns might have been dropped since the
4419 * query was parsed. If possible, use expandRTE() to handle that
4420 * case, since it has the tedious logic needed to find out about
4421 * dropped columns. However, if we're explaining a plan, then we
4422 * don't have rte->functions because the planner thinks that won't be
4423 * needed later, and that breaks expandRTE(). So in that case we have
4424 * to rely on rte->eref, which may lead us to report a dropped
4425 * column's old name; that seems close enough for EXPLAIN's purposes.
4427 * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4428 * which should be sufficiently up-to-date: no other RTE types can
4429 * have columns get dropped from under them after parsing.
4431 if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
4433 /* Since we're not creating Vars, rtindex etc. don't matter */
4434 expandRTE(rte, 1, 0, VAR_RETURNING_DEFAULT, -1,
4435 true /* include dropped */ , &colnames, NULL);
4437 else
4438 colnames = rte->eref->colnames;
4440 ncolumns = list_length(colnames);
4441 real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4443 i = 0;
4444 foreach(lc, colnames)
4447 * If the column name we find here is an empty string, then it's a
4448 * dropped column, so change to NULL.
4450 char *cname = strVal(lfirst(lc));
4452 if (cname[0] == '\0')
4453 cname = NULL;
4454 real_colnames[i] = cname;
4455 i++;
4460 * Ensure colinfo->colnames has a slot for each column. (It could be long
4461 * enough already, if we pushed down a name for the last column.) Note:
4462 * it's possible that there are now more columns than there were when the
4463 * query was parsed, ie colnames could be longer than rte->eref->colnames.
4464 * We must assign unique aliases to the new columns too, else there could
4465 * be unresolved conflicts when the view/rule is reloaded.
4467 expand_colnames_array_to(colinfo, ncolumns);
4468 Assert(colinfo->num_cols == ncolumns);
4471 * Make sufficiently large new_colnames and is_new_col arrays, too.
4473 * Note: because we leave colinfo->num_new_cols zero until after the loop,
4474 * colname_is_unique will not consult that array, which is fine because it
4475 * would only be duplicate effort.
4477 colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4478 colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4480 /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4481 build_colinfo_names_hash(colinfo);
4484 * Scan the columns, select a unique alias for each one, and store it in
4485 * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4486 * entries for dropped columns, the latter omits them. Also mark
4487 * new_colnames entries as to whether they are new since parse time; this
4488 * is the case for entries beyond the length of rte->eref->colnames.
4490 noldcolumns = list_length(rte->eref->colnames);
4491 changed_any = false;
4492 j = 0;
4493 for (i = 0; i < ncolumns; i++)
4495 char *real_colname = real_colnames[i];
4496 char *colname = colinfo->colnames[i];
4498 /* Skip dropped columns */
4499 if (real_colname == NULL)
4501 Assert(colname == NULL); /* colnames[i] is already NULL */
4502 continue;
4505 /* If alias already assigned, that's what to use */
4506 if (colname == NULL)
4508 /* If user wrote an alias, prefer that over real column name */
4509 if (rte->alias && i < list_length(rte->alias->colnames))
4510 colname = strVal(list_nth(rte->alias->colnames, i));
4511 else
4512 colname = real_colname;
4514 /* Unique-ify and insert into colinfo */
4515 colname = make_colname_unique(colname, dpns, colinfo);
4517 colinfo->colnames[i] = colname;
4518 add_to_names_hash(colinfo, colname);
4521 /* Put names of non-dropped columns in new_colnames[] too */
4522 colinfo->new_colnames[j] = colname;
4523 /* And mark them as new or not */
4524 colinfo->is_new_col[j] = (i >= noldcolumns);
4525 j++;
4527 /* Remember if any assigned aliases differ from "real" name */
4528 if (!changed_any && strcmp(colname, real_colname) != 0)
4529 changed_any = true;
4532 /* We're now done needing the colinfo's names_hash */
4533 destroy_colinfo_names_hash(colinfo);
4536 * Set correct length for new_colnames[] array. (Note: if columns have
4537 * been added, colinfo->num_cols includes them, which is not really quite
4538 * right but is harmless, since any new columns must be at the end where
4539 * they won't affect varattnos of pre-existing columns.)
4541 colinfo->num_new_cols = j;
4544 * For a relation RTE, we need only print the alias column names if any
4545 * are different from the underlying "real" names. For a function RTE,
4546 * always emit a complete column alias list; this is to protect against
4547 * possible instability of the default column names (eg, from altering
4548 * parameter names). For tablefunc RTEs, we never print aliases, because
4549 * the column names are part of the clause itself. For other RTE types,
4550 * print if we changed anything OR if there were user-written column
4551 * aliases (since the latter would be part of the underlying "reality").
4553 if (rte->rtekind == RTE_RELATION)
4554 colinfo->printaliases = changed_any;
4555 else if (rte->rtekind == RTE_FUNCTION)
4556 colinfo->printaliases = true;
4557 else if (rte->rtekind == RTE_TABLEFUNC)
4558 colinfo->printaliases = false;
4559 else if (rte->alias && rte->alias->colnames != NIL)
4560 colinfo->printaliases = true;
4561 else
4562 colinfo->printaliases = changed_any;
4566 * set_join_column_names: select column aliases for a join RTE
4568 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4569 * If any colnames entries are already filled in, those override local
4570 * choices. Also, names for USING columns were already chosen by
4571 * set_using_names(). We further expect that column alias selection has been
4572 * completed for both input RTEs.
4574 static void
4575 set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4576 deparse_columns *colinfo)
4578 deparse_columns *leftcolinfo;
4579 deparse_columns *rightcolinfo;
4580 bool changed_any;
4581 int noldcolumns;
4582 int nnewcolumns;
4583 Bitmapset *leftmerged = NULL;
4584 Bitmapset *rightmerged = NULL;
4585 int i;
4586 int j;
4587 int ic;
4588 int jc;
4590 /* Look up the previously-filled-in child deparse_columns structs */
4591 leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4592 rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4595 * Ensure colinfo->colnames has a slot for each column. (It could be long
4596 * enough already, if we pushed down a name for the last column.) Note:
4597 * it's possible that one or both inputs now have more columns than there
4598 * were when the query was parsed, but we'll deal with that below. We
4599 * only need entries in colnames for pre-existing columns.
4601 noldcolumns = list_length(rte->eref->colnames);
4602 expand_colnames_array_to(colinfo, noldcolumns);
4603 Assert(colinfo->num_cols == noldcolumns);
4605 /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4606 build_colinfo_names_hash(colinfo);
4609 * Scan the join output columns, select an alias for each one, and store
4610 * it in colinfo->colnames. If there are USING columns, set_using_names()
4611 * already selected their names, so we can start the loop at the first
4612 * non-merged column.
4614 changed_any = false;
4615 for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4617 char *colname = colinfo->colnames[i];
4618 char *real_colname;
4620 /* Join column must refer to at least one input column */
4621 Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4623 /* Get the child column name */
4624 if (colinfo->leftattnos[i] > 0)
4625 real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4626 else if (colinfo->rightattnos[i] > 0)
4627 real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4628 else
4630 /* We're joining system columns --- use eref name */
4631 real_colname = strVal(list_nth(rte->eref->colnames, i));
4634 /* If child col has been dropped, no need to assign a join colname */
4635 if (real_colname == NULL)
4637 colinfo->colnames[i] = NULL;
4638 continue;
4641 /* In an unnamed join, just report child column names as-is */
4642 if (rte->alias == NULL)
4644 colinfo->colnames[i] = real_colname;
4645 add_to_names_hash(colinfo, real_colname);
4646 continue;
4649 /* If alias already assigned, that's what to use */
4650 if (colname == NULL)
4652 /* If user wrote an alias, prefer that over real column name */
4653 if (rte->alias && i < list_length(rte->alias->colnames))
4654 colname = strVal(list_nth(rte->alias->colnames, i));
4655 else
4656 colname = real_colname;
4658 /* Unique-ify and insert into colinfo */
4659 colname = make_colname_unique(colname, dpns, colinfo);
4661 colinfo->colnames[i] = colname;
4662 add_to_names_hash(colinfo, colname);
4665 /* Remember if any assigned aliases differ from "real" name */
4666 if (!changed_any && strcmp(colname, real_colname) != 0)
4667 changed_any = true;
4671 * Calculate number of columns the join would have if it were re-parsed
4672 * now, and create storage for the new_colnames and is_new_col arrays.
4674 * Note: colname_is_unique will be consulting new_colnames[] during the
4675 * loops below, so its not-yet-filled entries must be zeroes.
4677 nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4678 list_length(colinfo->usingNames);
4679 colinfo->num_new_cols = nnewcolumns;
4680 colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
4681 colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
4684 * Generating the new_colnames array is a bit tricky since any new columns
4685 * added since parse time must be inserted in the right places. This code
4686 * must match the parser, which will order a join's columns as merged
4687 * columns first (in USING-clause order), then non-merged columns from the
4688 * left input (in attnum order), then non-merged columns from the right
4689 * input (ditto). If one of the inputs is itself a join, its columns will
4690 * be ordered according to the same rule, which means newly-added columns
4691 * might not be at the end. We can figure out what's what by consulting
4692 * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4694 * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4695 * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4696 * meanings for the current child RTE.
4699 /* Handle merged columns; they are first and can't be new */
4700 i = j = 0;
4701 while (i < noldcolumns &&
4702 colinfo->leftattnos[i] != 0 &&
4703 colinfo->rightattnos[i] != 0)
4705 /* column name is already determined and known unique */
4706 colinfo->new_colnames[j] = colinfo->colnames[i];
4707 colinfo->is_new_col[j] = false;
4709 /* build bitmapsets of child attnums of merged columns */
4710 if (colinfo->leftattnos[i] > 0)
4711 leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
4712 if (colinfo->rightattnos[i] > 0)
4713 rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4715 i++, j++;
4718 /* Handle non-merged left-child columns */
4719 ic = 0;
4720 for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4722 char *child_colname = leftcolinfo->new_colnames[jc];
4724 if (!leftcolinfo->is_new_col[jc])
4726 /* Advance ic to next non-dropped old column of left child */
4727 while (ic < leftcolinfo->num_cols &&
4728 leftcolinfo->colnames[ic] == NULL)
4729 ic++;
4730 Assert(ic < leftcolinfo->num_cols);
4731 ic++;
4732 /* If it is a merged column, we already processed it */
4733 if (bms_is_member(ic, leftmerged))
4734 continue;
4735 /* Else, advance i to the corresponding existing join column */
4736 while (i < colinfo->num_cols &&
4737 colinfo->colnames[i] == NULL)
4738 i++;
4739 Assert(i < colinfo->num_cols);
4740 Assert(ic == colinfo->leftattnos[i]);
4741 /* Use the already-assigned name of this column */
4742 colinfo->new_colnames[j] = colinfo->colnames[i];
4743 i++;
4745 else
4748 * Unique-ify the new child column name and assign, unless we're
4749 * in an unnamed join, in which case just copy
4751 if (rte->alias != NULL)
4753 colinfo->new_colnames[j] =
4754 make_colname_unique(child_colname, dpns, colinfo);
4755 if (!changed_any &&
4756 strcmp(colinfo->new_colnames[j], child_colname) != 0)
4757 changed_any = true;
4759 else
4760 colinfo->new_colnames[j] = child_colname;
4761 add_to_names_hash(colinfo, colinfo->new_colnames[j]);
4764 colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4765 j++;
4768 /* Handle non-merged right-child columns in exactly the same way */
4769 ic = 0;
4770 for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4772 char *child_colname = rightcolinfo->new_colnames[jc];
4774 if (!rightcolinfo->is_new_col[jc])
4776 /* Advance ic to next non-dropped old column of right child */
4777 while (ic < rightcolinfo->num_cols &&
4778 rightcolinfo->colnames[ic] == NULL)
4779 ic++;
4780 Assert(ic < rightcolinfo->num_cols);
4781 ic++;
4782 /* If it is a merged column, we already processed it */
4783 if (bms_is_member(ic, rightmerged))
4784 continue;
4785 /* Else, advance i to the corresponding existing join column */
4786 while (i < colinfo->num_cols &&
4787 colinfo->colnames[i] == NULL)
4788 i++;
4789 Assert(i < colinfo->num_cols);
4790 Assert(ic == colinfo->rightattnos[i]);
4791 /* Use the already-assigned name of this column */
4792 colinfo->new_colnames[j] = colinfo->colnames[i];
4793 i++;
4795 else
4798 * Unique-ify the new child column name and assign, unless we're
4799 * in an unnamed join, in which case just copy
4801 if (rte->alias != NULL)
4803 colinfo->new_colnames[j] =
4804 make_colname_unique(child_colname, dpns, colinfo);
4805 if (!changed_any &&
4806 strcmp(colinfo->new_colnames[j], child_colname) != 0)
4807 changed_any = true;
4809 else
4810 colinfo->new_colnames[j] = child_colname;
4811 add_to_names_hash(colinfo, colinfo->new_colnames[j]);
4814 colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4815 j++;
4818 /* Assert we processed the right number of columns */
4819 #ifdef USE_ASSERT_CHECKING
4820 while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4821 i++;
4822 Assert(i == colinfo->num_cols);
4823 Assert(j == nnewcolumns);
4824 #endif
4826 /* We're now done needing the colinfo's names_hash */
4827 destroy_colinfo_names_hash(colinfo);
4830 * For a named join, print column aliases if we changed any from the child
4831 * names. Unnamed joins cannot print aliases.
4833 if (rte->alias != NULL)
4834 colinfo->printaliases = changed_any;
4835 else
4836 colinfo->printaliases = false;
4840 * colname_is_unique: is colname distinct from already-chosen column names?
4842 * dpns is query-wide info, colinfo is for the column's RTE
4844 static bool
4845 colname_is_unique(const char *colname, deparse_namespace *dpns,
4846 deparse_columns *colinfo)
4848 int i;
4849 ListCell *lc;
4852 * If we have a hash table, consult that instead of linearly scanning the
4853 * colinfo's strings.
4855 if (colinfo->names_hash)
4857 if (hash_search(colinfo->names_hash,
4858 colname,
4859 HASH_FIND,
4860 NULL) != NULL)
4861 return false;
4863 else
4865 /* Check against already-assigned column aliases within RTE */
4866 for (i = 0; i < colinfo->num_cols; i++)
4868 char *oldname = colinfo->colnames[i];
4870 if (oldname && strcmp(oldname, colname) == 0)
4871 return false;
4875 * If we're building a new_colnames array, check that too (this will
4876 * be partially but not completely redundant with the previous checks)
4878 for (i = 0; i < colinfo->num_new_cols; i++)
4880 char *oldname = colinfo->new_colnames[i];
4882 if (oldname && strcmp(oldname, colname) == 0)
4883 return false;
4887 * Also check against names already assigned for parent-join USING
4888 * cols
4890 foreach(lc, colinfo->parentUsing)
4892 char *oldname = (char *) lfirst(lc);
4894 if (strcmp(oldname, colname) == 0)
4895 return false;
4900 * Also check against USING-column names that must be globally unique.
4901 * These are not hashed, but there should be few of them.
4903 foreach(lc, dpns->using_names)
4905 char *oldname = (char *) lfirst(lc);
4907 if (strcmp(oldname, colname) == 0)
4908 return false;
4911 return true;
4915 * make_colname_unique: modify colname if necessary to make it unique
4917 * dpns is query-wide info, colinfo is for the column's RTE
4919 static char *
4920 make_colname_unique(char *colname, deparse_namespace *dpns,
4921 deparse_columns *colinfo)
4924 * If the selected name isn't unique, append digits to make it so. For a
4925 * very long input name, we might have to truncate to stay within
4926 * NAMEDATALEN.
4928 if (!colname_is_unique(colname, dpns, colinfo))
4930 int colnamelen = strlen(colname);
4931 char *modname = (char *) palloc(colnamelen + 16);
4932 int i = 0;
4936 i++;
4937 for (;;)
4939 memcpy(modname, colname, colnamelen);
4940 sprintf(modname + colnamelen, "_%d", i);
4941 if (strlen(modname) < NAMEDATALEN)
4942 break;
4943 /* drop chars from colname to keep all the digits */
4944 colnamelen = pg_mbcliplen(colname, colnamelen,
4945 colnamelen - 1);
4947 } while (!colname_is_unique(modname, dpns, colinfo));
4948 colname = modname;
4950 return colname;
4954 * expand_colnames_array_to: make colinfo->colnames at least n items long
4956 * Any added array entries are initialized to zero.
4958 static void
4959 expand_colnames_array_to(deparse_columns *colinfo, int n)
4961 if (n > colinfo->num_cols)
4963 if (colinfo->colnames == NULL)
4964 colinfo->colnames = palloc0_array(char *, n);
4965 else
4966 colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4967 colinfo->num_cols = n;
4972 * build_colinfo_names_hash: optionally construct a hash table for colinfo
4974 static void
4975 build_colinfo_names_hash(deparse_columns *colinfo)
4977 HASHCTL hash_ctl;
4978 int i;
4979 ListCell *lc;
4982 * Use a hash table only for RTEs with at least 32 columns. (The cutoff
4983 * is somewhat arbitrary, but let's choose it so that this code does get
4984 * exercised in the regression tests.)
4986 if (colinfo->num_cols < 32)
4987 return;
4990 * Set up the hash table. The entries are just strings with no other
4991 * payload.
4993 hash_ctl.keysize = NAMEDATALEN;
4994 hash_ctl.entrysize = NAMEDATALEN;
4995 hash_ctl.hcxt = CurrentMemoryContext;
4996 colinfo->names_hash = hash_create("deparse_columns names",
4997 colinfo->num_cols + colinfo->num_new_cols,
4998 &hash_ctl,
4999 HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
5002 * Preload the hash table with any names already present (these would have
5003 * come from set_using_names).
5005 for (i = 0; i < colinfo->num_cols; i++)
5007 char *oldname = colinfo->colnames[i];
5009 if (oldname)
5010 add_to_names_hash(colinfo, oldname);
5013 for (i = 0; i < colinfo->num_new_cols; i++)
5015 char *oldname = colinfo->new_colnames[i];
5017 if (oldname)
5018 add_to_names_hash(colinfo, oldname);
5021 foreach(lc, colinfo->parentUsing)
5023 char *oldname = (char *) lfirst(lc);
5025 add_to_names_hash(colinfo, oldname);
5030 * add_to_names_hash: add a string to the names_hash, if we're using one
5032 static void
5033 add_to_names_hash(deparse_columns *colinfo, const char *name)
5035 if (colinfo->names_hash)
5036 (void) hash_search(colinfo->names_hash,
5037 name,
5038 HASH_ENTER,
5039 NULL);
5043 * destroy_colinfo_names_hash: destroy hash table when done with it
5045 static void
5046 destroy_colinfo_names_hash(deparse_columns *colinfo)
5048 if (colinfo->names_hash)
5050 hash_destroy(colinfo->names_hash);
5051 colinfo->names_hash = NULL;
5056 * identify_join_columns: figure out where columns of a join come from
5058 * Fills the join-specific fields of the colinfo struct, except for
5059 * usingNames which is filled later.
5061 static void
5062 identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
5063 deparse_columns *colinfo)
5065 int numjoincols;
5066 int jcolno;
5067 int rcolno;
5068 ListCell *lc;
5070 /* Extract left/right child RT indexes */
5071 if (IsA(j->larg, RangeTblRef))
5072 colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
5073 else if (IsA(j->larg, JoinExpr))
5074 colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
5075 else
5076 elog(ERROR, "unrecognized node type in jointree: %d",
5077 (int) nodeTag(j->larg));
5078 if (IsA(j->rarg, RangeTblRef))
5079 colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
5080 else if (IsA(j->rarg, JoinExpr))
5081 colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
5082 else
5083 elog(ERROR, "unrecognized node type in jointree: %d",
5084 (int) nodeTag(j->rarg));
5086 /* Assert children will be processed earlier than join in second pass */
5087 Assert(colinfo->leftrti < j->rtindex);
5088 Assert(colinfo->rightrti < j->rtindex);
5090 /* Initialize result arrays with zeroes */
5091 numjoincols = list_length(jrte->joinaliasvars);
5092 Assert(numjoincols == list_length(jrte->eref->colnames));
5093 colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
5094 colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
5097 * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
5098 * Recall that the column(s) merged due to USING are the first column(s)
5099 * of the join output. We need not do anything special while scanning
5100 * joinleftcols, but while scanning joinrightcols we must distinguish
5101 * merged from unmerged columns.
5103 jcolno = 0;
5104 foreach(lc, jrte->joinleftcols)
5106 int leftattno = lfirst_int(lc);
5108 colinfo->leftattnos[jcolno++] = leftattno;
5110 rcolno = 0;
5111 foreach(lc, jrte->joinrightcols)
5113 int rightattno = lfirst_int(lc);
5115 if (rcolno < jrte->joinmergedcols) /* merged column? */
5116 colinfo->rightattnos[rcolno] = rightattno;
5117 else
5118 colinfo->rightattnos[jcolno++] = rightattno;
5119 rcolno++;
5121 Assert(jcolno == numjoincols);
5125 * get_rtable_name: convenience function to get a previously assigned RTE alias
5127 * The RTE must belong to the topmost namespace level in "context".
5129 static char *
5130 get_rtable_name(int rtindex, deparse_context *context)
5132 deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
5134 Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
5135 return (char *) list_nth(dpns->rtable_names, rtindex - 1);
5139 * set_deparse_plan: set up deparse_namespace to parse subexpressions
5140 * of a given Plan node
5142 * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
5143 * and index_tlist fields. Caller must already have adjusted the ancestors
5144 * list if necessary. Note that the rtable, subplans, and ctes fields do
5145 * not need to change when shifting attention to different plan nodes in a
5146 * single plan tree.
5148 static void
5149 set_deparse_plan(deparse_namespace *dpns, Plan *plan)
5151 dpns->plan = plan;
5154 * We special-case Append and MergeAppend to pretend that the first child
5155 * plan is the OUTER referent; we have to interpret OUTER Vars in their
5156 * tlists according to one of the children, and the first one is the most
5157 * natural choice.
5159 if (IsA(plan, Append))
5160 dpns->outer_plan = linitial(((Append *) plan)->appendplans);
5161 else if (IsA(plan, MergeAppend))
5162 dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
5163 else
5164 dpns->outer_plan = outerPlan(plan);
5166 if (dpns->outer_plan)
5167 dpns->outer_tlist = dpns->outer_plan->targetlist;
5168 else
5169 dpns->outer_tlist = NIL;
5172 * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
5173 * use OUTER because that could someday conflict with the normal meaning.)
5174 * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
5175 * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
5176 * that as INNER referent.
5178 * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
5179 * INNER referent. This is the join from the target relation to the data
5180 * source, and all INNER_VAR Vars in other parts of the query refer to its
5181 * targetlist.
5183 * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
5184 * excluded expression's tlist. (Similar to the SubqueryScan we don't want
5185 * to reuse OUTER, it's used for RETURNING in some modify table cases,
5186 * although not INSERT .. CONFLICT).
5188 if (IsA(plan, SubqueryScan))
5189 dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
5190 else if (IsA(plan, CteScan))
5191 dpns->inner_plan = list_nth(dpns->subplans,
5192 ((CteScan *) plan)->ctePlanId - 1);
5193 else if (IsA(plan, WorkTableScan))
5194 dpns->inner_plan = find_recursive_union(dpns,
5195 (WorkTableScan *) plan);
5196 else if (IsA(plan, ModifyTable))
5198 if (((ModifyTable *) plan)->operation == CMD_MERGE)
5199 dpns->inner_plan = outerPlan(plan);
5200 else
5201 dpns->inner_plan = plan;
5203 else
5204 dpns->inner_plan = innerPlan(plan);
5206 if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
5207 dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5208 else if (dpns->inner_plan)
5209 dpns->inner_tlist = dpns->inner_plan->targetlist;
5210 else
5211 dpns->inner_tlist = NIL;
5213 /* Set up referent for INDEX_VAR Vars, if needed */
5214 if (IsA(plan, IndexOnlyScan))
5215 dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5216 else if (IsA(plan, ForeignScan))
5217 dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5218 else if (IsA(plan, CustomScan))
5219 dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5220 else
5221 dpns->index_tlist = NIL;
5225 * Locate the ancestor plan node that is the RecursiveUnion generating
5226 * the WorkTableScan's work table. We can match on wtParam, since that
5227 * should be unique within the plan tree.
5229 static Plan *
5230 find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
5232 ListCell *lc;
5234 foreach(lc, dpns->ancestors)
5236 Plan *ancestor = (Plan *) lfirst(lc);
5238 if (IsA(ancestor, RecursiveUnion) &&
5239 ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5240 return ancestor;
5242 elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5243 wtscan->wtParam);
5244 return NULL;
5248 * push_child_plan: temporarily transfer deparsing attention to a child plan
5250 * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
5251 * deparse context in case the referenced expression itself uses
5252 * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
5253 * affecting levelsup issues (although in a Plan tree there really shouldn't
5254 * be any).
5256 * Caller must provide a local deparse_namespace variable to save the
5257 * previous state for pop_child_plan.
5259 static void
5260 push_child_plan(deparse_namespace *dpns, Plan *plan,
5261 deparse_namespace *save_dpns)
5263 /* Save state for restoration later */
5264 *save_dpns = *dpns;
5266 /* Link current plan node into ancestors list */
5267 dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5269 /* Set attention on selected child */
5270 set_deparse_plan(dpns, plan);
5274 * pop_child_plan: undo the effects of push_child_plan
5276 static void
5277 pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5279 List *ancestors;
5281 /* Get rid of ancestors list cell added by push_child_plan */
5282 ancestors = list_delete_first(dpns->ancestors);
5284 /* Restore fields changed by push_child_plan */
5285 *dpns = *save_dpns;
5287 /* Make sure dpns->ancestors is right (may be unnecessary) */
5288 dpns->ancestors = ancestors;
5292 * push_ancestor_plan: temporarily transfer deparsing attention to an
5293 * ancestor plan
5295 * When expanding a Param reference, we must adjust the deparse context
5296 * to match the plan node that contains the expression being printed;
5297 * otherwise we'd fail if that expression itself contains a Param or
5298 * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
5300 * The target ancestor is conveniently identified by the ListCell holding it
5301 * in dpns->ancestors.
5303 * Caller must provide a local deparse_namespace variable to save the
5304 * previous state for pop_ancestor_plan.
5306 static void
5307 push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
5308 deparse_namespace *save_dpns)
5310 Plan *plan = (Plan *) lfirst(ancestor_cell);
5312 /* Save state for restoration later */
5313 *save_dpns = *dpns;
5315 /* Build a new ancestor list with just this node's ancestors */
5316 dpns->ancestors =
5317 list_copy_tail(dpns->ancestors,
5318 list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5320 /* Set attention on selected ancestor */
5321 set_deparse_plan(dpns, plan);
5325 * pop_ancestor_plan: undo the effects of push_ancestor_plan
5327 static void
5328 pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5330 /* Free the ancestor list made in push_ancestor_plan */
5331 list_free(dpns->ancestors);
5333 /* Restore fields changed by push_ancestor_plan */
5334 *dpns = *save_dpns;
5338 /* ----------
5339 * make_ruledef - reconstruct the CREATE RULE command
5340 * for a given pg_rewrite tuple
5341 * ----------
5343 static void
5344 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5345 int prettyFlags)
5347 char *rulename;
5348 char ev_type;
5349 Oid ev_class;
5350 bool is_instead;
5351 char *ev_qual;
5352 char *ev_action;
5353 List *actions;
5354 Relation ev_relation;
5355 TupleDesc viewResultDesc = NULL;
5356 int fno;
5357 Datum dat;
5358 bool isnull;
5361 * Get the attribute values from the rules tuple
5363 fno = SPI_fnumber(rulettc, "rulename");
5364 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5365 Assert(!isnull);
5366 rulename = NameStr(*(DatumGetName(dat)));
5368 fno = SPI_fnumber(rulettc, "ev_type");
5369 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5370 Assert(!isnull);
5371 ev_type = DatumGetChar(dat);
5373 fno = SPI_fnumber(rulettc, "ev_class");
5374 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5375 Assert(!isnull);
5376 ev_class = DatumGetObjectId(dat);
5378 fno = SPI_fnumber(rulettc, "is_instead");
5379 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5380 Assert(!isnull);
5381 is_instead = DatumGetBool(dat);
5383 fno = SPI_fnumber(rulettc, "ev_qual");
5384 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5385 Assert(ev_qual != NULL);
5387 fno = SPI_fnumber(rulettc, "ev_action");
5388 ev_action = SPI_getvalue(ruletup, rulettc, fno);
5389 Assert(ev_action != NULL);
5390 actions = (List *) stringToNode(ev_action);
5391 if (actions == NIL)
5392 elog(ERROR, "invalid empty ev_action list");
5394 ev_relation = table_open(ev_class, AccessShareLock);
5397 * Build the rules definition text
5399 appendStringInfo(buf, "CREATE RULE %s AS",
5400 quote_identifier(rulename));
5402 if (prettyFlags & PRETTYFLAG_INDENT)
5403 appendStringInfoString(buf, "\n ON ");
5404 else
5405 appendStringInfoString(buf, " ON ");
5407 /* The event the rule is fired for */
5408 switch (ev_type)
5410 case '1':
5411 appendStringInfoString(buf, "SELECT");
5412 viewResultDesc = RelationGetDescr(ev_relation);
5413 break;
5415 case '2':
5416 appendStringInfoString(buf, "UPDATE");
5417 break;
5419 case '3':
5420 appendStringInfoString(buf, "INSERT");
5421 break;
5423 case '4':
5424 appendStringInfoString(buf, "DELETE");
5425 break;
5427 default:
5428 ereport(ERROR,
5429 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5430 errmsg("rule \"%s\" has unsupported event type %d",
5431 rulename, ev_type)));
5432 break;
5435 /* The relation the rule is fired on */
5436 appendStringInfo(buf, " TO %s",
5437 (prettyFlags & PRETTYFLAG_SCHEMA) ?
5438 generate_relation_name(ev_class, NIL) :
5439 generate_qualified_relation_name(ev_class));
5441 /* If the rule has an event qualification, add it */
5442 if (strcmp(ev_qual, "<>") != 0)
5444 Node *qual;
5445 Query *query;
5446 deparse_context context;
5447 deparse_namespace dpns;
5449 if (prettyFlags & PRETTYFLAG_INDENT)
5450 appendStringInfoString(buf, "\n ");
5451 appendStringInfoString(buf, " WHERE ");
5453 qual = stringToNode(ev_qual);
5456 * We need to make a context for recognizing any Vars in the qual
5457 * (which can only be references to OLD and NEW). Use the rtable of
5458 * the first query in the action list for this purpose.
5460 query = (Query *) linitial(actions);
5463 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5464 * into the SELECT, and that's what we need to look at. (Ugly kluge
5465 * ... try to fix this when we redesign querytrees.)
5467 query = getInsertSelectQuery(query, NULL);
5469 /* Must acquire locks right away; see notes in get_query_def() */
5470 AcquireRewriteLocks(query, false, false);
5472 context.buf = buf;
5473 context.namespaces = list_make1(&dpns);
5474 context.resultDesc = NULL;
5475 context.targetList = NIL;
5476 context.windowClause = NIL;
5477 context.varprefix = (list_length(query->rtable) != 1);
5478 context.prettyFlags = prettyFlags;
5479 context.wrapColumn = WRAP_COLUMN_DEFAULT;
5480 context.indentLevel = PRETTYINDENT_STD;
5481 context.colNamesVisible = true;
5482 context.inGroupBy = false;
5483 context.varInOrderBy = false;
5484 context.appendparents = NULL;
5486 set_deparse_for_query(&dpns, query, NIL);
5488 get_rule_expr(qual, &context, false);
5491 appendStringInfoString(buf, " DO ");
5493 /* The INSTEAD keyword (if so) */
5494 if (is_instead)
5495 appendStringInfoString(buf, "INSTEAD ");
5497 /* Finally the rules actions */
5498 if (list_length(actions) > 1)
5500 ListCell *action;
5501 Query *query;
5503 appendStringInfoChar(buf, '(');
5504 foreach(action, actions)
5506 query = (Query *) lfirst(action);
5507 get_query_def(query, buf, NIL, viewResultDesc, true,
5508 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5509 if (prettyFlags)
5510 appendStringInfoString(buf, ";\n");
5511 else
5512 appendStringInfoString(buf, "; ");
5514 appendStringInfoString(buf, ");");
5516 else
5518 Query *query;
5520 query = (Query *) linitial(actions);
5521 get_query_def(query, buf, NIL, viewResultDesc, true,
5522 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5523 appendStringInfoChar(buf, ';');
5526 table_close(ev_relation, AccessShareLock);
5530 /* ----------
5531 * make_viewdef - reconstruct the SELECT part of a
5532 * view rewrite rule
5533 * ----------
5535 static void
5536 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5537 int prettyFlags, int wrapColumn)
5539 Query *query;
5540 char ev_type;
5541 Oid ev_class;
5542 bool is_instead;
5543 char *ev_qual;
5544 char *ev_action;
5545 List *actions;
5546 Relation ev_relation;
5547 int fno;
5548 Datum dat;
5549 bool isnull;
5552 * Get the attribute values from the rules tuple
5554 fno = SPI_fnumber(rulettc, "ev_type");
5555 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5556 Assert(!isnull);
5557 ev_type = DatumGetChar(dat);
5559 fno = SPI_fnumber(rulettc, "ev_class");
5560 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5561 Assert(!isnull);
5562 ev_class = DatumGetObjectId(dat);
5564 fno = SPI_fnumber(rulettc, "is_instead");
5565 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5566 Assert(!isnull);
5567 is_instead = DatumGetBool(dat);
5569 fno = SPI_fnumber(rulettc, "ev_qual");
5570 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5571 Assert(ev_qual != NULL);
5573 fno = SPI_fnumber(rulettc, "ev_action");
5574 ev_action = SPI_getvalue(ruletup, rulettc, fno);
5575 Assert(ev_action != NULL);
5576 actions = (List *) stringToNode(ev_action);
5578 if (list_length(actions) != 1)
5580 /* keep output buffer empty and leave */
5581 return;
5584 query = (Query *) linitial(actions);
5586 if (ev_type != '1' || !is_instead ||
5587 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5589 /* keep output buffer empty and leave */
5590 return;
5593 ev_relation = table_open(ev_class, AccessShareLock);
5595 get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
5596 prettyFlags, wrapColumn, 0);
5597 appendStringInfoChar(buf, ';');
5599 table_close(ev_relation, AccessShareLock);
5603 /* ----------
5604 * get_query_def - Parse back one query parsetree
5606 * query: parsetree to be displayed
5607 * buf: output text is appended to buf
5608 * parentnamespace: list (initially empty) of outer-level deparse_namespace's
5609 * resultDesc: if not NULL, the output tuple descriptor for the view
5610 * represented by a SELECT query. We use the column names from it
5611 * to label SELECT output columns, in preference to names in the query
5612 * colNamesVisible: true if the surrounding context cares about the output
5613 * column names at all (as, for example, an EXISTS() context does not);
5614 * when false, we can suppress dummy column labels such as "?column?"
5615 * prettyFlags: bitmask of PRETTYFLAG_XXX options
5616 * wrapColumn: maximum line length, or -1 to disable wrapping
5617 * startIndent: initial indentation amount
5618 * ----------
5620 static void
5621 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
5622 TupleDesc resultDesc, bool colNamesVisible,
5623 int prettyFlags, int wrapColumn, int startIndent)
5625 deparse_context context;
5626 deparse_namespace dpns;
5627 int rtable_size;
5629 /* Guard against excessively long or deeply-nested queries */
5630 CHECK_FOR_INTERRUPTS();
5631 check_stack_depth();
5633 rtable_size = query->hasGroupRTE ?
5634 list_length(query->rtable) - 1 :
5635 list_length(query->rtable);
5638 * Replace any Vars in the query's targetlist and havingQual that
5639 * reference GROUP outputs with the underlying grouping expressions.
5641 if (query->hasGroupRTE)
5643 query->targetList = (List *)
5644 flatten_group_exprs(NULL, query, (Node *) query->targetList);
5645 query->havingQual =
5646 flatten_group_exprs(NULL, query, query->havingQual);
5650 * Before we begin to examine the query, acquire locks on referenced
5651 * relations, and fix up deleted columns in JOIN RTEs. This ensures
5652 * consistent results. Note we assume it's OK to scribble on the passed
5653 * querytree!
5655 * We are only deparsing the query (we are not about to execute it), so we
5656 * only need AccessShareLock on the relations it mentions.
5658 AcquireRewriteLocks(query, false, false);
5660 context.buf = buf;
5661 context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5662 context.resultDesc = NULL;
5663 context.targetList = NIL;
5664 context.windowClause = NIL;
5665 context.varprefix = (parentnamespace != NIL ||
5666 rtable_size != 1);
5667 context.prettyFlags = prettyFlags;
5668 context.wrapColumn = wrapColumn;
5669 context.indentLevel = startIndent;
5670 context.colNamesVisible = colNamesVisible;
5671 context.inGroupBy = false;
5672 context.varInOrderBy = false;
5673 context.appendparents = NULL;
5675 set_deparse_for_query(&dpns, query, parentnamespace);
5677 switch (query->commandType)
5679 case CMD_SELECT:
5680 /* We set context.resultDesc only if it's a SELECT */
5681 context.resultDesc = resultDesc;
5682 get_select_query_def(query, &context);
5683 break;
5685 case CMD_UPDATE:
5686 get_update_query_def(query, &context);
5687 break;
5689 case CMD_INSERT:
5690 get_insert_query_def(query, &context);
5691 break;
5693 case CMD_DELETE:
5694 get_delete_query_def(query, &context);
5695 break;
5697 case CMD_MERGE:
5698 get_merge_query_def(query, &context);
5699 break;
5701 case CMD_NOTHING:
5702 appendStringInfoString(buf, "NOTHING");
5703 break;
5705 case CMD_UTILITY:
5706 get_utility_query_def(query, &context);
5707 break;
5709 default:
5710 elog(ERROR, "unrecognized query command type: %d",
5711 query->commandType);
5712 break;
5716 /* ----------
5717 * get_values_def - Parse back a VALUES list
5718 * ----------
5720 static void
5721 get_values_def(List *values_lists, deparse_context *context)
5723 StringInfo buf = context->buf;
5724 bool first_list = true;
5725 ListCell *vtl;
5727 appendStringInfoString(buf, "VALUES ");
5729 foreach(vtl, values_lists)
5731 List *sublist = (List *) lfirst(vtl);
5732 bool first_col = true;
5733 ListCell *lc;
5735 if (first_list)
5736 first_list = false;
5737 else
5738 appendStringInfoString(buf, ", ");
5740 appendStringInfoChar(buf, '(');
5741 foreach(lc, sublist)
5743 Node *col = (Node *) lfirst(lc);
5745 if (first_col)
5746 first_col = false;
5747 else
5748 appendStringInfoChar(buf, ',');
5751 * Print the value. Whole-row Vars need special treatment.
5753 get_rule_expr_toplevel(col, context, false);
5755 appendStringInfoChar(buf, ')');
5759 /* ----------
5760 * get_with_clause - Parse back a WITH clause
5761 * ----------
5763 static void
5764 get_with_clause(Query *query, deparse_context *context)
5766 StringInfo buf = context->buf;
5767 const char *sep;
5768 ListCell *l;
5770 if (query->cteList == NIL)
5771 return;
5773 if (PRETTY_INDENT(context))
5775 context->indentLevel += PRETTYINDENT_STD;
5776 appendStringInfoChar(buf, ' ');
5779 if (query->hasRecursive)
5780 sep = "WITH RECURSIVE ";
5781 else
5782 sep = "WITH ";
5783 foreach(l, query->cteList)
5785 CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5787 appendStringInfoString(buf, sep);
5788 appendStringInfoString(buf, quote_identifier(cte->ctename));
5789 if (cte->aliascolnames)
5791 bool first = true;
5792 ListCell *col;
5794 appendStringInfoChar(buf, '(');
5795 foreach(col, cte->aliascolnames)
5797 if (first)
5798 first = false;
5799 else
5800 appendStringInfoString(buf, ", ");
5801 appendStringInfoString(buf,
5802 quote_identifier(strVal(lfirst(col))));
5804 appendStringInfoChar(buf, ')');
5806 appendStringInfoString(buf, " AS ");
5807 switch (cte->ctematerialized)
5809 case CTEMaterializeDefault:
5810 break;
5811 case CTEMaterializeAlways:
5812 appendStringInfoString(buf, "MATERIALIZED ");
5813 break;
5814 case CTEMaterializeNever:
5815 appendStringInfoString(buf, "NOT MATERIALIZED ");
5816 break;
5818 appendStringInfoChar(buf, '(');
5819 if (PRETTY_INDENT(context))
5820 appendContextKeyword(context, "", 0, 0, 0);
5821 get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5822 true,
5823 context->prettyFlags, context->wrapColumn,
5824 context->indentLevel);
5825 if (PRETTY_INDENT(context))
5826 appendContextKeyword(context, "", 0, 0, 0);
5827 appendStringInfoChar(buf, ')');
5829 if (cte->search_clause)
5831 bool first = true;
5832 ListCell *lc;
5834 appendStringInfo(buf, " SEARCH %s FIRST BY ",
5835 cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
5837 foreach(lc, cte->search_clause->search_col_list)
5839 if (first)
5840 first = false;
5841 else
5842 appendStringInfoString(buf, ", ");
5843 appendStringInfoString(buf,
5844 quote_identifier(strVal(lfirst(lc))));
5847 appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
5850 if (cte->cycle_clause)
5852 bool first = true;
5853 ListCell *lc;
5855 appendStringInfoString(buf, " CYCLE ");
5857 foreach(lc, cte->cycle_clause->cycle_col_list)
5859 if (first)
5860 first = false;
5861 else
5862 appendStringInfoString(buf, ", ");
5863 appendStringInfoString(buf,
5864 quote_identifier(strVal(lfirst(lc))));
5867 appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5870 Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5871 Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5873 if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5874 cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5876 appendStringInfoString(buf, " TO ");
5877 get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
5878 appendStringInfoString(buf, " DEFAULT ");
5879 get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
5883 appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5886 sep = ", ";
5889 if (PRETTY_INDENT(context))
5891 context->indentLevel -= PRETTYINDENT_STD;
5892 appendContextKeyword(context, "", 0, 0, 0);
5894 else
5895 appendStringInfoChar(buf, ' ');
5898 /* ----------
5899 * get_select_query_def - Parse back a SELECT parsetree
5900 * ----------
5902 static void
5903 get_select_query_def(Query *query, deparse_context *context)
5905 StringInfo buf = context->buf;
5906 bool force_colno;
5907 ListCell *l;
5909 /* Insert the WITH clause if given */
5910 get_with_clause(query, context);
5912 /* Subroutines may need to consult the SELECT targetlist and windowClause */
5913 context->targetList = query->targetList;
5914 context->windowClause = query->windowClause;
5917 * If the Query node has a setOperations tree, then it's the top level of
5918 * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5919 * fields are interesting in the top query itself.
5921 if (query->setOperations)
5923 get_setop_query(query->setOperations, query, context);
5924 /* ORDER BY clauses must be simple in this case */
5925 force_colno = true;
5927 else
5929 get_basic_select_query(query, context);
5930 force_colno = false;
5933 /* Add the ORDER BY clause if given */
5934 if (query->sortClause != NIL)
5936 appendContextKeyword(context, " ORDER BY ",
5937 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5938 get_rule_orderby(query->sortClause, query->targetList,
5939 force_colno, context);
5943 * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5944 * standard spelling of LIMIT.
5946 if (query->limitOffset != NULL)
5948 appendContextKeyword(context, " OFFSET ",
5949 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5950 get_rule_expr(query->limitOffset, context, false);
5952 if (query->limitCount != NULL)
5954 if (query->limitOption == LIMIT_OPTION_WITH_TIES)
5956 appendContextKeyword(context, " FETCH FIRST ",
5957 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5958 get_rule_expr(query->limitCount, context, false);
5959 appendStringInfoString(buf, " ROWS WITH TIES");
5961 else
5963 appendContextKeyword(context, " LIMIT ",
5964 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5965 if (IsA(query->limitCount, Const) &&
5966 ((Const *) query->limitCount)->constisnull)
5967 appendStringInfoString(buf, "ALL");
5968 else
5969 get_rule_expr(query->limitCount, context, false);
5973 /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5974 if (query->hasForUpdate)
5976 foreach(l, query->rowMarks)
5978 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5980 /* don't print implicit clauses */
5981 if (rc->pushedDown)
5982 continue;
5984 switch (rc->strength)
5986 case LCS_NONE:
5987 /* we intentionally throw an error for LCS_NONE */
5988 elog(ERROR, "unrecognized LockClauseStrength %d",
5989 (int) rc->strength);
5990 break;
5991 case LCS_FORKEYSHARE:
5992 appendContextKeyword(context, " FOR KEY SHARE",
5993 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5994 break;
5995 case LCS_FORSHARE:
5996 appendContextKeyword(context, " FOR SHARE",
5997 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5998 break;
5999 case LCS_FORNOKEYUPDATE:
6000 appendContextKeyword(context, " FOR NO KEY UPDATE",
6001 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6002 break;
6003 case LCS_FORUPDATE:
6004 appendContextKeyword(context, " FOR UPDATE",
6005 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6006 break;
6009 appendStringInfo(buf, " OF %s",
6010 quote_identifier(get_rtable_name(rc->rti,
6011 context)));
6012 if (rc->waitPolicy == LockWaitError)
6013 appendStringInfoString(buf, " NOWAIT");
6014 else if (rc->waitPolicy == LockWaitSkip)
6015 appendStringInfoString(buf, " SKIP LOCKED");
6021 * Detect whether query looks like SELECT ... FROM VALUES(),
6022 * with no need to rename the output columns of the VALUES RTE.
6023 * If so, return the VALUES RTE. Otherwise return NULL.
6025 static RangeTblEntry *
6026 get_simple_values_rte(Query *query, TupleDesc resultDesc)
6028 RangeTblEntry *result = NULL;
6029 ListCell *lc;
6032 * We want to detect a match even if the Query also contains OLD or NEW
6033 * rule RTEs. So the idea is to scan the rtable and see if there is only
6034 * one inFromCl RTE that is a VALUES RTE.
6036 foreach(lc, query->rtable)
6038 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
6040 if (rte->rtekind == RTE_VALUES && rte->inFromCl)
6042 if (result)
6043 return NULL; /* multiple VALUES (probably not possible) */
6044 result = rte;
6046 else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
6047 continue; /* ignore rule entries */
6048 else
6049 return NULL; /* something else -> not simple VALUES */
6053 * We don't need to check the targetlist in any great detail, because
6054 * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
6055 * appear inside auto-generated sub-queries with very restricted
6056 * structure. However, DefineView might have modified the tlist by
6057 * injecting new column aliases, or we might have some other column
6058 * aliases forced by a resultDesc. We can only simplify if the RTE's
6059 * column names match the names that get_target_list() would select.
6061 if (result)
6063 ListCell *lcn;
6064 int colno;
6066 if (list_length(query->targetList) != list_length(result->eref->colnames))
6067 return NULL; /* this probably cannot happen */
6068 colno = 0;
6069 forboth(lc, query->targetList, lcn, result->eref->colnames)
6071 TargetEntry *tle = (TargetEntry *) lfirst(lc);
6072 char *cname = strVal(lfirst(lcn));
6073 char *colname;
6075 if (tle->resjunk)
6076 return NULL; /* this probably cannot happen */
6078 /* compute name that get_target_list would use for column */
6079 colno++;
6080 if (resultDesc && colno <= resultDesc->natts)
6081 colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6082 else
6083 colname = tle->resname;
6085 /* does it match the VALUES RTE? */
6086 if (colname == NULL || strcmp(colname, cname) != 0)
6087 return NULL; /* column name has been changed */
6091 return result;
6094 static void
6095 get_basic_select_query(Query *query, deparse_context *context)
6097 StringInfo buf = context->buf;
6098 RangeTblEntry *values_rte;
6099 char *sep;
6100 ListCell *l;
6102 if (PRETTY_INDENT(context))
6104 context->indentLevel += PRETTYINDENT_STD;
6105 appendStringInfoChar(buf, ' ');
6109 * If the query looks like SELECT * FROM (VALUES ...), then print just the
6110 * VALUES part. This reverses what transformValuesClause() did at parse
6111 * time.
6113 values_rte = get_simple_values_rte(query, context->resultDesc);
6114 if (values_rte)
6116 get_values_def(values_rte->values_lists, context);
6117 return;
6121 * Build up the query string - first we say SELECT
6123 if (query->isReturn)
6124 appendStringInfoString(buf, "RETURN");
6125 else
6126 appendStringInfoString(buf, "SELECT");
6128 /* Add the DISTINCT clause if given */
6129 if (query->distinctClause != NIL)
6131 if (query->hasDistinctOn)
6133 appendStringInfoString(buf, " DISTINCT ON (");
6134 sep = "";
6135 foreach(l, query->distinctClause)
6137 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6139 appendStringInfoString(buf, sep);
6140 get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList,
6141 false, context);
6142 sep = ", ";
6144 appendStringInfoChar(buf, ')');
6146 else
6147 appendStringInfoString(buf, " DISTINCT");
6150 /* Then we tell what to select (the targetlist) */
6151 get_target_list(query->targetList, context);
6153 /* Add the FROM clause if needed */
6154 get_from_clause(query, " FROM ", context);
6156 /* Add the WHERE clause if given */
6157 if (query->jointree->quals != NULL)
6159 appendContextKeyword(context, " WHERE ",
6160 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6161 get_rule_expr(query->jointree->quals, context, false);
6164 /* Add the GROUP BY clause if given */
6165 if (query->groupClause != NULL || query->groupingSets != NULL)
6167 bool save_ingroupby;
6169 appendContextKeyword(context, " GROUP BY ",
6170 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6171 if (query->groupDistinct)
6172 appendStringInfoString(buf, "DISTINCT ");
6174 save_ingroupby = context->inGroupBy;
6175 context->inGroupBy = true;
6177 if (query->groupingSets == NIL)
6179 sep = "";
6180 foreach(l, query->groupClause)
6182 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6184 appendStringInfoString(buf, sep);
6185 get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList,
6186 false, context);
6187 sep = ", ";
6190 else
6192 sep = "";
6193 foreach(l, query->groupingSets)
6195 GroupingSet *grp = lfirst(l);
6197 appendStringInfoString(buf, sep);
6198 get_rule_groupingset(grp, query->targetList, true, context);
6199 sep = ", ";
6203 context->inGroupBy = save_ingroupby;
6206 /* Add the HAVING clause if given */
6207 if (query->havingQual != NULL)
6209 appendContextKeyword(context, " HAVING ",
6210 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6211 get_rule_expr(query->havingQual, context, false);
6214 /* Add the WINDOW clause if needed */
6215 if (query->windowClause != NIL)
6216 get_rule_windowclause(query, context);
6219 /* ----------
6220 * get_target_list - Parse back a SELECT target list
6222 * This is also used for RETURNING lists in INSERT/UPDATE/DELETE/MERGE.
6223 * ----------
6225 static void
6226 get_target_list(List *targetList, deparse_context *context)
6228 StringInfo buf = context->buf;
6229 StringInfoData targetbuf;
6230 bool last_was_multiline = false;
6231 char *sep;
6232 int colno;
6233 ListCell *l;
6235 /* we use targetbuf to hold each TLE's text temporarily */
6236 initStringInfo(&targetbuf);
6238 sep = " ";
6239 colno = 0;
6240 foreach(l, targetList)
6242 TargetEntry *tle = (TargetEntry *) lfirst(l);
6243 char *colname;
6244 char *attname;
6246 if (tle->resjunk)
6247 continue; /* ignore junk entries */
6249 appendStringInfoString(buf, sep);
6250 sep = ", ";
6251 colno++;
6254 * Put the new field text into targetbuf so we can decide after we've
6255 * got it whether or not it needs to go on a new line.
6257 resetStringInfo(&targetbuf);
6258 context->buf = &targetbuf;
6261 * We special-case Var nodes rather than using get_rule_expr. This is
6262 * needed because get_rule_expr will display a whole-row Var as
6263 * "foo.*", which is the preferred notation in most contexts, but at
6264 * the top level of a SELECT list it's not right (the parser will
6265 * expand that notation into multiple columns, yielding behavior
6266 * different from a whole-row Var). We need to call get_variable
6267 * directly so that we can tell it to do the right thing, and so that
6268 * we can get the attribute name which is the default AS label.
6270 if (tle->expr && (IsA(tle->expr, Var)))
6272 attname = get_variable((Var *) tle->expr, 0, true, context);
6274 else
6276 get_rule_expr((Node *) tle->expr, context, true);
6279 * When colNamesVisible is true, we should always show the
6280 * assigned column name explicitly. Otherwise, show it only if
6281 * it's not FigureColname's fallback.
6283 attname = context->colNamesVisible ? NULL : "?column?";
6287 * Figure out what the result column should be called. In the context
6288 * of a view, use the view's tuple descriptor (so as to pick up the
6289 * effects of any column RENAME that's been done on the view).
6290 * Otherwise, just use what we can find in the TLE.
6292 if (context->resultDesc && colno <= context->resultDesc->natts)
6293 colname = NameStr(TupleDescAttr(context->resultDesc,
6294 colno - 1)->attname);
6295 else
6296 colname = tle->resname;
6298 /* Show AS unless the column's name is correct as-is */
6299 if (colname) /* resname could be NULL */
6301 if (attname == NULL || strcmp(attname, colname) != 0)
6302 appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6305 /* Restore context's output buffer */
6306 context->buf = buf;
6308 /* Consider line-wrapping if enabled */
6309 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6311 int leading_nl_pos;
6313 /* Does the new field start with a new line? */
6314 if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
6315 leading_nl_pos = 0;
6316 else
6317 leading_nl_pos = -1;
6319 /* If so, we shouldn't add anything */
6320 if (leading_nl_pos >= 0)
6322 /* instead, remove any trailing spaces currently in buf */
6323 removeStringInfoSpaces(buf);
6325 else
6327 char *trailing_nl;
6329 /* Locate the start of the current line in the output buffer */
6330 trailing_nl = strrchr(buf->data, '\n');
6331 if (trailing_nl == NULL)
6332 trailing_nl = buf->data;
6333 else
6334 trailing_nl++;
6337 * Add a newline, plus some indentation, if the new field is
6338 * not the first and either the new field would cause an
6339 * overflow or the last field used more than one line.
6341 if (colno > 1 &&
6342 ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
6343 last_was_multiline))
6344 appendContextKeyword(context, "", -PRETTYINDENT_STD,
6345 PRETTYINDENT_STD, PRETTYINDENT_VAR);
6348 /* Remember this field's multiline status for next iteration */
6349 last_was_multiline =
6350 (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6353 /* Add the new field */
6354 appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
6357 /* clean up */
6358 pfree(targetbuf.data);
6361 static void
6362 get_returning_clause(Query *query, deparse_context *context)
6364 StringInfo buf = context->buf;
6366 if (query->returningList)
6368 bool have_with = false;
6370 appendContextKeyword(context, " RETURNING",
6371 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6373 /* Add WITH (OLD/NEW) options, if they're not the defaults */
6374 if (query->returningOldAlias && strcmp(query->returningOldAlias, "old") != 0)
6376 appendStringInfo(buf, " WITH (OLD AS %s",
6377 quote_identifier(query->returningOldAlias));
6378 have_with = true;
6380 if (query->returningNewAlias && strcmp(query->returningNewAlias, "new") != 0)
6382 if (have_with)
6383 appendStringInfo(buf, ", NEW AS %s",
6384 quote_identifier(query->returningNewAlias));
6385 else
6387 appendStringInfo(buf, " WITH (NEW AS %s",
6388 quote_identifier(query->returningNewAlias));
6389 have_with = true;
6392 if (have_with)
6393 appendStringInfoChar(buf, ')');
6395 /* Add the returning expressions themselves */
6396 get_target_list(query->returningList, context);
6400 static void
6401 get_setop_query(Node *setOp, Query *query, deparse_context *context)
6403 StringInfo buf = context->buf;
6404 bool need_paren;
6406 /* Guard against excessively long or deeply-nested queries */
6407 CHECK_FOR_INTERRUPTS();
6408 check_stack_depth();
6410 if (IsA(setOp, RangeTblRef))
6412 RangeTblRef *rtr = (RangeTblRef *) setOp;
6413 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6414 Query *subquery = rte->subquery;
6416 Assert(subquery != NULL);
6419 * We need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y.
6420 * Also add parens if the leaf query contains its own set operations.
6421 * (That shouldn't happen unless one of the other clauses is also
6422 * present, see transformSetOperationTree; but let's be safe.)
6424 need_paren = (subquery->cteList ||
6425 subquery->sortClause ||
6426 subquery->rowMarks ||
6427 subquery->limitOffset ||
6428 subquery->limitCount ||
6429 subquery->setOperations);
6430 if (need_paren)
6431 appendStringInfoChar(buf, '(');
6432 get_query_def(subquery, buf, context->namespaces,
6433 context->resultDesc, context->colNamesVisible,
6434 context->prettyFlags, context->wrapColumn,
6435 context->indentLevel);
6436 if (need_paren)
6437 appendStringInfoChar(buf, ')');
6439 else if (IsA(setOp, SetOperationStmt))
6441 SetOperationStmt *op = (SetOperationStmt *) setOp;
6442 int subindent;
6443 bool save_colnamesvisible;
6446 * We force parens when nesting two SetOperationStmts, except when the
6447 * lefthand input is another setop of the same kind. Syntactically,
6448 * we could omit parens in rather more cases, but it seems best to use
6449 * parens to flag cases where the setop operator changes. If we use
6450 * parens, we also increase the indentation level for the child query.
6452 * There are some cases in which parens are needed around a leaf query
6453 * too, but those are more easily handled at the next level down (see
6454 * code above).
6456 if (IsA(op->larg, SetOperationStmt))
6458 SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6460 if (op->op == lop->op && op->all == lop->all)
6461 need_paren = false;
6462 else
6463 need_paren = true;
6465 else
6466 need_paren = false;
6468 if (need_paren)
6470 appendStringInfoChar(buf, '(');
6471 subindent = PRETTYINDENT_STD;
6472 appendContextKeyword(context, "", subindent, 0, 0);
6474 else
6475 subindent = 0;
6477 get_setop_query(op->larg, query, context);
6479 if (need_paren)
6480 appendContextKeyword(context, ") ", -subindent, 0, 0);
6481 else if (PRETTY_INDENT(context))
6482 appendContextKeyword(context, "", -subindent, 0, 0);
6483 else
6484 appendStringInfoChar(buf, ' ');
6486 switch (op->op)
6488 case SETOP_UNION:
6489 appendStringInfoString(buf, "UNION ");
6490 break;
6491 case SETOP_INTERSECT:
6492 appendStringInfoString(buf, "INTERSECT ");
6493 break;
6494 case SETOP_EXCEPT:
6495 appendStringInfoString(buf, "EXCEPT ");
6496 break;
6497 default:
6498 elog(ERROR, "unrecognized set op: %d",
6499 (int) op->op);
6501 if (op->all)
6502 appendStringInfoString(buf, "ALL ");
6504 /* Always parenthesize if RHS is another setop */
6505 need_paren = IsA(op->rarg, SetOperationStmt);
6508 * The indentation code here is deliberately a bit different from that
6509 * for the lefthand input, because we want the line breaks in
6510 * different places.
6512 if (need_paren)
6514 appendStringInfoChar(buf, '(');
6515 subindent = PRETTYINDENT_STD;
6517 else
6518 subindent = 0;
6519 appendContextKeyword(context, "", subindent, 0, 0);
6522 * The output column names of the RHS sub-select don't matter.
6524 save_colnamesvisible = context->colNamesVisible;
6525 context->colNamesVisible = false;
6527 get_setop_query(op->rarg, query, context);
6529 context->colNamesVisible = save_colnamesvisible;
6531 if (PRETTY_INDENT(context))
6532 context->indentLevel -= subindent;
6533 if (need_paren)
6534 appendContextKeyword(context, ")", 0, 0, 0);
6536 else
6538 elog(ERROR, "unrecognized node type: %d",
6539 (int) nodeTag(setOp));
6544 * Display a sort/group clause.
6546 * Also returns the expression tree, so caller need not find it again.
6548 static Node *
6549 get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
6550 deparse_context *context)
6552 StringInfo buf = context->buf;
6553 TargetEntry *tle;
6554 Node *expr;
6556 tle = get_sortgroupref_tle(ref, tlist);
6557 expr = (Node *) tle->expr;
6560 * Use column-number form if requested by caller. Otherwise, if
6561 * expression is a constant, force it to be dumped with an explicit cast
6562 * as decoration --- this is because a simple integer constant is
6563 * ambiguous (and will be misinterpreted by findTargetlistEntrySQL92()) if
6564 * we dump it without any decoration. Similarly, if it's just a Var,
6565 * there is risk of misinterpretation if the column name is reassigned in
6566 * the SELECT list, so we may need to force table qualification. And, if
6567 * it's anything more complex than a simple Var, then force extra parens
6568 * around it, to ensure it can't be misinterpreted as a cube() or rollup()
6569 * construct.
6571 if (force_colno)
6573 Assert(!tle->resjunk);
6574 appendStringInfo(buf, "%d", tle->resno);
6576 else if (!expr)
6577 /* do nothing, probably can't happen */ ;
6578 else if (IsA(expr, Const))
6579 get_const_expr((Const *) expr, context, 1);
6580 else if (IsA(expr, Var))
6582 /* Tell get_variable to check for name conflict */
6583 bool save_varinorderby = context->varInOrderBy;
6585 context->varInOrderBy = true;
6586 (void) get_variable((Var *) expr, 0, false, context);
6587 context->varInOrderBy = save_varinorderby;
6589 else
6592 * We must force parens for function-like expressions even if
6593 * PRETTY_PAREN is off, since those are the ones in danger of
6594 * misparsing. For other expressions we need to force them only if
6595 * PRETTY_PAREN is on, since otherwise the expression will output them
6596 * itself. (We can't skip the parens.)
6598 bool need_paren = (PRETTY_PAREN(context)
6599 || IsA(expr, FuncExpr)
6600 || IsA(expr, Aggref)
6601 || IsA(expr, WindowFunc)
6602 || IsA(expr, JsonConstructorExpr));
6604 if (need_paren)
6605 appendStringInfoChar(context->buf, '(');
6606 get_rule_expr(expr, context, true);
6607 if (need_paren)
6608 appendStringInfoChar(context->buf, ')');
6611 return expr;
6615 * Display a GroupingSet
6617 static void
6618 get_rule_groupingset(GroupingSet *gset, List *targetlist,
6619 bool omit_parens, deparse_context *context)
6621 ListCell *l;
6622 StringInfo buf = context->buf;
6623 bool omit_child_parens = true;
6624 char *sep = "";
6626 switch (gset->kind)
6628 case GROUPING_SET_EMPTY:
6629 appendStringInfoString(buf, "()");
6630 return;
6632 case GROUPING_SET_SIMPLE:
6634 if (!omit_parens || list_length(gset->content) != 1)
6635 appendStringInfoChar(buf, '(');
6637 foreach(l, gset->content)
6639 Index ref = lfirst_int(l);
6641 appendStringInfoString(buf, sep);
6642 get_rule_sortgroupclause(ref, targetlist,
6643 false, context);
6644 sep = ", ";
6647 if (!omit_parens || list_length(gset->content) != 1)
6648 appendStringInfoChar(buf, ')');
6650 return;
6652 case GROUPING_SET_ROLLUP:
6653 appendStringInfoString(buf, "ROLLUP(");
6654 break;
6655 case GROUPING_SET_CUBE:
6656 appendStringInfoString(buf, "CUBE(");
6657 break;
6658 case GROUPING_SET_SETS:
6659 appendStringInfoString(buf, "GROUPING SETS (");
6660 omit_child_parens = false;
6661 break;
6664 foreach(l, gset->content)
6666 appendStringInfoString(buf, sep);
6667 get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6668 sep = ", ";
6671 appendStringInfoChar(buf, ')');
6675 * Display an ORDER BY list.
6677 static void
6678 get_rule_orderby(List *orderList, List *targetList,
6679 bool force_colno, deparse_context *context)
6681 StringInfo buf = context->buf;
6682 const char *sep;
6683 ListCell *l;
6685 sep = "";
6686 foreach(l, orderList)
6688 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6689 Node *sortexpr;
6690 Oid sortcoltype;
6691 TypeCacheEntry *typentry;
6693 appendStringInfoString(buf, sep);
6694 sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6695 force_colno, context);
6696 sortcoltype = exprType(sortexpr);
6697 /* See whether operator is default < or > for datatype */
6698 typentry = lookup_type_cache(sortcoltype,
6699 TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
6700 if (srt->sortop == typentry->lt_opr)
6702 /* ASC is default, so emit nothing for it */
6703 if (srt->nulls_first)
6704 appendStringInfoString(buf, " NULLS FIRST");
6706 else if (srt->sortop == typentry->gt_opr)
6708 appendStringInfoString(buf, " DESC");
6709 /* DESC defaults to NULLS FIRST */
6710 if (!srt->nulls_first)
6711 appendStringInfoString(buf, " NULLS LAST");
6713 else
6715 appendStringInfo(buf, " USING %s",
6716 generate_operator_name(srt->sortop,
6717 sortcoltype,
6718 sortcoltype));
6719 /* be specific to eliminate ambiguity */
6720 if (srt->nulls_first)
6721 appendStringInfoString(buf, " NULLS FIRST");
6722 else
6723 appendStringInfoString(buf, " NULLS LAST");
6725 sep = ", ";
6730 * Display a WINDOW clause.
6732 * Note that the windowClause list might contain only anonymous window
6733 * specifications, in which case we should print nothing here.
6735 static void
6736 get_rule_windowclause(Query *query, deparse_context *context)
6738 StringInfo buf = context->buf;
6739 const char *sep;
6740 ListCell *l;
6742 sep = NULL;
6743 foreach(l, query->windowClause)
6745 WindowClause *wc = (WindowClause *) lfirst(l);
6747 if (wc->name == NULL)
6748 continue; /* ignore anonymous windows */
6750 if (sep == NULL)
6751 appendContextKeyword(context, " WINDOW ",
6752 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6753 else
6754 appendStringInfoString(buf, sep);
6756 appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6758 get_rule_windowspec(wc, query->targetList, context);
6760 sep = ", ";
6765 * Display a window definition
6767 static void
6768 get_rule_windowspec(WindowClause *wc, List *targetList,
6769 deparse_context *context)
6771 StringInfo buf = context->buf;
6772 bool needspace = false;
6773 const char *sep;
6774 ListCell *l;
6776 appendStringInfoChar(buf, '(');
6777 if (wc->refname)
6779 appendStringInfoString(buf, quote_identifier(wc->refname));
6780 needspace = true;
6782 /* partition clauses are always inherited, so only print if no refname */
6783 if (wc->partitionClause && !wc->refname)
6785 if (needspace)
6786 appendStringInfoChar(buf, ' ');
6787 appendStringInfoString(buf, "PARTITION BY ");
6788 sep = "";
6789 foreach(l, wc->partitionClause)
6791 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6793 appendStringInfoString(buf, sep);
6794 get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
6795 false, context);
6796 sep = ", ";
6798 needspace = true;
6800 /* print ordering clause only if not inherited */
6801 if (wc->orderClause && !wc->copiedOrder)
6803 if (needspace)
6804 appendStringInfoChar(buf, ' ');
6805 appendStringInfoString(buf, "ORDER BY ");
6806 get_rule_orderby(wc->orderClause, targetList, false, context);
6807 needspace = true;
6809 /* framing clause is never inherited, so print unless it's default */
6810 if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
6812 if (needspace)
6813 appendStringInfoChar(buf, ' ');
6814 if (wc->frameOptions & FRAMEOPTION_RANGE)
6815 appendStringInfoString(buf, "RANGE ");
6816 else if (wc->frameOptions & FRAMEOPTION_ROWS)
6817 appendStringInfoString(buf, "ROWS ");
6818 else if (wc->frameOptions & FRAMEOPTION_GROUPS)
6819 appendStringInfoString(buf, "GROUPS ");
6820 else
6821 Assert(false);
6822 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
6823 appendStringInfoString(buf, "BETWEEN ");
6824 if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
6825 appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
6826 else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
6827 appendStringInfoString(buf, "CURRENT ROW ");
6828 else if (wc->frameOptions & FRAMEOPTION_START_OFFSET)
6830 get_rule_expr(wc->startOffset, context, false);
6831 if (wc->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
6832 appendStringInfoString(buf, " PRECEDING ");
6833 else if (wc->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
6834 appendStringInfoString(buf, " FOLLOWING ");
6835 else
6836 Assert(false);
6838 else
6839 Assert(false);
6840 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
6842 appendStringInfoString(buf, "AND ");
6843 if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
6844 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
6845 else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
6846 appendStringInfoString(buf, "CURRENT ROW ");
6847 else if (wc->frameOptions & FRAMEOPTION_END_OFFSET)
6849 get_rule_expr(wc->endOffset, context, false);
6850 if (wc->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
6851 appendStringInfoString(buf, " PRECEDING ");
6852 else if (wc->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
6853 appendStringInfoString(buf, " FOLLOWING ");
6854 else
6855 Assert(false);
6857 else
6858 Assert(false);
6860 if (wc->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
6861 appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6862 else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6863 appendStringInfoString(buf, "EXCLUDE GROUP ");
6864 else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
6865 appendStringInfoString(buf, "EXCLUDE TIES ");
6866 /* we will now have a trailing space; remove it */
6867 buf->len--;
6869 appendStringInfoChar(buf, ')');
6872 /* ----------
6873 * get_insert_query_def - Parse back an INSERT parsetree
6874 * ----------
6876 static void
6877 get_insert_query_def(Query *query, deparse_context *context)
6879 StringInfo buf = context->buf;
6880 RangeTblEntry *select_rte = NULL;
6881 RangeTblEntry *values_rte = NULL;
6882 RangeTblEntry *rte;
6883 char *sep;
6884 ListCell *l;
6885 List *strippedexprs;
6887 /* Insert the WITH clause if given */
6888 get_with_clause(query, context);
6891 * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6892 * single RTE for the SELECT or VALUES. Plain VALUES has neither.
6894 foreach(l, query->rtable)
6896 rte = (RangeTblEntry *) lfirst(l);
6898 if (rte->rtekind == RTE_SUBQUERY)
6900 if (select_rte)
6901 elog(ERROR, "too many subquery RTEs in INSERT");
6902 select_rte = rte;
6905 if (rte->rtekind == RTE_VALUES)
6907 if (values_rte)
6908 elog(ERROR, "too many values RTEs in INSERT");
6909 values_rte = rte;
6912 if (select_rte && values_rte)
6913 elog(ERROR, "both subquery and values RTEs in INSERT");
6916 * Start the query with INSERT INTO relname
6918 rte = rt_fetch(query->resultRelation, query->rtable);
6919 Assert(rte->rtekind == RTE_RELATION);
6921 if (PRETTY_INDENT(context))
6923 context->indentLevel += PRETTYINDENT_STD;
6924 appendStringInfoChar(buf, ' ');
6926 appendStringInfo(buf, "INSERT INTO %s",
6927 generate_relation_name(rte->relid, NIL));
6929 /* Print the relation alias, if needed; INSERT requires explicit AS */
6930 get_rte_alias(rte, query->resultRelation, true, context);
6932 /* always want a space here */
6933 appendStringInfoChar(buf, ' ');
6936 * Add the insert-column-names list. Any indirection decoration needed on
6937 * the column names can be inferred from the top targetlist.
6939 strippedexprs = NIL;
6940 sep = "";
6941 if (query->targetList)
6942 appendStringInfoChar(buf, '(');
6943 foreach(l, query->targetList)
6945 TargetEntry *tle = (TargetEntry *) lfirst(l);
6947 if (tle->resjunk)
6948 continue; /* ignore junk entries */
6950 appendStringInfoString(buf, sep);
6951 sep = ", ";
6954 * Put out name of target column; look in the catalogs, not at
6955 * tle->resname, since resname will fail to track RENAME.
6957 appendStringInfoString(buf,
6958 quote_identifier(get_attname(rte->relid,
6959 tle->resno,
6960 false)));
6963 * Print any indirection needed (subfields or subscripts), and strip
6964 * off the top-level nodes representing the indirection assignments.
6965 * Add the stripped expressions to strippedexprs. (If it's a
6966 * single-VALUES statement, the stripped expressions are the VALUES to
6967 * print below. Otherwise they're just Vars and not really
6968 * interesting.)
6970 strippedexprs = lappend(strippedexprs,
6971 processIndirection((Node *) tle->expr,
6972 context));
6974 if (query->targetList)
6975 appendStringInfoString(buf, ") ");
6977 if (query->override)
6979 if (query->override == OVERRIDING_SYSTEM_VALUE)
6980 appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
6981 else if (query->override == OVERRIDING_USER_VALUE)
6982 appendStringInfoString(buf, "OVERRIDING USER VALUE ");
6985 if (select_rte)
6987 /* Add the SELECT */
6988 get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
6989 false,
6990 context->prettyFlags, context->wrapColumn,
6991 context->indentLevel);
6993 else if (values_rte)
6995 /* Add the multi-VALUES expression lists */
6996 get_values_def(values_rte->values_lists, context);
6998 else if (strippedexprs)
7000 /* Add the single-VALUES expression list */
7001 appendContextKeyword(context, "VALUES (",
7002 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7003 get_rule_list_toplevel(strippedexprs, context, false);
7004 appendStringInfoChar(buf, ')');
7006 else
7008 /* No expressions, so it must be DEFAULT VALUES */
7009 appendStringInfoString(buf, "DEFAULT VALUES");
7012 /* Add ON CONFLICT if present */
7013 if (query->onConflict)
7015 OnConflictExpr *confl = query->onConflict;
7017 appendStringInfoString(buf, " ON CONFLICT");
7019 if (confl->arbiterElems)
7021 /* Add the single-VALUES expression list */
7022 appendStringInfoChar(buf, '(');
7023 get_rule_expr((Node *) confl->arbiterElems, context, false);
7024 appendStringInfoChar(buf, ')');
7026 /* Add a WHERE clause (for partial indexes) if given */
7027 if (confl->arbiterWhere != NULL)
7029 bool save_varprefix;
7032 * Force non-prefixing of Vars, since parser assumes that they
7033 * belong to target relation. WHERE clause does not use
7034 * InferenceElem, so this is separately required.
7036 save_varprefix = context->varprefix;
7037 context->varprefix = false;
7039 appendContextKeyword(context, " WHERE ",
7040 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7041 get_rule_expr(confl->arbiterWhere, context, false);
7043 context->varprefix = save_varprefix;
7046 else if (OidIsValid(confl->constraint))
7048 char *constraint = get_constraint_name(confl->constraint);
7050 if (!constraint)
7051 elog(ERROR, "cache lookup failed for constraint %u",
7052 confl->constraint);
7053 appendStringInfo(buf, " ON CONSTRAINT %s",
7054 quote_identifier(constraint));
7057 if (confl->action == ONCONFLICT_NOTHING)
7059 appendStringInfoString(buf, " DO NOTHING");
7061 else
7063 appendStringInfoString(buf, " DO UPDATE SET ");
7064 /* Deparse targetlist */
7065 get_update_query_targetlist_def(query, confl->onConflictSet,
7066 context, rte);
7068 /* Add a WHERE clause if given */
7069 if (confl->onConflictWhere != NULL)
7071 appendContextKeyword(context, " WHERE ",
7072 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7073 get_rule_expr(confl->onConflictWhere, context, false);
7078 /* Add RETURNING if present */
7079 if (query->returningList)
7080 get_returning_clause(query, context);
7084 /* ----------
7085 * get_update_query_def - Parse back an UPDATE parsetree
7086 * ----------
7088 static void
7089 get_update_query_def(Query *query, deparse_context *context)
7091 StringInfo buf = context->buf;
7092 RangeTblEntry *rte;
7094 /* Insert the WITH clause if given */
7095 get_with_clause(query, context);
7098 * Start the query with UPDATE relname SET
7100 rte = rt_fetch(query->resultRelation, query->rtable);
7101 Assert(rte->rtekind == RTE_RELATION);
7102 if (PRETTY_INDENT(context))
7104 appendStringInfoChar(buf, ' ');
7105 context->indentLevel += PRETTYINDENT_STD;
7107 appendStringInfo(buf, "UPDATE %s%s",
7108 only_marker(rte),
7109 generate_relation_name(rte->relid, NIL));
7111 /* Print the relation alias, if needed */
7112 get_rte_alias(rte, query->resultRelation, false, context);
7114 appendStringInfoString(buf, " SET ");
7116 /* Deparse targetlist */
7117 get_update_query_targetlist_def(query, query->targetList, context, rte);
7119 /* Add the FROM clause if needed */
7120 get_from_clause(query, " FROM ", context);
7122 /* Add a WHERE clause if given */
7123 if (query->jointree->quals != NULL)
7125 appendContextKeyword(context, " WHERE ",
7126 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7127 get_rule_expr(query->jointree->quals, context, false);
7130 /* Add RETURNING if present */
7131 if (query->returningList)
7132 get_returning_clause(query, context);
7136 /* ----------
7137 * get_update_query_targetlist_def - Parse back an UPDATE targetlist
7138 * ----------
7140 static void
7141 get_update_query_targetlist_def(Query *query, List *targetList,
7142 deparse_context *context, RangeTblEntry *rte)
7144 StringInfo buf = context->buf;
7145 ListCell *l;
7146 ListCell *next_ma_cell;
7147 int remaining_ma_columns;
7148 const char *sep;
7149 SubLink *cur_ma_sublink;
7150 List *ma_sublinks;
7153 * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
7154 * into a list. We expect them to appear, in ID order, in resjunk tlist
7155 * entries.
7157 ma_sublinks = NIL;
7158 if (query->hasSubLinks) /* else there can't be any */
7160 foreach(l, targetList)
7162 TargetEntry *tle = (TargetEntry *) lfirst(l);
7164 if (tle->resjunk && IsA(tle->expr, SubLink))
7166 SubLink *sl = (SubLink *) tle->expr;
7168 if (sl->subLinkType == MULTIEXPR_SUBLINK)
7170 ma_sublinks = lappend(ma_sublinks, sl);
7171 Assert(sl->subLinkId == list_length(ma_sublinks));
7176 next_ma_cell = list_head(ma_sublinks);
7177 cur_ma_sublink = NULL;
7178 remaining_ma_columns = 0;
7180 /* Add the comma separated list of 'attname = value' */
7181 sep = "";
7182 foreach(l, targetList)
7184 TargetEntry *tle = (TargetEntry *) lfirst(l);
7185 Node *expr;
7187 if (tle->resjunk)
7188 continue; /* ignore junk entries */
7190 /* Emit separator (OK whether we're in multiassignment or not) */
7191 appendStringInfoString(buf, sep);
7192 sep = ", ";
7195 * Check to see if we're starting a multiassignment group: if so,
7196 * output a left paren.
7198 if (next_ma_cell != NULL && cur_ma_sublink == NULL)
7201 * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
7202 * Param. That could be buried under FieldStores and
7203 * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
7204 * and underneath those there could be an implicit type coercion.
7205 * Because we would ignore implicit type coercions anyway, we
7206 * don't need to be as careful as processIndirection() is about
7207 * descending past implicit CoerceToDomains.
7209 expr = (Node *) tle->expr;
7210 while (expr)
7212 if (IsA(expr, FieldStore))
7214 FieldStore *fstore = (FieldStore *) expr;
7216 expr = (Node *) linitial(fstore->newvals);
7218 else if (IsA(expr, SubscriptingRef))
7220 SubscriptingRef *sbsref = (SubscriptingRef *) expr;
7222 if (sbsref->refassgnexpr == NULL)
7223 break;
7225 expr = (Node *) sbsref->refassgnexpr;
7227 else if (IsA(expr, CoerceToDomain))
7229 CoerceToDomain *cdomain = (CoerceToDomain *) expr;
7231 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
7232 break;
7233 expr = (Node *) cdomain->arg;
7235 else
7236 break;
7238 expr = strip_implicit_coercions(expr);
7240 if (expr && IsA(expr, Param) &&
7241 ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
7243 cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
7244 next_ma_cell = lnext(ma_sublinks, next_ma_cell);
7245 remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
7246 Assert(((Param *) expr)->paramid ==
7247 ((cur_ma_sublink->subLinkId << 16) | 1));
7248 appendStringInfoChar(buf, '(');
7253 * Put out name of target column; look in the catalogs, not at
7254 * tle->resname, since resname will fail to track RENAME.
7256 appendStringInfoString(buf,
7257 quote_identifier(get_attname(rte->relid,
7258 tle->resno,
7259 false)));
7262 * Print any indirection needed (subfields or subscripts), and strip
7263 * off the top-level nodes representing the indirection assignments.
7265 expr = processIndirection((Node *) tle->expr, context);
7268 * If we're in a multiassignment, skip printing anything more, unless
7269 * this is the last column; in which case, what we print should be the
7270 * sublink, not the Param.
7272 if (cur_ma_sublink != NULL)
7274 if (--remaining_ma_columns > 0)
7275 continue; /* not the last column of multiassignment */
7276 appendStringInfoChar(buf, ')');
7277 expr = (Node *) cur_ma_sublink;
7278 cur_ma_sublink = NULL;
7281 appendStringInfoString(buf, " = ");
7283 get_rule_expr(expr, context, false);
7288 /* ----------
7289 * get_delete_query_def - Parse back a DELETE parsetree
7290 * ----------
7292 static void
7293 get_delete_query_def(Query *query, deparse_context *context)
7295 StringInfo buf = context->buf;
7296 RangeTblEntry *rte;
7298 /* Insert the WITH clause if given */
7299 get_with_clause(query, context);
7302 * Start the query with DELETE FROM relname
7304 rte = rt_fetch(query->resultRelation, query->rtable);
7305 Assert(rte->rtekind == RTE_RELATION);
7306 if (PRETTY_INDENT(context))
7308 appendStringInfoChar(buf, ' ');
7309 context->indentLevel += PRETTYINDENT_STD;
7311 appendStringInfo(buf, "DELETE FROM %s%s",
7312 only_marker(rte),
7313 generate_relation_name(rte->relid, NIL));
7315 /* Print the relation alias, if needed */
7316 get_rte_alias(rte, query->resultRelation, false, context);
7318 /* Add the USING clause if given */
7319 get_from_clause(query, " USING ", context);
7321 /* Add a WHERE clause if given */
7322 if (query->jointree->quals != NULL)
7324 appendContextKeyword(context, " WHERE ",
7325 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7326 get_rule_expr(query->jointree->quals, context, false);
7329 /* Add RETURNING if present */
7330 if (query->returningList)
7331 get_returning_clause(query, context);
7335 /* ----------
7336 * get_merge_query_def - Parse back a MERGE parsetree
7337 * ----------
7339 static void
7340 get_merge_query_def(Query *query, deparse_context *context)
7342 StringInfo buf = context->buf;
7343 RangeTblEntry *rte;
7344 ListCell *lc;
7345 bool haveNotMatchedBySource;
7347 /* Insert the WITH clause if given */
7348 get_with_clause(query, context);
7351 * Start the query with MERGE INTO relname
7353 rte = rt_fetch(query->resultRelation, query->rtable);
7354 Assert(rte->rtekind == RTE_RELATION);
7355 if (PRETTY_INDENT(context))
7357 appendStringInfoChar(buf, ' ');
7358 context->indentLevel += PRETTYINDENT_STD;
7360 appendStringInfo(buf, "MERGE INTO %s%s",
7361 only_marker(rte),
7362 generate_relation_name(rte->relid, NIL));
7364 /* Print the relation alias, if needed */
7365 get_rte_alias(rte, query->resultRelation, false, context);
7367 /* Print the source relation and join clause */
7368 get_from_clause(query, " USING ", context);
7369 appendContextKeyword(context, " ON ",
7370 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7371 get_rule_expr(query->mergeJoinCondition, context, false);
7374 * Test for any NOT MATCHED BY SOURCE actions. If there are none, then
7375 * any NOT MATCHED BY TARGET actions are output as "WHEN NOT MATCHED", per
7376 * SQL standard. Otherwise, we have a non-SQL-standard query, so output
7377 * "BY SOURCE" / "BY TARGET" qualifiers for all NOT MATCHED actions, to be
7378 * more explicit.
7380 haveNotMatchedBySource = false;
7381 foreach(lc, query->mergeActionList)
7383 MergeAction *action = lfirst_node(MergeAction, lc);
7385 if (action->matchKind == MERGE_WHEN_NOT_MATCHED_BY_SOURCE)
7387 haveNotMatchedBySource = true;
7388 break;
7392 /* Print each merge action */
7393 foreach(lc, query->mergeActionList)
7395 MergeAction *action = lfirst_node(MergeAction, lc);
7397 appendContextKeyword(context, " WHEN ",
7398 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7399 switch (action->matchKind)
7401 case MERGE_WHEN_MATCHED:
7402 appendStringInfoString(buf, "MATCHED");
7403 break;
7404 case MERGE_WHEN_NOT_MATCHED_BY_SOURCE:
7405 appendStringInfoString(buf, "NOT MATCHED BY SOURCE");
7406 break;
7407 case MERGE_WHEN_NOT_MATCHED_BY_TARGET:
7408 if (haveNotMatchedBySource)
7409 appendStringInfoString(buf, "NOT MATCHED BY TARGET");
7410 else
7411 appendStringInfoString(buf, "NOT MATCHED");
7412 break;
7413 default:
7414 elog(ERROR, "unrecognized matchKind: %d",
7415 (int) action->matchKind);
7418 if (action->qual)
7420 appendContextKeyword(context, " AND ",
7421 -PRETTYINDENT_STD, PRETTYINDENT_STD, 3);
7422 get_rule_expr(action->qual, context, false);
7424 appendContextKeyword(context, " THEN ",
7425 -PRETTYINDENT_STD, PRETTYINDENT_STD, 3);
7427 if (action->commandType == CMD_INSERT)
7429 /* This generally matches get_insert_query_def() */
7430 List *strippedexprs = NIL;
7431 const char *sep = "";
7432 ListCell *lc2;
7434 appendStringInfoString(buf, "INSERT");
7436 if (action->targetList)
7437 appendStringInfoString(buf, " (");
7438 foreach(lc2, action->targetList)
7440 TargetEntry *tle = (TargetEntry *) lfirst(lc2);
7442 Assert(!tle->resjunk);
7444 appendStringInfoString(buf, sep);
7445 sep = ", ";
7447 appendStringInfoString(buf,
7448 quote_identifier(get_attname(rte->relid,
7449 tle->resno,
7450 false)));
7451 strippedexprs = lappend(strippedexprs,
7452 processIndirection((Node *) tle->expr,
7453 context));
7455 if (action->targetList)
7456 appendStringInfoChar(buf, ')');
7458 if (action->override)
7460 if (action->override == OVERRIDING_SYSTEM_VALUE)
7461 appendStringInfoString(buf, " OVERRIDING SYSTEM VALUE");
7462 else if (action->override == OVERRIDING_USER_VALUE)
7463 appendStringInfoString(buf, " OVERRIDING USER VALUE");
7466 if (strippedexprs)
7468 appendContextKeyword(context, " VALUES (",
7469 -PRETTYINDENT_STD, PRETTYINDENT_STD, 4);
7470 get_rule_list_toplevel(strippedexprs, context, false);
7471 appendStringInfoChar(buf, ')');
7473 else
7474 appendStringInfoString(buf, " DEFAULT VALUES");
7476 else if (action->commandType == CMD_UPDATE)
7478 appendStringInfoString(buf, "UPDATE SET ");
7479 get_update_query_targetlist_def(query, action->targetList,
7480 context, rte);
7482 else if (action->commandType == CMD_DELETE)
7483 appendStringInfoString(buf, "DELETE");
7484 else if (action->commandType == CMD_NOTHING)
7485 appendStringInfoString(buf, "DO NOTHING");
7488 /* Add RETURNING if present */
7489 if (query->returningList)
7490 get_returning_clause(query, context);
7494 /* ----------
7495 * get_utility_query_def - Parse back a UTILITY parsetree
7496 * ----------
7498 static void
7499 get_utility_query_def(Query *query, deparse_context *context)
7501 StringInfo buf = context->buf;
7503 if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7505 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7507 appendContextKeyword(context, "",
7508 0, PRETTYINDENT_STD, 1);
7509 appendStringInfo(buf, "NOTIFY %s",
7510 quote_identifier(stmt->conditionname));
7511 if (stmt->payload)
7513 appendStringInfoString(buf, ", ");
7514 simple_quote_literal(buf, stmt->payload);
7517 else
7519 /* Currently only NOTIFY utility commands can appear in rules */
7520 elog(ERROR, "unexpected utility statement type");
7525 * Display a Var appropriately.
7527 * In some cases (currently only when recursing into an unnamed join)
7528 * the Var's varlevelsup has to be interpreted with respect to a context
7529 * above the current one; levelsup indicates the offset.
7531 * If istoplevel is true, the Var is at the top level of a SELECT's
7532 * targetlist, which means we need special treatment of whole-row Vars.
7533 * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
7534 * dirty hack to prevent "tab.*" from being expanded into multiple columns.
7535 * (The parser will strip the useless coercion, so no inefficiency is added in
7536 * dump and reload.) We used to print just "tab" in such cases, but that is
7537 * ambiguous and will yield the wrong result if "tab" is also a plain column
7538 * name in the query.
7540 * Returns the attname of the Var, or NULL if the Var has no attname (because
7541 * it is a whole-row Var or a subplan output reference).
7543 static char *
7544 get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
7546 StringInfo buf = context->buf;
7547 RangeTblEntry *rte;
7548 AttrNumber attnum;
7549 int netlevelsup;
7550 deparse_namespace *dpns;
7551 int varno;
7552 AttrNumber varattno;
7553 deparse_columns *colinfo;
7554 char *refname;
7555 char *attname;
7556 bool need_prefix;
7558 /* Find appropriate nesting depth */
7559 netlevelsup = var->varlevelsup + levelsup;
7560 if (netlevelsup >= list_length(context->namespaces))
7561 elog(ERROR, "bogus varlevelsup: %d offset %d",
7562 var->varlevelsup, levelsup);
7563 dpns = (deparse_namespace *) list_nth(context->namespaces,
7564 netlevelsup);
7567 * If we have a syntactic referent for the Var, and we're working from a
7568 * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7569 * on the semantic referent. (Forcing use of the semantic referent when
7570 * printing plan trees is a design choice that's perhaps more motivated by
7571 * backwards compatibility than anything else. But it does have the
7572 * advantage of making plans more explicit.)
7574 if (var->varnosyn > 0 && dpns->plan == NULL)
7576 varno = var->varnosyn;
7577 varattno = var->varattnosyn;
7579 else
7581 varno = var->varno;
7582 varattno = var->varattno;
7586 * Try to find the relevant RTE in this rtable. In a plan tree, it's
7587 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7588 * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7589 * find the aliases previously assigned for this RTE.
7591 if (varno >= 1 && varno <= list_length(dpns->rtable))
7594 * We might have been asked to map child Vars to some parent relation.
7596 if (context->appendparents && dpns->appendrels)
7598 int pvarno = varno;
7599 AttrNumber pvarattno = varattno;
7600 AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7601 bool found = false;
7603 /* Only map up to inheritance parents, not UNION ALL appendrels */
7604 while (appinfo &&
7605 rt_fetch(appinfo->parent_relid,
7606 dpns->rtable)->rtekind == RTE_RELATION)
7608 found = false;
7609 if (pvarattno > 0) /* system columns stay as-is */
7611 if (pvarattno > appinfo->num_child_cols)
7612 break; /* safety check */
7613 pvarattno = appinfo->parent_colnos[pvarattno - 1];
7614 if (pvarattno == 0)
7615 break; /* Var is local to child */
7618 pvarno = appinfo->parent_relid;
7619 found = true;
7621 /* If the parent is itself a child, continue up. */
7622 Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7623 appinfo = dpns->appendrels[pvarno];
7627 * If we found an ancestral rel, and that rel is included in
7628 * appendparents, print that column not the original one.
7630 if (found && bms_is_member(pvarno, context->appendparents))
7632 varno = pvarno;
7633 varattno = pvarattno;
7637 rte = rt_fetch(varno, dpns->rtable);
7639 /* might be returning old/new column value */
7640 if (var->varreturningtype == VAR_RETURNING_OLD)
7641 refname = dpns->ret_old_alias;
7642 else if (var->varreturningtype == VAR_RETURNING_NEW)
7643 refname = dpns->ret_new_alias;
7644 else
7645 refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7647 colinfo = deparse_columns_fetch(varno, dpns);
7648 attnum = varattno;
7650 else
7652 resolve_special_varno((Node *) var, context,
7653 get_special_variable, NULL);
7654 return NULL;
7658 * The planner will sometimes emit Vars referencing resjunk elements of a
7659 * subquery's target list (this is currently only possible if it chooses
7660 * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7661 * Although we prefer to print subquery-referencing Vars using the
7662 * subquery's alias, that's not possible for resjunk items since they have
7663 * no alias. So in that case, drill down to the subplan and print the
7664 * contents of the referenced tlist item. This works because in a plan
7665 * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
7666 * we'll have set dpns->inner_plan to reference the child plan node.
7668 if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7669 attnum > list_length(rte->eref->colnames) &&
7670 dpns->inner_plan)
7672 TargetEntry *tle;
7673 deparse_namespace save_dpns;
7675 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7676 if (!tle)
7677 elog(ERROR, "invalid attnum %d for relation \"%s\"",
7678 attnum, rte->eref->aliasname);
7680 Assert(netlevelsup == 0);
7681 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7684 * Force parentheses because our caller probably assumed a Var is a
7685 * simple expression.
7687 if (!IsA(tle->expr, Var))
7688 appendStringInfoChar(buf, '(');
7689 get_rule_expr((Node *) tle->expr, context, true);
7690 if (!IsA(tle->expr, Var))
7691 appendStringInfoChar(buf, ')');
7693 pop_child_plan(dpns, &save_dpns);
7694 return NULL;
7698 * If it's an unnamed join, look at the expansion of the alias variable.
7699 * If it's a simple reference to one of the input vars, then recursively
7700 * print the name of that var instead. When it's not a simple reference,
7701 * we have to just print the unqualified join column name. (This can only
7702 * happen with "dangerous" merged columns in a JOIN USING; we took pains
7703 * previously to make the unqualified column name unique in such cases.)
7705 * This wouldn't work in decompiling plan trees, because we don't store
7706 * joinaliasvars lists after planning; but a plan tree should never
7707 * contain a join alias variable.
7709 if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7711 if (rte->joinaliasvars == NIL)
7712 elog(ERROR, "cannot decompile join alias var in plan tree");
7713 if (attnum > 0)
7715 Var *aliasvar;
7717 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7718 /* we intentionally don't strip implicit coercions here */
7719 if (aliasvar && IsA(aliasvar, Var))
7721 return get_variable(aliasvar, var->varlevelsup + levelsup,
7722 istoplevel, context);
7727 * Unnamed join has no refname. (Note: since it's unnamed, there is
7728 * no way the user could have referenced it to create a whole-row Var
7729 * for it. So we don't have to cover that case below.)
7731 Assert(refname == NULL);
7734 if (attnum == InvalidAttrNumber)
7735 attname = NULL;
7736 else if (attnum > 0)
7738 /* Get column name to use from the colinfo struct */
7739 if (attnum > colinfo->num_cols)
7740 elog(ERROR, "invalid attnum %d for relation \"%s\"",
7741 attnum, rte->eref->aliasname);
7742 attname = colinfo->colnames[attnum - 1];
7745 * If we find a Var referencing a dropped column, it seems better to
7746 * print something (anything) than to fail. In general this should
7747 * not happen, but it used to be possible for some cases involving
7748 * functions returning named composite types, and perhaps there are
7749 * still bugs out there.
7751 if (attname == NULL)
7752 attname = "?dropped?column?";
7754 else
7756 /* System column - name is fixed, get it from the catalog */
7757 attname = get_rte_attribute_name(rte, attnum);
7760 need_prefix = (context->varprefix || attname == NULL ||
7761 var->varreturningtype != VAR_RETURNING_DEFAULT);
7764 * If we're considering a plain Var in an ORDER BY (but not GROUP BY)
7765 * clause, we may need to add a table-name prefix to prevent
7766 * findTargetlistEntrySQL92 from misinterpreting the name as an
7767 * output-column name. To avoid cluttering the output with unnecessary
7768 * prefixes, do so only if there is a name match to a SELECT tlist item
7769 * that is different from the Var.
7771 if (context->varInOrderBy && !context->inGroupBy && !need_prefix)
7773 int colno = 0;
7775 foreach_node(TargetEntry, tle, context->targetList)
7777 char *colname;
7779 if (tle->resjunk)
7780 continue; /* ignore junk entries */
7781 colno++;
7783 /* This must match colname-choosing logic in get_target_list() */
7784 if (context->resultDesc && colno <= context->resultDesc->natts)
7785 colname = NameStr(TupleDescAttr(context->resultDesc,
7786 colno - 1)->attname);
7787 else
7788 colname = tle->resname;
7790 if (colname && strcmp(colname, attname) == 0 &&
7791 !equal(var, tle->expr))
7793 need_prefix = true;
7794 break;
7799 if (refname && need_prefix)
7801 appendStringInfoString(buf, quote_identifier(refname));
7802 appendStringInfoChar(buf, '.');
7804 if (attname)
7805 appendStringInfoString(buf, quote_identifier(attname));
7806 else
7808 appendStringInfoChar(buf, '*');
7809 if (istoplevel)
7810 appendStringInfo(buf, "::%s",
7811 format_type_with_typemod(var->vartype,
7812 var->vartypmod));
7815 return attname;
7819 * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
7820 * routine is actually a callback for resolve_special_varno, which handles
7821 * finding the correct TargetEntry. We get the expression contained in that
7822 * TargetEntry and just need to deparse it, a job we can throw back on
7823 * get_rule_expr.
7825 static void
7826 get_special_variable(Node *node, deparse_context *context, void *callback_arg)
7828 StringInfo buf = context->buf;
7831 * For a non-Var referent, force parentheses because our caller probably
7832 * assumed a Var is a simple expression.
7834 if (!IsA(node, Var))
7835 appendStringInfoChar(buf, '(');
7836 get_rule_expr(node, context, true);
7837 if (!IsA(node, Var))
7838 appendStringInfoChar(buf, ')');
7842 * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
7843 * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
7844 * invoke the callback provided.
7846 static void
7847 resolve_special_varno(Node *node, deparse_context *context,
7848 rsv_callback callback, void *callback_arg)
7850 Var *var;
7851 deparse_namespace *dpns;
7853 /* This function is recursive, so let's be paranoid. */
7854 check_stack_depth();
7856 /* If it's not a Var, invoke the callback. */
7857 if (!IsA(node, Var))
7859 (*callback) (node, context, callback_arg);
7860 return;
7863 /* Find appropriate nesting depth */
7864 var = (Var *) node;
7865 dpns = (deparse_namespace *) list_nth(context->namespaces,
7866 var->varlevelsup);
7869 * If varno is special, recurse. (Don't worry about varnosyn; if we're
7870 * here, we already decided not to use that.)
7872 if (var->varno == OUTER_VAR && dpns->outer_tlist)
7874 TargetEntry *tle;
7875 deparse_namespace save_dpns;
7876 Bitmapset *save_appendparents;
7878 tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
7879 if (!tle)
7880 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7883 * If we're descending to the first child of an Append or MergeAppend,
7884 * update appendparents. This will affect deparsing of all Vars
7885 * appearing within the eventually-resolved subexpression.
7887 save_appendparents = context->appendparents;
7889 if (IsA(dpns->plan, Append))
7890 context->appendparents = bms_union(context->appendparents,
7891 ((Append *) dpns->plan)->apprelids);
7892 else if (IsA(dpns->plan, MergeAppend))
7893 context->appendparents = bms_union(context->appendparents,
7894 ((MergeAppend *) dpns->plan)->apprelids);
7896 push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7897 resolve_special_varno((Node *) tle->expr, context,
7898 callback, callback_arg);
7899 pop_child_plan(dpns, &save_dpns);
7900 context->appendparents = save_appendparents;
7901 return;
7903 else if (var->varno == INNER_VAR && dpns->inner_tlist)
7905 TargetEntry *tle;
7906 deparse_namespace save_dpns;
7908 tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
7909 if (!tle)
7910 elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7912 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7913 resolve_special_varno((Node *) tle->expr, context,
7914 callback, callback_arg);
7915 pop_child_plan(dpns, &save_dpns);
7916 return;
7918 else if (var->varno == INDEX_VAR && dpns->index_tlist)
7920 TargetEntry *tle;
7922 tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
7923 if (!tle)
7924 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
7926 resolve_special_varno((Node *) tle->expr, context,
7927 callback, callback_arg);
7928 return;
7930 else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
7931 elog(ERROR, "bogus varno: %d", var->varno);
7933 /* Not special. Just invoke the callback. */
7934 (*callback) (node, context, callback_arg);
7938 * Get the name of a field of an expression of composite type. The
7939 * expression is usually a Var, but we handle other cases too.
7941 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
7943 * This is fairly straightforward when the expression has a named composite
7944 * type; we need only look up the type in the catalogs. However, the type
7945 * could also be RECORD. Since no actual table or view column is allowed to
7946 * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
7947 * or to a subquery output. We drill down to find the ultimate defining
7948 * expression and attempt to infer the field name from it. We ereport if we
7949 * can't determine the name.
7951 * Similarly, a PARAM of type RECORD has to refer to some expression of
7952 * a determinable composite type.
7954 static const char *
7955 get_name_for_var_field(Var *var, int fieldno,
7956 int levelsup, deparse_context *context)
7958 RangeTblEntry *rte;
7959 AttrNumber attnum;
7960 int netlevelsup;
7961 deparse_namespace *dpns;
7962 int varno;
7963 AttrNumber varattno;
7964 TupleDesc tupleDesc;
7965 Node *expr;
7968 * If it's a RowExpr that was expanded from a whole-row Var, use the
7969 * column names attached to it. (We could let get_expr_result_tupdesc()
7970 * handle this, but it's much cheaper to just pull out the name we need.)
7972 if (IsA(var, RowExpr))
7974 RowExpr *r = (RowExpr *) var;
7976 if (fieldno > 0 && fieldno <= list_length(r->colnames))
7977 return strVal(list_nth(r->colnames, fieldno - 1));
7981 * If it's a Param of type RECORD, try to find what the Param refers to.
7983 if (IsA(var, Param))
7985 Param *param = (Param *) var;
7986 ListCell *ancestor_cell;
7988 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7989 if (expr)
7991 /* Found a match, so recurse to decipher the field name */
7992 deparse_namespace save_dpns;
7993 const char *result;
7995 push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7996 result = get_name_for_var_field((Var *) expr, fieldno,
7997 0, context);
7998 pop_ancestor_plan(dpns, &save_dpns);
7999 return result;
8004 * If it's a Var of type RECORD, we have to find what the Var refers to;
8005 * if not, we can use get_expr_result_tupdesc().
8007 if (!IsA(var, Var) ||
8008 var->vartype != RECORDOID)
8010 tupleDesc = get_expr_result_tupdesc((Node *) var, false);
8011 /* Got the tupdesc, so we can extract the field name */
8012 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8013 return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8016 /* Find appropriate nesting depth */
8017 netlevelsup = var->varlevelsup + levelsup;
8018 if (netlevelsup >= list_length(context->namespaces))
8019 elog(ERROR, "bogus varlevelsup: %d offset %d",
8020 var->varlevelsup, levelsup);
8021 dpns = (deparse_namespace *) list_nth(context->namespaces,
8022 netlevelsup);
8025 * If we have a syntactic referent for the Var, and we're working from a
8026 * parse tree, prefer to use the syntactic referent. Otherwise, fall back
8027 * on the semantic referent. (See comments in get_variable().)
8029 if (var->varnosyn > 0 && dpns->plan == NULL)
8031 varno = var->varnosyn;
8032 varattno = var->varattnosyn;
8034 else
8036 varno = var->varno;
8037 varattno = var->varattno;
8041 * Try to find the relevant RTE in this rtable. In a plan tree, it's
8042 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
8043 * down into the subplans, or INDEX_VAR, which is resolved similarly.
8045 * Note: unlike get_variable and resolve_special_varno, we need not worry
8046 * about inheritance mapping: a child Var should have the same datatype as
8047 * its parent, and here we're really only interested in the Var's type.
8049 if (varno >= 1 && varno <= list_length(dpns->rtable))
8051 rte = rt_fetch(varno, dpns->rtable);
8052 attnum = varattno;
8054 else if (varno == OUTER_VAR && dpns->outer_tlist)
8056 TargetEntry *tle;
8057 deparse_namespace save_dpns;
8058 const char *result;
8060 tle = get_tle_by_resno(dpns->outer_tlist, varattno);
8061 if (!tle)
8062 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
8064 Assert(netlevelsup == 0);
8065 push_child_plan(dpns, dpns->outer_plan, &save_dpns);
8067 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8068 levelsup, context);
8070 pop_child_plan(dpns, &save_dpns);
8071 return result;
8073 else if (varno == INNER_VAR && dpns->inner_tlist)
8075 TargetEntry *tle;
8076 deparse_namespace save_dpns;
8077 const char *result;
8079 tle = get_tle_by_resno(dpns->inner_tlist, varattno);
8080 if (!tle)
8081 elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
8083 Assert(netlevelsup == 0);
8084 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8086 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8087 levelsup, context);
8089 pop_child_plan(dpns, &save_dpns);
8090 return result;
8092 else if (varno == INDEX_VAR && dpns->index_tlist)
8094 TargetEntry *tle;
8095 const char *result;
8097 tle = get_tle_by_resno(dpns->index_tlist, varattno);
8098 if (!tle)
8099 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
8101 Assert(netlevelsup == 0);
8103 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8104 levelsup, context);
8106 return result;
8108 else
8110 elog(ERROR, "bogus varno: %d", varno);
8111 return NULL; /* keep compiler quiet */
8114 if (attnum == InvalidAttrNumber)
8116 /* Var is whole-row reference to RTE, so select the right field */
8117 return get_rte_attribute_name(rte, fieldno);
8121 * This part has essentially the same logic as the parser's
8122 * expandRecordVariable() function, but we are dealing with a different
8123 * representation of the input context, and we only need one field name
8124 * not a TupleDesc. Also, we need special cases for finding subquery and
8125 * CTE subplans when deparsing Plan trees.
8127 expr = (Node *) var; /* default if we can't drill down */
8129 switch (rte->rtekind)
8131 case RTE_RELATION:
8132 case RTE_VALUES:
8133 case RTE_NAMEDTUPLESTORE:
8134 case RTE_RESULT:
8137 * This case should not occur: a column of a table, values list,
8138 * or ENR shouldn't have type RECORD. Fall through and fail (most
8139 * likely) at the bottom.
8141 break;
8142 case RTE_SUBQUERY:
8143 /* Subselect-in-FROM: examine sub-select's output expr */
8145 if (rte->subquery)
8147 TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
8148 attnum);
8150 if (ste == NULL || ste->resjunk)
8151 elog(ERROR, "subquery %s does not have attribute %d",
8152 rte->eref->aliasname, attnum);
8153 expr = (Node *) ste->expr;
8154 if (IsA(expr, Var))
8157 * Recurse into the sub-select to see what its Var
8158 * refers to. We have to build an additional level of
8159 * namespace to keep in step with varlevelsup in the
8160 * subselect; furthermore, the subquery RTE might be
8161 * from an outer query level, in which case the
8162 * namespace for the subselect must have that outer
8163 * level as parent namespace.
8165 List *save_nslist = context->namespaces;
8166 List *parent_namespaces;
8167 deparse_namespace mydpns;
8168 const char *result;
8170 parent_namespaces = list_copy_tail(context->namespaces,
8171 netlevelsup);
8173 set_deparse_for_query(&mydpns, rte->subquery,
8174 parent_namespaces);
8176 context->namespaces = lcons(&mydpns, parent_namespaces);
8178 result = get_name_for_var_field((Var *) expr, fieldno,
8179 0, context);
8181 context->namespaces = save_nslist;
8183 return result;
8185 /* else fall through to inspect the expression */
8187 else
8190 * We're deparsing a Plan tree so we don't have complete
8191 * RTE entries (in particular, rte->subquery is NULL). But
8192 * the only place we'd normally see a Var directly
8193 * referencing a SUBQUERY RTE is in a SubqueryScan plan
8194 * node, and we can look into the child plan's tlist
8195 * instead. An exception occurs if the subquery was
8196 * proven empty and optimized away: then we'd find such a
8197 * Var in a childless Result node, and there's nothing in
8198 * the plan tree that would let us figure out what it had
8199 * originally referenced. In that case, fall back on
8200 * printing "fN", analogously to the default column names
8201 * for RowExprs.
8203 TargetEntry *tle;
8204 deparse_namespace save_dpns;
8205 const char *result;
8207 if (!dpns->inner_plan)
8209 char *dummy_name = palloc(32);
8211 Assert(dpns->plan && IsA(dpns->plan, Result));
8212 snprintf(dummy_name, 32, "f%d", fieldno);
8213 return dummy_name;
8215 Assert(dpns->plan && IsA(dpns->plan, SubqueryScan));
8217 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8218 if (!tle)
8219 elog(ERROR, "bogus varattno for subquery var: %d",
8220 attnum);
8221 Assert(netlevelsup == 0);
8222 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8224 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8225 levelsup, context);
8227 pop_child_plan(dpns, &save_dpns);
8228 return result;
8231 break;
8232 case RTE_JOIN:
8233 /* Join RTE --- recursively inspect the alias variable */
8234 if (rte->joinaliasvars == NIL)
8235 elog(ERROR, "cannot decompile join alias var in plan tree");
8236 Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
8237 expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
8238 Assert(expr != NULL);
8239 /* we intentionally don't strip implicit coercions here */
8240 if (IsA(expr, Var))
8241 return get_name_for_var_field((Var *) expr, fieldno,
8242 var->varlevelsup + levelsup,
8243 context);
8244 /* else fall through to inspect the expression */
8245 break;
8246 case RTE_FUNCTION:
8247 case RTE_TABLEFUNC:
8250 * We couldn't get here unless a function is declared with one of
8251 * its result columns as RECORD, which is not allowed.
8253 break;
8254 case RTE_CTE:
8255 /* CTE reference: examine subquery's output expr */
8257 CommonTableExpr *cte = NULL;
8258 Index ctelevelsup;
8259 ListCell *lc;
8262 * Try to find the referenced CTE using the namespace stack.
8264 ctelevelsup = rte->ctelevelsup + netlevelsup;
8265 if (ctelevelsup >= list_length(context->namespaces))
8266 lc = NULL;
8267 else
8269 deparse_namespace *ctedpns;
8271 ctedpns = (deparse_namespace *)
8272 list_nth(context->namespaces, ctelevelsup);
8273 foreach(lc, ctedpns->ctes)
8275 cte = (CommonTableExpr *) lfirst(lc);
8276 if (strcmp(cte->ctename, rte->ctename) == 0)
8277 break;
8280 if (lc != NULL)
8282 Query *ctequery = (Query *) cte->ctequery;
8283 TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte),
8284 attnum);
8286 if (ste == NULL || ste->resjunk)
8287 elog(ERROR, "CTE %s does not have attribute %d",
8288 rte->eref->aliasname, attnum);
8289 expr = (Node *) ste->expr;
8290 if (IsA(expr, Var))
8293 * Recurse into the CTE to see what its Var refers to.
8294 * We have to build an additional level of namespace
8295 * to keep in step with varlevelsup in the CTE;
8296 * furthermore it could be an outer CTE (compare
8297 * SUBQUERY case above).
8299 List *save_nslist = context->namespaces;
8300 List *parent_namespaces;
8301 deparse_namespace mydpns;
8302 const char *result;
8304 parent_namespaces = list_copy_tail(context->namespaces,
8305 ctelevelsup);
8307 set_deparse_for_query(&mydpns, ctequery,
8308 parent_namespaces);
8310 context->namespaces = lcons(&mydpns, parent_namespaces);
8312 result = get_name_for_var_field((Var *) expr, fieldno,
8313 0, context);
8315 context->namespaces = save_nslist;
8317 return result;
8319 /* else fall through to inspect the expression */
8321 else
8324 * We're deparsing a Plan tree so we don't have a CTE
8325 * list. But the only places we'd normally see a Var
8326 * directly referencing a CTE RTE are in CteScan or
8327 * WorkTableScan plan nodes. For those cases,
8328 * set_deparse_plan arranged for dpns->inner_plan to be
8329 * the plan node that emits the CTE or RecursiveUnion
8330 * result, and we can look at its tlist instead. As
8331 * above, this can fail if the CTE has been proven empty,
8332 * in which case fall back to "fN".
8334 TargetEntry *tle;
8335 deparse_namespace save_dpns;
8336 const char *result;
8338 if (!dpns->inner_plan)
8340 char *dummy_name = palloc(32);
8342 Assert(dpns->plan && IsA(dpns->plan, Result));
8343 snprintf(dummy_name, 32, "f%d", fieldno);
8344 return dummy_name;
8346 Assert(dpns->plan && (IsA(dpns->plan, CteScan) ||
8347 IsA(dpns->plan, WorkTableScan)));
8349 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8350 if (!tle)
8351 elog(ERROR, "bogus varattno for subquery var: %d",
8352 attnum);
8353 Assert(netlevelsup == 0);
8354 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8356 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8357 levelsup, context);
8359 pop_child_plan(dpns, &save_dpns);
8360 return result;
8363 break;
8364 case RTE_GROUP:
8367 * We couldn't get here: any Vars that reference the RTE_GROUP RTE
8368 * should have been replaced with the underlying grouping
8369 * expressions.
8371 break;
8375 * We now have an expression we can't expand any more, so see if
8376 * get_expr_result_tupdesc() can do anything with it.
8378 tupleDesc = get_expr_result_tupdesc(expr, false);
8379 /* Got the tupdesc, so we can extract the field name */
8380 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8381 return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8385 * Try to find the referenced expression for a PARAM_EXEC Param that might
8386 * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
8388 * If successful, return the expression and set *dpns_p and *ancestor_cell_p
8389 * appropriately for calling push_ancestor_plan(). If no referent can be
8390 * found, return NULL.
8392 static Node *
8393 find_param_referent(Param *param, deparse_context *context,
8394 deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
8396 /* Initialize output parameters to prevent compiler warnings */
8397 *dpns_p = NULL;
8398 *ancestor_cell_p = NULL;
8401 * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
8402 * SubPlan argument. This will necessarily be in some ancestor of the
8403 * current expression's Plan node.
8405 if (param->paramkind == PARAM_EXEC)
8407 deparse_namespace *dpns;
8408 Plan *child_plan;
8409 ListCell *lc;
8411 dpns = (deparse_namespace *) linitial(context->namespaces);
8412 child_plan = dpns->plan;
8414 foreach(lc, dpns->ancestors)
8416 Node *ancestor = (Node *) lfirst(lc);
8417 ListCell *lc2;
8420 * NestLoops transmit params to their inner child only.
8422 if (IsA(ancestor, NestLoop) &&
8423 child_plan == innerPlan(ancestor))
8425 NestLoop *nl = (NestLoop *) ancestor;
8427 foreach(lc2, nl->nestParams)
8429 NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
8431 if (nlp->paramno == param->paramid)
8433 /* Found a match, so return it */
8434 *dpns_p = dpns;
8435 *ancestor_cell_p = lc;
8436 return (Node *) nlp->paramval;
8442 * If ancestor is a SubPlan, check the arguments it provides.
8444 if (IsA(ancestor, SubPlan))
8446 SubPlan *subplan = (SubPlan *) ancestor;
8447 ListCell *lc3;
8448 ListCell *lc4;
8450 forboth(lc3, subplan->parParam, lc4, subplan->args)
8452 int paramid = lfirst_int(lc3);
8453 Node *arg = (Node *) lfirst(lc4);
8455 if (paramid == param->paramid)
8458 * Found a match, so return it. But, since Vars in
8459 * the arg are to be evaluated in the surrounding
8460 * context, we have to point to the next ancestor item
8461 * that is *not* a SubPlan.
8463 ListCell *rest;
8465 for_each_cell(rest, dpns->ancestors,
8466 lnext(dpns->ancestors, lc))
8468 Node *ancestor2 = (Node *) lfirst(rest);
8470 if (!IsA(ancestor2, SubPlan))
8472 *dpns_p = dpns;
8473 *ancestor_cell_p = rest;
8474 return arg;
8477 elog(ERROR, "SubPlan cannot be outermost ancestor");
8481 /* SubPlan isn't a kind of Plan, so skip the rest */
8482 continue;
8486 * We need not consider the ancestor's initPlan list, since
8487 * initplans never have any parParams.
8490 /* No luck, crawl up to next ancestor */
8491 child_plan = (Plan *) ancestor;
8495 /* No referent found */
8496 return NULL;
8500 * Try to find a subplan/initplan that emits the value for a PARAM_EXEC Param.
8502 * If successful, return the generating subplan/initplan and set *column_p
8503 * to the subplan's 0-based output column number.
8504 * Otherwise, return NULL.
8506 static SubPlan *
8507 find_param_generator(Param *param, deparse_context *context, int *column_p)
8509 /* Initialize output parameter to prevent compiler warnings */
8510 *column_p = 0;
8513 * If it's a PARAM_EXEC parameter, search the current plan node as well as
8514 * ancestor nodes looking for a subplan or initplan that emits the value
8515 * for the Param. It could appear in the setParams of an initplan or
8516 * MULTIEXPR_SUBLINK subplan, or in the paramIds of an ancestral SubPlan.
8518 if (param->paramkind == PARAM_EXEC)
8520 SubPlan *result;
8521 deparse_namespace *dpns;
8522 ListCell *lc;
8524 dpns = (deparse_namespace *) linitial(context->namespaces);
8526 /* First check the innermost plan node's initplans */
8527 result = find_param_generator_initplan(param, dpns->plan, column_p);
8528 if (result)
8529 return result;
8532 * The plan's targetlist might contain MULTIEXPR_SUBLINK SubPlans,
8533 * which can be referenced by Params elsewhere in the targetlist.
8534 * (Such Params should always be in the same targetlist, so there's no
8535 * need to do this work at upper plan nodes.)
8537 foreach_node(TargetEntry, tle, dpns->plan->targetlist)
8539 if (tle->expr && IsA(tle->expr, SubPlan))
8541 SubPlan *subplan = (SubPlan *) tle->expr;
8543 if (subplan->subLinkType == MULTIEXPR_SUBLINK)
8545 foreach_int(paramid, subplan->setParam)
8547 if (paramid == param->paramid)
8549 /* Found a match, so return it. */
8550 *column_p = foreach_current_index(paramid);
8551 return subplan;
8558 /* No luck, so check the ancestor nodes */
8559 foreach(lc, dpns->ancestors)
8561 Node *ancestor = (Node *) lfirst(lc);
8564 * If ancestor is a SubPlan, check the paramIds it provides.
8566 if (IsA(ancestor, SubPlan))
8568 SubPlan *subplan = (SubPlan *) ancestor;
8570 foreach_int(paramid, subplan->paramIds)
8572 if (paramid == param->paramid)
8574 /* Found a match, so return it. */
8575 *column_p = foreach_current_index(paramid);
8576 return subplan;
8580 /* SubPlan isn't a kind of Plan, so skip the rest */
8581 continue;
8585 * Otherwise, it's some kind of Plan node, so check its initplans.
8587 result = find_param_generator_initplan(param, (Plan *) ancestor,
8588 column_p);
8589 if (result)
8590 return result;
8592 /* No luck, crawl up to next ancestor */
8596 /* No generator found */
8597 return NULL;
8601 * Subroutine for find_param_generator: search one Plan node's initplans
8603 static SubPlan *
8604 find_param_generator_initplan(Param *param, Plan *plan, int *column_p)
8606 foreach_node(SubPlan, subplan, plan->initPlan)
8608 foreach_int(paramid, subplan->setParam)
8610 if (paramid == param->paramid)
8612 /* Found a match, so return it. */
8613 *column_p = foreach_current_index(paramid);
8614 return subplan;
8618 return NULL;
8622 * Display a Param appropriately.
8624 static void
8625 get_parameter(Param *param, deparse_context *context)
8627 Node *expr;
8628 deparse_namespace *dpns;
8629 ListCell *ancestor_cell;
8630 SubPlan *subplan;
8631 int column;
8634 * If it's a PARAM_EXEC parameter, try to locate the expression from which
8635 * the parameter was computed. This stanza handles only cases in which
8636 * the Param represents an input to the subplan we are currently in.
8638 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8639 if (expr)
8641 /* Found a match, so print it */
8642 deparse_namespace save_dpns;
8643 bool save_varprefix;
8644 bool need_paren;
8646 /* Switch attention to the ancestor plan node */
8647 push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8650 * Force prefixing of Vars, since they won't belong to the relation
8651 * being scanned in the original plan node.
8653 save_varprefix = context->varprefix;
8654 context->varprefix = true;
8657 * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8658 * upper-level Param, which wouldn't need extra parentheses.
8659 * Otherwise, insert parens to ensure the expression looks atomic.
8661 need_paren = !(IsA(expr, Var) ||
8662 IsA(expr, Aggref) ||
8663 IsA(expr, GroupingFunc) ||
8664 IsA(expr, Param));
8665 if (need_paren)
8666 appendStringInfoChar(context->buf, '(');
8668 get_rule_expr(expr, context, false);
8670 if (need_paren)
8671 appendStringInfoChar(context->buf, ')');
8673 context->varprefix = save_varprefix;
8675 pop_ancestor_plan(dpns, &save_dpns);
8677 return;
8681 * Alternatively, maybe it's a subplan output, which we print as a
8682 * reference to the subplan. (We could drill down into the subplan and
8683 * print the relevant targetlist expression, but that has been deemed too
8684 * confusing since it would violate normal SQL scope rules. Also, we're
8685 * relying on this reference to show that the testexpr containing the
8686 * Param has anything to do with that subplan at all.)
8688 subplan = find_param_generator(param, context, &column);
8689 if (subplan)
8691 appendStringInfo(context->buf, "(%s%s).col%d",
8692 subplan->useHashTable ? "hashed " : "",
8693 subplan->plan_name, column + 1);
8695 return;
8699 * If it's an external parameter, see if the outermost namespace provides
8700 * function argument names.
8702 if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8704 dpns = llast(context->namespaces);
8705 if (dpns->argnames &&
8706 param->paramid > 0 &&
8707 param->paramid <= dpns->numargs)
8709 char *argname = dpns->argnames[param->paramid - 1];
8711 if (argname)
8713 bool should_qualify = false;
8714 ListCell *lc;
8717 * Qualify the parameter name if there are any other deparse
8718 * namespaces with range tables. This avoids qualifying in
8719 * trivial cases like "RETURN a + b", but makes it safe in all
8720 * other cases.
8722 foreach(lc, context->namespaces)
8724 deparse_namespace *depns = lfirst(lc);
8726 if (depns->rtable_names != NIL)
8728 should_qualify = true;
8729 break;
8732 if (should_qualify)
8734 appendStringInfoString(context->buf, quote_identifier(dpns->funcname));
8735 appendStringInfoChar(context->buf, '.');
8738 appendStringInfoString(context->buf, quote_identifier(argname));
8739 return;
8745 * Not PARAM_EXEC, or couldn't find referent: just print $N.
8747 * It's a bug if we get here for anything except PARAM_EXTERN Params, but
8748 * in production builds printing $N seems more useful than failing.
8750 Assert(param->paramkind == PARAM_EXTERN);
8752 appendStringInfo(context->buf, "$%d", param->paramid);
8756 * get_simple_binary_op_name
8758 * helper function for isSimpleNode
8759 * will return single char binary operator name, or NULL if it's not
8761 static const char *
8762 get_simple_binary_op_name(OpExpr *expr)
8764 List *args = expr->args;
8766 if (list_length(args) == 2)
8768 /* binary operator */
8769 Node *arg1 = (Node *) linitial(args);
8770 Node *arg2 = (Node *) lsecond(args);
8771 const char *op;
8773 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
8774 if (strlen(op) == 1)
8775 return op;
8777 return NULL;
8782 * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
8784 * true : simple in the context of parent node's type
8785 * false : not simple
8787 static bool
8788 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
8790 if (!node)
8791 return false;
8793 switch (nodeTag(node))
8795 case T_Var:
8796 case T_Const:
8797 case T_Param:
8798 case T_CoerceToDomainValue:
8799 case T_SetToDefault:
8800 case T_CurrentOfExpr:
8801 /* single words: always simple */
8802 return true;
8804 case T_SubscriptingRef:
8805 case T_ArrayExpr:
8806 case T_RowExpr:
8807 case T_CoalesceExpr:
8808 case T_MinMaxExpr:
8809 case T_SQLValueFunction:
8810 case T_XmlExpr:
8811 case T_NextValueExpr:
8812 case T_NullIfExpr:
8813 case T_Aggref:
8814 case T_GroupingFunc:
8815 case T_WindowFunc:
8816 case T_MergeSupportFunc:
8817 case T_FuncExpr:
8818 case T_JsonConstructorExpr:
8819 case T_JsonExpr:
8820 /* function-like: name(..) or name[..] */
8821 return true;
8823 /* CASE keywords act as parentheses */
8824 case T_CaseExpr:
8825 return true;
8827 case T_FieldSelect:
8830 * appears simple since . has top precedence, unless parent is
8831 * T_FieldSelect itself!
8833 return !IsA(parentNode, FieldSelect);
8835 case T_FieldStore:
8838 * treat like FieldSelect (probably doesn't matter)
8840 return !IsA(parentNode, FieldStore);
8842 case T_CoerceToDomain:
8843 /* maybe simple, check args */
8844 return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8845 node, prettyFlags);
8846 case T_RelabelType:
8847 return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8848 node, prettyFlags);
8849 case T_CoerceViaIO:
8850 return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
8851 node, prettyFlags);
8852 case T_ArrayCoerceExpr:
8853 return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8854 node, prettyFlags);
8855 case T_ConvertRowtypeExpr:
8856 return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8857 node, prettyFlags);
8858 case T_ReturningExpr:
8859 return isSimpleNode((Node *) ((ReturningExpr *) node)->retexpr,
8860 node, prettyFlags);
8862 case T_OpExpr:
8864 /* depends on parent node type; needs further checking */
8865 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8867 const char *op;
8868 const char *parentOp;
8869 bool is_lopriop;
8870 bool is_hipriop;
8871 bool is_lopriparent;
8872 bool is_hipriparent;
8874 op = get_simple_binary_op_name((OpExpr *) node);
8875 if (!op)
8876 return false;
8878 /* We know only the basic operators + - and * / % */
8879 is_lopriop = (strchr("+-", *op) != NULL);
8880 is_hipriop = (strchr("*/%", *op) != NULL);
8881 if (!(is_lopriop || is_hipriop))
8882 return false;
8884 parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8885 if (!parentOp)
8886 return false;
8888 is_lopriparent = (strchr("+-", *parentOp) != NULL);
8889 is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8890 if (!(is_lopriparent || is_hipriparent))
8891 return false;
8893 if (is_hipriop && is_lopriparent)
8894 return true; /* op binds tighter than parent */
8896 if (is_lopriop && is_hipriparent)
8897 return false;
8900 * Operators are same priority --- can skip parens only if
8901 * we have (a - b) - c, not a - (b - c).
8903 if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
8904 return true;
8906 return false;
8908 /* else do the same stuff as for T_SubLink et al. */
8910 /* FALLTHROUGH */
8912 case T_SubLink:
8913 case T_NullTest:
8914 case T_BooleanTest:
8915 case T_DistinctExpr:
8916 case T_JsonIsPredicate:
8917 switch (nodeTag(parentNode))
8919 case T_FuncExpr:
8921 /* special handling for casts and COERCE_SQL_SYNTAX */
8922 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8924 if (type == COERCE_EXPLICIT_CAST ||
8925 type == COERCE_IMPLICIT_CAST ||
8926 type == COERCE_SQL_SYNTAX)
8927 return false;
8928 return true; /* own parentheses */
8930 case T_BoolExpr: /* lower precedence */
8931 case T_SubscriptingRef: /* other separators */
8932 case T_ArrayExpr: /* other separators */
8933 case T_RowExpr: /* other separators */
8934 case T_CoalesceExpr: /* own parentheses */
8935 case T_MinMaxExpr: /* own parentheses */
8936 case T_XmlExpr: /* own parentheses */
8937 case T_NullIfExpr: /* other separators */
8938 case T_Aggref: /* own parentheses */
8939 case T_GroupingFunc: /* own parentheses */
8940 case T_WindowFunc: /* own parentheses */
8941 case T_CaseExpr: /* other separators */
8942 return true;
8943 default:
8944 return false;
8947 case T_BoolExpr:
8948 switch (nodeTag(parentNode))
8950 case T_BoolExpr:
8951 if (prettyFlags & PRETTYFLAG_PAREN)
8953 BoolExprType type;
8954 BoolExprType parentType;
8956 type = ((BoolExpr *) node)->boolop;
8957 parentType = ((BoolExpr *) parentNode)->boolop;
8958 switch (type)
8960 case NOT_EXPR:
8961 case AND_EXPR:
8962 if (parentType == AND_EXPR || parentType == OR_EXPR)
8963 return true;
8964 break;
8965 case OR_EXPR:
8966 if (parentType == OR_EXPR)
8967 return true;
8968 break;
8971 return false;
8972 case T_FuncExpr:
8974 /* special handling for casts and COERCE_SQL_SYNTAX */
8975 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8977 if (type == COERCE_EXPLICIT_CAST ||
8978 type == COERCE_IMPLICIT_CAST ||
8979 type == COERCE_SQL_SYNTAX)
8980 return false;
8981 return true; /* own parentheses */
8983 case T_SubscriptingRef: /* other separators */
8984 case T_ArrayExpr: /* other separators */
8985 case T_RowExpr: /* other separators */
8986 case T_CoalesceExpr: /* own parentheses */
8987 case T_MinMaxExpr: /* own parentheses */
8988 case T_XmlExpr: /* own parentheses */
8989 case T_NullIfExpr: /* other separators */
8990 case T_Aggref: /* own parentheses */
8991 case T_GroupingFunc: /* own parentheses */
8992 case T_WindowFunc: /* own parentheses */
8993 case T_CaseExpr: /* other separators */
8994 case T_JsonExpr: /* own parentheses */
8995 return true;
8996 default:
8997 return false;
9000 case T_JsonValueExpr:
9001 /* maybe simple, check args */
9002 return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
9003 node, prettyFlags);
9005 default:
9006 break;
9008 /* those we don't know: in dubio complexo */
9009 return false;
9014 * appendContextKeyword - append a keyword to buffer
9016 * If prettyPrint is enabled, perform a line break, and adjust indentation.
9017 * Otherwise, just append the keyword.
9019 static void
9020 appendContextKeyword(deparse_context *context, const char *str,
9021 int indentBefore, int indentAfter, int indentPlus)
9023 StringInfo buf = context->buf;
9025 if (PRETTY_INDENT(context))
9027 int indentAmount;
9029 context->indentLevel += indentBefore;
9031 /* remove any trailing spaces currently in the buffer ... */
9032 removeStringInfoSpaces(buf);
9033 /* ... then add a newline and some spaces */
9034 appendStringInfoChar(buf, '\n');
9036 if (context->indentLevel < PRETTYINDENT_LIMIT)
9037 indentAmount = Max(context->indentLevel, 0) + indentPlus;
9038 else
9041 * If we're indented more than PRETTYINDENT_LIMIT characters, try
9042 * to conserve horizontal space by reducing the per-level
9043 * indentation. For best results the scale factor here should
9044 * divide all the indent amounts that get added to indentLevel
9045 * (PRETTYINDENT_STD, etc). It's important that the indentation
9046 * not grow unboundedly, else deeply-nested trees use O(N^2)
9047 * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
9049 indentAmount = PRETTYINDENT_LIMIT +
9050 (context->indentLevel - PRETTYINDENT_LIMIT) /
9051 (PRETTYINDENT_STD / 2);
9052 indentAmount %= PRETTYINDENT_LIMIT;
9053 /* scale/wrap logic affects indentLevel, but not indentPlus */
9054 indentAmount += indentPlus;
9056 appendStringInfoSpaces(buf, indentAmount);
9058 appendStringInfoString(buf, str);
9060 context->indentLevel += indentAfter;
9061 if (context->indentLevel < 0)
9062 context->indentLevel = 0;
9064 else
9065 appendStringInfoString(buf, str);
9069 * removeStringInfoSpaces - delete trailing spaces from a buffer.
9071 * Possibly this should move to stringinfo.c at some point.
9073 static void
9074 removeStringInfoSpaces(StringInfo str)
9076 while (str->len > 0 && str->data[str->len - 1] == ' ')
9077 str->data[--(str->len)] = '\0';
9082 * get_rule_expr_paren - deparse expr using get_rule_expr,
9083 * embracing the string with parentheses if necessary for prettyPrint.
9085 * Never embrace if prettyFlags=0, because it's done in the calling node.
9087 * Any node that does *not* embrace its argument node by sql syntax (with
9088 * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
9089 * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
9090 * added.
9092 static void
9093 get_rule_expr_paren(Node *node, deparse_context *context,
9094 bool showimplicit, Node *parentNode)
9096 bool need_paren;
9098 need_paren = PRETTY_PAREN(context) &&
9099 !isSimpleNode(node, parentNode, context->prettyFlags);
9101 if (need_paren)
9102 appendStringInfoChar(context->buf, '(');
9104 get_rule_expr(node, context, showimplicit);
9106 if (need_paren)
9107 appendStringInfoChar(context->buf, ')');
9110 static void
9111 get_json_behavior(JsonBehavior *behavior, deparse_context *context,
9112 const char *on)
9115 * The order of array elements must correspond to the order of
9116 * JsonBehaviorType members.
9118 const char *behavior_names[] =
9120 " NULL",
9121 " ERROR",
9122 " EMPTY",
9123 " TRUE",
9124 " FALSE",
9125 " UNKNOWN",
9126 " EMPTY ARRAY",
9127 " EMPTY OBJECT",
9128 " DEFAULT "
9131 if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
9132 elog(ERROR, "invalid json behavior type: %d", behavior->btype);
9134 appendStringInfoString(context->buf, behavior_names[behavior->btype]);
9136 if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
9137 get_rule_expr(behavior->expr, context, false);
9139 appendStringInfo(context->buf, " ON %s", on);
9143 * get_json_expr_options
9145 * Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and
9146 * JSON_TABLE columns.
9148 static void
9149 get_json_expr_options(JsonExpr *jsexpr, deparse_context *context,
9150 JsonBehaviorType default_behavior)
9152 if (jsexpr->op == JSON_QUERY_OP)
9154 if (jsexpr->wrapper == JSW_CONDITIONAL)
9155 appendStringInfoString(context->buf, " WITH CONDITIONAL WRAPPER");
9156 else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
9157 appendStringInfoString(context->buf, " WITH UNCONDITIONAL WRAPPER");
9158 /* The default */
9159 else if (jsexpr->wrapper == JSW_NONE || jsexpr->wrapper == JSW_UNSPEC)
9160 appendStringInfoString(context->buf, " WITHOUT WRAPPER");
9162 if (jsexpr->omit_quotes)
9163 appendStringInfoString(context->buf, " OMIT QUOTES");
9164 /* The default */
9165 else
9166 appendStringInfoString(context->buf, " KEEP QUOTES");
9169 if (jsexpr->on_empty && jsexpr->on_empty->btype != default_behavior)
9170 get_json_behavior(jsexpr->on_empty, context, "EMPTY");
9172 if (jsexpr->on_error && jsexpr->on_error->btype != default_behavior)
9173 get_json_behavior(jsexpr->on_error, context, "ERROR");
9176 /* ----------
9177 * get_rule_expr - Parse back an expression
9179 * Note: showimplicit determines whether we display any implicit cast that
9180 * is present at the top of the expression tree. It is a passed argument,
9181 * not a field of the context struct, because we change the value as we
9182 * recurse down into the expression. In general we suppress implicit casts
9183 * when the result type is known with certainty (eg, the arguments of an
9184 * OR must be boolean). We display implicit casts for arguments of functions
9185 * and operators, since this is needed to be certain that the same function
9186 * or operator will be chosen when the expression is re-parsed.
9187 * ----------
9189 static void
9190 get_rule_expr(Node *node, deparse_context *context,
9191 bool showimplicit)
9193 StringInfo buf = context->buf;
9195 if (node == NULL)
9196 return;
9198 /* Guard against excessively long or deeply-nested queries */
9199 CHECK_FOR_INTERRUPTS();
9200 check_stack_depth();
9203 * Each level of get_rule_expr must emit an indivisible term
9204 * (parenthesized if necessary) to ensure result is reparsed into the same
9205 * expression tree. The only exception is that when the input is a List,
9206 * we emit the component items comma-separated with no surrounding
9207 * decoration; this is convenient for most callers.
9209 switch (nodeTag(node))
9211 case T_Var:
9212 (void) get_variable((Var *) node, 0, false, context);
9213 break;
9215 case T_Const:
9216 get_const_expr((Const *) node, context, 0);
9217 break;
9219 case T_Param:
9220 get_parameter((Param *) node, context);
9221 break;
9223 case T_Aggref:
9224 get_agg_expr((Aggref *) node, context, (Aggref *) node);
9225 break;
9227 case T_GroupingFunc:
9229 GroupingFunc *gexpr = (GroupingFunc *) node;
9231 appendStringInfoString(buf, "GROUPING(");
9232 get_rule_expr((Node *) gexpr->args, context, true);
9233 appendStringInfoChar(buf, ')');
9235 break;
9237 case T_WindowFunc:
9238 get_windowfunc_expr((WindowFunc *) node, context);
9239 break;
9241 case T_MergeSupportFunc:
9242 appendStringInfoString(buf, "MERGE_ACTION()");
9243 break;
9245 case T_SubscriptingRef:
9247 SubscriptingRef *sbsref = (SubscriptingRef *) node;
9248 bool need_parens;
9251 * If the argument is a CaseTestExpr, we must be inside a
9252 * FieldStore, ie, we are assigning to an element of an array
9253 * within a composite column. Since we already punted on
9254 * displaying the FieldStore's target information, just punt
9255 * here too, and display only the assignment source
9256 * expression.
9258 if (IsA(sbsref->refexpr, CaseTestExpr))
9260 Assert(sbsref->refassgnexpr);
9261 get_rule_expr((Node *) sbsref->refassgnexpr,
9262 context, showimplicit);
9263 break;
9267 * Parenthesize the argument unless it's a simple Var or a
9268 * FieldSelect. (In particular, if it's another
9269 * SubscriptingRef, we *must* parenthesize to avoid
9270 * confusion.)
9272 need_parens = !IsA(sbsref->refexpr, Var) &&
9273 !IsA(sbsref->refexpr, FieldSelect);
9274 if (need_parens)
9275 appendStringInfoChar(buf, '(');
9276 get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
9277 if (need_parens)
9278 appendStringInfoChar(buf, ')');
9281 * If there's a refassgnexpr, we want to print the node in the
9282 * format "container[subscripts] := refassgnexpr". This is
9283 * not legal SQL, so decompilation of INSERT or UPDATE
9284 * statements should always use processIndirection as part of
9285 * the statement-level syntax. We should only see this when
9286 * EXPLAIN tries to print the targetlist of a plan resulting
9287 * from such a statement.
9289 if (sbsref->refassgnexpr)
9291 Node *refassgnexpr;
9294 * Use processIndirection to print this node's subscripts
9295 * as well as any additional field selections or
9296 * subscripting in immediate descendants. It returns the
9297 * RHS expr that is actually being "assigned".
9299 refassgnexpr = processIndirection(node, context);
9300 appendStringInfoString(buf, " := ");
9301 get_rule_expr(refassgnexpr, context, showimplicit);
9303 else
9305 /* Just an ordinary container fetch, so print subscripts */
9306 printSubscripts(sbsref, context);
9309 break;
9311 case T_FuncExpr:
9312 get_func_expr((FuncExpr *) node, context, showimplicit);
9313 break;
9315 case T_NamedArgExpr:
9317 NamedArgExpr *na = (NamedArgExpr *) node;
9319 appendStringInfo(buf, "%s => ", quote_identifier(na->name));
9320 get_rule_expr((Node *) na->arg, context, showimplicit);
9322 break;
9324 case T_OpExpr:
9325 get_oper_expr((OpExpr *) node, context);
9326 break;
9328 case T_DistinctExpr:
9330 DistinctExpr *expr = (DistinctExpr *) node;
9331 List *args = expr->args;
9332 Node *arg1 = (Node *) linitial(args);
9333 Node *arg2 = (Node *) lsecond(args);
9335 if (!PRETTY_PAREN(context))
9336 appendStringInfoChar(buf, '(');
9337 get_rule_expr_paren(arg1, context, true, node);
9338 appendStringInfoString(buf, " IS DISTINCT FROM ");
9339 get_rule_expr_paren(arg2, context, true, node);
9340 if (!PRETTY_PAREN(context))
9341 appendStringInfoChar(buf, ')');
9343 break;
9345 case T_NullIfExpr:
9347 NullIfExpr *nullifexpr = (NullIfExpr *) node;
9349 appendStringInfoString(buf, "NULLIF(");
9350 get_rule_expr((Node *) nullifexpr->args, context, true);
9351 appendStringInfoChar(buf, ')');
9353 break;
9355 case T_ScalarArrayOpExpr:
9357 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
9358 List *args = expr->args;
9359 Node *arg1 = (Node *) linitial(args);
9360 Node *arg2 = (Node *) lsecond(args);
9362 if (!PRETTY_PAREN(context))
9363 appendStringInfoChar(buf, '(');
9364 get_rule_expr_paren(arg1, context, true, node);
9365 appendStringInfo(buf, " %s %s (",
9366 generate_operator_name(expr->opno,
9367 exprType(arg1),
9368 get_base_element_type(exprType(arg2))),
9369 expr->useOr ? "ANY" : "ALL");
9370 get_rule_expr_paren(arg2, context, true, node);
9373 * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
9374 * a bare sub-SELECT. Since we're here, the sub-SELECT must
9375 * be meant as a scalar sub-SELECT yielding an array value to
9376 * be used in ScalarArrayOpExpr; but the grammar will
9377 * preferentially interpret such a construct as an ANY/ALL
9378 * SubLink. To prevent misparsing the output that way, insert
9379 * a dummy coercion (which will be stripped by parse analysis,
9380 * so no inefficiency is added in dump and reload). This is
9381 * indeed most likely what the user wrote to get the construct
9382 * accepted in the first place.
9384 if (IsA(arg2, SubLink) &&
9385 ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
9386 appendStringInfo(buf, "::%s",
9387 format_type_with_typemod(exprType(arg2),
9388 exprTypmod(arg2)));
9389 appendStringInfoChar(buf, ')');
9390 if (!PRETTY_PAREN(context))
9391 appendStringInfoChar(buf, ')');
9393 break;
9395 case T_BoolExpr:
9397 BoolExpr *expr = (BoolExpr *) node;
9398 Node *first_arg = linitial(expr->args);
9399 ListCell *arg;
9401 switch (expr->boolop)
9403 case AND_EXPR:
9404 if (!PRETTY_PAREN(context))
9405 appendStringInfoChar(buf, '(');
9406 get_rule_expr_paren(first_arg, context,
9407 false, node);
9408 for_each_from(arg, expr->args, 1)
9410 appendStringInfoString(buf, " AND ");
9411 get_rule_expr_paren((Node *) lfirst(arg), context,
9412 false, node);
9414 if (!PRETTY_PAREN(context))
9415 appendStringInfoChar(buf, ')');
9416 break;
9418 case OR_EXPR:
9419 if (!PRETTY_PAREN(context))
9420 appendStringInfoChar(buf, '(');
9421 get_rule_expr_paren(first_arg, context,
9422 false, node);
9423 for_each_from(arg, expr->args, 1)
9425 appendStringInfoString(buf, " OR ");
9426 get_rule_expr_paren((Node *) lfirst(arg), context,
9427 false, node);
9429 if (!PRETTY_PAREN(context))
9430 appendStringInfoChar(buf, ')');
9431 break;
9433 case NOT_EXPR:
9434 if (!PRETTY_PAREN(context))
9435 appendStringInfoChar(buf, '(');
9436 appendStringInfoString(buf, "NOT ");
9437 get_rule_expr_paren(first_arg, context,
9438 false, node);
9439 if (!PRETTY_PAREN(context))
9440 appendStringInfoChar(buf, ')');
9441 break;
9443 default:
9444 elog(ERROR, "unrecognized boolop: %d",
9445 (int) expr->boolop);
9448 break;
9450 case T_SubLink:
9451 get_sublink_expr((SubLink *) node, context);
9452 break;
9454 case T_SubPlan:
9456 SubPlan *subplan = (SubPlan *) node;
9459 * We cannot see an already-planned subplan in rule deparsing,
9460 * only while EXPLAINing a query plan. We don't try to
9461 * reconstruct the original SQL, just reference the subplan
9462 * that appears elsewhere in EXPLAIN's result. It does seem
9463 * useful to show the subLinkType and testexpr (if any), and
9464 * we also note whether the subplan will be hashed.
9466 switch (subplan->subLinkType)
9468 case EXISTS_SUBLINK:
9469 appendStringInfoString(buf, "EXISTS(");
9470 Assert(subplan->testexpr == NULL);
9471 break;
9472 case ALL_SUBLINK:
9473 appendStringInfoString(buf, "(ALL ");
9474 Assert(subplan->testexpr != NULL);
9475 break;
9476 case ANY_SUBLINK:
9477 appendStringInfoString(buf, "(ANY ");
9478 Assert(subplan->testexpr != NULL);
9479 break;
9480 case ROWCOMPARE_SUBLINK:
9481 /* Parenthesizing the testexpr seems sufficient */
9482 appendStringInfoChar(buf, '(');
9483 Assert(subplan->testexpr != NULL);
9484 break;
9485 case EXPR_SUBLINK:
9486 /* No need to decorate these subplan references */
9487 appendStringInfoChar(buf, '(');
9488 Assert(subplan->testexpr == NULL);
9489 break;
9490 case MULTIEXPR_SUBLINK:
9491 /* MULTIEXPR isn't executed in the normal way */
9492 appendStringInfoString(buf, "(rescan ");
9493 Assert(subplan->testexpr == NULL);
9494 break;
9495 case ARRAY_SUBLINK:
9496 appendStringInfoString(buf, "ARRAY(");
9497 Assert(subplan->testexpr == NULL);
9498 break;
9499 case CTE_SUBLINK:
9500 /* This case is unreachable within expressions */
9501 appendStringInfoString(buf, "CTE(");
9502 Assert(subplan->testexpr == NULL);
9503 break;
9506 if (subplan->testexpr != NULL)
9508 deparse_namespace *dpns;
9511 * Push SubPlan into ancestors list while deparsing
9512 * testexpr, so that we can handle PARAM_EXEC references
9513 * to the SubPlan's paramIds. (This makes it look like
9514 * the SubPlan is an "ancestor" of the current plan node,
9515 * which is a little weird, but it does no harm.) In this
9516 * path, we don't need to mention the SubPlan explicitly,
9517 * because the referencing Params will show its existence.
9519 dpns = (deparse_namespace *) linitial(context->namespaces);
9520 dpns->ancestors = lcons(subplan, dpns->ancestors);
9522 get_rule_expr(subplan->testexpr, context, showimplicit);
9523 appendStringInfoChar(buf, ')');
9525 dpns->ancestors = list_delete_first(dpns->ancestors);
9527 else
9529 /* No referencing Params, so show the SubPlan's name */
9530 if (subplan->useHashTable)
9531 appendStringInfo(buf, "hashed %s)", subplan->plan_name);
9532 else
9533 appendStringInfo(buf, "%s)", subplan->plan_name);
9536 break;
9538 case T_AlternativeSubPlan:
9540 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
9541 ListCell *lc;
9544 * This case cannot be reached in normal usage, since no
9545 * AlternativeSubPlan can appear either in parsetrees or
9546 * finished plan trees. We keep it just in case somebody
9547 * wants to use this code to print planner data structures.
9549 appendStringInfoString(buf, "(alternatives: ");
9550 foreach(lc, asplan->subplans)
9552 SubPlan *splan = lfirst_node(SubPlan, lc);
9554 if (splan->useHashTable)
9555 appendStringInfo(buf, "hashed %s", splan->plan_name);
9556 else
9557 appendStringInfoString(buf, splan->plan_name);
9558 if (lnext(asplan->subplans, lc))
9559 appendStringInfoString(buf, " or ");
9561 appendStringInfoChar(buf, ')');
9563 break;
9565 case T_FieldSelect:
9567 FieldSelect *fselect = (FieldSelect *) node;
9568 Node *arg = (Node *) fselect->arg;
9569 int fno = fselect->fieldnum;
9570 const char *fieldname;
9571 bool need_parens;
9574 * Parenthesize the argument unless it's an SubscriptingRef or
9575 * another FieldSelect. Note in particular that it would be
9576 * WRONG to not parenthesize a Var argument; simplicity is not
9577 * the issue here, having the right number of names is.
9579 need_parens = !IsA(arg, SubscriptingRef) &&
9580 !IsA(arg, FieldSelect);
9581 if (need_parens)
9582 appendStringInfoChar(buf, '(');
9583 get_rule_expr(arg, context, true);
9584 if (need_parens)
9585 appendStringInfoChar(buf, ')');
9588 * Get and print the field name.
9590 fieldname = get_name_for_var_field((Var *) arg, fno,
9591 0, context);
9592 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
9594 break;
9596 case T_FieldStore:
9598 FieldStore *fstore = (FieldStore *) node;
9599 bool need_parens;
9602 * There is no good way to represent a FieldStore as real SQL,
9603 * so decompilation of INSERT or UPDATE statements should
9604 * always use processIndirection as part of the
9605 * statement-level syntax. We should only get here when
9606 * EXPLAIN tries to print the targetlist of a plan resulting
9607 * from such a statement. The plan case is even harder than
9608 * ordinary rules would be, because the planner tries to
9609 * collapse multiple assignments to the same field or subfield
9610 * into one FieldStore; so we can see a list of target fields
9611 * not just one, and the arguments could be FieldStores
9612 * themselves. We don't bother to try to print the target
9613 * field names; we just print the source arguments, with a
9614 * ROW() around them if there's more than one. This isn't
9615 * terribly complete, but it's probably good enough for
9616 * EXPLAIN's purposes; especially since anything more would be
9617 * either hopelessly confusing or an even poorer
9618 * representation of what the plan is actually doing.
9620 need_parens = (list_length(fstore->newvals) != 1);
9621 if (need_parens)
9622 appendStringInfoString(buf, "ROW(");
9623 get_rule_expr((Node *) fstore->newvals, context, showimplicit);
9624 if (need_parens)
9625 appendStringInfoChar(buf, ')');
9627 break;
9629 case T_RelabelType:
9631 RelabelType *relabel = (RelabelType *) node;
9632 Node *arg = (Node *) relabel->arg;
9634 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
9635 !showimplicit)
9637 /* don't show the implicit cast */
9638 get_rule_expr_paren(arg, context, false, node);
9640 else
9642 get_coercion_expr(arg, context,
9643 relabel->resulttype,
9644 relabel->resulttypmod,
9645 node);
9648 break;
9650 case T_CoerceViaIO:
9652 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
9653 Node *arg = (Node *) iocoerce->arg;
9655 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9656 !showimplicit)
9658 /* don't show the implicit cast */
9659 get_rule_expr_paren(arg, context, false, node);
9661 else
9663 get_coercion_expr(arg, context,
9664 iocoerce->resulttype,
9666 node);
9669 break;
9671 case T_ArrayCoerceExpr:
9673 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
9674 Node *arg = (Node *) acoerce->arg;
9676 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9677 !showimplicit)
9679 /* don't show the implicit cast */
9680 get_rule_expr_paren(arg, context, false, node);
9682 else
9684 get_coercion_expr(arg, context,
9685 acoerce->resulttype,
9686 acoerce->resulttypmod,
9687 node);
9690 break;
9692 case T_ConvertRowtypeExpr:
9694 ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
9695 Node *arg = (Node *) convert->arg;
9697 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
9698 !showimplicit)
9700 /* don't show the implicit cast */
9701 get_rule_expr_paren(arg, context, false, node);
9703 else
9705 get_coercion_expr(arg, context,
9706 convert->resulttype, -1,
9707 node);
9710 break;
9712 case T_CollateExpr:
9714 CollateExpr *collate = (CollateExpr *) node;
9715 Node *arg = (Node *) collate->arg;
9717 if (!PRETTY_PAREN(context))
9718 appendStringInfoChar(buf, '(');
9719 get_rule_expr_paren(arg, context, showimplicit, node);
9720 appendStringInfo(buf, " COLLATE %s",
9721 generate_collation_name(collate->collOid));
9722 if (!PRETTY_PAREN(context))
9723 appendStringInfoChar(buf, ')');
9725 break;
9727 case T_CaseExpr:
9729 CaseExpr *caseexpr = (CaseExpr *) node;
9730 ListCell *temp;
9732 appendContextKeyword(context, "CASE",
9733 0, PRETTYINDENT_VAR, 0);
9734 if (caseexpr->arg)
9736 appendStringInfoChar(buf, ' ');
9737 get_rule_expr((Node *) caseexpr->arg, context, true);
9739 foreach(temp, caseexpr->args)
9741 CaseWhen *when = (CaseWhen *) lfirst(temp);
9742 Node *w = (Node *) when->expr;
9744 if (caseexpr->arg)
9747 * The parser should have produced WHEN clauses of the
9748 * form "CaseTestExpr = RHS", possibly with an
9749 * implicit coercion inserted above the CaseTestExpr.
9750 * For accurate decompilation of rules it's essential
9751 * that we show just the RHS. However in an
9752 * expression that's been through the optimizer, the
9753 * WHEN clause could be almost anything (since the
9754 * equality operator could have been expanded into an
9755 * inline function). If we don't recognize the form
9756 * of the WHEN clause, just punt and display it as-is.
9758 if (IsA(w, OpExpr))
9760 List *args = ((OpExpr *) w)->args;
9762 if (list_length(args) == 2 &&
9763 IsA(strip_implicit_coercions(linitial(args)),
9764 CaseTestExpr))
9765 w = (Node *) lsecond(args);
9769 if (!PRETTY_INDENT(context))
9770 appendStringInfoChar(buf, ' ');
9771 appendContextKeyword(context, "WHEN ",
9772 0, 0, 0);
9773 get_rule_expr(w, context, false);
9774 appendStringInfoString(buf, " THEN ");
9775 get_rule_expr((Node *) when->result, context, true);
9777 if (!PRETTY_INDENT(context))
9778 appendStringInfoChar(buf, ' ');
9779 appendContextKeyword(context, "ELSE ",
9780 0, 0, 0);
9781 get_rule_expr((Node *) caseexpr->defresult, context, true);
9782 if (!PRETTY_INDENT(context))
9783 appendStringInfoChar(buf, ' ');
9784 appendContextKeyword(context, "END",
9785 -PRETTYINDENT_VAR, 0, 0);
9787 break;
9789 case T_CaseTestExpr:
9792 * Normally we should never get here, since for expressions
9793 * that can contain this node type we attempt to avoid
9794 * recursing to it. But in an optimized expression we might
9795 * be unable to avoid that (see comments for CaseExpr). If we
9796 * do see one, print it as CASE_TEST_EXPR.
9798 appendStringInfoString(buf, "CASE_TEST_EXPR");
9800 break;
9802 case T_ArrayExpr:
9804 ArrayExpr *arrayexpr = (ArrayExpr *) node;
9806 appendStringInfoString(buf, "ARRAY[");
9807 get_rule_expr((Node *) arrayexpr->elements, context, true);
9808 appendStringInfoChar(buf, ']');
9811 * If the array isn't empty, we assume its elements are
9812 * coerced to the desired type. If it's empty, though, we
9813 * need an explicit coercion to the array type.
9815 if (arrayexpr->elements == NIL)
9816 appendStringInfo(buf, "::%s",
9817 format_type_with_typemod(arrayexpr->array_typeid, -1));
9819 break;
9821 case T_RowExpr:
9823 RowExpr *rowexpr = (RowExpr *) node;
9824 TupleDesc tupdesc = NULL;
9825 ListCell *arg;
9826 int i;
9827 char *sep;
9830 * If it's a named type and not RECORD, we may have to skip
9831 * dropped columns and/or claim there are NULLs for added
9832 * columns.
9834 if (rowexpr->row_typeid != RECORDOID)
9836 tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
9837 Assert(list_length(rowexpr->args) <= tupdesc->natts);
9841 * SQL99 allows "ROW" to be omitted when there is more than
9842 * one column, but for simplicity we always print it.
9844 appendStringInfoString(buf, "ROW(");
9845 sep = "";
9846 i = 0;
9847 foreach(arg, rowexpr->args)
9849 Node *e = (Node *) lfirst(arg);
9851 if (tupdesc == NULL ||
9852 !TupleDescAttr(tupdesc, i)->attisdropped)
9854 appendStringInfoString(buf, sep);
9855 /* Whole-row Vars need special treatment here */
9856 get_rule_expr_toplevel(e, context, true);
9857 sep = ", ";
9859 i++;
9861 if (tupdesc != NULL)
9863 while (i < tupdesc->natts)
9865 if (!TupleDescAttr(tupdesc, i)->attisdropped)
9867 appendStringInfoString(buf, sep);
9868 appendStringInfoString(buf, "NULL");
9869 sep = ", ";
9871 i++;
9874 ReleaseTupleDesc(tupdesc);
9876 appendStringInfoChar(buf, ')');
9877 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
9878 appendStringInfo(buf, "::%s",
9879 format_type_with_typemod(rowexpr->row_typeid, -1));
9881 break;
9883 case T_RowCompareExpr:
9885 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
9888 * SQL99 allows "ROW" to be omitted when there is more than
9889 * one column, but for simplicity we always print it. Within
9890 * a ROW expression, whole-row Vars need special treatment, so
9891 * use get_rule_list_toplevel.
9893 appendStringInfoString(buf, "(ROW(");
9894 get_rule_list_toplevel(rcexpr->largs, context, true);
9897 * We assume that the name of the first-column operator will
9898 * do for all the rest too. This is definitely open to
9899 * failure, eg if some but not all operators were renamed
9900 * since the construct was parsed, but there seems no way to
9901 * be perfect.
9903 appendStringInfo(buf, ") %s ROW(",
9904 generate_operator_name(linitial_oid(rcexpr->opnos),
9905 exprType(linitial(rcexpr->largs)),
9906 exprType(linitial(rcexpr->rargs))));
9907 get_rule_list_toplevel(rcexpr->rargs, context, true);
9908 appendStringInfoString(buf, "))");
9910 break;
9912 case T_CoalesceExpr:
9914 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
9916 appendStringInfoString(buf, "COALESCE(");
9917 get_rule_expr((Node *) coalesceexpr->args, context, true);
9918 appendStringInfoChar(buf, ')');
9920 break;
9922 case T_MinMaxExpr:
9924 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
9926 switch (minmaxexpr->op)
9928 case IS_GREATEST:
9929 appendStringInfoString(buf, "GREATEST(");
9930 break;
9931 case IS_LEAST:
9932 appendStringInfoString(buf, "LEAST(");
9933 break;
9935 get_rule_expr((Node *) minmaxexpr->args, context, true);
9936 appendStringInfoChar(buf, ')');
9938 break;
9940 case T_SQLValueFunction:
9942 SQLValueFunction *svf = (SQLValueFunction *) node;
9945 * Note: this code knows that typmod for time, timestamp, and
9946 * timestamptz just prints as integer.
9948 switch (svf->op)
9950 case SVFOP_CURRENT_DATE:
9951 appendStringInfoString(buf, "CURRENT_DATE");
9952 break;
9953 case SVFOP_CURRENT_TIME:
9954 appendStringInfoString(buf, "CURRENT_TIME");
9955 break;
9956 case SVFOP_CURRENT_TIME_N:
9957 appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
9958 break;
9959 case SVFOP_CURRENT_TIMESTAMP:
9960 appendStringInfoString(buf, "CURRENT_TIMESTAMP");
9961 break;
9962 case SVFOP_CURRENT_TIMESTAMP_N:
9963 appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
9964 svf->typmod);
9965 break;
9966 case SVFOP_LOCALTIME:
9967 appendStringInfoString(buf, "LOCALTIME");
9968 break;
9969 case SVFOP_LOCALTIME_N:
9970 appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
9971 break;
9972 case SVFOP_LOCALTIMESTAMP:
9973 appendStringInfoString(buf, "LOCALTIMESTAMP");
9974 break;
9975 case SVFOP_LOCALTIMESTAMP_N:
9976 appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
9977 svf->typmod);
9978 break;
9979 case SVFOP_CURRENT_ROLE:
9980 appendStringInfoString(buf, "CURRENT_ROLE");
9981 break;
9982 case SVFOP_CURRENT_USER:
9983 appendStringInfoString(buf, "CURRENT_USER");
9984 break;
9985 case SVFOP_USER:
9986 appendStringInfoString(buf, "USER");
9987 break;
9988 case SVFOP_SESSION_USER:
9989 appendStringInfoString(buf, "SESSION_USER");
9990 break;
9991 case SVFOP_CURRENT_CATALOG:
9992 appendStringInfoString(buf, "CURRENT_CATALOG");
9993 break;
9994 case SVFOP_CURRENT_SCHEMA:
9995 appendStringInfoString(buf, "CURRENT_SCHEMA");
9996 break;
9999 break;
10001 case T_XmlExpr:
10003 XmlExpr *xexpr = (XmlExpr *) node;
10004 bool needcomma = false;
10005 ListCell *arg;
10006 ListCell *narg;
10007 Const *con;
10009 switch (xexpr->op)
10011 case IS_XMLCONCAT:
10012 appendStringInfoString(buf, "XMLCONCAT(");
10013 break;
10014 case IS_XMLELEMENT:
10015 appendStringInfoString(buf, "XMLELEMENT(");
10016 break;
10017 case IS_XMLFOREST:
10018 appendStringInfoString(buf, "XMLFOREST(");
10019 break;
10020 case IS_XMLPARSE:
10021 appendStringInfoString(buf, "XMLPARSE(");
10022 break;
10023 case IS_XMLPI:
10024 appendStringInfoString(buf, "XMLPI(");
10025 break;
10026 case IS_XMLROOT:
10027 appendStringInfoString(buf, "XMLROOT(");
10028 break;
10029 case IS_XMLSERIALIZE:
10030 appendStringInfoString(buf, "XMLSERIALIZE(");
10031 break;
10032 case IS_DOCUMENT:
10033 break;
10035 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
10037 if (xexpr->xmloption == XMLOPTION_DOCUMENT)
10038 appendStringInfoString(buf, "DOCUMENT ");
10039 else
10040 appendStringInfoString(buf, "CONTENT ");
10042 if (xexpr->name)
10044 appendStringInfo(buf, "NAME %s",
10045 quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
10046 needcomma = true;
10048 if (xexpr->named_args)
10050 if (xexpr->op != IS_XMLFOREST)
10052 if (needcomma)
10053 appendStringInfoString(buf, ", ");
10054 appendStringInfoString(buf, "XMLATTRIBUTES(");
10055 needcomma = false;
10057 forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
10059 Node *e = (Node *) lfirst(arg);
10060 char *argname = strVal(lfirst(narg));
10062 if (needcomma)
10063 appendStringInfoString(buf, ", ");
10064 get_rule_expr((Node *) e, context, true);
10065 appendStringInfo(buf, " AS %s",
10066 quote_identifier(map_xml_name_to_sql_identifier(argname)));
10067 needcomma = true;
10069 if (xexpr->op != IS_XMLFOREST)
10070 appendStringInfoChar(buf, ')');
10072 if (xexpr->args)
10074 if (needcomma)
10075 appendStringInfoString(buf, ", ");
10076 switch (xexpr->op)
10078 case IS_XMLCONCAT:
10079 case IS_XMLELEMENT:
10080 case IS_XMLFOREST:
10081 case IS_XMLPI:
10082 case IS_XMLSERIALIZE:
10083 /* no extra decoration needed */
10084 get_rule_expr((Node *) xexpr->args, context, true);
10085 break;
10086 case IS_XMLPARSE:
10087 Assert(list_length(xexpr->args) == 2);
10089 get_rule_expr((Node *) linitial(xexpr->args),
10090 context, true);
10092 con = lsecond_node(Const, xexpr->args);
10093 Assert(!con->constisnull);
10094 if (DatumGetBool(con->constvalue))
10095 appendStringInfoString(buf,
10096 " PRESERVE WHITESPACE");
10097 else
10098 appendStringInfoString(buf,
10099 " STRIP WHITESPACE");
10100 break;
10101 case IS_XMLROOT:
10102 Assert(list_length(xexpr->args) == 3);
10104 get_rule_expr((Node *) linitial(xexpr->args),
10105 context, true);
10107 appendStringInfoString(buf, ", VERSION ");
10108 con = (Const *) lsecond(xexpr->args);
10109 if (IsA(con, Const) &&
10110 con->constisnull)
10111 appendStringInfoString(buf, "NO VALUE");
10112 else
10113 get_rule_expr((Node *) con, context, false);
10115 con = lthird_node(Const, xexpr->args);
10116 if (con->constisnull)
10117 /* suppress STANDALONE NO VALUE */ ;
10118 else
10120 switch (DatumGetInt32(con->constvalue))
10122 case XML_STANDALONE_YES:
10123 appendStringInfoString(buf,
10124 ", STANDALONE YES");
10125 break;
10126 case XML_STANDALONE_NO:
10127 appendStringInfoString(buf,
10128 ", STANDALONE NO");
10129 break;
10130 case XML_STANDALONE_NO_VALUE:
10131 appendStringInfoString(buf,
10132 ", STANDALONE NO VALUE");
10133 break;
10134 default:
10135 break;
10138 break;
10139 case IS_DOCUMENT:
10140 get_rule_expr_paren((Node *) xexpr->args, context, false, node);
10141 break;
10144 if (xexpr->op == IS_XMLSERIALIZE)
10145 appendStringInfo(buf, " AS %s",
10146 format_type_with_typemod(xexpr->type,
10147 xexpr->typmod));
10148 if (xexpr->op == IS_DOCUMENT)
10149 appendStringInfoString(buf, " IS DOCUMENT");
10150 else
10151 appendStringInfoChar(buf, ')');
10153 break;
10155 case T_NullTest:
10157 NullTest *ntest = (NullTest *) node;
10159 if (!PRETTY_PAREN(context))
10160 appendStringInfoChar(buf, '(');
10161 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
10164 * For scalar inputs, we prefer to print as IS [NOT] NULL,
10165 * which is shorter and traditional. If it's a rowtype input
10166 * but we're applying a scalar test, must print IS [NOT]
10167 * DISTINCT FROM NULL to be semantically correct.
10169 if (ntest->argisrow ||
10170 !type_is_rowtype(exprType((Node *) ntest->arg)))
10172 switch (ntest->nulltesttype)
10174 case IS_NULL:
10175 appendStringInfoString(buf, " IS NULL");
10176 break;
10177 case IS_NOT_NULL:
10178 appendStringInfoString(buf, " IS NOT NULL");
10179 break;
10180 default:
10181 elog(ERROR, "unrecognized nulltesttype: %d",
10182 (int) ntest->nulltesttype);
10185 else
10187 switch (ntest->nulltesttype)
10189 case IS_NULL:
10190 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
10191 break;
10192 case IS_NOT_NULL:
10193 appendStringInfoString(buf, " IS DISTINCT FROM NULL");
10194 break;
10195 default:
10196 elog(ERROR, "unrecognized nulltesttype: %d",
10197 (int) ntest->nulltesttype);
10200 if (!PRETTY_PAREN(context))
10201 appendStringInfoChar(buf, ')');
10203 break;
10205 case T_BooleanTest:
10207 BooleanTest *btest = (BooleanTest *) node;
10209 if (!PRETTY_PAREN(context))
10210 appendStringInfoChar(buf, '(');
10211 get_rule_expr_paren((Node *) btest->arg, context, false, node);
10212 switch (btest->booltesttype)
10214 case IS_TRUE:
10215 appendStringInfoString(buf, " IS TRUE");
10216 break;
10217 case IS_NOT_TRUE:
10218 appendStringInfoString(buf, " IS NOT TRUE");
10219 break;
10220 case IS_FALSE:
10221 appendStringInfoString(buf, " IS FALSE");
10222 break;
10223 case IS_NOT_FALSE:
10224 appendStringInfoString(buf, " IS NOT FALSE");
10225 break;
10226 case IS_UNKNOWN:
10227 appendStringInfoString(buf, " IS UNKNOWN");
10228 break;
10229 case IS_NOT_UNKNOWN:
10230 appendStringInfoString(buf, " IS NOT UNKNOWN");
10231 break;
10232 default:
10233 elog(ERROR, "unrecognized booltesttype: %d",
10234 (int) btest->booltesttype);
10236 if (!PRETTY_PAREN(context))
10237 appendStringInfoChar(buf, ')');
10239 break;
10241 case T_CoerceToDomain:
10243 CoerceToDomain *ctest = (CoerceToDomain *) node;
10244 Node *arg = (Node *) ctest->arg;
10246 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
10247 !showimplicit)
10249 /* don't show the implicit cast */
10250 get_rule_expr(arg, context, false);
10252 else
10254 get_coercion_expr(arg, context,
10255 ctest->resulttype,
10256 ctest->resulttypmod,
10257 node);
10260 break;
10262 case T_CoerceToDomainValue:
10263 appendStringInfoString(buf, "VALUE");
10264 break;
10266 case T_SetToDefault:
10267 appendStringInfoString(buf, "DEFAULT");
10268 break;
10270 case T_CurrentOfExpr:
10272 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
10274 if (cexpr->cursor_name)
10275 appendStringInfo(buf, "CURRENT OF %s",
10276 quote_identifier(cexpr->cursor_name));
10277 else
10278 appendStringInfo(buf, "CURRENT OF $%d",
10279 cexpr->cursor_param);
10281 break;
10283 case T_NextValueExpr:
10285 NextValueExpr *nvexpr = (NextValueExpr *) node;
10288 * This isn't exactly nextval(), but that seems close enough
10289 * for EXPLAIN's purposes.
10291 appendStringInfoString(buf, "nextval(");
10292 simple_quote_literal(buf,
10293 generate_relation_name(nvexpr->seqid,
10294 NIL));
10295 appendStringInfoChar(buf, ')');
10297 break;
10299 case T_InferenceElem:
10301 InferenceElem *iexpr = (InferenceElem *) node;
10302 bool save_varprefix;
10303 bool need_parens;
10306 * InferenceElem can only refer to target relation, so a
10307 * prefix is not useful, and indeed would cause parse errors.
10309 save_varprefix = context->varprefix;
10310 context->varprefix = false;
10313 * Parenthesize the element unless it's a simple Var or a bare
10314 * function call. Follows pg_get_indexdef_worker().
10316 need_parens = !IsA(iexpr->expr, Var);
10317 if (IsA(iexpr->expr, FuncExpr) &&
10318 ((FuncExpr *) iexpr->expr)->funcformat ==
10319 COERCE_EXPLICIT_CALL)
10320 need_parens = false;
10322 if (need_parens)
10323 appendStringInfoChar(buf, '(');
10324 get_rule_expr((Node *) iexpr->expr,
10325 context, false);
10326 if (need_parens)
10327 appendStringInfoChar(buf, ')');
10329 context->varprefix = save_varprefix;
10331 if (iexpr->infercollid)
10332 appendStringInfo(buf, " COLLATE %s",
10333 generate_collation_name(iexpr->infercollid));
10335 /* Add the operator class name, if not default */
10336 if (iexpr->inferopclass)
10338 Oid inferopclass = iexpr->inferopclass;
10339 Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
10341 get_opclass_name(inferopclass, inferopcinputtype, buf);
10344 break;
10346 case T_ReturningExpr:
10348 ReturningExpr *retExpr = (ReturningExpr *) node;
10351 * We cannot see a ReturningExpr in rule deparsing, only while
10352 * EXPLAINing a query plan (ReturningExpr nodes are only ever
10353 * adding during query rewriting). Just display the expression
10354 * returned (an expanded view column).
10356 get_rule_expr((Node *) retExpr->retexpr, context, showimplicit);
10358 break;
10360 case T_PartitionBoundSpec:
10362 PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
10363 ListCell *cell;
10364 char *sep;
10366 if (spec->is_default)
10368 appendStringInfoString(buf, "DEFAULT");
10369 break;
10372 switch (spec->strategy)
10374 case PARTITION_STRATEGY_HASH:
10375 Assert(spec->modulus > 0 && spec->remainder >= 0);
10376 Assert(spec->modulus > spec->remainder);
10378 appendStringInfoString(buf, "FOR VALUES");
10379 appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
10380 spec->modulus, spec->remainder);
10381 break;
10383 case PARTITION_STRATEGY_LIST:
10384 Assert(spec->listdatums != NIL);
10386 appendStringInfoString(buf, "FOR VALUES IN (");
10387 sep = "";
10388 foreach(cell, spec->listdatums)
10390 Const *val = lfirst_node(Const, cell);
10392 appendStringInfoString(buf, sep);
10393 get_const_expr(val, context, -1);
10394 sep = ", ";
10397 appendStringInfoChar(buf, ')');
10398 break;
10400 case PARTITION_STRATEGY_RANGE:
10401 Assert(spec->lowerdatums != NIL &&
10402 spec->upperdatums != NIL &&
10403 list_length(spec->lowerdatums) ==
10404 list_length(spec->upperdatums));
10406 appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
10407 get_range_partbound_string(spec->lowerdatums),
10408 get_range_partbound_string(spec->upperdatums));
10409 break;
10411 default:
10412 elog(ERROR, "unrecognized partition strategy: %d",
10413 (int) spec->strategy);
10414 break;
10417 break;
10419 case T_JsonValueExpr:
10421 JsonValueExpr *jve = (JsonValueExpr *) node;
10423 get_rule_expr((Node *) jve->raw_expr, context, false);
10424 get_json_format(jve->format, context->buf);
10426 break;
10428 case T_JsonConstructorExpr:
10429 get_json_constructor((JsonConstructorExpr *) node, context, false);
10430 break;
10432 case T_JsonIsPredicate:
10434 JsonIsPredicate *pred = (JsonIsPredicate *) node;
10436 if (!PRETTY_PAREN(context))
10437 appendStringInfoChar(context->buf, '(');
10439 get_rule_expr_paren(pred->expr, context, true, node);
10441 appendStringInfoString(context->buf, " IS JSON");
10443 /* TODO: handle FORMAT clause */
10445 switch (pred->item_type)
10447 case JS_TYPE_SCALAR:
10448 appendStringInfoString(context->buf, " SCALAR");
10449 break;
10450 case JS_TYPE_ARRAY:
10451 appendStringInfoString(context->buf, " ARRAY");
10452 break;
10453 case JS_TYPE_OBJECT:
10454 appendStringInfoString(context->buf, " OBJECT");
10455 break;
10456 default:
10457 break;
10460 if (pred->unique_keys)
10461 appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
10463 if (!PRETTY_PAREN(context))
10464 appendStringInfoChar(context->buf, ')');
10466 break;
10468 case T_JsonExpr:
10470 JsonExpr *jexpr = (JsonExpr *) node;
10472 switch (jexpr->op)
10474 case JSON_EXISTS_OP:
10475 appendStringInfoString(buf, "JSON_EXISTS(");
10476 break;
10477 case JSON_QUERY_OP:
10478 appendStringInfoString(buf, "JSON_QUERY(");
10479 break;
10480 case JSON_VALUE_OP:
10481 appendStringInfoString(buf, "JSON_VALUE(");
10482 break;
10483 default:
10484 elog(ERROR, "unrecognized JsonExpr op: %d",
10485 (int) jexpr->op);
10488 get_rule_expr(jexpr->formatted_expr, context, showimplicit);
10490 appendStringInfoString(buf, ", ");
10492 get_json_path_spec(jexpr->path_spec, context, showimplicit);
10494 if (jexpr->passing_values)
10496 ListCell *lc1,
10497 *lc2;
10498 bool needcomma = false;
10500 appendStringInfoString(buf, " PASSING ");
10502 forboth(lc1, jexpr->passing_names,
10503 lc2, jexpr->passing_values)
10505 if (needcomma)
10506 appendStringInfoString(buf, ", ");
10507 needcomma = true;
10509 get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
10510 appendStringInfo(buf, " AS %s",
10511 quote_identifier(lfirst_node(String, lc1)->sval));
10515 if (jexpr->op != JSON_EXISTS_OP ||
10516 jexpr->returning->typid != BOOLOID)
10517 get_json_returning(jexpr->returning, context->buf,
10518 jexpr->op == JSON_QUERY_OP);
10520 get_json_expr_options(jexpr, context,
10521 jexpr->op != JSON_EXISTS_OP ?
10522 JSON_BEHAVIOR_NULL :
10523 JSON_BEHAVIOR_FALSE);
10525 appendStringInfoChar(buf, ')');
10527 break;
10529 case T_List:
10531 char *sep;
10532 ListCell *l;
10534 sep = "";
10535 foreach(l, (List *) node)
10537 appendStringInfoString(buf, sep);
10538 get_rule_expr((Node *) lfirst(l), context, showimplicit);
10539 sep = ", ";
10542 break;
10544 case T_TableFunc:
10545 get_tablefunc((TableFunc *) node, context, showimplicit);
10546 break;
10548 default:
10549 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
10550 break;
10555 * get_rule_expr_toplevel - Parse back a toplevel expression
10557 * Same as get_rule_expr(), except that if the expr is just a Var, we pass
10558 * istoplevel = true not false to get_variable(). This causes whole-row Vars
10559 * to get printed with decoration that will prevent expansion of "*".
10560 * We need to use this in contexts such as ROW() and VALUES(), where the
10561 * parser would expand "foo.*" appearing at top level. (In principle we'd
10562 * use this in get_target_list() too, but that has additional worries about
10563 * whether to print AS, so it needs to invoke get_variable() directly anyway.)
10565 static void
10566 get_rule_expr_toplevel(Node *node, deparse_context *context,
10567 bool showimplicit)
10569 if (node && IsA(node, Var))
10570 (void) get_variable((Var *) node, 0, true, context);
10571 else
10572 get_rule_expr(node, context, showimplicit);
10576 * get_rule_list_toplevel - Parse back a list of toplevel expressions
10578 * Apply get_rule_expr_toplevel() to each element of a List.
10580 * This adds commas between the expressions, but caller is responsible
10581 * for printing surrounding decoration.
10583 static void
10584 get_rule_list_toplevel(List *lst, deparse_context *context,
10585 bool showimplicit)
10587 const char *sep;
10588 ListCell *lc;
10590 sep = "";
10591 foreach(lc, lst)
10593 Node *e = (Node *) lfirst(lc);
10595 appendStringInfoString(context->buf, sep);
10596 get_rule_expr_toplevel(e, context, showimplicit);
10597 sep = ", ";
10602 * get_rule_expr_funccall - Parse back a function-call expression
10604 * Same as get_rule_expr(), except that we guarantee that the output will
10605 * look like a function call, or like one of the things the grammar treats as
10606 * equivalent to a function call (see the func_expr_windowless production).
10607 * This is needed in places where the grammar uses func_expr_windowless and
10608 * you can't substitute a parenthesized a_expr. If what we have isn't going
10609 * to look like a function call, wrap it in a dummy CAST() expression, which
10610 * will satisfy the grammar --- and, indeed, is likely what the user wrote to
10611 * produce such a thing.
10613 static void
10614 get_rule_expr_funccall(Node *node, deparse_context *context,
10615 bool showimplicit)
10617 if (looks_like_function(node))
10618 get_rule_expr(node, context, showimplicit);
10619 else
10621 StringInfo buf = context->buf;
10623 appendStringInfoString(buf, "CAST(");
10624 /* no point in showing any top-level implicit cast */
10625 get_rule_expr(node, context, false);
10626 appendStringInfo(buf, " AS %s)",
10627 format_type_with_typemod(exprType(node),
10628 exprTypmod(node)));
10633 * Helper function to identify node types that satisfy func_expr_windowless.
10634 * If in doubt, "false" is always a safe answer.
10636 static bool
10637 looks_like_function(Node *node)
10639 if (node == NULL)
10640 return false; /* probably shouldn't happen */
10641 switch (nodeTag(node))
10643 case T_FuncExpr:
10644 /* OK, unless it's going to deparse as a cast */
10645 return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
10646 ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
10647 case T_NullIfExpr:
10648 case T_CoalesceExpr:
10649 case T_MinMaxExpr:
10650 case T_SQLValueFunction:
10651 case T_XmlExpr:
10652 case T_JsonExpr:
10653 /* these are all accepted by func_expr_common_subexpr */
10654 return true;
10655 default:
10656 break;
10658 return false;
10663 * get_oper_expr - Parse back an OpExpr node
10665 static void
10666 get_oper_expr(OpExpr *expr, deparse_context *context)
10668 StringInfo buf = context->buf;
10669 Oid opno = expr->opno;
10670 List *args = expr->args;
10672 if (!PRETTY_PAREN(context))
10673 appendStringInfoChar(buf, '(');
10674 if (list_length(args) == 2)
10676 /* binary operator */
10677 Node *arg1 = (Node *) linitial(args);
10678 Node *arg2 = (Node *) lsecond(args);
10680 get_rule_expr_paren(arg1, context, true, (Node *) expr);
10681 appendStringInfo(buf, " %s ",
10682 generate_operator_name(opno,
10683 exprType(arg1),
10684 exprType(arg2)));
10685 get_rule_expr_paren(arg2, context, true, (Node *) expr);
10687 else
10689 /* prefix operator */
10690 Node *arg = (Node *) linitial(args);
10692 appendStringInfo(buf, "%s ",
10693 generate_operator_name(opno,
10694 InvalidOid,
10695 exprType(arg)));
10696 get_rule_expr_paren(arg, context, true, (Node *) expr);
10698 if (!PRETTY_PAREN(context))
10699 appendStringInfoChar(buf, ')');
10703 * get_func_expr - Parse back a FuncExpr node
10705 static void
10706 get_func_expr(FuncExpr *expr, deparse_context *context,
10707 bool showimplicit)
10709 StringInfo buf = context->buf;
10710 Oid funcoid = expr->funcid;
10711 Oid argtypes[FUNC_MAX_ARGS];
10712 int nargs;
10713 List *argnames;
10714 bool use_variadic;
10715 ListCell *l;
10718 * If the function call came from an implicit coercion, then just show the
10719 * first argument --- unless caller wants to see implicit coercions.
10721 if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
10723 get_rule_expr_paren((Node *) linitial(expr->args), context,
10724 false, (Node *) expr);
10725 return;
10729 * If the function call came from a cast, then show the first argument
10730 * plus an explicit cast operation.
10732 if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10733 expr->funcformat == COERCE_IMPLICIT_CAST)
10735 Node *arg = linitial(expr->args);
10736 Oid rettype = expr->funcresulttype;
10737 int32 coercedTypmod;
10739 /* Get the typmod if this is a length-coercion function */
10740 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10742 get_coercion_expr(arg, context,
10743 rettype, coercedTypmod,
10744 (Node *) expr);
10746 return;
10750 * If the function was called using one of the SQL spec's random special
10751 * syntaxes, try to reproduce that. If we don't recognize the function,
10752 * fall through.
10754 if (expr->funcformat == COERCE_SQL_SYNTAX)
10756 if (get_func_sql_syntax(expr, context))
10757 return;
10761 * Normal function: display as proname(args). First we need to extract
10762 * the argument datatypes.
10764 if (list_length(expr->args) > FUNC_MAX_ARGS)
10765 ereport(ERROR,
10766 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10767 errmsg("too many arguments")));
10768 nargs = 0;
10769 argnames = NIL;
10770 foreach(l, expr->args)
10772 Node *arg = (Node *) lfirst(l);
10774 if (IsA(arg, NamedArgExpr))
10775 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10776 argtypes[nargs] = exprType(arg);
10777 nargs++;
10780 appendStringInfo(buf, "%s(",
10781 generate_function_name(funcoid, nargs,
10782 argnames, argtypes,
10783 expr->funcvariadic,
10784 &use_variadic,
10785 context->inGroupBy));
10786 nargs = 0;
10787 foreach(l, expr->args)
10789 if (nargs++ > 0)
10790 appendStringInfoString(buf, ", ");
10791 if (use_variadic && lnext(expr->args, l) == NULL)
10792 appendStringInfoString(buf, "VARIADIC ");
10793 get_rule_expr((Node *) lfirst(l), context, true);
10795 appendStringInfoChar(buf, ')');
10799 * get_agg_expr - Parse back an Aggref node
10801 static void
10802 get_agg_expr(Aggref *aggref, deparse_context *context,
10803 Aggref *original_aggref)
10805 get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10806 false);
10810 * get_agg_expr_helper - subroutine for get_agg_expr and
10811 * get_json_agg_constructor
10813 static void
10814 get_agg_expr_helper(Aggref *aggref, deparse_context *context,
10815 Aggref *original_aggref, const char *funcname,
10816 const char *options, bool is_json_objectagg)
10818 StringInfo buf = context->buf;
10819 Oid argtypes[FUNC_MAX_ARGS];
10820 int nargs;
10821 bool use_variadic = false;
10824 * For a combining aggregate, we look up and deparse the corresponding
10825 * partial aggregate instead. This is necessary because our input
10826 * argument list has been replaced; the new argument list always has just
10827 * one element, which will point to a partial Aggref that supplies us with
10828 * transition states to combine.
10830 if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10832 TargetEntry *tle;
10834 Assert(list_length(aggref->args) == 1);
10835 tle = linitial_node(TargetEntry, aggref->args);
10836 resolve_special_varno((Node *) tle->expr, context,
10837 get_agg_combine_expr, original_aggref);
10838 return;
10842 * Mark as PARTIAL, if appropriate. We look to the original aggref so as
10843 * to avoid printing this when recursing from the code just above.
10845 if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10846 appendStringInfoString(buf, "PARTIAL ");
10848 /* Extract the argument types as seen by the parser */
10849 nargs = get_aggregate_argtypes(aggref, argtypes);
10851 if (!funcname)
10852 funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10853 argtypes, aggref->aggvariadic,
10854 &use_variadic,
10855 context->inGroupBy);
10857 /* Print the aggregate name, schema-qualified if needed */
10858 appendStringInfo(buf, "%s(%s", funcname,
10859 (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10861 if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10864 * Ordered-set aggregates do not use "*" syntax. Also, we needn't
10865 * worry about inserting VARIADIC. So we can just dump the direct
10866 * args as-is.
10868 Assert(!aggref->aggvariadic);
10869 get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10870 Assert(aggref->aggorder != NIL);
10871 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10872 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10874 else
10876 /* aggstar can be set only in zero-argument aggregates */
10877 if (aggref->aggstar)
10878 appendStringInfoChar(buf, '*');
10879 else
10881 ListCell *l;
10882 int i;
10884 i = 0;
10885 foreach(l, aggref->args)
10887 TargetEntry *tle = (TargetEntry *) lfirst(l);
10888 Node *arg = (Node *) tle->expr;
10890 Assert(!IsA(arg, NamedArgExpr));
10891 if (tle->resjunk)
10892 continue;
10893 if (i++ > 0)
10895 if (is_json_objectagg)
10898 * the ABSENT ON NULL and WITH UNIQUE args are printed
10899 * separately, so ignore them here
10901 if (i > 2)
10902 break;
10904 appendStringInfoString(buf, " : ");
10906 else
10907 appendStringInfoString(buf, ", ");
10909 if (use_variadic && i == nargs)
10910 appendStringInfoString(buf, "VARIADIC ");
10911 get_rule_expr(arg, context, true);
10915 if (aggref->aggorder != NIL)
10917 appendStringInfoString(buf, " ORDER BY ");
10918 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10922 if (options)
10923 appendStringInfoString(buf, options);
10925 if (aggref->aggfilter != NULL)
10927 appendStringInfoString(buf, ") FILTER (WHERE ");
10928 get_rule_expr((Node *) aggref->aggfilter, context, false);
10931 appendStringInfoChar(buf, ')');
10935 * This is a helper function for get_agg_expr(). It's used when we deparse
10936 * a combining Aggref; resolve_special_varno locates the corresponding partial
10937 * Aggref and then calls this.
10939 static void
10940 get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
10942 Aggref *aggref;
10943 Aggref *original_aggref = callback_arg;
10945 if (!IsA(node, Aggref))
10946 elog(ERROR, "combining Aggref does not point to an Aggref");
10948 aggref = (Aggref *) node;
10949 get_agg_expr(aggref, context, original_aggref);
10953 * get_windowfunc_expr - Parse back a WindowFunc node
10955 static void
10956 get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
10958 get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
10963 * get_windowfunc_expr_helper - subroutine for get_windowfunc_expr and
10964 * get_json_agg_constructor
10966 static void
10967 get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
10968 const char *funcname, const char *options,
10969 bool is_json_objectagg)
10971 StringInfo buf = context->buf;
10972 Oid argtypes[FUNC_MAX_ARGS];
10973 int nargs;
10974 List *argnames;
10975 ListCell *l;
10977 if (list_length(wfunc->args) > FUNC_MAX_ARGS)
10978 ereport(ERROR,
10979 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10980 errmsg("too many arguments")));
10981 nargs = 0;
10982 argnames = NIL;
10983 foreach(l, wfunc->args)
10985 Node *arg = (Node *) lfirst(l);
10987 if (IsA(arg, NamedArgExpr))
10988 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10989 argtypes[nargs] = exprType(arg);
10990 nargs++;
10993 if (!funcname)
10994 funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
10995 argtypes, false, NULL,
10996 context->inGroupBy);
10998 appendStringInfo(buf, "%s(", funcname);
11000 /* winstar can be set only in zero-argument aggregates */
11001 if (wfunc->winstar)
11002 appendStringInfoChar(buf, '*');
11003 else
11005 if (is_json_objectagg)
11007 get_rule_expr((Node *) linitial(wfunc->args), context, false);
11008 appendStringInfoString(buf, " : ");
11009 get_rule_expr((Node *) lsecond(wfunc->args), context, false);
11011 else
11012 get_rule_expr((Node *) wfunc->args, context, true);
11015 if (options)
11016 appendStringInfoString(buf, options);
11018 if (wfunc->aggfilter != NULL)
11020 appendStringInfoString(buf, ") FILTER (WHERE ");
11021 get_rule_expr((Node *) wfunc->aggfilter, context, false);
11024 appendStringInfoString(buf, ") OVER ");
11026 foreach(l, context->windowClause)
11028 WindowClause *wc = (WindowClause *) lfirst(l);
11030 if (wc->winref == wfunc->winref)
11032 if (wc->name)
11033 appendStringInfoString(buf, quote_identifier(wc->name));
11034 else
11035 get_rule_windowspec(wc, context->targetList, context);
11036 break;
11039 if (l == NULL)
11041 if (context->windowClause)
11042 elog(ERROR, "could not find window clause for winref %u",
11043 wfunc->winref);
11046 * In EXPLAIN, we don't have window context information available, so
11047 * we have to settle for this:
11049 appendStringInfoString(buf, "(?)");
11054 * get_func_sql_syntax - Parse back a SQL-syntax function call
11056 * Returns true if we successfully deparsed, false if we did not
11057 * recognize the function.
11059 static bool
11060 get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
11062 StringInfo buf = context->buf;
11063 Oid funcoid = expr->funcid;
11065 switch (funcoid)
11067 case F_TIMEZONE_INTERVAL_TIMESTAMP:
11068 case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
11069 case F_TIMEZONE_INTERVAL_TIMETZ:
11070 case F_TIMEZONE_TEXT_TIMESTAMP:
11071 case F_TIMEZONE_TEXT_TIMESTAMPTZ:
11072 case F_TIMEZONE_TEXT_TIMETZ:
11073 /* AT TIME ZONE ... note reversed argument order */
11074 appendStringInfoChar(buf, '(');
11075 get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
11076 (Node *) expr);
11077 appendStringInfoString(buf, " AT TIME ZONE ");
11078 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11079 (Node *) expr);
11080 appendStringInfoChar(buf, ')');
11081 return true;
11083 case F_TIMEZONE_TIMESTAMP:
11084 case F_TIMEZONE_TIMESTAMPTZ:
11085 case F_TIMEZONE_TIMETZ:
11086 /* AT LOCAL */
11087 appendStringInfoChar(buf, '(');
11088 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11089 (Node *) expr);
11090 appendStringInfoString(buf, " AT LOCAL)");
11091 return true;
11093 case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
11094 case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
11095 case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
11096 case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
11097 case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
11098 case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
11099 case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
11100 case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
11101 case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
11102 case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
11103 case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
11104 case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
11105 case F_OVERLAPS_TIME_TIME_TIME_TIME:
11106 /* (x1, x2) OVERLAPS (y1, y2) */
11107 appendStringInfoString(buf, "((");
11108 get_rule_expr((Node *) linitial(expr->args), context, false);
11109 appendStringInfoString(buf, ", ");
11110 get_rule_expr((Node *) lsecond(expr->args), context, false);
11111 appendStringInfoString(buf, ") OVERLAPS (");
11112 get_rule_expr((Node *) lthird(expr->args), context, false);
11113 appendStringInfoString(buf, ", ");
11114 get_rule_expr((Node *) lfourth(expr->args), context, false);
11115 appendStringInfoString(buf, "))");
11116 return true;
11118 case F_EXTRACT_TEXT_DATE:
11119 case F_EXTRACT_TEXT_TIME:
11120 case F_EXTRACT_TEXT_TIMETZ:
11121 case F_EXTRACT_TEXT_TIMESTAMP:
11122 case F_EXTRACT_TEXT_TIMESTAMPTZ:
11123 case F_EXTRACT_TEXT_INTERVAL:
11124 /* EXTRACT (x FROM y) */
11125 appendStringInfoString(buf, "EXTRACT(");
11127 Const *con = (Const *) linitial(expr->args);
11129 Assert(IsA(con, Const) &&
11130 con->consttype == TEXTOID &&
11131 !con->constisnull);
11132 appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
11134 appendStringInfoString(buf, " FROM ");
11135 get_rule_expr((Node *) lsecond(expr->args), context, false);
11136 appendStringInfoChar(buf, ')');
11137 return true;
11139 case F_IS_NORMALIZED:
11140 /* IS xxx NORMALIZED */
11141 appendStringInfoChar(buf, '(');
11142 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11143 (Node *) expr);
11144 appendStringInfoString(buf, " IS");
11145 if (list_length(expr->args) == 2)
11147 Const *con = (Const *) lsecond(expr->args);
11149 Assert(IsA(con, Const) &&
11150 con->consttype == TEXTOID &&
11151 !con->constisnull);
11152 appendStringInfo(buf, " %s",
11153 TextDatumGetCString(con->constvalue));
11155 appendStringInfoString(buf, " NORMALIZED)");
11156 return true;
11158 case F_PG_COLLATION_FOR:
11159 /* COLLATION FOR */
11160 appendStringInfoString(buf, "COLLATION FOR (");
11161 get_rule_expr((Node *) linitial(expr->args), context, false);
11162 appendStringInfoChar(buf, ')');
11163 return true;
11165 case F_NORMALIZE:
11166 /* NORMALIZE() */
11167 appendStringInfoString(buf, "NORMALIZE(");
11168 get_rule_expr((Node *) linitial(expr->args), context, false);
11169 if (list_length(expr->args) == 2)
11171 Const *con = (Const *) lsecond(expr->args);
11173 Assert(IsA(con, Const) &&
11174 con->consttype == TEXTOID &&
11175 !con->constisnull);
11176 appendStringInfo(buf, ", %s",
11177 TextDatumGetCString(con->constvalue));
11179 appendStringInfoChar(buf, ')');
11180 return true;
11182 case F_OVERLAY_BIT_BIT_INT4:
11183 case F_OVERLAY_BIT_BIT_INT4_INT4:
11184 case F_OVERLAY_BYTEA_BYTEA_INT4:
11185 case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
11186 case F_OVERLAY_TEXT_TEXT_INT4:
11187 case F_OVERLAY_TEXT_TEXT_INT4_INT4:
11188 /* OVERLAY() */
11189 appendStringInfoString(buf, "OVERLAY(");
11190 get_rule_expr((Node *) linitial(expr->args), context, false);
11191 appendStringInfoString(buf, " PLACING ");
11192 get_rule_expr((Node *) lsecond(expr->args), context, false);
11193 appendStringInfoString(buf, " FROM ");
11194 get_rule_expr((Node *) lthird(expr->args), context, false);
11195 if (list_length(expr->args) == 4)
11197 appendStringInfoString(buf, " FOR ");
11198 get_rule_expr((Node *) lfourth(expr->args), context, false);
11200 appendStringInfoChar(buf, ')');
11201 return true;
11203 case F_POSITION_BIT_BIT:
11204 case F_POSITION_BYTEA_BYTEA:
11205 case F_POSITION_TEXT_TEXT:
11206 /* POSITION() ... extra parens since args are b_expr not a_expr */
11207 appendStringInfoString(buf, "POSITION((");
11208 get_rule_expr((Node *) lsecond(expr->args), context, false);
11209 appendStringInfoString(buf, ") IN (");
11210 get_rule_expr((Node *) linitial(expr->args), context, false);
11211 appendStringInfoString(buf, "))");
11212 return true;
11214 case F_SUBSTRING_BIT_INT4:
11215 case F_SUBSTRING_BIT_INT4_INT4:
11216 case F_SUBSTRING_BYTEA_INT4:
11217 case F_SUBSTRING_BYTEA_INT4_INT4:
11218 case F_SUBSTRING_TEXT_INT4:
11219 case F_SUBSTRING_TEXT_INT4_INT4:
11220 /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
11221 appendStringInfoString(buf, "SUBSTRING(");
11222 get_rule_expr((Node *) linitial(expr->args), context, false);
11223 appendStringInfoString(buf, " FROM ");
11224 get_rule_expr((Node *) lsecond(expr->args), context, false);
11225 if (list_length(expr->args) == 3)
11227 appendStringInfoString(buf, " FOR ");
11228 get_rule_expr((Node *) lthird(expr->args), context, false);
11230 appendStringInfoChar(buf, ')');
11231 return true;
11233 case F_SUBSTRING_TEXT_TEXT_TEXT:
11234 /* SUBSTRING SIMILAR/ESCAPE */
11235 appendStringInfoString(buf, "SUBSTRING(");
11236 get_rule_expr((Node *) linitial(expr->args), context, false);
11237 appendStringInfoString(buf, " SIMILAR ");
11238 get_rule_expr((Node *) lsecond(expr->args), context, false);
11239 appendStringInfoString(buf, " ESCAPE ");
11240 get_rule_expr((Node *) lthird(expr->args), context, false);
11241 appendStringInfoChar(buf, ')');
11242 return true;
11244 case F_BTRIM_BYTEA_BYTEA:
11245 case F_BTRIM_TEXT:
11246 case F_BTRIM_TEXT_TEXT:
11247 /* TRIM() */
11248 appendStringInfoString(buf, "TRIM(BOTH");
11249 if (list_length(expr->args) == 2)
11251 appendStringInfoChar(buf, ' ');
11252 get_rule_expr((Node *) lsecond(expr->args), context, false);
11254 appendStringInfoString(buf, " FROM ");
11255 get_rule_expr((Node *) linitial(expr->args), context, false);
11256 appendStringInfoChar(buf, ')');
11257 return true;
11259 case F_LTRIM_BYTEA_BYTEA:
11260 case F_LTRIM_TEXT:
11261 case F_LTRIM_TEXT_TEXT:
11262 /* TRIM() */
11263 appendStringInfoString(buf, "TRIM(LEADING");
11264 if (list_length(expr->args) == 2)
11266 appendStringInfoChar(buf, ' ');
11267 get_rule_expr((Node *) lsecond(expr->args), context, false);
11269 appendStringInfoString(buf, " FROM ");
11270 get_rule_expr((Node *) linitial(expr->args), context, false);
11271 appendStringInfoChar(buf, ')');
11272 return true;
11274 case F_RTRIM_BYTEA_BYTEA:
11275 case F_RTRIM_TEXT:
11276 case F_RTRIM_TEXT_TEXT:
11277 /* TRIM() */
11278 appendStringInfoString(buf, "TRIM(TRAILING");
11279 if (list_length(expr->args) == 2)
11281 appendStringInfoChar(buf, ' ');
11282 get_rule_expr((Node *) lsecond(expr->args), context, false);
11284 appendStringInfoString(buf, " FROM ");
11285 get_rule_expr((Node *) linitial(expr->args), context, false);
11286 appendStringInfoChar(buf, ')');
11287 return true;
11289 case F_SYSTEM_USER:
11290 appendStringInfoString(buf, "SYSTEM_USER");
11291 return true;
11293 case F_XMLEXISTS:
11294 /* XMLEXISTS ... extra parens because args are c_expr */
11295 appendStringInfoString(buf, "XMLEXISTS((");
11296 get_rule_expr((Node *) linitial(expr->args), context, false);
11297 appendStringInfoString(buf, ") PASSING (");
11298 get_rule_expr((Node *) lsecond(expr->args), context, false);
11299 appendStringInfoString(buf, "))");
11300 return true;
11302 return false;
11305 /* ----------
11306 * get_coercion_expr
11308 * Make a string representation of a value coerced to a specific type
11309 * ----------
11311 static void
11312 get_coercion_expr(Node *arg, deparse_context *context,
11313 Oid resulttype, int32 resulttypmod,
11314 Node *parentNode)
11316 StringInfo buf = context->buf;
11319 * Since parse_coerce.c doesn't immediately collapse application of
11320 * length-coercion functions to constants, what we'll typically see in
11321 * such cases is a Const with typmod -1 and a length-coercion function
11322 * right above it. Avoid generating redundant output. However, beware of
11323 * suppressing casts when the user actually wrote something like
11324 * 'foo'::text::char(3).
11326 * Note: it might seem that we are missing the possibility of needing to
11327 * print a COLLATE clause for such a Const. However, a Const could only
11328 * have nondefault collation in a post-constant-folding tree, in which the
11329 * length coercion would have been folded too. See also the special
11330 * handling of CollateExpr in coerce_to_target_type(): any collation
11331 * marking will be above the coercion node, not below it.
11333 if (arg && IsA(arg, Const) &&
11334 ((Const *) arg)->consttype == resulttype &&
11335 ((Const *) arg)->consttypmod == -1)
11337 /* Show the constant without normal ::typename decoration */
11338 get_const_expr((Const *) arg, context, -1);
11340 else
11342 if (!PRETTY_PAREN(context))
11343 appendStringInfoChar(buf, '(');
11344 get_rule_expr_paren(arg, context, false, parentNode);
11345 if (!PRETTY_PAREN(context))
11346 appendStringInfoChar(buf, ')');
11350 * Never emit resulttype(arg) functional notation. A pg_proc entry could
11351 * take precedence, and a resulttype in pg_temp would require schema
11352 * qualification that format_type_with_typemod() would usually omit. We've
11353 * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
11354 * would work fine.
11356 appendStringInfo(buf, "::%s",
11357 format_type_with_typemod(resulttype, resulttypmod));
11360 /* ----------
11361 * get_const_expr
11363 * Make a string representation of a Const
11365 * showtype can be -1 to never show "::typename" decoration, or +1 to always
11366 * show it, or 0 to show it only if the constant wouldn't be assumed to be
11367 * the right type by default.
11369 * If the Const's collation isn't default for its type, show that too.
11370 * We mustn't do this when showtype is -1 (since that means the caller will
11371 * print "::typename", and we can't put a COLLATE clause in between). It's
11372 * caller's responsibility that collation isn't missed in such cases.
11373 * ----------
11375 static void
11376 get_const_expr(Const *constval, deparse_context *context, int showtype)
11378 StringInfo buf = context->buf;
11379 Oid typoutput;
11380 bool typIsVarlena;
11381 char *extval;
11382 bool needlabel = false;
11384 if (constval->constisnull)
11387 * Always label the type of a NULL constant to prevent misdecisions
11388 * about type when reparsing.
11390 appendStringInfoString(buf, "NULL");
11391 if (showtype >= 0)
11393 appendStringInfo(buf, "::%s",
11394 format_type_with_typemod(constval->consttype,
11395 constval->consttypmod));
11396 get_const_collation(constval, context);
11398 return;
11401 getTypeOutputInfo(constval->consttype,
11402 &typoutput, &typIsVarlena);
11404 extval = OidOutputFunctionCall(typoutput, constval->constvalue);
11406 switch (constval->consttype)
11408 case INT4OID:
11411 * INT4 can be printed without any decoration, unless it is
11412 * negative; in that case print it as '-nnn'::integer to ensure
11413 * that the output will re-parse as a constant, not as a constant
11414 * plus operator. In most cases we could get away with printing
11415 * (-nnn) instead, because of the way that gram.y handles negative
11416 * literals; but that doesn't work for INT_MIN, and it doesn't
11417 * seem that much prettier anyway.
11419 if (extval[0] != '-')
11420 appendStringInfoString(buf, extval);
11421 else
11423 appendStringInfo(buf, "'%s'", extval);
11424 needlabel = true; /* we must attach a cast */
11426 break;
11428 case NUMERICOID:
11431 * NUMERIC can be printed without quotes if it looks like a float
11432 * constant (not an integer, and not Infinity or NaN) and doesn't
11433 * have a leading sign (for the same reason as for INT4).
11435 if (isdigit((unsigned char) extval[0]) &&
11436 strcspn(extval, "eE.") != strlen(extval))
11438 appendStringInfoString(buf, extval);
11440 else
11442 appendStringInfo(buf, "'%s'", extval);
11443 needlabel = true; /* we must attach a cast */
11445 break;
11447 case BOOLOID:
11448 if (strcmp(extval, "t") == 0)
11449 appendStringInfoString(buf, "true");
11450 else
11451 appendStringInfoString(buf, "false");
11452 break;
11454 default:
11455 simple_quote_literal(buf, extval);
11456 break;
11459 pfree(extval);
11461 if (showtype < 0)
11462 return;
11465 * For showtype == 0, append ::typename unless the constant will be
11466 * implicitly typed as the right type when it is read in.
11468 * XXX this code has to be kept in sync with the behavior of the parser,
11469 * especially make_const.
11471 switch (constval->consttype)
11473 case BOOLOID:
11474 case UNKNOWNOID:
11475 /* These types can be left unlabeled */
11476 needlabel = false;
11477 break;
11478 case INT4OID:
11479 /* We determined above whether a label is needed */
11480 break;
11481 case NUMERICOID:
11484 * Float-looking constants will be typed as numeric, which we
11485 * checked above; but if there's a nondefault typmod we need to
11486 * show it.
11488 needlabel |= (constval->consttypmod >= 0);
11489 break;
11490 default:
11491 needlabel = true;
11492 break;
11494 if (needlabel || showtype > 0)
11495 appendStringInfo(buf, "::%s",
11496 format_type_with_typemod(constval->consttype,
11497 constval->consttypmod));
11499 get_const_collation(constval, context);
11503 * helper for get_const_expr: append COLLATE if needed
11505 static void
11506 get_const_collation(Const *constval, deparse_context *context)
11508 StringInfo buf = context->buf;
11510 if (OidIsValid(constval->constcollid))
11512 Oid typcollation = get_typcollation(constval->consttype);
11514 if (constval->constcollid != typcollation)
11516 appendStringInfo(buf, " COLLATE %s",
11517 generate_collation_name(constval->constcollid));
11523 * get_json_path_spec - Parse back a JSON path specification
11525 static void
11526 get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
11528 if (IsA(path_spec, Const))
11529 get_const_expr((Const *) path_spec, context, -1);
11530 else
11531 get_rule_expr(path_spec, context, showimplicit);
11535 * get_json_format - Parse back a JsonFormat node
11537 static void
11538 get_json_format(JsonFormat *format, StringInfo buf)
11540 if (format->format_type == JS_FORMAT_DEFAULT)
11541 return;
11543 appendStringInfoString(buf,
11544 format->format_type == JS_FORMAT_JSONB ?
11545 " FORMAT JSONB" : " FORMAT JSON");
11547 if (format->encoding != JS_ENC_DEFAULT)
11549 const char *encoding;
11551 encoding =
11552 format->encoding == JS_ENC_UTF16 ? "UTF16" :
11553 format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
11555 appendStringInfo(buf, " ENCODING %s", encoding);
11560 * get_json_returning - Parse back a JsonReturning structure
11562 static void
11563 get_json_returning(JsonReturning *returning, StringInfo buf,
11564 bool json_format_by_default)
11566 if (!OidIsValid(returning->typid))
11567 return;
11569 appendStringInfo(buf, " RETURNING %s",
11570 format_type_with_typemod(returning->typid,
11571 returning->typmod));
11573 if (!json_format_by_default ||
11574 returning->format->format_type !=
11575 (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
11576 get_json_format(returning->format, buf);
11580 * get_json_constructor - Parse back a JsonConstructorExpr node
11582 static void
11583 get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context,
11584 bool showimplicit)
11586 StringInfo buf = context->buf;
11587 const char *funcname;
11588 bool is_json_object;
11589 int curridx;
11590 ListCell *lc;
11592 if (ctor->type == JSCTOR_JSON_OBJECTAGG)
11594 get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
11595 return;
11597 else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
11599 get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
11600 return;
11603 switch (ctor->type)
11605 case JSCTOR_JSON_OBJECT:
11606 funcname = "JSON_OBJECT";
11607 break;
11608 case JSCTOR_JSON_ARRAY:
11609 funcname = "JSON_ARRAY";
11610 break;
11611 case JSCTOR_JSON_PARSE:
11612 funcname = "JSON";
11613 break;
11614 case JSCTOR_JSON_SCALAR:
11615 funcname = "JSON_SCALAR";
11616 break;
11617 case JSCTOR_JSON_SERIALIZE:
11618 funcname = "JSON_SERIALIZE";
11619 break;
11620 default:
11621 elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
11624 appendStringInfo(buf, "%s(", funcname);
11626 is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
11627 foreach(lc, ctor->args)
11629 curridx = foreach_current_index(lc);
11630 if (curridx > 0)
11632 const char *sep;
11634 sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
11635 appendStringInfoString(buf, sep);
11638 get_rule_expr((Node *) lfirst(lc), context, true);
11641 get_json_constructor_options(ctor, buf);
11642 appendStringInfoChar(buf, ')');
11646 * Append options, if any, to the JSON constructor being deparsed
11648 static void
11649 get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
11651 if (ctor->absent_on_null)
11653 if (ctor->type == JSCTOR_JSON_OBJECT ||
11654 ctor->type == JSCTOR_JSON_OBJECTAGG)
11655 appendStringInfoString(buf, " ABSENT ON NULL");
11657 else
11659 if (ctor->type == JSCTOR_JSON_ARRAY ||
11660 ctor->type == JSCTOR_JSON_ARRAYAGG)
11661 appendStringInfoString(buf, " NULL ON NULL");
11664 if (ctor->unique)
11665 appendStringInfoString(buf, " WITH UNIQUE KEYS");
11668 * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
11669 * support one.
11671 if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
11672 get_json_returning(ctor->returning, buf, true);
11676 * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
11678 static void
11679 get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context,
11680 const char *funcname, bool is_json_objectagg)
11682 StringInfoData options;
11684 initStringInfo(&options);
11685 get_json_constructor_options(ctor, &options);
11687 if (IsA(ctor->func, Aggref))
11688 get_agg_expr_helper((Aggref *) ctor->func, context,
11689 (Aggref *) ctor->func,
11690 funcname, options.data, is_json_objectagg);
11691 else if (IsA(ctor->func, WindowFunc))
11692 get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
11693 funcname, options.data,
11694 is_json_objectagg);
11695 else
11696 elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
11697 nodeTag(ctor->func));
11701 * simple_quote_literal - Format a string as a SQL literal, append to buf
11703 static void
11704 simple_quote_literal(StringInfo buf, const char *val)
11706 const char *valptr;
11709 * We form the string literal according to the prevailing setting of
11710 * standard_conforming_strings; we never use E''. User is responsible for
11711 * making sure result is used correctly.
11713 appendStringInfoChar(buf, '\'');
11714 for (valptr = val; *valptr; valptr++)
11716 char ch = *valptr;
11718 if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
11719 appendStringInfoChar(buf, ch);
11720 appendStringInfoChar(buf, ch);
11722 appendStringInfoChar(buf, '\'');
11726 /* ----------
11727 * get_sublink_expr - Parse back a sublink
11728 * ----------
11730 static void
11731 get_sublink_expr(SubLink *sublink, deparse_context *context)
11733 StringInfo buf = context->buf;
11734 Query *query = (Query *) (sublink->subselect);
11735 char *opname = NULL;
11736 bool need_paren;
11738 if (sublink->subLinkType == ARRAY_SUBLINK)
11739 appendStringInfoString(buf, "ARRAY(");
11740 else
11741 appendStringInfoChar(buf, '(');
11744 * Note that we print the name of only the first operator, when there are
11745 * multiple combining operators. This is an approximation that could go
11746 * wrong in various scenarios (operators in different schemas, renamed
11747 * operators, etc) but there is not a whole lot we can do about it, since
11748 * the syntax allows only one operator to be shown.
11750 if (sublink->testexpr)
11752 if (IsA(sublink->testexpr, OpExpr))
11754 /* single combining operator */
11755 OpExpr *opexpr = (OpExpr *) sublink->testexpr;
11757 get_rule_expr(linitial(opexpr->args), context, true);
11758 opname = generate_operator_name(opexpr->opno,
11759 exprType(linitial(opexpr->args)),
11760 exprType(lsecond(opexpr->args)));
11762 else if (IsA(sublink->testexpr, BoolExpr))
11764 /* multiple combining operators, = or <> cases */
11765 char *sep;
11766 ListCell *l;
11768 appendStringInfoChar(buf, '(');
11769 sep = "";
11770 foreach(l, ((BoolExpr *) sublink->testexpr)->args)
11772 OpExpr *opexpr = lfirst_node(OpExpr, l);
11774 appendStringInfoString(buf, sep);
11775 get_rule_expr(linitial(opexpr->args), context, true);
11776 if (!opname)
11777 opname = generate_operator_name(opexpr->opno,
11778 exprType(linitial(opexpr->args)),
11779 exprType(lsecond(opexpr->args)));
11780 sep = ", ";
11782 appendStringInfoChar(buf, ')');
11784 else if (IsA(sublink->testexpr, RowCompareExpr))
11786 /* multiple combining operators, < <= > >= cases */
11787 RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
11789 appendStringInfoChar(buf, '(');
11790 get_rule_expr((Node *) rcexpr->largs, context, true);
11791 opname = generate_operator_name(linitial_oid(rcexpr->opnos),
11792 exprType(linitial(rcexpr->largs)),
11793 exprType(linitial(rcexpr->rargs)));
11794 appendStringInfoChar(buf, ')');
11796 else
11797 elog(ERROR, "unrecognized testexpr type: %d",
11798 (int) nodeTag(sublink->testexpr));
11801 need_paren = true;
11803 switch (sublink->subLinkType)
11805 case EXISTS_SUBLINK:
11806 appendStringInfoString(buf, "EXISTS ");
11807 break;
11809 case ANY_SUBLINK:
11810 if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
11811 appendStringInfoString(buf, " IN ");
11812 else
11813 appendStringInfo(buf, " %s ANY ", opname);
11814 break;
11816 case ALL_SUBLINK:
11817 appendStringInfo(buf, " %s ALL ", opname);
11818 break;
11820 case ROWCOMPARE_SUBLINK:
11821 appendStringInfo(buf, " %s ", opname);
11822 break;
11824 case EXPR_SUBLINK:
11825 case MULTIEXPR_SUBLINK:
11826 case ARRAY_SUBLINK:
11827 need_paren = false;
11828 break;
11830 case CTE_SUBLINK: /* shouldn't occur in a SubLink */
11831 default:
11832 elog(ERROR, "unrecognized sublink type: %d",
11833 (int) sublink->subLinkType);
11834 break;
11837 if (need_paren)
11838 appendStringInfoChar(buf, '(');
11840 get_query_def(query, buf, context->namespaces, NULL, false,
11841 context->prettyFlags, context->wrapColumn,
11842 context->indentLevel);
11844 if (need_paren)
11845 appendStringInfoString(buf, "))");
11846 else
11847 appendStringInfoChar(buf, ')');
11851 /* ----------
11852 * get_xmltable - Parse back a XMLTABLE function
11853 * ----------
11855 static void
11856 get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
11858 StringInfo buf = context->buf;
11860 appendStringInfoString(buf, "XMLTABLE(");
11862 if (tf->ns_uris != NIL)
11864 ListCell *lc1,
11865 *lc2;
11866 bool first = true;
11868 appendStringInfoString(buf, "XMLNAMESPACES (");
11869 forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
11871 Node *expr = (Node *) lfirst(lc1);
11872 String *ns_node = lfirst_node(String, lc2);
11874 if (!first)
11875 appendStringInfoString(buf, ", ");
11876 else
11877 first = false;
11879 if (ns_node != NULL)
11881 get_rule_expr(expr, context, showimplicit);
11882 appendStringInfo(buf, " AS %s",
11883 quote_identifier(strVal(ns_node)));
11885 else
11887 appendStringInfoString(buf, "DEFAULT ");
11888 get_rule_expr(expr, context, showimplicit);
11891 appendStringInfoString(buf, "), ");
11894 appendStringInfoChar(buf, '(');
11895 get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
11896 appendStringInfoString(buf, ") PASSING (");
11897 get_rule_expr((Node *) tf->docexpr, context, showimplicit);
11898 appendStringInfoChar(buf, ')');
11900 if (tf->colexprs != NIL)
11902 ListCell *l1;
11903 ListCell *l2;
11904 ListCell *l3;
11905 ListCell *l4;
11906 ListCell *l5;
11907 int colnum = 0;
11909 appendStringInfoString(buf, " COLUMNS ");
11910 forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
11911 l4, tf->colexprs, l5, tf->coldefexprs)
11913 char *colname = strVal(lfirst(l1));
11914 Oid typid = lfirst_oid(l2);
11915 int32 typmod = lfirst_int(l3);
11916 Node *colexpr = (Node *) lfirst(l4);
11917 Node *coldefexpr = (Node *) lfirst(l5);
11918 bool ordinality = (tf->ordinalitycol == colnum);
11919 bool notnull = bms_is_member(colnum, tf->notnulls);
11921 if (colnum > 0)
11922 appendStringInfoString(buf, ", ");
11923 colnum++;
11925 appendStringInfo(buf, "%s %s", quote_identifier(colname),
11926 ordinality ? "FOR ORDINALITY" :
11927 format_type_with_typemod(typid, typmod));
11928 if (ordinality)
11929 continue;
11931 if (coldefexpr != NULL)
11933 appendStringInfoString(buf, " DEFAULT (");
11934 get_rule_expr((Node *) coldefexpr, context, showimplicit);
11935 appendStringInfoChar(buf, ')');
11937 if (colexpr != NULL)
11939 appendStringInfoString(buf, " PATH (");
11940 get_rule_expr((Node *) colexpr, context, showimplicit);
11941 appendStringInfoChar(buf, ')');
11943 if (notnull)
11944 appendStringInfoString(buf, " NOT NULL");
11948 appendStringInfoChar(buf, ')');
11952 * get_json_table_nested_columns - Parse back nested JSON_TABLE columns
11954 static void
11955 get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan,
11956 deparse_context *context, bool showimplicit,
11957 bool needcomma)
11959 if (IsA(plan, JsonTablePathScan))
11961 JsonTablePathScan *scan = castNode(JsonTablePathScan, plan);
11963 if (needcomma)
11964 appendStringInfoChar(context->buf, ',');
11966 appendStringInfoChar(context->buf, ' ');
11967 appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
11968 get_const_expr(scan->path->value, context, -1);
11969 appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
11970 get_json_table_columns(tf, scan, context, showimplicit);
11972 else if (IsA(plan, JsonTableSiblingJoin))
11974 JsonTableSiblingJoin *join = (JsonTableSiblingJoin *) plan;
11976 get_json_table_nested_columns(tf, join->lplan, context, showimplicit,
11977 needcomma);
11978 get_json_table_nested_columns(tf, join->rplan, context, showimplicit,
11979 true);
11984 * get_json_table_columns - Parse back JSON_TABLE columns
11986 static void
11987 get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan,
11988 deparse_context *context,
11989 bool showimplicit)
11991 StringInfo buf = context->buf;
11992 ListCell *lc_colname;
11993 ListCell *lc_coltype;
11994 ListCell *lc_coltypmod;
11995 ListCell *lc_colvalexpr;
11996 int colnum = 0;
11998 appendStringInfoChar(buf, ' ');
11999 appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
12001 if (PRETTY_INDENT(context))
12002 context->indentLevel += PRETTYINDENT_VAR;
12004 forfour(lc_colname, tf->colnames,
12005 lc_coltype, tf->coltypes,
12006 lc_coltypmod, tf->coltypmods,
12007 lc_colvalexpr, tf->colvalexprs)
12009 char *colname = strVal(lfirst(lc_colname));
12010 JsonExpr *colexpr;
12011 Oid typid;
12012 int32 typmod;
12013 bool ordinality;
12014 JsonBehaviorType default_behavior;
12016 typid = lfirst_oid(lc_coltype);
12017 typmod = lfirst_int(lc_coltypmod);
12018 colexpr = castNode(JsonExpr, lfirst(lc_colvalexpr));
12020 /* Skip columns that don't belong to this scan. */
12021 if (scan->colMin < 0 || colnum < scan->colMin)
12023 colnum++;
12024 continue;
12026 if (colnum > scan->colMax)
12027 break;
12029 if (colnum > scan->colMin)
12030 appendStringInfoString(buf, ", ");
12032 colnum++;
12034 ordinality = !colexpr;
12036 appendContextKeyword(context, "", 0, 0, 0);
12038 appendStringInfo(buf, "%s %s", quote_identifier(colname),
12039 ordinality ? "FOR ORDINALITY" :
12040 format_type_with_typemod(typid, typmod));
12041 if (ordinality)
12042 continue;
12045 * Set default_behavior to guide get_json_expr_options() on whether to
12046 * to emit the ON ERROR / EMPTY clauses.
12048 if (colexpr->op == JSON_EXISTS_OP)
12050 appendStringInfoString(buf, " EXISTS");
12051 default_behavior = JSON_BEHAVIOR_FALSE;
12053 else
12055 if (colexpr->op == JSON_QUERY_OP)
12057 char typcategory;
12058 bool typispreferred;
12060 get_type_category_preferred(typid, &typcategory, &typispreferred);
12062 if (typcategory == TYPCATEGORY_STRING)
12063 appendStringInfoString(buf,
12064 colexpr->format->format_type == JS_FORMAT_JSONB ?
12065 " FORMAT JSONB" : " FORMAT JSON");
12068 default_behavior = JSON_BEHAVIOR_NULL;
12071 appendStringInfoString(buf, " PATH ");
12073 get_json_path_spec(colexpr->path_spec, context, showimplicit);
12075 get_json_expr_options(colexpr, context, default_behavior);
12078 if (scan->child)
12079 get_json_table_nested_columns(tf, scan->child, context, showimplicit,
12080 scan->colMin >= 0);
12082 if (PRETTY_INDENT(context))
12083 context->indentLevel -= PRETTYINDENT_VAR;
12085 appendContextKeyword(context, ")", 0, 0, 0);
12088 /* ----------
12089 * get_json_table - Parse back a JSON_TABLE function
12090 * ----------
12092 static void
12093 get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
12095 StringInfo buf = context->buf;
12096 JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
12097 JsonTablePathScan *root = castNode(JsonTablePathScan, tf->plan);
12099 appendStringInfoString(buf, "JSON_TABLE(");
12101 if (PRETTY_INDENT(context))
12102 context->indentLevel += PRETTYINDENT_VAR;
12104 appendContextKeyword(context, "", 0, 0, 0);
12106 get_rule_expr(jexpr->formatted_expr, context, showimplicit);
12108 appendStringInfoString(buf, ", ");
12110 get_const_expr(root->path->value, context, -1);
12112 appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
12114 if (jexpr->passing_values)
12116 ListCell *lc1,
12117 *lc2;
12118 bool needcomma = false;
12120 appendStringInfoChar(buf, ' ');
12121 appendContextKeyword(context, "PASSING ", 0, 0, 0);
12123 if (PRETTY_INDENT(context))
12124 context->indentLevel += PRETTYINDENT_VAR;
12126 forboth(lc1, jexpr->passing_names,
12127 lc2, jexpr->passing_values)
12129 if (needcomma)
12130 appendStringInfoString(buf, ", ");
12131 needcomma = true;
12133 appendContextKeyword(context, "", 0, 0, 0);
12135 get_rule_expr((Node *) lfirst(lc2), context, false);
12136 appendStringInfo(buf, " AS %s",
12137 quote_identifier((lfirst_node(String, lc1))->sval)
12141 if (PRETTY_INDENT(context))
12142 context->indentLevel -= PRETTYINDENT_VAR;
12145 get_json_table_columns(tf, castNode(JsonTablePathScan, tf->plan), context,
12146 showimplicit);
12148 if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY_ARRAY)
12149 get_json_behavior(jexpr->on_error, context, "ERROR");
12151 if (PRETTY_INDENT(context))
12152 context->indentLevel -= PRETTYINDENT_VAR;
12154 appendContextKeyword(context, ")", 0, 0, 0);
12157 /* ----------
12158 * get_tablefunc - Parse back a table function
12159 * ----------
12161 static void
12162 get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
12164 /* XMLTABLE and JSON_TABLE are the only existing implementations. */
12166 if (tf->functype == TFT_XMLTABLE)
12167 get_xmltable(tf, context, showimplicit);
12168 else if (tf->functype == TFT_JSON_TABLE)
12169 get_json_table(tf, context, showimplicit);
12172 /* ----------
12173 * get_from_clause - Parse back a FROM clause
12175 * "prefix" is the keyword that denotes the start of the list of FROM
12176 * elements. It is FROM when used to parse back SELECT and UPDATE, but
12177 * is USING when parsing back DELETE.
12178 * ----------
12180 static void
12181 get_from_clause(Query *query, const char *prefix, deparse_context *context)
12183 StringInfo buf = context->buf;
12184 bool first = true;
12185 ListCell *l;
12188 * We use the query's jointree as a guide to what to print. However, we
12189 * must ignore auto-added RTEs that are marked not inFromCl. (These can
12190 * only appear at the top level of the jointree, so it's sufficient to
12191 * check here.) This check also ensures we ignore the rule pseudo-RTEs
12192 * for NEW and OLD.
12194 foreach(l, query->jointree->fromlist)
12196 Node *jtnode = (Node *) lfirst(l);
12198 if (IsA(jtnode, RangeTblRef))
12200 int varno = ((RangeTblRef *) jtnode)->rtindex;
12201 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12203 if (!rte->inFromCl)
12204 continue;
12207 if (first)
12209 appendContextKeyword(context, prefix,
12210 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
12211 first = false;
12213 get_from_clause_item(jtnode, query, context);
12215 else
12217 StringInfoData itembuf;
12219 appendStringInfoString(buf, ", ");
12222 * Put the new FROM item's text into itembuf so we can decide
12223 * after we've got it whether or not it needs to go on a new line.
12225 initStringInfo(&itembuf);
12226 context->buf = &itembuf;
12228 get_from_clause_item(jtnode, query, context);
12230 /* Restore context's output buffer */
12231 context->buf = buf;
12233 /* Consider line-wrapping if enabled */
12234 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
12236 /* Does the new item start with a new line? */
12237 if (itembuf.len > 0 && itembuf.data[0] == '\n')
12239 /* If so, we shouldn't add anything */
12240 /* instead, remove any trailing spaces currently in buf */
12241 removeStringInfoSpaces(buf);
12243 else
12245 char *trailing_nl;
12247 /* Locate the start of the current line in the buffer */
12248 trailing_nl = strrchr(buf->data, '\n');
12249 if (trailing_nl == NULL)
12250 trailing_nl = buf->data;
12251 else
12252 trailing_nl++;
12255 * Add a newline, plus some indentation, if the new item
12256 * would cause an overflow.
12258 if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
12259 appendContextKeyword(context, "", -PRETTYINDENT_STD,
12260 PRETTYINDENT_STD,
12261 PRETTYINDENT_VAR);
12265 /* Add the new item */
12266 appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
12268 /* clean up */
12269 pfree(itembuf.data);
12274 static void
12275 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
12277 StringInfo buf = context->buf;
12278 deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
12280 if (IsA(jtnode, RangeTblRef))
12282 int varno = ((RangeTblRef *) jtnode)->rtindex;
12283 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12284 deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12285 RangeTblFunction *rtfunc1 = NULL;
12287 if (rte->lateral)
12288 appendStringInfoString(buf, "LATERAL ");
12290 /* Print the FROM item proper */
12291 switch (rte->rtekind)
12293 case RTE_RELATION:
12294 /* Normal relation RTE */
12295 appendStringInfo(buf, "%s%s",
12296 only_marker(rte),
12297 generate_relation_name(rte->relid,
12298 context->namespaces));
12299 break;
12300 case RTE_SUBQUERY:
12301 /* Subquery RTE */
12302 appendStringInfoChar(buf, '(');
12303 get_query_def(rte->subquery, buf, context->namespaces, NULL,
12304 true,
12305 context->prettyFlags, context->wrapColumn,
12306 context->indentLevel);
12307 appendStringInfoChar(buf, ')');
12308 break;
12309 case RTE_FUNCTION:
12310 /* Function RTE */
12311 rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
12314 * Omit ROWS FROM() syntax for just one function, unless it
12315 * has both a coldeflist and WITH ORDINALITY. If it has both,
12316 * we must use ROWS FROM() syntax to avoid ambiguity about
12317 * whether the coldeflist includes the ordinality column.
12319 if (list_length(rte->functions) == 1 &&
12320 (rtfunc1->funccolnames == NIL || !rte->funcordinality))
12322 get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
12323 /* we'll print the coldeflist below, if it has one */
12325 else
12327 bool all_unnest;
12328 ListCell *lc;
12331 * If all the function calls in the list are to unnest,
12332 * and none need a coldeflist, then collapse the list back
12333 * down to UNNEST(args). (If we had more than one
12334 * built-in unnest function, this would get more
12335 * difficult.)
12337 * XXX This is pretty ugly, since it makes not-terribly-
12338 * future-proof assumptions about what the parser would do
12339 * with the output; but the alternative is to emit our
12340 * nonstandard ROWS FROM() notation for what might have
12341 * been a perfectly spec-compliant multi-argument
12342 * UNNEST().
12344 all_unnest = true;
12345 foreach(lc, rte->functions)
12347 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12349 if (!IsA(rtfunc->funcexpr, FuncExpr) ||
12350 ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
12351 rtfunc->funccolnames != NIL)
12353 all_unnest = false;
12354 break;
12358 if (all_unnest)
12360 List *allargs = NIL;
12362 foreach(lc, rte->functions)
12364 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12365 List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
12367 allargs = list_concat(allargs, args);
12370 appendStringInfoString(buf, "UNNEST(");
12371 get_rule_expr((Node *) allargs, context, true);
12372 appendStringInfoChar(buf, ')');
12374 else
12376 int funcno = 0;
12378 appendStringInfoString(buf, "ROWS FROM(");
12379 foreach(lc, rte->functions)
12381 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12383 if (funcno > 0)
12384 appendStringInfoString(buf, ", ");
12385 get_rule_expr_funccall(rtfunc->funcexpr, context, true);
12386 if (rtfunc->funccolnames != NIL)
12388 /* Reconstruct the column definition list */
12389 appendStringInfoString(buf, " AS ");
12390 get_from_clause_coldeflist(rtfunc,
12391 NULL,
12392 context);
12394 funcno++;
12396 appendStringInfoChar(buf, ')');
12398 /* prevent printing duplicate coldeflist below */
12399 rtfunc1 = NULL;
12401 if (rte->funcordinality)
12402 appendStringInfoString(buf, " WITH ORDINALITY");
12403 break;
12404 case RTE_TABLEFUNC:
12405 get_tablefunc(rte->tablefunc, context, true);
12406 break;
12407 case RTE_VALUES:
12408 /* Values list RTE */
12409 appendStringInfoChar(buf, '(');
12410 get_values_def(rte->values_lists, context);
12411 appendStringInfoChar(buf, ')');
12412 break;
12413 case RTE_CTE:
12414 appendStringInfoString(buf, quote_identifier(rte->ctename));
12415 break;
12416 default:
12417 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
12418 break;
12421 /* Print the relation alias, if needed */
12422 get_rte_alias(rte, varno, false, context);
12424 /* Print the column definitions or aliases, if needed */
12425 if (rtfunc1 && rtfunc1->funccolnames != NIL)
12427 /* Reconstruct the columndef list, which is also the aliases */
12428 get_from_clause_coldeflist(rtfunc1, colinfo, context);
12430 else
12432 /* Else print column aliases as needed */
12433 get_column_alias_list(colinfo, context);
12436 /* Tablesample clause must go after any alias */
12437 if (rte->rtekind == RTE_RELATION && rte->tablesample)
12438 get_tablesample_def(rte->tablesample, context);
12440 else if (IsA(jtnode, JoinExpr))
12442 JoinExpr *j = (JoinExpr *) jtnode;
12443 deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
12444 bool need_paren_on_right;
12446 need_paren_on_right = PRETTY_PAREN(context) &&
12447 !IsA(j->rarg, RangeTblRef) &&
12448 !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
12450 if (!PRETTY_PAREN(context) || j->alias != NULL)
12451 appendStringInfoChar(buf, '(');
12453 get_from_clause_item(j->larg, query, context);
12455 switch (j->jointype)
12457 case JOIN_INNER:
12458 if (j->quals)
12459 appendContextKeyword(context, " JOIN ",
12460 -PRETTYINDENT_STD,
12461 PRETTYINDENT_STD,
12462 PRETTYINDENT_JOIN);
12463 else
12464 appendContextKeyword(context, " CROSS JOIN ",
12465 -PRETTYINDENT_STD,
12466 PRETTYINDENT_STD,
12467 PRETTYINDENT_JOIN);
12468 break;
12469 case JOIN_LEFT:
12470 appendContextKeyword(context, " LEFT JOIN ",
12471 -PRETTYINDENT_STD,
12472 PRETTYINDENT_STD,
12473 PRETTYINDENT_JOIN);
12474 break;
12475 case JOIN_FULL:
12476 appendContextKeyword(context, " FULL JOIN ",
12477 -PRETTYINDENT_STD,
12478 PRETTYINDENT_STD,
12479 PRETTYINDENT_JOIN);
12480 break;
12481 case JOIN_RIGHT:
12482 appendContextKeyword(context, " RIGHT JOIN ",
12483 -PRETTYINDENT_STD,
12484 PRETTYINDENT_STD,
12485 PRETTYINDENT_JOIN);
12486 break;
12487 default:
12488 elog(ERROR, "unrecognized join type: %d",
12489 (int) j->jointype);
12492 if (need_paren_on_right)
12493 appendStringInfoChar(buf, '(');
12494 get_from_clause_item(j->rarg, query, context);
12495 if (need_paren_on_right)
12496 appendStringInfoChar(buf, ')');
12498 if (j->usingClause)
12500 ListCell *lc;
12501 bool first = true;
12503 appendStringInfoString(buf, " USING (");
12504 /* Use the assigned names, not what's in usingClause */
12505 foreach(lc, colinfo->usingNames)
12507 char *colname = (char *) lfirst(lc);
12509 if (first)
12510 first = false;
12511 else
12512 appendStringInfoString(buf, ", ");
12513 appendStringInfoString(buf, quote_identifier(colname));
12515 appendStringInfoChar(buf, ')');
12517 if (j->join_using_alias)
12518 appendStringInfo(buf, " AS %s",
12519 quote_identifier(j->join_using_alias->aliasname));
12521 else if (j->quals)
12523 appendStringInfoString(buf, " ON ");
12524 if (!PRETTY_PAREN(context))
12525 appendStringInfoChar(buf, '(');
12526 get_rule_expr(j->quals, context, false);
12527 if (!PRETTY_PAREN(context))
12528 appendStringInfoChar(buf, ')');
12530 else if (j->jointype != JOIN_INNER)
12532 /* If we didn't say CROSS JOIN above, we must provide an ON */
12533 appendStringInfoString(buf, " ON TRUE");
12536 if (!PRETTY_PAREN(context) || j->alias != NULL)
12537 appendStringInfoChar(buf, ')');
12539 /* Yes, it's correct to put alias after the right paren ... */
12540 if (j->alias != NULL)
12543 * Note that it's correct to emit an alias clause if and only if
12544 * there was one originally. Otherwise we'd be converting a named
12545 * join to unnamed or vice versa, which creates semantic
12546 * subtleties we don't want. However, we might print a different
12547 * alias name than was there originally.
12549 appendStringInfo(buf, " %s",
12550 quote_identifier(get_rtable_name(j->rtindex,
12551 context)));
12552 get_column_alias_list(colinfo, context);
12555 else
12556 elog(ERROR, "unrecognized node type: %d",
12557 (int) nodeTag(jtnode));
12561 * get_rte_alias - print the relation's alias, if needed
12563 * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
12565 static void
12566 get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
12567 deparse_context *context)
12569 deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
12570 char *refname = get_rtable_name(varno, context);
12571 deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12572 bool printalias = false;
12574 if (rte->alias != NULL)
12576 /* Always print alias if user provided one */
12577 printalias = true;
12579 else if (colinfo->printaliases)
12581 /* Always print alias if we need to print column aliases */
12582 printalias = true;
12584 else if (rte->rtekind == RTE_RELATION)
12587 * No need to print alias if it's same as relation name (this would
12588 * normally be the case, but not if set_rtable_names had to resolve a
12589 * conflict).
12591 if (strcmp(refname, get_relation_name(rte->relid)) != 0)
12592 printalias = true;
12594 else if (rte->rtekind == RTE_FUNCTION)
12597 * For a function RTE, always print alias. This covers possible
12598 * renaming of the function and/or instability of the FigureColname
12599 * rules for things that aren't simple functions. Note we'd need to
12600 * force it anyway for the columndef list case.
12602 printalias = true;
12604 else if (rte->rtekind == RTE_SUBQUERY ||
12605 rte->rtekind == RTE_VALUES)
12608 * For a subquery, always print alias. This makes the output
12609 * SQL-spec-compliant, even though we allow such aliases to be omitted
12610 * on input.
12612 printalias = true;
12614 else if (rte->rtekind == RTE_CTE)
12617 * No need to print alias if it's same as CTE name (this would
12618 * normally be the case, but not if set_rtable_names had to resolve a
12619 * conflict).
12621 if (strcmp(refname, rte->ctename) != 0)
12622 printalias = true;
12625 if (printalias)
12626 appendStringInfo(context->buf, "%s%s",
12627 use_as ? " AS " : " ",
12628 quote_identifier(refname));
12632 * get_column_alias_list - print column alias list for an RTE
12634 * Caller must already have printed the relation's alias name.
12636 static void
12637 get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
12639 StringInfo buf = context->buf;
12640 int i;
12641 bool first = true;
12643 /* Don't print aliases if not needed */
12644 if (!colinfo->printaliases)
12645 return;
12647 for (i = 0; i < colinfo->num_new_cols; i++)
12649 char *colname = colinfo->new_colnames[i];
12651 if (first)
12653 appendStringInfoChar(buf, '(');
12654 first = false;
12656 else
12657 appendStringInfoString(buf, ", ");
12658 appendStringInfoString(buf, quote_identifier(colname));
12660 if (!first)
12661 appendStringInfoChar(buf, ')');
12665 * get_from_clause_coldeflist - reproduce FROM clause coldeflist
12667 * When printing a top-level coldeflist (which is syntactically also the
12668 * relation's column alias list), use column names from colinfo. But when
12669 * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
12670 * original coldeflist's names, which are available in rtfunc->funccolnames.
12671 * Pass NULL for colinfo to select the latter behavior.
12673 * The coldeflist is appended immediately (no space) to buf. Caller is
12674 * responsible for ensuring that an alias or AS is present before it.
12676 static void
12677 get_from_clause_coldeflist(RangeTblFunction *rtfunc,
12678 deparse_columns *colinfo,
12679 deparse_context *context)
12681 StringInfo buf = context->buf;
12682 ListCell *l1;
12683 ListCell *l2;
12684 ListCell *l3;
12685 ListCell *l4;
12686 int i;
12688 appendStringInfoChar(buf, '(');
12690 i = 0;
12691 forfour(l1, rtfunc->funccoltypes,
12692 l2, rtfunc->funccoltypmods,
12693 l3, rtfunc->funccolcollations,
12694 l4, rtfunc->funccolnames)
12696 Oid atttypid = lfirst_oid(l1);
12697 int32 atttypmod = lfirst_int(l2);
12698 Oid attcollation = lfirst_oid(l3);
12699 char *attname;
12701 if (colinfo)
12702 attname = colinfo->colnames[i];
12703 else
12704 attname = strVal(lfirst(l4));
12706 Assert(attname); /* shouldn't be any dropped columns here */
12708 if (i > 0)
12709 appendStringInfoString(buf, ", ");
12710 appendStringInfo(buf, "%s %s",
12711 quote_identifier(attname),
12712 format_type_with_typemod(atttypid, atttypmod));
12713 if (OidIsValid(attcollation) &&
12714 attcollation != get_typcollation(atttypid))
12715 appendStringInfo(buf, " COLLATE %s",
12716 generate_collation_name(attcollation));
12718 i++;
12721 appendStringInfoChar(buf, ')');
12725 * get_tablesample_def - print a TableSampleClause
12727 static void
12728 get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
12730 StringInfo buf = context->buf;
12731 Oid argtypes[1];
12732 int nargs;
12733 ListCell *l;
12736 * We should qualify the handler's function name if it wouldn't be
12737 * resolved by lookup in the current search path.
12739 argtypes[0] = INTERNALOID;
12740 appendStringInfo(buf, " TABLESAMPLE %s (",
12741 generate_function_name(tablesample->tsmhandler, 1,
12742 NIL, argtypes,
12743 false, NULL, false));
12745 nargs = 0;
12746 foreach(l, tablesample->args)
12748 if (nargs++ > 0)
12749 appendStringInfoString(buf, ", ");
12750 get_rule_expr((Node *) lfirst(l), context, false);
12752 appendStringInfoChar(buf, ')');
12754 if (tablesample->repeatable != NULL)
12756 appendStringInfoString(buf, " REPEATABLE (");
12757 get_rule_expr((Node *) tablesample->repeatable, context, false);
12758 appendStringInfoChar(buf, ')');
12763 * get_opclass_name - fetch name of an index operator class
12765 * The opclass name is appended (after a space) to buf.
12767 * Output is suppressed if the opclass is the default for the given
12768 * actual_datatype. (If you don't want this behavior, just pass
12769 * InvalidOid for actual_datatype.)
12771 static void
12772 get_opclass_name(Oid opclass, Oid actual_datatype,
12773 StringInfo buf)
12775 HeapTuple ht_opc;
12776 Form_pg_opclass opcrec;
12777 char *opcname;
12778 char *nspname;
12780 ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
12781 if (!HeapTupleIsValid(ht_opc))
12782 elog(ERROR, "cache lookup failed for opclass %u", opclass);
12783 opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
12785 if (!OidIsValid(actual_datatype) ||
12786 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
12788 /* Okay, we need the opclass name. Do we need to qualify it? */
12789 opcname = NameStr(opcrec->opcname);
12790 if (OpclassIsVisible(opclass))
12791 appendStringInfo(buf, " %s", quote_identifier(opcname));
12792 else
12794 nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
12795 appendStringInfo(buf, " %s.%s",
12796 quote_identifier(nspname),
12797 quote_identifier(opcname));
12800 ReleaseSysCache(ht_opc);
12804 * generate_opclass_name
12805 * Compute the name to display for an opclass specified by OID
12807 * The result includes all necessary quoting and schema-prefixing.
12809 char *
12810 generate_opclass_name(Oid opclass)
12812 StringInfoData buf;
12814 initStringInfo(&buf);
12815 get_opclass_name(opclass, InvalidOid, &buf);
12817 return &buf.data[1]; /* get_opclass_name() prepends space */
12821 * processIndirection - take care of array and subfield assignment
12823 * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
12824 * appear in the input, printing them as decoration for the base column
12825 * name (which we assume the caller just printed). We might also need to
12826 * strip CoerceToDomain nodes, but only ones that appear above assignment
12827 * nodes.
12829 * Returns the subexpression that's to be assigned.
12831 static Node *
12832 processIndirection(Node *node, deparse_context *context)
12834 StringInfo buf = context->buf;
12835 CoerceToDomain *cdomain = NULL;
12837 for (;;)
12839 if (node == NULL)
12840 break;
12841 if (IsA(node, FieldStore))
12843 FieldStore *fstore = (FieldStore *) node;
12844 Oid typrelid;
12845 char *fieldname;
12847 /* lookup tuple type */
12848 typrelid = get_typ_typrelid(fstore->resulttype);
12849 if (!OidIsValid(typrelid))
12850 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
12851 format_type_be(fstore->resulttype));
12854 * Print the field name. There should only be one target field in
12855 * stored rules. There could be more than that in executable
12856 * target lists, but this function cannot be used for that case.
12858 Assert(list_length(fstore->fieldnums) == 1);
12859 fieldname = get_attname(typrelid,
12860 linitial_int(fstore->fieldnums), false);
12861 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
12864 * We ignore arg since it should be an uninteresting reference to
12865 * the target column or subcolumn.
12867 node = (Node *) linitial(fstore->newvals);
12869 else if (IsA(node, SubscriptingRef))
12871 SubscriptingRef *sbsref = (SubscriptingRef *) node;
12873 if (sbsref->refassgnexpr == NULL)
12874 break;
12876 printSubscripts(sbsref, context);
12879 * We ignore refexpr since it should be an uninteresting reference
12880 * to the target column or subcolumn.
12882 node = (Node *) sbsref->refassgnexpr;
12884 else if (IsA(node, CoerceToDomain))
12886 cdomain = (CoerceToDomain *) node;
12887 /* If it's an explicit domain coercion, we're done */
12888 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
12889 break;
12890 /* Tentatively descend past the CoerceToDomain */
12891 node = (Node *) cdomain->arg;
12893 else
12894 break;
12898 * If we descended past a CoerceToDomain whose argument turned out not to
12899 * be a FieldStore or array assignment, back up to the CoerceToDomain.
12900 * (This is not enough to be fully correct if there are nested implicit
12901 * CoerceToDomains, but such cases shouldn't ever occur.)
12903 if (cdomain && node == (Node *) cdomain->arg)
12904 node = (Node *) cdomain;
12906 return node;
12909 static void
12910 printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
12912 StringInfo buf = context->buf;
12913 ListCell *lowlist_item;
12914 ListCell *uplist_item;
12916 lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
12917 foreach(uplist_item, sbsref->refupperindexpr)
12919 appendStringInfoChar(buf, '[');
12920 if (lowlist_item)
12922 /* If subexpression is NULL, get_rule_expr prints nothing */
12923 get_rule_expr((Node *) lfirst(lowlist_item), context, false);
12924 appendStringInfoChar(buf, ':');
12925 lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
12927 /* If subexpression is NULL, get_rule_expr prints nothing */
12928 get_rule_expr((Node *) lfirst(uplist_item), context, false);
12929 appendStringInfoChar(buf, ']');
12934 * quote_identifier - Quote an identifier only if needed
12936 * When quotes are needed, we palloc the required space; slightly
12937 * space-wasteful but well worth it for notational simplicity.
12939 const char *
12940 quote_identifier(const char *ident)
12943 * Can avoid quoting if ident starts with a lowercase letter or underscore
12944 * and contains only lowercase letters, digits, and underscores, *and* is
12945 * not any SQL keyword. Otherwise, supply quotes.
12947 int nquotes = 0;
12948 bool safe;
12949 const char *ptr;
12950 char *result;
12951 char *optr;
12954 * would like to use <ctype.h> macros here, but they might yield unwanted
12955 * locale-specific results...
12957 safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
12959 for (ptr = ident; *ptr; ptr++)
12961 char ch = *ptr;
12963 if ((ch >= 'a' && ch <= 'z') ||
12964 (ch >= '0' && ch <= '9') ||
12965 (ch == '_'))
12967 /* okay */
12969 else
12971 safe = false;
12972 if (ch == '"')
12973 nquotes++;
12977 if (quote_all_identifiers)
12978 safe = false;
12980 if (safe)
12983 * Check for keyword. We quote keywords except for unreserved ones.
12984 * (In some cases we could avoid quoting a col_name or type_func_name
12985 * keyword, but it seems much harder than it's worth to tell that.)
12987 * Note: ScanKeywordLookup() does case-insensitive comparison, but
12988 * that's fine, since we already know we have all-lower-case.
12990 int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
12992 if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
12993 safe = false;
12996 if (safe)
12997 return ident; /* no change needed */
12999 result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
13001 optr = result;
13002 *optr++ = '"';
13003 for (ptr = ident; *ptr; ptr++)
13005 char ch = *ptr;
13007 if (ch == '"')
13008 *optr++ = '"';
13009 *optr++ = ch;
13011 *optr++ = '"';
13012 *optr = '\0';
13014 return result;
13018 * quote_qualified_identifier - Quote a possibly-qualified identifier
13020 * Return a name of the form qualifier.ident, or just ident if qualifier
13021 * is NULL, quoting each component if necessary. The result is palloc'd.
13023 char *
13024 quote_qualified_identifier(const char *qualifier,
13025 const char *ident)
13027 StringInfoData buf;
13029 initStringInfo(&buf);
13030 if (qualifier)
13031 appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
13032 appendStringInfoString(&buf, quote_identifier(ident));
13033 return buf.data;
13037 * get_relation_name
13038 * Get the unqualified name of a relation specified by OID
13040 * This differs from the underlying get_rel_name() function in that it will
13041 * throw error instead of silently returning NULL if the OID is bad.
13043 static char *
13044 get_relation_name(Oid relid)
13046 char *relname = get_rel_name(relid);
13048 if (!relname)
13049 elog(ERROR, "cache lookup failed for relation %u", relid);
13050 return relname;
13054 * generate_relation_name
13055 * Compute the name to display for a relation specified by OID
13057 * The result includes all necessary quoting and schema-prefixing.
13059 * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
13060 * We will forcibly qualify the relation name if it equals any CTE name
13061 * visible in the namespace list.
13063 static char *
13064 generate_relation_name(Oid relid, List *namespaces)
13066 HeapTuple tp;
13067 Form_pg_class reltup;
13068 bool need_qual;
13069 ListCell *nslist;
13070 char *relname;
13071 char *nspname;
13072 char *result;
13074 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13075 if (!HeapTupleIsValid(tp))
13076 elog(ERROR, "cache lookup failed for relation %u", relid);
13077 reltup = (Form_pg_class) GETSTRUCT(tp);
13078 relname = NameStr(reltup->relname);
13080 /* Check for conflicting CTE name */
13081 need_qual = false;
13082 foreach(nslist, namespaces)
13084 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
13085 ListCell *ctlist;
13087 foreach(ctlist, dpns->ctes)
13089 CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
13091 if (strcmp(cte->ctename, relname) == 0)
13093 need_qual = true;
13094 break;
13097 if (need_qual)
13098 break;
13101 /* Otherwise, qualify the name if not visible in search path */
13102 if (!need_qual)
13103 need_qual = !RelationIsVisible(relid);
13105 if (need_qual)
13106 nspname = get_namespace_name_or_temp(reltup->relnamespace);
13107 else
13108 nspname = NULL;
13110 result = quote_qualified_identifier(nspname, relname);
13112 ReleaseSysCache(tp);
13114 return result;
13118 * generate_qualified_relation_name
13119 * Compute the name to display for a relation specified by OID
13121 * As above, but unconditionally schema-qualify the name.
13123 static char *
13124 generate_qualified_relation_name(Oid relid)
13126 HeapTuple tp;
13127 Form_pg_class reltup;
13128 char *relname;
13129 char *nspname;
13130 char *result;
13132 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13133 if (!HeapTupleIsValid(tp))
13134 elog(ERROR, "cache lookup failed for relation %u", relid);
13135 reltup = (Form_pg_class) GETSTRUCT(tp);
13136 relname = NameStr(reltup->relname);
13138 nspname = get_namespace_name_or_temp(reltup->relnamespace);
13139 if (!nspname)
13140 elog(ERROR, "cache lookup failed for namespace %u",
13141 reltup->relnamespace);
13143 result = quote_qualified_identifier(nspname, relname);
13145 ReleaseSysCache(tp);
13147 return result;
13151 * generate_function_name
13152 * Compute the name to display for a function specified by OID,
13153 * given that it is being called with the specified actual arg names and
13154 * types. (Those matter because of ambiguous-function resolution rules.)
13156 * If we're dealing with a potentially variadic function (in practice, this
13157 * means a FuncExpr or Aggref, not some other way of calling a function), then
13158 * has_variadic must specify whether variadic arguments have been merged,
13159 * and *use_variadic_p will be set to indicate whether to print VARIADIC in
13160 * the output. For non-FuncExpr cases, has_variadic should be false and
13161 * use_variadic_p can be NULL.
13163 * inGroupBy must be true if we're deparsing a GROUP BY clause.
13165 * The result includes all necessary quoting and schema-prefixing.
13167 static char *
13168 generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
13169 bool has_variadic, bool *use_variadic_p,
13170 bool inGroupBy)
13172 char *result;
13173 HeapTuple proctup;
13174 Form_pg_proc procform;
13175 char *proname;
13176 bool use_variadic;
13177 char *nspname;
13178 FuncDetailCode p_result;
13179 Oid p_funcid;
13180 Oid p_rettype;
13181 bool p_retset;
13182 int p_nvargs;
13183 Oid p_vatype;
13184 Oid *p_true_typeids;
13185 bool force_qualify = false;
13187 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
13188 if (!HeapTupleIsValid(proctup))
13189 elog(ERROR, "cache lookup failed for function %u", funcid);
13190 procform = (Form_pg_proc) GETSTRUCT(proctup);
13191 proname = NameStr(procform->proname);
13194 * Due to parser hacks to avoid needing to reserve CUBE, we need to force
13195 * qualification of some function names within GROUP BY.
13197 if (inGroupBy)
13199 if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
13200 force_qualify = true;
13204 * Determine whether VARIADIC should be printed. We must do this first
13205 * since it affects the lookup rules in func_get_detail().
13207 * We always print VARIADIC if the function has a merged variadic-array
13208 * argument. Note that this is always the case for functions taking a
13209 * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
13210 * and printed the array elements as separate arguments, the call could
13211 * match a newer non-VARIADIC function.
13213 if (use_variadic_p)
13215 /* Parser should not have set funcvariadic unless fn is variadic */
13216 Assert(!has_variadic || OidIsValid(procform->provariadic));
13217 use_variadic = has_variadic;
13218 *use_variadic_p = use_variadic;
13220 else
13222 Assert(!has_variadic);
13223 use_variadic = false;
13227 * The idea here is to schema-qualify only if the parser would fail to
13228 * resolve the correct function given the unqualified func name with the
13229 * specified argtypes and VARIADIC flag. But if we already decided to
13230 * force qualification, then we can skip the lookup and pretend we didn't
13231 * find it.
13233 if (!force_qualify)
13234 p_result = func_get_detail(list_make1(makeString(proname)),
13235 NIL, argnames, nargs, argtypes,
13236 !use_variadic, true, false,
13237 &p_funcid, &p_rettype,
13238 &p_retset, &p_nvargs, &p_vatype,
13239 &p_true_typeids, NULL);
13240 else
13242 p_result = FUNCDETAIL_NOTFOUND;
13243 p_funcid = InvalidOid;
13246 if ((p_result == FUNCDETAIL_NORMAL ||
13247 p_result == FUNCDETAIL_AGGREGATE ||
13248 p_result == FUNCDETAIL_WINDOWFUNC) &&
13249 p_funcid == funcid)
13250 nspname = NULL;
13251 else
13252 nspname = get_namespace_name_or_temp(procform->pronamespace);
13254 result = quote_qualified_identifier(nspname, proname);
13256 ReleaseSysCache(proctup);
13258 return result;
13262 * generate_operator_name
13263 * Compute the name to display for an operator specified by OID,
13264 * given that it is being called with the specified actual arg types.
13265 * (Arg types matter because of ambiguous-operator resolution rules.
13266 * Pass InvalidOid for unused arg of a unary operator.)
13268 * The result includes all necessary quoting and schema-prefixing,
13269 * plus the OPERATOR() decoration needed to use a qualified operator name
13270 * in an expression.
13272 static char *
13273 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
13275 StringInfoData buf;
13276 HeapTuple opertup;
13277 Form_pg_operator operform;
13278 char *oprname;
13279 char *nspname;
13280 Operator p_result;
13282 initStringInfo(&buf);
13284 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
13285 if (!HeapTupleIsValid(opertup))
13286 elog(ERROR, "cache lookup failed for operator %u", operid);
13287 operform = (Form_pg_operator) GETSTRUCT(opertup);
13288 oprname = NameStr(operform->oprname);
13291 * The idea here is to schema-qualify only if the parser would fail to
13292 * resolve the correct operator given the unqualified op name with the
13293 * specified argtypes.
13295 switch (operform->oprkind)
13297 case 'b':
13298 p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
13299 true, -1);
13300 break;
13301 case 'l':
13302 p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
13303 true, -1);
13304 break;
13305 default:
13306 elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
13307 p_result = NULL; /* keep compiler quiet */
13308 break;
13311 if (p_result != NULL && oprid(p_result) == operid)
13312 nspname = NULL;
13313 else
13315 nspname = get_namespace_name_or_temp(operform->oprnamespace);
13316 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
13319 appendStringInfoString(&buf, oprname);
13321 if (nspname)
13322 appendStringInfoChar(&buf, ')');
13324 if (p_result != NULL)
13325 ReleaseSysCache(p_result);
13327 ReleaseSysCache(opertup);
13329 return buf.data;
13333 * generate_operator_clause --- generate a binary-operator WHERE clause
13335 * This is used for internally-generated-and-executed SQL queries, where
13336 * precision is essential and readability is secondary. The basic
13337 * requirement is to append "leftop op rightop" to buf, where leftop and
13338 * rightop are given as strings and are assumed to yield types leftoptype
13339 * and rightoptype; the operator is identified by OID. The complexity
13340 * comes from needing to be sure that the parser will select the desired
13341 * operator when the query is parsed. We always name the operator using
13342 * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
13343 * We have to emit casts too, if either input isn't already the input type
13344 * of the operator; else we are at the mercy of the parser's heuristics for
13345 * ambiguous-operator resolution. The caller must ensure that leftop and
13346 * rightop are suitable arguments for a cast operation; it's best to insert
13347 * parentheses if they aren't just variables or parameters.
13349 void
13350 generate_operator_clause(StringInfo buf,
13351 const char *leftop, Oid leftoptype,
13352 Oid opoid,
13353 const char *rightop, Oid rightoptype)
13355 HeapTuple opertup;
13356 Form_pg_operator operform;
13357 char *oprname;
13358 char *nspname;
13360 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
13361 if (!HeapTupleIsValid(opertup))
13362 elog(ERROR, "cache lookup failed for operator %u", opoid);
13363 operform = (Form_pg_operator) GETSTRUCT(opertup);
13364 Assert(operform->oprkind == 'b');
13365 oprname = NameStr(operform->oprname);
13367 nspname = get_namespace_name(operform->oprnamespace);
13369 appendStringInfoString(buf, leftop);
13370 if (leftoptype != operform->oprleft)
13371 add_cast_to(buf, operform->oprleft);
13372 appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
13373 appendStringInfoString(buf, oprname);
13374 appendStringInfo(buf, ") %s", rightop);
13375 if (rightoptype != operform->oprright)
13376 add_cast_to(buf, operform->oprright);
13378 ReleaseSysCache(opertup);
13382 * Add a cast specification to buf. We spell out the type name the hard way,
13383 * intentionally not using format_type_be(). This is to avoid corner cases
13384 * for CHARACTER, BIT, and perhaps other types, where specifying the type
13385 * using SQL-standard syntax results in undesirable data truncation. By
13386 * doing it this way we can be certain that the cast will have default (-1)
13387 * target typmod.
13389 static void
13390 add_cast_to(StringInfo buf, Oid typid)
13392 HeapTuple typetup;
13393 Form_pg_type typform;
13394 char *typname;
13395 char *nspname;
13397 typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13398 if (!HeapTupleIsValid(typetup))
13399 elog(ERROR, "cache lookup failed for type %u", typid);
13400 typform = (Form_pg_type) GETSTRUCT(typetup);
13402 typname = NameStr(typform->typname);
13403 nspname = get_namespace_name_or_temp(typform->typnamespace);
13405 appendStringInfo(buf, "::%s.%s",
13406 quote_identifier(nspname), quote_identifier(typname));
13408 ReleaseSysCache(typetup);
13412 * generate_qualified_type_name
13413 * Compute the name to display for a type specified by OID
13415 * This is different from format_type_be() in that we unconditionally
13416 * schema-qualify the name. That also means no special syntax for
13417 * SQL-standard type names ... although in current usage, this should
13418 * only get used for domains, so such cases wouldn't occur anyway.
13420 static char *
13421 generate_qualified_type_name(Oid typid)
13423 HeapTuple tp;
13424 Form_pg_type typtup;
13425 char *typname;
13426 char *nspname;
13427 char *result;
13429 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13430 if (!HeapTupleIsValid(tp))
13431 elog(ERROR, "cache lookup failed for type %u", typid);
13432 typtup = (Form_pg_type) GETSTRUCT(tp);
13433 typname = NameStr(typtup->typname);
13435 nspname = get_namespace_name_or_temp(typtup->typnamespace);
13436 if (!nspname)
13437 elog(ERROR, "cache lookup failed for namespace %u",
13438 typtup->typnamespace);
13440 result = quote_qualified_identifier(nspname, typname);
13442 ReleaseSysCache(tp);
13444 return result;
13448 * generate_collation_name
13449 * Compute the name to display for a collation specified by OID
13451 * The result includes all necessary quoting and schema-prefixing.
13453 char *
13454 generate_collation_name(Oid collid)
13456 HeapTuple tp;
13457 Form_pg_collation colltup;
13458 char *collname;
13459 char *nspname;
13460 char *result;
13462 tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
13463 if (!HeapTupleIsValid(tp))
13464 elog(ERROR, "cache lookup failed for collation %u", collid);
13465 colltup = (Form_pg_collation) GETSTRUCT(tp);
13466 collname = NameStr(colltup->collname);
13468 if (!CollationIsVisible(collid))
13469 nspname = get_namespace_name_or_temp(colltup->collnamespace);
13470 else
13471 nspname = NULL;
13473 result = quote_qualified_identifier(nspname, collname);
13475 ReleaseSysCache(tp);
13477 return result;
13481 * Given a C string, produce a TEXT datum.
13483 * We assume that the input was palloc'd and may be freed.
13485 static text *
13486 string_to_text(char *str)
13488 text *result;
13490 result = cstring_to_text(str);
13491 pfree(str);
13492 return result;
13496 * Generate a C string representing a relation options from text[] datum.
13498 static void
13499 get_reloptions(StringInfo buf, Datum reloptions)
13501 Datum *options;
13502 int noptions;
13503 int i;
13505 deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
13506 &options, NULL, &noptions);
13508 for (i = 0; i < noptions; i++)
13510 char *option = TextDatumGetCString(options[i]);
13511 char *name;
13512 char *separator;
13513 char *value;
13516 * Each array element should have the form name=value. If the "=" is
13517 * missing for some reason, treat it like an empty value.
13519 name = option;
13520 separator = strchr(option, '=');
13521 if (separator)
13523 *separator = '\0';
13524 value = separator + 1;
13526 else
13527 value = "";
13529 if (i > 0)
13530 appendStringInfoString(buf, ", ");
13531 appendStringInfo(buf, "%s=", quote_identifier(name));
13534 * In general we need to quote the value; but to avoid unnecessary
13535 * clutter, do not quote if it is an identifier that would not need
13536 * quoting. (We could also allow numbers, but that is a bit trickier
13537 * than it looks --- for example, are leading zeroes significant? We
13538 * don't want to assume very much here about what custom reloptions
13539 * might mean.)
13541 if (quote_identifier(value) == value)
13542 appendStringInfoString(buf, value);
13543 else
13544 simple_quote_literal(buf, value);
13546 pfree(option);
13551 * Generate a C string representing a relation's reloptions, or NULL if none.
13553 static char *
13554 flatten_reloptions(Oid relid)
13556 char *result = NULL;
13557 HeapTuple tuple;
13558 Datum reloptions;
13559 bool isnull;
13561 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13562 if (!HeapTupleIsValid(tuple))
13563 elog(ERROR, "cache lookup failed for relation %u", relid);
13565 reloptions = SysCacheGetAttr(RELOID, tuple,
13566 Anum_pg_class_reloptions, &isnull);
13567 if (!isnull)
13569 StringInfoData buf;
13571 initStringInfo(&buf);
13572 get_reloptions(&buf, reloptions);
13574 result = buf.data;
13577 ReleaseSysCache(tuple);
13579 return result;
13583 * get_range_partbound_string
13584 * A C string representation of one range partition bound
13586 char *
13587 get_range_partbound_string(List *bound_datums)
13589 deparse_context context;
13590 StringInfo buf = makeStringInfo();
13591 ListCell *cell;
13592 char *sep;
13594 memset(&context, 0, sizeof(deparse_context));
13595 context.buf = buf;
13597 appendStringInfoChar(buf, '(');
13598 sep = "";
13599 foreach(cell, bound_datums)
13601 PartitionRangeDatum *datum =
13602 lfirst_node(PartitionRangeDatum, cell);
13604 appendStringInfoString(buf, sep);
13605 if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
13606 appendStringInfoString(buf, "MINVALUE");
13607 else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
13608 appendStringInfoString(buf, "MAXVALUE");
13609 else
13611 Const *val = castNode(Const, datum->value);
13613 get_const_expr(val, &context, -1);
13615 sep = ", ";
13617 appendStringInfoChar(buf, ')');
13619 return buf->data;