PostgreSQL Source Code git master
Loading...
Searching...
No Matches
ruleutils.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * ruleutils.c
4 * Functions to convert stored expressions/querytrees back to
5 * source text
6 *
7 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 *
11 * IDENTIFICATION
12 * src/backend/utils/adt/ruleutils.c
13 *
14 *-------------------------------------------------------------------------
15 */
16#include "postgres.h"
17
18#include <ctype.h>
19#include <unistd.h>
20#include <fcntl.h>
21
22#include "access/amapi.h"
23#include "access/htup_details.h"
24#include "access/relation.h"
25#include "access/table.h"
27#include "catalog/pg_am.h"
28#include "catalog/pg_authid.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"
36#include "catalog/pg_proc.h"
43#include "catalog/pg_trigger.h"
44#include "catalog/pg_type.h"
45#include "commands/defrem.h"
46#include "commands/tablespace.h"
47#include "common/keywords.h"
48#include "executor/spi.h"
49#include "funcapi.h"
50#include "mb/pg_wchar.h"
51#include "miscadmin.h"
52#include "nodes/makefuncs.h"
53#include "nodes/nodeFuncs.h"
54#include "nodes/pathnodes.h"
55#include "optimizer/optimizer.h"
56#include "parser/parse_agg.h"
57#include "parser/parse_func.h"
58#include "parser/parse_oper.h"
60#include "parser/parser.h"
61#include "parser/parsetree.h"
65#include "utils/array.h"
66#include "utils/builtins.h"
67#include "utils/fmgroids.h"
68#include "utils/guc.h"
69#include "utils/hsearch.h"
70#include "utils/lsyscache.h"
71#include "utils/partcache.h"
72#include "utils/rel.h"
73#include "utils/ruleutils.h"
74#include "utils/snapmgr.h"
75#include "utils/syscache.h"
76#include "utils/typcache.h"
77#include "utils/varlena.h"
78#include "utils/xml.h"
79
80/* ----------
81 * Pretty formatting constants
82 * ----------
83 */
84
85/* Indent counts */
86#define PRETTYINDENT_STD 8
87#define PRETTYINDENT_JOIN 4
88#define PRETTYINDENT_VAR 4
89
90#define PRETTYINDENT_LIMIT 40 /* wrap limit */
91
92/* Pretty flags */
93#define PRETTYFLAG_PAREN 0x0001
94#define PRETTYFLAG_INDENT 0x0002
95#define PRETTYFLAG_SCHEMA 0x0004
96
97/* Standard conversion of a "bool pretty" option to detailed flags */
98#define GET_PRETTY_FLAGS(pretty) \
99 ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
100 : PRETTYFLAG_INDENT)
101
102/* Default line length for pretty-print wrapping: 0 means wrap always */
103#define WRAP_COLUMN_DEFAULT 0
104
105/* macros to test if pretty action needed */
106#define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
107#define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
108#define PRETTY_SCHEMA(context) ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
109
110
111/* ----------
112 * Local data types
113 * ----------
114 */
115
116/* Context info needed for invoking a recursive querytree display routine */
117typedef struct
118{
119 StringInfo buf; /* output buffer to append to */
120 List *namespaces; /* List of deparse_namespace nodes */
121 TupleDesc resultDesc; /* if top level of a view, the view's tupdesc */
122 List *targetList; /* Current query level's SELECT targetlist */
123 List *windowClause; /* Current query level's WINDOW clause */
124 int prettyFlags; /* enabling of pretty-print functions */
125 int wrapColumn; /* max line length, or -1 for no limit */
126 int indentLevel; /* current indent level for pretty-print */
127 bool varprefix; /* true to print prefixes on Vars */
128 bool colNamesVisible; /* do we care about output column names? */
129 bool inGroupBy; /* deparsing GROUP BY clause? */
130 bool varInOrderBy; /* deparsing simple Var in ORDER BY? */
131 Bitmapset *appendparents; /* if not null, map child Vars of these relids
132 * back to the parent rel */
134
135/*
136 * Each level of query context around a subtree needs a level of Var namespace.
137 * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
138 * the current context's namespaces list.
139 *
140 * rtable is the list of actual RTEs from the Query or PlannedStmt.
141 * rtable_names holds the alias name to be used for each RTE (either a C
142 * string, or NULL for nameless RTEs such as unnamed joins).
143 * rtable_columns holds the column alias names to be used for each RTE.
144 *
145 * subplans is a list of Plan trees for SubPlans and CTEs (it's only used
146 * in the PlannedStmt case).
147 * ctes is a list of CommonTableExpr nodes (only used in the Query case).
148 * appendrels, if not null (it's only used in the PlannedStmt case), is an
149 * array of AppendRelInfo nodes, indexed by child relid. We use that to map
150 * child-table Vars to their inheritance parents.
151 *
152 * In some cases we need to make names of merged JOIN USING columns unique
153 * across the whole query, not only per-RTE. If so, unique_using is true
154 * and using_names is a list of C strings representing names already assigned
155 * to USING columns.
156 *
157 * When deparsing plan trees, there is always just a single item in the
158 * deparse_namespace list (since a plan tree never contains Vars with
159 * varlevelsup > 0). We store the Plan node that is the immediate
160 * parent of the expression to be deparsed, as well as a list of that
161 * Plan's ancestors. In addition, we store its outer and inner subplan nodes,
162 * as well as their targetlists, and the index tlist if the current plan node
163 * might contain INDEX_VAR Vars. (These fields could be derived on-the-fly
164 * from the current Plan node, but it seems notationally clearer to set them
165 * up as separate fields.)
166 */
167typedef struct
168{
169 List *rtable; /* List of RangeTblEntry nodes */
170 List *rtable_names; /* Parallel list of names for RTEs */
171 List *rtable_columns; /* Parallel list of deparse_columns structs */
172 List *subplans; /* List of Plan trees for SubPlans */
173 List *ctes; /* List of CommonTableExpr nodes */
174 AppendRelInfo **appendrels; /* Array of AppendRelInfo nodes, or NULL */
175 char *ret_old_alias; /* alias for OLD in RETURNING list */
176 char *ret_new_alias; /* alias for NEW in RETURNING list */
177 /* Workspace for column alias assignment: */
178 bool unique_using; /* Are we making USING names globally unique */
179 List *using_names; /* List of assigned names for USING columns */
180 /* Remaining fields are used only when deparsing a Plan tree: */
181 Plan *plan; /* immediate parent of current expression */
182 List *ancestors; /* ancestors of plan */
183 Plan *outer_plan; /* outer subnode, or NULL if none */
184 Plan *inner_plan; /* inner subnode, or NULL if none */
185 List *outer_tlist; /* referent for OUTER_VAR Vars */
186 List *inner_tlist; /* referent for INNER_VAR Vars */
187 List *index_tlist; /* referent for INDEX_VAR Vars */
188 /* Special namespace representing a function signature: */
189 char *funcname;
191 char **argnames;
193
194/*
195 * Per-relation data about column alias names.
196 *
197 * Selecting aliases is unreasonably complicated because of the need to dump
198 * rules/views whose underlying tables may have had columns added, deleted, or
199 * renamed since the query was parsed. We must nonetheless print the rule/view
200 * in a form that can be reloaded and will produce the same results as before.
201 *
202 * For each RTE used in the query, we must assign column aliases that are
203 * unique within that RTE. SQL does not require this of the original query,
204 * but due to factors such as *-expansion we need to be able to uniquely
205 * reference every column in a decompiled query. As long as we qualify all
206 * column references, per-RTE uniqueness is sufficient for that.
207 *
208 * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
209 * since they just inherit column names from their input RTEs, and we can't
210 * rename the columns at the join level. Most of the time this isn't an issue
211 * because we don't need to reference the join's output columns as such; we
212 * can reference the input columns instead. That approach can fail for merged
213 * JOIN USING columns, however, so when we have one of those in an unnamed
214 * join, we have to make that column's alias globally unique across the whole
215 * query to ensure it can be referenced unambiguously.
216 *
217 * Another problem is that a JOIN USING clause requires the columns to be
218 * merged to have the same aliases in both input RTEs, and that no other
219 * columns in those RTEs or their children conflict with the USING names.
220 * To handle that, we do USING-column alias assignment in a recursive
221 * traversal of the query's jointree. When descending through a JOIN with
222 * USING, we preassign the USING column names to the child columns, overriding
223 * other rules for column alias assignment. We also mark each RTE with a list
224 * of all USING column names selected for joins containing that RTE, so that
225 * when we assign other columns' aliases later, we can avoid conflicts.
226 *
227 * Another problem is that if a JOIN's input tables have had columns added or
228 * deleted since the query was parsed, we must generate a column alias list
229 * for the join that matches the current set of input columns --- otherwise, a
230 * change in the number of columns in the left input would throw off matching
231 * of aliases to columns of the right input. Thus, positions in the printable
232 * column alias list are not necessarily one-for-one with varattnos of the
233 * JOIN, so we need a separate new_colnames[] array for printing purposes.
234 *
235 * Finally, when dealing with wide tables we risk O(N^2) costs in assigning
236 * non-duplicate column names. We ameliorate that by using a hash table that
237 * holds all the strings appearing in colnames, new_colnames, and parentUsing.
238 */
239typedef struct
240{
241 /*
242 * colnames is an array containing column aliases to use for columns that
243 * existed when the query was parsed. Dropped columns have NULL entries.
244 * This array can be directly indexed by varattno to get a Var's name.
245 *
246 * Non-NULL entries are guaranteed unique within the RTE, *except* when
247 * this is for an unnamed JOIN RTE. In that case we merely copy up names
248 * from the two input RTEs.
249 *
250 * During the recursive descent in set_using_names(), forcible assignment
251 * of a child RTE's column name is represented by pre-setting that element
252 * of the child's colnames array. So at that stage, NULL entries in this
253 * array just mean that no name has been preassigned, not necessarily that
254 * the column is dropped.
255 */
256 int num_cols; /* length of colnames[] array */
257 char **colnames; /* array of C strings and NULLs */
258
259 /*
260 * new_colnames is an array containing column aliases to use for columns
261 * that would exist if the query was re-parsed against the current
262 * definitions of its base tables. This is what to print as the column
263 * alias list for the RTE. This array does not include dropped columns,
264 * but it will include columns added since original parsing. Indexes in
265 * it therefore have little to do with current varattno values. As above,
266 * entries are unique unless this is for an unnamed JOIN RTE. (In such an
267 * RTE, we never actually print this array, but we must compute it anyway
268 * for possible use in computing column names of upper joins.) The
269 * parallel array is_new_col marks which of these columns are new since
270 * original parsing. Entries with is_new_col false must match the
271 * non-NULL colnames entries one-for-one.
272 */
273 int num_new_cols; /* length of new_colnames[] array */
274 char **new_colnames; /* array of C strings */
275 bool *is_new_col; /* array of bool flags */
276
277 /* This flag tells whether we should actually print a column alias list */
279
280 /* This list has all names used as USING names in joins above this RTE */
281 List *parentUsing; /* names assigned to parent merged columns */
282
283 /*
284 * If this struct is for a JOIN RTE, we fill these fields during the
285 * set_using_names() pass to describe its relationship to its child RTEs.
286 *
287 * leftattnos and rightattnos are arrays with one entry per existing
288 * output column of the join (hence, indexable by join varattno). For a
289 * simple reference to a column of the left child, leftattnos[i] is the
290 * child RTE's attno and rightattnos[i] is zero; and conversely for a
291 * column of the right child. But for merged columns produced by JOIN
292 * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
293 * Note that a simple reference might be to a child RTE column that's been
294 * dropped; but that's OK since the column could not be used in the query.
295 *
296 * If it's a JOIN USING, usingNames holds the alias names selected for the
297 * merged columns (these might be different from the original USING list,
298 * if we had to modify names to achieve uniqueness).
299 */
300 int leftrti; /* rangetable index of left child */
301 int rightrti; /* rangetable index of right child */
302 int *leftattnos; /* left-child varattnos of join cols, or 0 */
303 int *rightattnos; /* right-child varattnos of join cols, or 0 */
304 List *usingNames; /* names assigned to merged columns */
305
306 /*
307 * Hash table holding copies of all the strings appearing in this struct's
308 * colnames, new_colnames, and parentUsing. We use a hash table only for
309 * sufficiently wide relations, and only during the colname-assignment
310 * functions set_relation_column_names and set_join_column_names;
311 * otherwise, names_hash is NULL.
312 */
313 HTAB *names_hash; /* entries are just strings */
315
316/* This macro is analogous to rt_fetch(), but for deparse_columns structs */
317#define deparse_columns_fetch(rangetable_index, dpns) \
318 ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
319
320/*
321 * Entry in set_rtable_names' hash table
322 */
323typedef struct
324{
325 char name[NAMEDATALEN]; /* Hash key --- must be first */
326 int counter; /* Largest addition used so far for name */
328
329/* Callback signature for resolve_special_varno() */
330typedef void (*rsv_callback) (Node *node, deparse_context *context,
331 void *callback_arg);
332
333
334/* ----------
335 * Global data
336 * ----------
337 */
339static const char *const query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
341static const char *const query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
342
343/* GUC parameters */
345
346
347/* ----------
348 * Local functions
349 *
350 * Most of these functions used to use fixed-size buffers to build their
351 * results. Now, they take an (already initialized) StringInfo object
352 * as a parameter, and append their text output to its contents.
353 * ----------
354 */
355static char *deparse_expression_pretty(Node *expr, List *dpcontext,
356 bool forceprefix, bool showimplicit,
357 int prettyFlags, int startIndent);
358static char *pg_get_viewdef_worker(Oid viewoid,
359 int prettyFlags, int wrapColumn);
360static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
363static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
364static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
365 const Oid *excludeOps,
366 bool attrsOnly, bool keysOnly,
367 bool showTblSpc, bool inherits,
368 int prettyFlags, bool missing_ok);
373 bool missing_ok);
374static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
375 bool attrsOnly, bool missing_ok);
377 int prettyFlags, bool missing_ok);
378static text *pg_get_expr_worker(text *expr, Oid relid, int prettyFlags);
390static void set_using_names(deparse_namespace *dpns, Node *jtnode,
391 List *parentUsing);
397static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
399static char *make_colname_unique(char *colname, deparse_namespace *dpns,
403static void add_to_names_hash(deparse_columns *colinfo, const char *name);
407static char *get_rtable_name(int rtindex, deparse_context *context);
420 int prettyFlags);
422 int prettyFlags, int wrapColumn);
424 TupleDesc resultDesc, bool colNamesVisible,
425 int prettyFlags, int wrapColumn, int startIndent);
426static void get_values_def(List *values_lists, deparse_context *context);
427static void get_with_clause(Query *query, deparse_context *context);
428static void get_select_query_def(Query *query, deparse_context *context);
429static void get_insert_query_def(Query *query, deparse_context *context);
430static void get_update_query_def(Query *query, deparse_context *context);
431static void get_update_query_targetlist_def(Query *query, List *targetList,
432 deparse_context *context,
434static void get_delete_query_def(Query *query, deparse_context *context);
435static void get_merge_query_def(Query *query, deparse_context *context);
436static void get_utility_query_def(Query *query, deparse_context *context);
437static char *get_lock_clause_strength(LockClauseStrength strength);
438static void get_basic_select_query(Query *query, deparse_context *context);
439static void get_target_list(List *targetList, deparse_context *context);
440static void get_returning_clause(Query *query, deparse_context *context);
441static void get_setop_query(Node *setOp, Query *query,
442 deparse_context *context);
444 bool force_colno,
445 deparse_context *context);
446static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
447 bool omit_parens, deparse_context *context);
448static void get_rule_orderby(List *orderList, List *targetList,
449 bool force_colno, deparse_context *context);
450static void get_rule_windowclause(Query *query, deparse_context *context);
451static void get_rule_windowspec(WindowClause *wc, List *targetList,
452 deparse_context *context);
453static void get_window_frame_options(int frameOptions,
454 Node *startOffset, Node *endOffset,
455 deparse_context *context);
456static char *get_variable(Var *var, int levelsup, bool istoplevel,
457 deparse_context *context);
458static void get_special_variable(Node *node, deparse_context *context,
459 void *callback_arg);
460static void resolve_special_varno(Node *node, deparse_context *context,
461 rsv_callback callback, void *callback_arg);
462static Node *find_param_referent(Param *param, deparse_context *context,
464static SubPlan *find_param_generator(Param *param, deparse_context *context,
465 int *column_p);
467 int *column_p);
468static void get_parameter(Param *param, deparse_context *context);
469static const char *get_simple_binary_op_name(OpExpr *expr);
470static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
471static void appendContextKeyword(deparse_context *context, const char *str,
472 int indentBefore, int indentAfter, int indentPlus);
474static void get_rule_expr(Node *node, deparse_context *context,
475 bool showimplicit);
476static void get_rule_expr_toplevel(Node *node, deparse_context *context,
477 bool showimplicit);
478static void get_rule_list_toplevel(List *lst, deparse_context *context,
479 bool showimplicit);
480static void get_rule_expr_funccall(Node *node, deparse_context *context,
481 bool showimplicit);
482static bool looks_like_function(Node *node);
483static void get_oper_expr(OpExpr *expr, deparse_context *context);
484static void get_func_expr(FuncExpr *expr, deparse_context *context,
485 bool showimplicit);
486static void get_agg_expr(Aggref *aggref, deparse_context *context,
488static void get_agg_expr_helper(Aggref *aggref, deparse_context *context,
489 Aggref *original_aggref, const char *funcname,
490 const char *options, bool is_json_objectagg);
491static void get_agg_combine_expr(Node *node, deparse_context *context,
492 void *callback_arg);
493static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
494static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
495 const char *funcname, const char *options,
496 bool is_json_objectagg);
497static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context);
498static void get_coercion_expr(Node *arg, deparse_context *context,
499 Oid resulttype, int32 resulttypmod,
501static void get_const_expr(Const *constval, deparse_context *context,
502 int showtype);
503static void get_const_collation(Const *constval, deparse_context *context);
505static void get_json_returning(JsonReturning *returning, StringInfo buf,
508 deparse_context *context, bool showimplicit);
512 deparse_context *context,
513 const char *funcname,
514 bool is_json_objectagg);
515static void simple_quote_literal(StringInfo buf, const char *val);
516static void get_sublink_expr(SubLink *sublink, deparse_context *context);
517static void get_tablefunc(TableFunc *tf, deparse_context *context,
518 bool showimplicit);
519static void get_from_clause(Query *query, const char *prefix,
520 deparse_context *context);
521static void get_from_clause_item(Node *jtnode, Query *query,
522 deparse_context *context);
523static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
524 deparse_context *context);
526 deparse_context *context);
529 deparse_context *context);
530static void get_tablesample_def(TableSampleClause *tablesample,
531 deparse_context *context);
532static void get_opclass_name(Oid opclass, Oid actual_datatype,
534static Node *processIndirection(Node *node, deparse_context *context);
535static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
536static char *get_relation_name(Oid relid);
537static char *generate_relation_name(Oid relid, List *namespaces);
538static char *generate_qualified_relation_name(Oid relid);
539static char *generate_function_name(Oid funcid, int nargs,
540 List *argnames, Oid *argtypes,
541 bool has_variadic, bool *use_variadic_p,
542 bool inGroupBy);
544static void add_cast_to(StringInfo buf, Oid typid);
545static char *generate_qualified_type_name(Oid typid);
546static text *string_to_text(char *str);
547static char *flatten_reloptions(Oid relid);
548static void get_reloptions(StringInfo buf, Datum reloptions);
549static void get_json_path_spec(Node *path_spec, deparse_context *context,
550 bool showimplicit);
552 deparse_context *context,
553 bool showimplicit);
555 deparse_context *context,
556 bool showimplicit,
557 bool needcomma);
558
559#define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
560
561
562/* ----------
563 * pg_get_ruledef - Do it all and return a text
564 * that could be used as a statement
565 * to recreate the rule
566 * ----------
567 */
568Datum
570{
572 int prettyFlags;
573 char *res;
574
575 prettyFlags = PRETTYFLAG_INDENT;
576
577 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
578
579 if (res == NULL)
581
583}
584
585
586Datum
588{
590 bool pretty = PG_GETARG_BOOL(1);
591 int prettyFlags;
592 char *res;
593
594 prettyFlags = GET_PRETTY_FLAGS(pretty);
595
596 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
597
598 if (res == NULL)
600
602}
603
604
605static char *
607{
608 Datum args[1];
609 char nulls[1];
610 int spirc;
614
615 /*
616 * Do this first so that string is alloc'd in outer context not SPI's.
617 */
619
620 /*
621 * Connect to SPI manager
622 */
623 SPI_connect();
624
625 /*
626 * On the first call prepare the plan to lookup pg_rewrite. We read
627 * pg_rewrite over the SPI manager instead of using the syscache to be
628 * checked for read access on pg_rewrite.
629 */
630 if (plan_getrulebyoid == NULL)
631 {
632 Oid argtypes[1];
634
635 argtypes[0] = OIDOID;
636 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
637 if (plan == NULL)
638 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
641 }
642
643 /*
644 * Get the pg_rewrite tuple for this rule
645 */
646 args[0] = ObjectIdGetDatum(ruleoid);
647 nulls[0] = ' ';
648 spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
649 if (spirc != SPI_OK_SELECT)
650 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
651 if (SPI_processed != 1)
652 {
653 /*
654 * There is no tuple data available here, just keep the output buffer
655 * empty.
656 */
657 }
658 else
659 {
660 /*
661 * Get the rule's definition and put it into executor's memory
662 */
665 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
666 }
667
668 /*
669 * Disconnect from SPI manager
670 */
671 if (SPI_finish() != SPI_OK_FINISH)
672 elog(ERROR, "SPI_finish failed");
673
674 if (buf.len == 0)
675 return NULL;
676
677 return buf.data;
678}
679
680
681/* ----------
682 * pg_get_viewdef - Mainly the same thing, but we
683 * only return the SELECT part of a view
684 * ----------
685 */
686Datum
688{
689 /* By OID */
690 Oid viewoid = PG_GETARG_OID(0);
691 int prettyFlags;
692 char *res;
693
694 prettyFlags = PRETTYFLAG_INDENT;
695
696 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
697
698 if (res == NULL)
700
702}
703
704
705Datum
707{
708 /* By OID */
709 Oid viewoid = PG_GETARG_OID(0);
710 bool pretty = PG_GETARG_BOOL(1);
711 int prettyFlags;
712 char *res;
713
714 prettyFlags = GET_PRETTY_FLAGS(pretty);
715
716 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
717
718 if (res == NULL)
720
722}
723
724Datum
726{
727 /* By OID */
728 Oid viewoid = PG_GETARG_OID(0);
729 int wrap = PG_GETARG_INT32(1);
730 int prettyFlags;
731 char *res;
732
733 /* calling this implies we want pretty printing */
734 prettyFlags = GET_PRETTY_FLAGS(true);
735
736 res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
737
738 if (res == NULL)
740
742}
743
744Datum
746{
747 /* By qualified name */
749 int prettyFlags;
751 Oid viewoid;
752 char *res;
753
754 prettyFlags = PRETTYFLAG_INDENT;
755
756 /* Look up view name. Can't lock it - we might not have privileges. */
758 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
759
760 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
761
762 if (res == NULL)
764
766}
767
768
769Datum
771{
772 /* By qualified name */
774 bool pretty = PG_GETARG_BOOL(1);
775 int prettyFlags;
777 Oid viewoid;
778 char *res;
779
780 prettyFlags = GET_PRETTY_FLAGS(pretty);
781
782 /* Look up view name. Can't lock it - we might not have privileges. */
784 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
785
786 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
787
788 if (res == NULL)
790
792}
793
794/*
795 * Common code for by-OID and by-name variants of pg_get_viewdef
796 */
797static char *
798pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
799{
800 Datum args[2];
801 char nulls[2];
802 int spirc;
806
807 /*
808 * Do this first so that string is alloc'd in outer context not SPI's.
809 */
811
812 /*
813 * Connect to SPI manager
814 */
815 SPI_connect();
816
817 /*
818 * On the first call prepare the plan to lookup pg_rewrite. We read
819 * pg_rewrite over the SPI manager instead of using the syscache to be
820 * checked for read access on pg_rewrite.
821 */
822 if (plan_getviewrule == NULL)
823 {
824 Oid argtypes[2];
826
827 argtypes[0] = OIDOID;
828 argtypes[1] = NAMEOID;
829 plan = SPI_prepare(query_getviewrule, 2, argtypes);
830 if (plan == NULL)
831 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
834 }
835
836 /*
837 * Get the pg_rewrite tuple for the view's SELECT rule
838 */
839 args[0] = ObjectIdGetDatum(viewoid);
841 nulls[0] = ' ';
842 nulls[1] = ' ';
843 spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
844 if (spirc != SPI_OK_SELECT)
845 elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
846 if (SPI_processed != 1)
847 {
848 /*
849 * There is no tuple data available here, just keep the output buffer
850 * empty.
851 */
852 }
853 else
854 {
855 /*
856 * Get the rule's definition and put it into executor's memory
857 */
860 make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
861 }
862
863 /*
864 * Disconnect from SPI manager
865 */
866 if (SPI_finish() != SPI_OK_FINISH)
867 elog(ERROR, "SPI_finish failed");
868
869 if (buf.len == 0)
870 return NULL;
871
872 return buf.data;
873}
874
875/* ----------
876 * pg_get_triggerdef - Get the definition of a trigger
877 * ----------
878 */
879Datum
881{
883 char *res;
884
885 res = pg_get_triggerdef_worker(trigid, false);
886
887 if (res == NULL)
889
891}
892
893Datum
895{
897 bool pretty = PG_GETARG_BOOL(1);
898 char *res;
899
901
902 if (res == NULL)
904
906}
907
908static char *
910{
915 ScanKeyData skey[1];
917 int findx = 0;
918 char *tgname;
919 char *tgoldtable;
920 char *tgnewtable;
921 Datum value;
922 bool isnull;
923
924 /*
925 * Fetch the pg_trigger tuple by the Oid of the trigger
926 */
928
929 ScanKeyInit(&skey[0],
933
935 NULL, 1, skey);
936
938
940 {
943 return NULL;
944 }
945
947
948 /*
949 * Start the trigger definition. Note that the trigger's name should never
950 * be schema-qualified, but the trigger rel's name may be.
951 */
953
954 tgname = NameStr(trigrec->tgname);
955 appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
956 OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
957 quote_identifier(tgname));
958
959 if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
960 appendStringInfoString(&buf, "BEFORE");
961 else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
962 appendStringInfoString(&buf, "AFTER");
963 else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
964 appendStringInfoString(&buf, "INSTEAD OF");
965 else
966 elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
967
968 if (TRIGGER_FOR_INSERT(trigrec->tgtype))
969 {
970 appendStringInfoString(&buf, " INSERT");
971 findx++;
972 }
973 if (TRIGGER_FOR_DELETE(trigrec->tgtype))
974 {
975 if (findx > 0)
976 appendStringInfoString(&buf, " OR DELETE");
977 else
978 appendStringInfoString(&buf, " DELETE");
979 findx++;
980 }
981 if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
982 {
983 if (findx > 0)
984 appendStringInfoString(&buf, " OR UPDATE");
985 else
986 appendStringInfoString(&buf, " UPDATE");
987 findx++;
988 /* tgattr is first var-width field, so OK to access directly */
989 if (trigrec->tgattr.dim1 > 0)
990 {
991 int i;
992
993 appendStringInfoString(&buf, " OF ");
994 for (i = 0; i < trigrec->tgattr.dim1; i++)
995 {
996 char *attname;
997
998 if (i > 0)
1000 attname = get_attname(trigrec->tgrelid,
1001 trigrec->tgattr.values[i], false);
1003 }
1004 }
1005 }
1006 if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
1007 {
1008 if (findx > 0)
1009 appendStringInfoString(&buf, " OR TRUNCATE");
1010 else
1011 appendStringInfoString(&buf, " TRUNCATE");
1012 findx++;
1013 }
1014
1015 /*
1016 * In non-pretty mode, always schema-qualify the target table name for
1017 * safety. In pretty mode, schema-qualify only if not visible.
1018 */
1019 appendStringInfo(&buf, " ON %s ",
1020 pretty ?
1023
1024 if (OidIsValid(trigrec->tgconstraint))
1025 {
1026 if (OidIsValid(trigrec->tgconstrrelid))
1027 appendStringInfo(&buf, "FROM %s ",
1028 generate_relation_name(trigrec->tgconstrrelid, NIL));
1029 if (!trigrec->tgdeferrable)
1030 appendStringInfoString(&buf, "NOT ");
1031 appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
1032 if (trigrec->tginitdeferred)
1033 appendStringInfoString(&buf, "DEFERRED ");
1034 else
1035 appendStringInfoString(&buf, "IMMEDIATE ");
1036 }
1037
1039 tgrel->rd_att, &isnull);
1040 if (!isnull)
1041 tgoldtable = NameStr(*DatumGetName(value));
1042 else
1043 tgoldtable = NULL;
1045 tgrel->rd_att, &isnull);
1046 if (!isnull)
1047 tgnewtable = NameStr(*DatumGetName(value));
1048 else
1049 tgnewtable = NULL;
1050 if (tgoldtable != NULL || tgnewtable != NULL)
1051 {
1052 appendStringInfoString(&buf, "REFERENCING ");
1053 if (tgoldtable != NULL)
1054 appendStringInfo(&buf, "OLD TABLE AS %s ",
1055 quote_identifier(tgoldtable));
1056 if (tgnewtable != NULL)
1057 appendStringInfo(&buf, "NEW TABLE AS %s ",
1058 quote_identifier(tgnewtable));
1059 }
1060
1061 if (TRIGGER_FOR_ROW(trigrec->tgtype))
1062 appendStringInfoString(&buf, "FOR EACH ROW ");
1063 else
1064 appendStringInfoString(&buf, "FOR EACH STATEMENT ");
1065
1066 /* If the trigger has a WHEN qualification, add that */
1068 tgrel->rd_att, &isnull);
1069 if (!isnull)
1070 {
1071 Node *qual;
1072 char relkind;
1073 deparse_context context;
1077
1078 appendStringInfoString(&buf, "WHEN (");
1079
1081
1082 relkind = get_rel_relkind(trigrec->tgrelid);
1083
1084 /* Build minimal OLD and NEW RTEs for the rel */
1086 oldrte->rtekind = RTE_RELATION;
1087 oldrte->relid = trigrec->tgrelid;
1088 oldrte->relkind = relkind;
1089 oldrte->rellockmode = AccessShareLock;
1090 oldrte->alias = makeAlias("old", NIL);
1091 oldrte->eref = oldrte->alias;
1092 oldrte->lateral = false;
1093 oldrte->inh = false;
1094 oldrte->inFromCl = true;
1095
1097 newrte->rtekind = RTE_RELATION;
1098 newrte->relid = trigrec->tgrelid;
1099 newrte->relkind = relkind;
1100 newrte->rellockmode = AccessShareLock;
1101 newrte->alias = makeAlias("new", NIL);
1102 newrte->eref = newrte->alias;
1103 newrte->lateral = false;
1104 newrte->inh = false;
1105 newrte->inFromCl = true;
1106
1107 /* Build two-element rtable */
1108 memset(&dpns, 0, sizeof(dpns));
1109 dpns.rtable = list_make2(oldrte, newrte);
1110 dpns.subplans = NIL;
1111 dpns.ctes = NIL;
1112 dpns.appendrels = NULL;
1115
1116 /* Set up context with one-deep namespace stack */
1117 context.buf = &buf;
1118 context.namespaces = list_make1(&dpns);
1119 context.resultDesc = NULL;
1120 context.targetList = NIL;
1121 context.windowClause = NIL;
1122 context.varprefix = true;
1125 context.indentLevel = PRETTYINDENT_STD;
1126 context.colNamesVisible = true;
1127 context.inGroupBy = false;
1128 context.varInOrderBy = false;
1129 context.appendparents = NULL;
1130
1131 get_rule_expr(qual, &context, false);
1132
1134 }
1135
1136 appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
1138 NIL, NULL,
1139 false, NULL, false));
1140
1141 if (trigrec->tgnargs > 0)
1142 {
1143 char *p;
1144 int i;
1145
1147 tgrel->rd_att, &isnull);
1148 if (isnull)
1149 elog(ERROR, "tgargs is null for trigger %u", trigid);
1150 p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1151 for (i = 0; i < trigrec->tgnargs; i++)
1152 {
1153 if (i > 0)
1156 /* advance p to next string embedded in tgargs */
1157 while (*p)
1158 p++;
1159 p++;
1160 }
1161 }
1162
1163 /* We deliberately do not put semi-colon at end */
1165
1166 /* Clean up */
1168
1170
1171 return buf.data;
1172}
1173
1174/* ----------
1175 * pg_get_indexdef - Get the definition of an index
1176 *
1177 * In the extended version, there is a colno argument as well as pretty bool.
1178 * if colno == 0, we want a complete index definition.
1179 * if colno > 0, we only want the Nth index key's variable or expression.
1180 *
1181 * Note that the SQL-function versions of this omit any info about the
1182 * index tablespace; this is intentional because pg_dump wants it that way.
1183 * However pg_get_indexdef_string() includes the index tablespace.
1184 * ----------
1185 */
1186Datum
1188{
1189 Oid indexrelid = PG_GETARG_OID(0);
1190 int prettyFlags;
1191 char *res;
1192
1193 prettyFlags = PRETTYFLAG_INDENT;
1194
1195 res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1196 false, false,
1197 false, false,
1198 prettyFlags, true);
1199
1200 if (res == NULL)
1202
1204}
1205
1206Datum
1208{
1209 Oid indexrelid = PG_GETARG_OID(0);
1210 int32 colno = PG_GETARG_INT32(1);
1211 bool pretty = PG_GETARG_BOOL(2);
1212 int prettyFlags;
1213 char *res;
1214
1215 prettyFlags = GET_PRETTY_FLAGS(pretty);
1216
1217 res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1218 colno != 0, false,
1219 false, false,
1220 prettyFlags, true);
1221
1222 if (res == NULL)
1224
1226}
1227
1228/*
1229 * Internal version for use by ALTER TABLE.
1230 * Includes a tablespace clause in the result.
1231 * Returns a palloc'd C string; no pretty-printing.
1232 */
1233char *
1235{
1236 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1237 false, false,
1238 true, true,
1239 0, false);
1240}
1241
1242/* Internal version that just reports the key-column definitions */
1243char *
1245{
1246 int prettyFlags;
1247
1248 prettyFlags = GET_PRETTY_FLAGS(pretty);
1249
1250 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1251 true, true,
1252 false, false,
1253 prettyFlags, false);
1254}
1255
1256/* Internal version, extensible with flags to control its behavior */
1257char *
1259{
1260 bool pretty = ((flags & RULE_INDEXDEF_PRETTY) != 0);
1261 bool keys_only = ((flags & RULE_INDEXDEF_KEYS_ONLY) != 0);
1262 int prettyFlags;
1263
1264 prettyFlags = GET_PRETTY_FLAGS(pretty);
1265
1266 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1267 true, keys_only,
1268 false, false,
1269 prettyFlags, false);
1270}
1271
1272/*
1273 * Internal workhorse to decompile an index definition.
1274 *
1275 * This is now used for exclusion constraints as well: if excludeOps is not
1276 * NULL then it points to an array of exclusion operator OIDs.
1277 */
1278static char *
1279pg_get_indexdef_worker(Oid indexrelid, int colno,
1280 const Oid *excludeOps,
1281 bool attrsOnly, bool keysOnly,
1282 bool showTblSpc, bool inherits,
1283 int prettyFlags, bool missing_ok)
1284{
1285 /* might want a separate isConstraint parameter later */
1286 bool isConstraint = (excludeOps != NULL);
1294 List *indexprs;
1296 List *context;
1297 Oid indrelid;
1298 int keyno;
1306 char *str;
1307 char *sep;
1308
1309 /*
1310 * Fetch the pg_index tuple by the Oid of the index
1311 */
1314 {
1315 if (missing_ok)
1316 return NULL;
1317 elog(ERROR, "cache lookup failed for index %u", indexrelid);
1318 }
1320
1321 indrelid = idxrec->indrelid;
1322 Assert(indexrelid == idxrec->indexrelid);
1323
1324 /* Must get indcollation, indclass, and indoption the hard way */
1328
1332
1336
1337 /*
1338 * Fetch the pg_class tuple of the index relation
1339 */
1342 elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1344
1345 /*
1346 * Fetch the pg_am tuple of the index' access method
1347 */
1349 if (!HeapTupleIsValid(ht_am))
1350 elog(ERROR, "cache lookup failed for access method %u",
1351 idxrelrec->relam);
1353
1354 /* Fetch the index AM's API struct */
1355 amroutine = GetIndexAmRoutine(amrec->amhandler);
1356
1357 /*
1358 * Get the index expressions, if any. (NOTE: we do not use the relcache
1359 * versions of the expressions and predicate, because we want to display
1360 * non-const-folded expressions.)
1361 */
1363 {
1365 char *exprsString;
1366
1372 }
1373 else
1374 indexprs = NIL;
1375
1377
1379
1380 /*
1381 * Start the index definition. Note that the index's name should never be
1382 * schema-qualified, but the indexed rel's name may be.
1383 */
1385
1386 if (!attrsOnly)
1387 {
1388 if (!isConstraint)
1389 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
1390 idxrec->indisunique ? "UNIQUE " : "",
1393 && !inherits ? "ONLY " : "",
1394 (prettyFlags & PRETTYFLAG_SCHEMA) ?
1397 quote_identifier(NameStr(amrec->amname)));
1398 else /* currently, must be EXCLUDE constraint */
1399 appendStringInfo(&buf, "EXCLUDE USING %s (",
1400 quote_identifier(NameStr(amrec->amname)));
1401 }
1402
1403 /*
1404 * Report the indexed attributes
1405 */
1406 sep = "";
1407 for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1408 {
1409 AttrNumber attnum = idxrec->indkey.values[keyno];
1412
1413 /*
1414 * Ignore non-key attributes if told to.
1415 */
1416 if (keysOnly && keyno >= idxrec->indnkeyatts)
1417 break;
1418
1419 /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1420 if (!colno && keyno == idxrec->indnkeyatts)
1421 {
1422 appendStringInfoString(&buf, ") INCLUDE (");
1423 sep = "";
1424 }
1425
1426 if (!colno)
1428 sep = ", ";
1429
1430 if (attnum != 0)
1431 {
1432 /* Simple index column */
1433 char *attname;
1435
1437 if (!colno || colno == keyno + 1)
1442 }
1443 else
1444 {
1445 /* expressional index */
1446 Node *indexkey;
1447
1448 if (indexpr_item == NULL)
1449 elog(ERROR, "too few entries in indexprs list");
1452 /* Deparse */
1453 str = deparse_expression_pretty(indexkey, context, false, false,
1454 prettyFlags, 0);
1455 if (!colno || colno == keyno + 1)
1456 {
1457 /* Need parens if it's not a bare function call */
1460 else
1461 appendStringInfo(&buf, "(%s)", str);
1462 }
1465 }
1466
1467 /* Print additional decoration for (selected) key columns */
1469 (!colno || colno == keyno + 1))
1470 {
1471 int16 opt = indoption->values[keyno];
1472 Oid indcoll = indcollation->values[keyno];
1473 Datum attoptions = get_attoptions(indexrelid, keyno + 1);
1474 bool has_options = attoptions != (Datum) 0;
1475
1476 /* Add collation, if not default for column */
1478 appendStringInfo(&buf, " COLLATE %s",
1480
1481 /* Add the operator class name, if not default */
1482 get_opclass_name(indclass->values[keyno],
1484
1485 if (has_options)
1486 {
1488 get_reloptions(&buf, attoptions);
1490 }
1491
1492 /* Add options if relevant */
1493 if (amroutine->amcanorder)
1494 {
1495 /* if it supports sort ordering, report DESC and NULLS opts */
1496 if (opt & INDOPTION_DESC)
1497 {
1498 appendStringInfoString(&buf, " DESC");
1499 /* NULLS FIRST is the default in this case */
1500 if (!(opt & INDOPTION_NULLS_FIRST))
1501 appendStringInfoString(&buf, " NULLS LAST");
1502 }
1503 else
1504 {
1505 if (opt & INDOPTION_NULLS_FIRST)
1506 appendStringInfoString(&buf, " NULLS FIRST");
1507 }
1508 }
1509
1510 /* Add the exclusion operator if relevant */
1511 if (excludeOps != NULL)
1512 appendStringInfo(&buf, " WITH %s",
1514 keycoltype,
1515 keycoltype));
1516 }
1517 }
1518
1519 if (!attrsOnly)
1520 {
1522
1523 if (idxrec->indnullsnotdistinct)
1524 appendStringInfoString(&buf, " NULLS NOT DISTINCT");
1525
1526 /*
1527 * If it has options, append "WITH (options)"
1528 */
1529 str = flatten_reloptions(indexrelid);
1530 if (str)
1531 {
1532 appendStringInfo(&buf, " WITH (%s)", str);
1533 pfree(str);
1534 }
1535
1536 /*
1537 * Print tablespace, but only if requested
1538 */
1539 if (showTblSpc)
1540 {
1541 Oid tblspc;
1542
1543 tblspc = get_rel_tablespace(indexrelid);
1544 if (OidIsValid(tblspc))
1545 {
1546 if (isConstraint)
1547 appendStringInfoString(&buf, " USING INDEX");
1548 appendStringInfo(&buf, " TABLESPACE %s",
1550 }
1551 }
1552
1553 /*
1554 * If it's a partial index, decompile and append the predicate
1555 */
1557 {
1558 Node *node;
1560 char *predString;
1561
1562 /* Convert text string to node tree */
1566 node = (Node *) stringToNode(predString);
1568
1569 /* Deparse */
1570 str = deparse_expression_pretty(node, context, false, false,
1571 prettyFlags, 0);
1572 if (isConstraint)
1573 appendStringInfo(&buf, " WHERE (%s)", str);
1574 else
1575 appendStringInfo(&buf, " WHERE %s", str);
1576 }
1577 }
1578
1579 /* Clean up */
1583
1584 return buf.data;
1585}
1586
1587/* ----------
1588 * pg_get_querydef
1589 *
1590 * Public entry point to deparse one query parsetree.
1591 * The pretty flags are determined by GET_PRETTY_FLAGS(pretty).
1592 *
1593 * The result is a palloc'd C string.
1594 * ----------
1595 */
1596char *
1598{
1600 int prettyFlags;
1601
1602 prettyFlags = GET_PRETTY_FLAGS(pretty);
1603
1605
1606 get_query_def(query, &buf, NIL, NULL, true,
1607 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1608
1609 return buf.data;
1610}
1611
1612/*
1613 * pg_get_propgraphdef - get the definition of a property graph
1614 */
1615Datum
1617{
1622 char *name;
1623 char *nsp;
1624
1626
1630
1632 name = NameStr(classform->relname);
1633
1634 if (classform->relkind != RELKIND_PROPGRAPH)
1635 ereport(ERROR,
1637 errmsg("\"%s\" is not a property graph", name)));
1638
1639 nsp = get_namespace_name(classform->relnamespace);
1640
1641 appendStringInfo(&buf, "CREATE PROPERTY GRAPH %s",
1643
1645
1648
1650}
1651
1652/*
1653 * Generates a VERTEX TABLES (...) or EDGE TABLES (...) clause. Pass in the
1654 * property graph relation OID and the element kind (vertex or edge). Result
1655 * is appended to buf.
1656 */
1657static void
1659{
1662 SysScanDesc scan;
1663 bool first;
1664 HeapTuple tup;
1665
1667
1668 ScanKeyInit(&scankey[0],
1672
1674
1675 first = true;
1676 while ((tup = systable_getnext(scan)))
1677 {
1679 char *relname;
1680 Datum datum;
1681 bool isnull;
1682
1683 if (pgeform->pgekind != pgekind)
1684 continue;
1685
1686 if (first)
1687 {
1688 appendStringInfo(buf, "\n %s TABLES (\n", pgekind == PGEKIND_VERTEX ? "VERTEX" : "EDGE");
1689 first = false;
1690 }
1691 else
1692 appendStringInfo(buf, ",\n");
1693
1694 relname = get_rel_name(pgeform->pgerelid);
1695 if (relname && strcmp(relname, NameStr(pgeform->pgealias)) == 0)
1696 appendStringInfo(buf, " %s",
1697 generate_relation_name(pgeform->pgerelid, NIL));
1698 else
1699 appendStringInfo(buf, " %s AS %s",
1701 quote_identifier(NameStr(pgeform->pgealias)));
1702
1704 if (!isnull)
1705 {
1706 appendStringInfoString(buf, " KEY (");
1707 decompile_column_index_array(datum, pgeform->pgerelid, false, buf);
1709 }
1710 else
1711 elog(ERROR, "null pgekey for element %u", pgeform->oid);
1712
1713 if (pgekind == PGEKIND_EDGE)
1714 {
1715 Datum srckey;
1716 Datum srcref;
1717 Datum destkey;
1718 Datum destref;
1721
1723 srckey = isnull ? 0 : datum;
1725 srcref = isnull ? 0 : datum;
1727 destkey = isnull ? 0 : datum;
1729 destref = isnull ? 0 : datum;
1730
1731 appendStringInfoString(buf, " SOURCE");
1733 if (!tup2)
1734 elog(ERROR, "cache lookup failed for property graph element %u", pgeform->pgesrcvertexid);
1736 if (srckey)
1737 {
1738 appendStringInfoString(buf, " KEY (");
1739 decompile_column_index_array(srckey, pgeform->pgerelid, false, buf);
1740 appendStringInfo(buf, ") REFERENCES %s (", quote_identifier(NameStr(pgeform2->pgealias)));
1741 decompile_column_index_array(srcref, pgeform2->pgerelid, false, buf);
1743 }
1744 else
1747
1748 appendStringInfoString(buf, " DESTINATION");
1750 if (!tup2)
1751 elog(ERROR, "cache lookup failed for property graph element %u", pgeform->pgedestvertexid);
1753 if (destkey)
1754 {
1755 appendStringInfoString(buf, " KEY (");
1756 decompile_column_index_array(destkey, pgeform->pgerelid, false, buf);
1757 appendStringInfo(buf, ") REFERENCES %s (", quote_identifier(NameStr(pgeform2->pgealias)));
1758 decompile_column_index_array(destref, pgeform2->pgerelid, false, buf);
1760 }
1761 else
1764 }
1765
1766 make_propgraphdef_labels(buf, pgeform->oid, NameStr(pgeform->pgealias), pgeform->pgerelid);
1767 }
1768 if (!first)
1769 appendStringInfo(buf, "\n )");
1770
1771 systable_endscan(scan);
1773}
1774
1776{
1778 char *str;
1779};
1780
1781static int
1783{
1784 struct oid_str_pair *v1 = lfirst(p1);
1785 struct oid_str_pair *v2 = lfirst(p2);
1786
1787 return strcmp(v1->str, v2->str);
1788}
1789
1790/*
1791 * Generates label and properties list. Pass in the element OID, the element
1792 * alias, and the graph relation OID. Result is appended to buf.
1793 */
1794static void
1796{
1799 SysScanDesc scan;
1800 int count;
1801 HeapTuple tup;
1802 List *label_list = NIL;
1803
1805
1806 ScanKeyInit(&scankey[0],
1810
1811 /*
1812 * We want to output the labels in a deterministic order. So we first
1813 * read all the data, then sort, then print it.
1814 */
1816
1817 while ((tup = systable_getnext(scan)))
1818 {
1820 struct oid_str_pair *osp;
1821
1822 osp = palloc_object(struct oid_str_pair);
1823 osp->oid = pgelform->oid;
1824 osp->str = get_propgraph_label_name(pgelform->pgellabelid);
1825
1827 }
1828
1829 systable_endscan(scan);
1831
1832 count = list_length(label_list);
1833
1834 /* Each element has at least one label. */
1835 Assert(count > 0);
1836
1837 /*
1838 * It is enough for the comparison function to compare just labels, since
1839 * all the labels of an element table should have distinct names.
1840 */
1842
1844 {
1845 if (strcmp(osp->str, elalias) == 0)
1846 {
1847 /* If the default label is the only label, don't print anything. */
1848 if (count != 1)
1849 appendStringInfo(buf, " DEFAULT LABEL");
1850 }
1851 else
1852 appendStringInfo(buf, " LABEL %s", quote_identifier(osp->str));
1853
1855 }
1856}
1857
1858/*
1859 * Helper function for make_propgraphdef_properties(): Sort (propname, expr)
1860 * pairs by name.
1861 */
1862static int
1864{
1865 List *la = lfirst_node(List, a);
1866 List *lb = lfirst_node(List, b);
1867 char *pna = strVal(linitial(la));
1868 char *pnb = strVal(linitial(lb));
1869
1870 return strcmp(pna, pnb);
1871}
1872
1873/*
1874 * Generates element table properties clause (PROPERTIES (...) or NO
1875 * PROPERTIES). Pass in label OID and element table OID. Result is appended
1876 * to buf.
1877 */
1878static void
1880{
1883 SysScanDesc scan;
1884 HeapTuple tup;
1885 List *outlist = NIL;
1886
1888
1889 ScanKeyInit(&scankey[0],
1893
1894 /*
1895 * We want to output the properties in a deterministic order. So we first
1896 * read all the data, then sort, then print it.
1897 */
1899
1900 while ((tup = systable_getnext(scan)))
1901 {
1904 bool isnull;
1905 char *tmp;
1906 Node *expr;
1907 char *propname;
1908
1910 Assert(!isnull);
1912 expr = stringToNode(tmp);
1913 pfree(tmp);
1914
1916
1917 outlist = lappend(outlist, list_make2(makeString(propname), expr));
1918 }
1919
1920 systable_endscan(scan);
1922
1924
1925 if (outlist)
1926 {
1927 List *context;
1928 ListCell *lc;
1929 bool first = true;
1930
1932
1933 appendStringInfo(buf, " PROPERTIES (");
1934
1935 foreach(lc, outlist)
1936 {
1938 char *propname = strVal(linitial(data));
1939 Node *expr = lsecond(data);
1940
1941 if (first)
1942 first = false;
1943 else
1944 appendStringInfo(buf, ", ");
1945
1946 if (IsA(expr, Var) && strcmp(propname, get_attname(elrelid, castNode(Var, expr)->varattno, false)) == 0)
1948 else
1949 appendStringInfo(buf, "%s AS %s",
1950 deparse_expression_pretty(expr, context, false, false, 0, 0),
1952 }
1953
1954 appendStringInfo(buf, ")");
1955 }
1956 else
1957 appendStringInfo(buf, " NO PROPERTIES");
1958}
1959
1960/*
1961 * pg_get_statisticsobjdef
1962 * Get the definition of an extended statistics object
1963 */
1964Datum
1966{
1968 char *res;
1969
1970 res = pg_get_statisticsobj_worker(statextid, false, true);
1971
1972 if (res == NULL)
1974
1976}
1977
1978/*
1979 * Internal version for use by ALTER TABLE.
1980 * Returns a palloc'd C string; no pretty-printing.
1981 */
1982char *
1987
1988/*
1989 * pg_get_statisticsobjdef_columns
1990 * Get columns and expressions for an extended statistics object
1991 */
1992Datum
1994{
1996 char *res;
1997
1998 res = pg_get_statisticsobj_worker(statextid, true, true);
1999
2000 if (res == NULL)
2002
2004}
2005
2006/*
2007 * Internal workhorse to decompile an extended statistics object.
2008 */
2009static char *
2011{
2015 int colno;
2016 char *nsp;
2017 ArrayType *arr;
2018 char *enabled;
2019 Datum datum;
2020 bool ndistinct_enabled;
2022 bool mcv_enabled;
2023 int i;
2024 List *context;
2025 ListCell *lc;
2026 List *exprs = NIL;
2027 bool has_exprs;
2028 int ncolumns;
2029
2031
2033 {
2034 if (missing_ok)
2035 return NULL;
2036 elog(ERROR, "cache lookup failed for statistics object %u", statextid);
2037 }
2038
2039 /* has the statistics expressions? */
2041
2043
2044 /*
2045 * Get the statistics expressions, if any. (NOTE: we do not use the
2046 * relcache versions of the expressions, because we want to display
2047 * non-const-folded expressions.)
2048 */
2049 if (has_exprs)
2050 {
2052 char *exprsString;
2053
2057 exprs = (List *) stringToNode(exprsString);
2059 }
2060 else
2061 exprs = NIL;
2062
2063 /* count the number of columns (attributes and expressions) */
2064 ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
2065
2067
2068 if (!columns_only)
2069 {
2070 nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
2071 appendStringInfo(&buf, "CREATE STATISTICS %s",
2073 NameStr(statextrec->stxname)));
2074
2075 /*
2076 * Decode the stxkind column so that we know which stats types to
2077 * print.
2078 */
2081 arr = DatumGetArrayTypeP(datum);
2082 if (ARR_NDIM(arr) != 1 ||
2083 ARR_HASNULL(arr) ||
2084 ARR_ELEMTYPE(arr) != CHAROID)
2085 elog(ERROR, "stxkind is not a 1-D char array");
2086 enabled = (char *) ARR_DATA_PTR(arr);
2087
2088 ndistinct_enabled = false;
2089 dependencies_enabled = false;
2090 mcv_enabled = false;
2091
2092 for (i = 0; i < ARR_DIMS(arr)[0]; i++)
2093 {
2094 if (enabled[i] == STATS_EXT_NDISTINCT)
2095 ndistinct_enabled = true;
2096 else if (enabled[i] == STATS_EXT_DEPENDENCIES)
2097 dependencies_enabled = true;
2098 else if (enabled[i] == STATS_EXT_MCV)
2099 mcv_enabled = true;
2100
2101 /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
2102 }
2103
2104 /*
2105 * If any option is disabled, then we'll need to append the types
2106 * clause to show which options are enabled. We omit the types clause
2107 * on purpose when all options are enabled, so a pg_dump/pg_restore
2108 * will create all statistics types on a newer postgres version, if
2109 * the statistics had all options enabled on the original version.
2110 *
2111 * But if the statistics is defined on just a single column, it has to
2112 * be an expression statistics. In that case we don't need to specify
2113 * kinds.
2114 */
2116 (ncolumns > 1))
2117 {
2118 bool gotone = false;
2119
2121
2123 {
2124 appendStringInfoString(&buf, "ndistinct");
2125 gotone = true;
2126 }
2127
2129 {
2130 appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
2131 gotone = true;
2132 }
2133
2134 if (mcv_enabled)
2135 appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
2136
2138 }
2139
2140 appendStringInfoString(&buf, " ON ");
2141 }
2142
2143 /* decode simple column references */
2144 for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
2145 {
2146 AttrNumber attnum = statextrec->stxkeys.values[colno];
2147 char *attname;
2148
2149 if (colno > 0)
2151
2152 attname = get_attname(statextrec->stxrelid, attnum, false);
2153
2155 }
2156
2158 statextrec->stxrelid);
2159
2160 foreach(lc, exprs)
2161 {
2162 Node *expr = (Node *) lfirst(lc);
2163 char *str;
2164 int prettyFlags = PRETTYFLAG_PAREN;
2165
2166 str = deparse_expression_pretty(expr, context, false, false,
2167 prettyFlags, 0);
2168
2169 if (colno > 0)
2171
2172 /* Need parens if it's not a bare function call */
2173 if (looks_like_function(expr))
2175 else
2176 appendStringInfo(&buf, "(%s)", str);
2177
2178 colno++;
2179 }
2180
2181 if (!columns_only)
2182 appendStringInfo(&buf, " FROM %s",
2184
2186
2187 return buf.data;
2188}
2189
2190/*
2191 * Generate text array of expressions for statistics object.
2192 */
2193Datum
2195{
2199 Datum datum;
2200 List *context;
2201 ListCell *lc;
2202 List *exprs = NIL;
2203 bool has_exprs;
2204 char *tmp;
2205 ArrayBuildState *astate = NULL;
2206
2208
2211
2212 /* Does the stats object have expressions? */
2214
2215 /* no expressions? we're done */
2216 if (!has_exprs)
2217 {
2220 }
2221
2223
2224 /*
2225 * Get the statistics expressions, and deparse them into text values.
2226 */
2229 tmp = TextDatumGetCString(datum);
2230 exprs = (List *) stringToNode(tmp);
2231 pfree(tmp);
2232
2234 statextrec->stxrelid);
2235
2236 foreach(lc, exprs)
2237 {
2238 Node *expr = (Node *) lfirst(lc);
2239 char *str;
2240 int prettyFlags = PRETTYFLAG_INDENT;
2241
2242 str = deparse_expression_pretty(expr, context, false, false,
2243 prettyFlags, 0);
2244
2245 astate = accumArrayResult(astate,
2247 false,
2248 TEXTOID,
2250 }
2251
2253
2255}
2256
2257/*
2258 * pg_get_partkeydef
2259 *
2260 * Returns the partition key specification, ie, the following:
2261 *
2262 * { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
2263 */
2264Datum
2266{
2267 Oid relid = PG_GETARG_OID(0);
2268 char *res;
2269
2270 res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
2271
2272 if (res == NULL)
2274
2276}
2277
2278/* Internal version that just reports the column definitions */
2279char *
2281{
2282 int prettyFlags;
2283
2284 prettyFlags = GET_PRETTY_FLAGS(pretty);
2285
2286 return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
2287}
2288
2289/*
2290 * Internal workhorse to decompile a partition key definition.
2291 */
2292static char *
2293pg_get_partkeydef_worker(Oid relid, int prettyFlags,
2294 bool attrsOnly, bool missing_ok)
2295{
2297 HeapTuple tuple;
2299 oidvector *partcollation;
2300 List *partexprs;
2302 List *context;
2303 Datum datum;
2305 int keyno;
2306 char *str;
2307 char *sep;
2308
2310 if (!HeapTupleIsValid(tuple))
2311 {
2312 if (missing_ok)
2313 return NULL;
2314 elog(ERROR, "cache lookup failed for partition key of %u", relid);
2315 }
2316
2318
2319 Assert(form->partrelid == relid);
2320
2321 /* Must get partclass and partcollation the hard way */
2322 datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
2324 partclass = (oidvector *) DatumGetPointer(datum);
2325
2326 datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
2328 partcollation = (oidvector *) DatumGetPointer(datum);
2329
2330
2331 /*
2332 * Get the expressions, if any. (NOTE: we do not use the relcache
2333 * versions of the expressions, because we want to display
2334 * non-const-folded expressions.)
2335 */
2337 {
2339 char *exprsString;
2340
2344 partexprs = (List *) stringToNode(exprsString);
2345
2346 if (!IsA(partexprs, List))
2347 elog(ERROR, "unexpected node type found in partexprs: %d",
2348 (int) nodeTag(partexprs));
2349
2351 }
2352 else
2353 partexprs = NIL;
2354
2355 partexpr_item = list_head(partexprs);
2356 context = deparse_context_for(get_relation_name(relid), relid);
2357
2359
2360 switch (form->partstrat)
2361 {
2363 if (!attrsOnly)
2364 appendStringInfoString(&buf, "HASH");
2365 break;
2367 if (!attrsOnly)
2368 appendStringInfoString(&buf, "LIST");
2369 break;
2371 if (!attrsOnly)
2372 appendStringInfoString(&buf, "RANGE");
2373 break;
2374 default:
2375 elog(ERROR, "unexpected partition strategy: %d",
2376 (int) form->partstrat);
2377 }
2378
2379 if (!attrsOnly)
2381 sep = "";
2382 for (keyno = 0; keyno < form->partnatts; keyno++)
2383 {
2384 AttrNumber attnum = form->partattrs.values[keyno];
2387 Oid partcoll;
2388
2390 sep = ", ";
2391 if (attnum != 0)
2392 {
2393 /* Simple attribute reference */
2394 char *attname;
2396
2397 attname = get_attname(relid, attnum, false);
2402 }
2403 else
2404 {
2405 /* Expression */
2406 Node *partkey;
2407
2408 if (partexpr_item == NULL)
2409 elog(ERROR, "too few entries in partexprs list");
2411 partexpr_item = lnext(partexprs, partexpr_item);
2412
2413 /* Deparse */
2414 str = deparse_expression_pretty(partkey, context, false, false,
2415 prettyFlags, 0);
2416 /* Need parens if it's not a bare function call */
2419 else
2420 appendStringInfo(&buf, "(%s)", str);
2421
2424 }
2425
2426 /* Add collation, if not default for column */
2427 partcoll = partcollation->values[keyno];
2429 appendStringInfo(&buf, " COLLATE %s",
2431
2432 /* Add the operator class name, if not default */
2433 if (!attrsOnly)
2434 get_opclass_name(partclass->values[keyno], keycoltype, &buf);
2435 }
2436
2437 if (!attrsOnly)
2439
2440 /* Clean up */
2441 ReleaseSysCache(tuple);
2442
2443 return buf.data;
2444}
2445
2446/*
2447 * pg_get_partition_constraintdef
2448 *
2449 * Returns partition constraint expression as a string for the input relation
2450 */
2451Datum
2453{
2456 int prettyFlags;
2457 List *context;
2458 char *consrc;
2459
2461
2462 /* Quick exit if no partition constraint */
2463 if (constr_expr == NULL)
2465
2466 /*
2467 * Deparse and return the constraint expression.
2468 */
2469 prettyFlags = PRETTYFLAG_INDENT;
2471 consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2472 false, prettyFlags, 0);
2473
2475}
2476
2477/*
2478 * pg_get_partconstrdef_string
2479 *
2480 * Returns the partition constraint as a C-string for the input relation, with
2481 * the given alias. No pretty-printing.
2482 */
2483char *
2485{
2487 List *context;
2488
2490 context = deparse_context_for(aliasname, partitionId);
2491
2492 return deparse_expression((Node *) constr_expr, context, true, false);
2493}
2494
2495/*
2496 * pg_get_constraintdef
2497 *
2498 * Returns the definition for the constraint, ie, everything that needs to
2499 * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
2500 */
2501Datum
2503{
2505 int prettyFlags;
2506 char *res;
2507
2508 prettyFlags = PRETTYFLAG_INDENT;
2509
2510 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2511
2512 if (res == NULL)
2514
2516}
2517
2518Datum
2520{
2522 bool pretty = PG_GETARG_BOOL(1);
2523 int prettyFlags;
2524 char *res;
2525
2526 prettyFlags = GET_PRETTY_FLAGS(pretty);
2527
2528 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2529
2530 if (res == NULL)
2532
2534}
2535
2536/*
2537 * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
2538 */
2539char *
2544
2545/*
2546 * As of 9.4, we now use an MVCC snapshot for this.
2547 */
2548static char *
2550 int prettyFlags, bool missing_ok)
2551{
2552 HeapTuple tup;
2555 SysScanDesc scandesc;
2559
2560 ScanKeyInit(&scankey[0],
2564
2565 scandesc = systable_beginscan(relation,
2567 true,
2568 snapshot,
2569 1,
2570 scankey);
2571
2572 /*
2573 * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2574 * via SearchSysCache, which works fine.
2575 */
2576 tup = systable_getnext(scandesc);
2577
2578 UnregisterSnapshot(snapshot);
2579
2580 if (!HeapTupleIsValid(tup))
2581 {
2582 if (missing_ok)
2583 {
2584 systable_endscan(scandesc);
2585 table_close(relation, AccessShareLock);
2586 return NULL;
2587 }
2588 elog(ERROR, "could not find tuple for constraint %u", constraintId);
2589 }
2590
2592
2594
2595 if (fullCommand)
2596 {
2597 if (OidIsValid(conForm->conrelid))
2598 {
2599 /*
2600 * Currently, callers want ALTER TABLE (without ONLY) for CHECK
2601 * constraints, and other types of constraints don't inherit
2602 * anyway so it doesn't matter whether we say ONLY or not. Someday
2603 * we might need to let callers specify whether to put ONLY in the
2604 * command.
2605 */
2606 appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2608 quote_identifier(NameStr(conForm->conname)));
2609 }
2610 else
2611 {
2612 /* Must be a domain constraint */
2613 Assert(OidIsValid(conForm->contypid));
2614 appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
2616 quote_identifier(NameStr(conForm->conname)));
2617 }
2618 }
2619
2620 switch (conForm->contype)
2621 {
2622 case CONSTRAINT_FOREIGN:
2623 {
2624 Datum val;
2625 bool isnull;
2626 const char *string;
2627
2628 /* Start off the constraint definition */
2629 appendStringInfoString(&buf, "FOREIGN KEY (");
2630
2631 /* Fetch and build referencing-column list */
2634
2635 /* If it is a temporal foreign key then it uses PERIOD. */
2636 decompile_column_index_array(val, conForm->conrelid, conForm->conperiod, &buf);
2637
2638 /* add foreign relation name */
2639 appendStringInfo(&buf, ") REFERENCES %s(",
2641 NIL));
2642
2643 /* Fetch and build referenced-column list */
2646
2647 decompile_column_index_array(val, conForm->confrelid, conForm->conperiod, &buf);
2648
2650
2651 /* Add match type */
2652 switch (conForm->confmatchtype)
2653 {
2655 string = " MATCH FULL";
2656 break;
2658 string = " MATCH PARTIAL";
2659 break;
2661 string = "";
2662 break;
2663 default:
2664 elog(ERROR, "unrecognized confmatchtype: %d",
2665 conForm->confmatchtype);
2666 string = ""; /* keep compiler quiet */
2667 break;
2668 }
2669 appendStringInfoString(&buf, string);
2670
2671 /* Add ON UPDATE and ON DELETE clauses, if needed */
2672 switch (conForm->confupdtype)
2673 {
2675 string = NULL; /* suppress default */
2676 break;
2678 string = "RESTRICT";
2679 break;
2681 string = "CASCADE";
2682 break;
2684 string = "SET NULL";
2685 break;
2687 string = "SET DEFAULT";
2688 break;
2689 default:
2690 elog(ERROR, "unrecognized confupdtype: %d",
2691 conForm->confupdtype);
2692 string = NULL; /* keep compiler quiet */
2693 break;
2694 }
2695 if (string)
2696 appendStringInfo(&buf, " ON UPDATE %s", string);
2697
2698 switch (conForm->confdeltype)
2699 {
2701 string = NULL; /* suppress default */
2702 break;
2704 string = "RESTRICT";
2705 break;
2707 string = "CASCADE";
2708 break;
2710 string = "SET NULL";
2711 break;
2713 string = "SET DEFAULT";
2714 break;
2715 default:
2716 elog(ERROR, "unrecognized confdeltype: %d",
2717 conForm->confdeltype);
2718 string = NULL; /* keep compiler quiet */
2719 break;
2720 }
2721 if (string)
2722 appendStringInfo(&buf, " ON DELETE %s", string);
2723
2724 /*
2725 * Add columns specified to SET NULL or SET DEFAULT if
2726 * provided.
2727 */
2730 if (!isnull)
2731 {
2733 decompile_column_index_array(val, conForm->conrelid, false, &buf);
2735 }
2736
2737 break;
2738 }
2739 case CONSTRAINT_PRIMARY:
2740 case CONSTRAINT_UNIQUE:
2741 {
2742 Datum val;
2743 Oid indexId;
2744 int keyatts;
2746
2747 /* Start off the constraint definition */
2748 if (conForm->contype == CONSTRAINT_PRIMARY)
2749 appendStringInfoString(&buf, "PRIMARY KEY ");
2750 else
2751 appendStringInfoString(&buf, "UNIQUE ");
2752
2753 indexId = conForm->conindid;
2754
2757 elog(ERROR, "cache lookup failed for index %u", indexId);
2758 if (conForm->contype == CONSTRAINT_UNIQUE &&
2759 ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
2760 appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
2761
2763
2764 /* Fetch and build target column list */
2767
2768 keyatts = decompile_column_index_array(val, conForm->conrelid, false, &buf);
2769 if (conForm->conperiod)
2770 appendStringInfoString(&buf, " WITHOUT OVERLAPS");
2771
2773
2774 /* Build including column list (from pg_index.indkeys) */
2777 if (DatumGetInt32(val) > keyatts)
2778 {
2779 Datum cols;
2780 Datum *keys;
2781 int nKeys;
2782 int j;
2783
2784 appendStringInfoString(&buf, " INCLUDE (");
2785
2788
2790 &keys, NULL, &nKeys);
2791
2792 for (j = keyatts; j < nKeys; j++)
2793 {
2794 char *colName;
2795
2796 colName = get_attname(conForm->conrelid,
2797 DatumGetInt16(keys[j]), false);
2798 if (j > keyatts)
2801 }
2802
2804 }
2806
2807 /* XXX why do we only print these bits if fullCommand? */
2809 {
2811 Oid tblspc;
2812
2813 if (options)
2814 {
2815 appendStringInfo(&buf, " WITH (%s)", options);
2816 pfree(options);
2817 }
2818
2819 /*
2820 * Print the tablespace, unless it's the database default.
2821 * This is to help ALTER TABLE usage of this facility,
2822 * which needs this behavior to recreate exact catalog
2823 * state.
2824 */
2826 if (OidIsValid(tblspc))
2827 appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2829 }
2830
2831 break;
2832 }
2833 case CONSTRAINT_CHECK:
2834 {
2835 Datum val;
2836 char *conbin;
2837 char *consrc;
2838 Node *expr;
2839 List *context;
2840
2841 /* Fetch constraint expression in parsetree form */
2844
2846 expr = stringToNode(conbin);
2847
2848 /* Set up deparsing context for Var nodes in constraint */
2849 if (conForm->conrelid != InvalidOid)
2850 {
2851 /* relation constraint */
2852 context = deparse_context_for(get_relation_name(conForm->conrelid),
2853 conForm->conrelid);
2854 }
2855 else
2856 {
2857 /* domain constraint --- can't have Vars */
2858 context = NIL;
2859 }
2860
2861 consrc = deparse_expression_pretty(expr, context, false, false,
2862 prettyFlags, 0);
2863
2864 /*
2865 * Now emit the constraint definition, adding NO INHERIT if
2866 * necessary.
2867 *
2868 * There are cases where the constraint expression will be
2869 * fully parenthesized and we don't need the outer parens ...
2870 * but there are other cases where we do need 'em. Be
2871 * conservative for now.
2872 *
2873 * Note that simply checking for leading '(' and trailing ')'
2874 * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2875 */
2876 appendStringInfo(&buf, "CHECK (%s)%s",
2877 consrc,
2878 conForm->connoinherit ? " NO INHERIT" : "");
2879 break;
2880 }
2881 case CONSTRAINT_NOTNULL:
2882 {
2883 if (conForm->conrelid)
2884 {
2886
2888
2889 appendStringInfo(&buf, "NOT NULL %s",
2891 attnum, false)));
2893 appendStringInfoString(&buf, " NO INHERIT");
2894 }
2895 else if (conForm->contypid)
2896 {
2897 /* conkey is null for domain not-null constraints */
2898 appendStringInfoString(&buf, "NOT NULL");
2899 }
2900 break;
2901 }
2902
2903 case CONSTRAINT_TRIGGER:
2904
2905 /*
2906 * There isn't an ALTER TABLE syntax for creating a user-defined
2907 * constraint trigger, but it seems better to print something than
2908 * throw an error; if we throw error then this function couldn't
2909 * safely be applied to all rows of pg_constraint.
2910 */
2911 appendStringInfoString(&buf, "TRIGGER");
2912 break;
2914 {
2915 Oid indexOid = conForm->conindid;
2916 Datum val;
2917 Datum *elems;
2918 int nElems;
2919 int i;
2920 Oid *operators;
2921
2922 /* Extract operator OIDs from the pg_constraint tuple */
2925
2927 &elems, NULL, &nElems);
2928
2929 operators = (Oid *) palloc(nElems * sizeof(Oid));
2930 for (i = 0; i < nElems; i++)
2931 operators[i] = DatumGetObjectId(elems[i]);
2932
2933 /* pg_get_indexdef_worker does the rest */
2934 /* suppress tablespace because pg_dump wants it that way */
2936 pg_get_indexdef_worker(indexOid,
2937 0,
2938 operators,
2939 false,
2940 false,
2941 false,
2942 false,
2943 prettyFlags,
2944 false));
2945 break;
2946 }
2947 default:
2948 elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2949 break;
2950 }
2951
2952 if (conForm->condeferrable)
2953 appendStringInfoString(&buf, " DEFERRABLE");
2954 if (conForm->condeferred)
2955 appendStringInfoString(&buf, " INITIALLY DEFERRED");
2956
2957 /* Validated status is irrelevant when the constraint is NOT ENFORCED. */
2958 if (!conForm->conenforced)
2959 appendStringInfoString(&buf, " NOT ENFORCED");
2960 else if (!conForm->convalidated)
2961 appendStringInfoString(&buf, " NOT VALID");
2962
2963 /* Cleanup */
2964 systable_endscan(scandesc);
2965 table_close(relation, AccessShareLock);
2966
2967 return buf.data;
2968}
2969
2970
2971/*
2972 * Convert an int16[] Datum into a comma-separated list of column names
2973 * for the indicated relation; append the list to buf. Returns the number
2974 * of keys.
2975 */
2976static int
2979{
2980 Datum *keys;
2981 int nKeys;
2982 int j;
2983
2984 /* Extract data from array of int16 */
2986 &keys, NULL, &nKeys);
2987
2988 for (j = 0; j < nKeys; j++)
2989 {
2990 char *colName;
2991
2992 colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2993
2994 if (j == 0)
2996 else
2997 appendStringInfo(buf, ", %s%s",
2998 (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
3000 }
3001
3002 return nKeys;
3003}
3004
3005
3006/* ----------
3007 * pg_get_expr - Decompile an expression tree
3008 *
3009 * Input: an expression tree in nodeToString form, and a relation OID
3010 *
3011 * Output: reverse-listed expression
3012 *
3013 * Currently, the expression can only refer to a single relation, namely
3014 * the one specified by the second parameter. This is sufficient for
3015 * partial indexes, column default expressions, etc. We also support
3016 * Var-free expressions, for which the OID can be InvalidOid.
3017 *
3018 * If the OID is nonzero but not actually valid, don't throw an error,
3019 * just return NULL. This is a bit questionable, but it's what we've
3020 * done historically, and it can help avoid unwanted failures when
3021 * examining catalog entries for just-deleted relations.
3022 *
3023 * We expect this function to work, or throw a reasonably clean error,
3024 * for any node tree that can appear in a catalog pg_node_tree column.
3025 * Query trees, such as those appearing in pg_rewrite.ev_action, are
3026 * not supported. Nor are expressions in more than one relation, which
3027 * can appear in places like pg_rewrite.ev_qual.
3028 * ----------
3029 */
3030Datum
3032{
3033 text *expr = PG_GETARG_TEXT_PP(0);
3034 Oid relid = PG_GETARG_OID(1);
3035 text *result;
3036 int prettyFlags;
3037
3038 prettyFlags = PRETTYFLAG_INDENT;
3039
3040 result = pg_get_expr_worker(expr, relid, prettyFlags);
3041 if (result)
3042 PG_RETURN_TEXT_P(result);
3043 else
3045}
3046
3047Datum
3049{
3050 text *expr = PG_GETARG_TEXT_PP(0);
3051 Oid relid = PG_GETARG_OID(1);
3052 bool pretty = PG_GETARG_BOOL(2);
3053 text *result;
3054 int prettyFlags;
3055
3056 prettyFlags = GET_PRETTY_FLAGS(pretty);
3057
3058 result = pg_get_expr_worker(expr, relid, prettyFlags);
3059 if (result)
3060 PG_RETURN_TEXT_P(result);
3061 else
3063}
3064
3065static text *
3066pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
3067{
3068 Node *node;
3069 Node *tst;
3070 Relids relids;
3071 List *context;
3072 char *exprstr;
3073 Relation rel = NULL;
3074 char *str;
3075
3076 /* Convert input pg_node_tree (really TEXT) object to C string */
3077 exprstr = text_to_cstring(expr);
3078
3079 /* Convert expression to node tree */
3080 node = (Node *) stringToNode(exprstr);
3081
3082 pfree(exprstr);
3083
3084 /*
3085 * Throw error if the input is a querytree rather than an expression tree.
3086 * While we could support queries here, there seems no very good reason
3087 * to. In most such catalog columns, we'll see a List of Query nodes, or
3088 * even nested Lists, so drill down to a non-List node before checking.
3089 */
3090 tst = node;
3091 while (tst && IsA(tst, List))
3092 tst = linitial((List *) tst);
3093 if (tst && IsA(tst, Query))
3094 ereport(ERROR,
3096 errmsg("input is a query, not an expression")));
3097
3098 /*
3099 * Throw error if the expression contains Vars we won't be able to
3100 * deparse.
3101 */
3102 relids = pull_varnos(NULL, node);
3103 if (OidIsValid(relid))
3104 {
3105 if (!bms_is_subset(relids, bms_make_singleton(1)))
3106 ereport(ERROR,
3108 errmsg("expression contains variables of more than one relation")));
3109 }
3110 else
3111 {
3112 if (!bms_is_empty(relids))
3113 ereport(ERROR,
3115 errmsg("expression contains variables")));
3116 }
3117
3118 /*
3119 * Prepare deparse context if needed. If we are deparsing with a relid,
3120 * we need to transiently open and lock the rel, to make sure it won't go
3121 * away underneath us. (set_relation_column_names would lock it anyway,
3122 * so this isn't really introducing any new behavior.)
3123 */
3124 if (OidIsValid(relid))
3125 {
3126 rel = try_relation_open(relid, AccessShareLock);
3127 if (rel == NULL)
3128 return NULL;
3129 context = deparse_context_for(RelationGetRelationName(rel), relid);
3130 }
3131 else
3132 context = NIL;
3133
3134 /* Deparse */
3135 str = deparse_expression_pretty(node, context, false, false,
3136 prettyFlags, 0);
3137
3138 if (rel != NULL)
3140
3141 return string_to_text(str);
3142}
3143
3144
3145/* ----------
3146 * pg_get_userbyid - Get a user name by roleid and
3147 * fallback to 'unknown (OID=n)'
3148 * ----------
3149 */
3150Datum
3152{
3153 Oid roleid = PG_GETARG_OID(0);
3154 Name result;
3157
3158 /*
3159 * Allocate space for the result
3160 */
3161 result = (Name) palloc(NAMEDATALEN);
3162 memset(NameStr(*result), 0, NAMEDATALEN);
3163
3164 /*
3165 * Get the pg_authid entry and print the result
3166 */
3169 {
3171 *result = role_rec->rolname;
3173 }
3174 else
3175 sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
3176
3177 PG_RETURN_NAME(result);
3178}
3179
3180
3181/*
3182 * pg_get_serial_sequence
3183 * Get the name of the sequence used by an identity or serial column,
3184 * formatted suitably for passing to setval, nextval or currval.
3185 * First parameter is not treated as double-quoted, second parameter
3186 * is --- see documentation for reason.
3187 */
3188Datum
3190{
3191 text *tablename = PG_GETARG_TEXT_PP(0);
3194 Oid tableOid;
3195 char *column;
3199 ScanKeyData key[3];
3200 SysScanDesc scan;
3201 HeapTuple tup;
3202
3203 /* Look up table name. Can't lock it - we might not have privileges. */
3205 tableOid = RangeVarGetRelid(tablerv, NoLock, false);
3206
3207 /* Get the number of the column */
3209
3210 attnum = get_attnum(tableOid, column);
3212 ereport(ERROR,
3214 errmsg("column \"%s\" of relation \"%s\" does not exist",
3215 column, tablerv->relname)));
3216
3217 /* Search the dependency table for the dependent sequence */
3219
3220 ScanKeyInit(&key[0],
3224 ScanKeyInit(&key[1],
3227 ObjectIdGetDatum(tableOid));
3228 ScanKeyInit(&key[2],
3232
3234 NULL, 3, key);
3235
3236 while (HeapTupleIsValid(tup = systable_getnext(scan)))
3237 {
3239
3240 /*
3241 * Look for an auto dependency (serial column) or internal dependency
3242 * (identity column) of a sequence on a column. (We need the relkind
3243 * test because indexes can also have auto dependencies on columns.)
3244 */
3245 if (deprec->classid == RelationRelationId &&
3246 deprec->objsubid == 0 &&
3247 (deprec->deptype == DEPENDENCY_AUTO ||
3248 deprec->deptype == DEPENDENCY_INTERNAL) &&
3250 {
3251 sequenceId = deprec->objid;
3252 break;
3253 }
3254 }
3255
3256 systable_endscan(scan);
3258
3260 {
3261 char *result;
3262
3264
3266 }
3267
3269}
3270
3271
3272/*
3273 * pg_get_functiondef
3274 * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
3275 * the specified function.
3276 *
3277 * Note: if you change the output format of this function, be careful not
3278 * to break psql's rules (in \ef and \sf) for identifying the start of the
3279 * function body. To wit: the function body starts on a line that begins with
3280 * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
3281 */
3282Datum
3284{
3285 Oid funcid = PG_GETARG_OID(0);
3289 Form_pg_proc proc;
3290 bool isfunction;
3291 Datum tmp;
3292 bool isnull;
3293 const char *prosrc;
3294 const char *name;
3295 const char *nsp;
3297 int oldlen;
3298
3300
3301 /* Look up the function */
3305
3306 proc = (Form_pg_proc) GETSTRUCT(proctup);
3307 name = NameStr(proc->proname);
3308
3309 if (proc->prokind == PROKIND_AGGREGATE)
3310 ereport(ERROR,
3312 errmsg("\"%s\" is an aggregate function", name)));
3313
3314 isfunction = (proc->prokind != PROKIND_PROCEDURE);
3315
3316 /*
3317 * We always qualify the function name, to ensure the right function gets
3318 * replaced.
3319 */
3320 nsp = get_namespace_name_or_temp(proc->pronamespace);
3321 appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
3322 isfunction ? "FUNCTION" : "PROCEDURE",
3324 (void) print_function_arguments(&buf, proctup, false, true);
3325 appendStringInfoString(&buf, ")\n");
3326 if (isfunction)
3327 {
3328 appendStringInfoString(&buf, " RETURNS ");
3330 appendStringInfoChar(&buf, '\n');
3331 }
3332
3334
3335 appendStringInfo(&buf, " LANGUAGE %s\n",
3336 quote_identifier(get_language_name(proc->prolang, false)));
3337
3338 /* Emit some miscellaneous options on one line */
3339 oldlen = buf.len;
3340
3341 if (proc->prokind == PROKIND_WINDOW)
3342 appendStringInfoString(&buf, " WINDOW");
3343 switch (proc->provolatile)
3344 {
3346 appendStringInfoString(&buf, " IMMUTABLE");
3347 break;
3348 case PROVOLATILE_STABLE:
3349 appendStringInfoString(&buf, " STABLE");
3350 break;
3352 break;
3353 }
3354
3355 switch (proc->proparallel)
3356 {
3357 case PROPARALLEL_SAFE:
3358 appendStringInfoString(&buf, " PARALLEL SAFE");
3359 break;
3361 appendStringInfoString(&buf, " PARALLEL RESTRICTED");
3362 break;
3363 case PROPARALLEL_UNSAFE:
3364 break;
3365 }
3366
3367 if (proc->proisstrict)
3368 appendStringInfoString(&buf, " STRICT");
3369 if (proc->prosecdef)
3370 appendStringInfoString(&buf, " SECURITY DEFINER");
3371 if (proc->proleakproof)
3372 appendStringInfoString(&buf, " LEAKPROOF");
3373
3374 /* This code for the default cost and rows should match functioncmds.c */
3375 if (proc->prolang == INTERNALlanguageId ||
3376 proc->prolang == ClanguageId)
3377 procost = 1;
3378 else
3379 procost = 100;
3380 if (proc->procost != procost)
3381 appendStringInfo(&buf, " COST %g", proc->procost);
3382
3383 if (proc->prorows > 0 && proc->prorows != 1000)
3384 appendStringInfo(&buf, " ROWS %g", proc->prorows);
3385
3386 if (proc->prosupport)
3387 {
3388 Oid argtypes[1];
3389
3390 /*
3391 * We should qualify the support function's name if it wouldn't be
3392 * resolved by lookup in the current search path.
3393 */
3394 argtypes[0] = INTERNALOID;
3395 appendStringInfo(&buf, " SUPPORT %s",
3396 generate_function_name(proc->prosupport, 1,
3397 NIL, argtypes,
3398 false, NULL, false));
3399 }
3400
3401 if (oldlen != buf.len)
3402 appendStringInfoChar(&buf, '\n');
3403
3404 /* Emit any proconfig options, one per line */
3406 if (!isnull)
3407 {
3409 int i;
3410
3412 Assert(ARR_NDIM(a) == 1);
3413 Assert(ARR_LBOUND(a)[0] == 1);
3414
3415 for (i = 1; i <= ARR_DIMS(a)[0]; i++)
3416 {
3417 Datum d;
3418
3419 d = array_ref(a, 1, &i,
3420 -1 /* varlenarray */ ,
3421 -1 /* TEXT's typlen */ ,
3422 false /* TEXT's typbyval */ ,
3423 TYPALIGN_INT /* TEXT's typalign */ ,
3424 &isnull);
3425 if (!isnull)
3426 {
3428 char *pos;
3429
3430 pos = strchr(configitem, '=');
3431 if (pos == NULL)
3432 continue;
3433 *pos++ = '\0';
3434
3435 appendStringInfo(&buf, " SET %s TO ",
3437
3438 /*
3439 * Variables that are marked GUC_LIST_QUOTE were already fully
3440 * quoted by flatten_set_variable_args() before they were put
3441 * into the proconfig array. However, because the quoting
3442 * rules used there aren't exactly like SQL's, we have to
3443 * break the list value apart and then quote the elements as
3444 * string literals. (The elements may be double-quoted as-is,
3445 * but we can't just feed them to the SQL parser; it would do
3446 * the wrong thing with elements that are zero-length or
3447 * longer than NAMEDATALEN.) Also, we need a special case for
3448 * empty lists.
3449 *
3450 * Variables that are not so marked should just be emitted as
3451 * simple string literals. If the variable is not known to
3452 * guc.c, we'll do that; this makes it unsafe to use
3453 * GUC_LIST_QUOTE for extension variables.
3454 */
3456 {
3457 List *namelist;
3458 ListCell *lc;
3459
3460 /* Parse string into list of identifiers */
3461 if (!SplitGUCList(pos, ',', &namelist))
3462 {
3463 /* this shouldn't fail really */
3464 elog(ERROR, "invalid list syntax in proconfig item");
3465 }
3466 /* Special case: represent an empty list as NULL */
3467 if (namelist == NIL)
3468 appendStringInfoString(&buf, "NULL");
3469 foreach(lc, namelist)
3470 {
3471 char *curname = (char *) lfirst(lc);
3472
3474 if (lnext(namelist, lc))
3476 }
3477 }
3478 else
3480 appendStringInfoChar(&buf, '\n');
3481 }
3482 }
3483 }
3484
3485 /* And finally the function definition ... */
3487 if (proc->prolang == SQLlanguageId && !isnull)
3488 {
3490 }
3491 else
3492 {
3493 appendStringInfoString(&buf, "AS ");
3494
3496 if (!isnull)
3497 {
3499 appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
3500 }
3501
3503 prosrc = TextDatumGetCString(tmp);
3504
3505 /*
3506 * We always use dollar quoting. Figure out a suitable delimiter.
3507 *
3508 * Since the user is likely to be editing the function body string, we
3509 * shouldn't use a short delimiter that he might easily create a
3510 * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3511 * if needed.
3512 */
3514 appendStringInfoChar(&dq, '$');
3515 appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3516 while (strstr(prosrc, dq.data) != NULL)
3517 appendStringInfoChar(&dq, 'x');
3518 appendStringInfoChar(&dq, '$');
3519
3520 appendBinaryStringInfo(&buf, dq.data, dq.len);
3521 appendStringInfoString(&buf, prosrc);
3522 appendBinaryStringInfo(&buf, dq.data, dq.len);
3523 }
3524
3525 appendStringInfoChar(&buf, '\n');
3526
3528
3530}
3531
3532/*
3533 * pg_get_function_arguments
3534 * Get a nicely-formatted list of arguments for a function.
3535 * This is everything that would go between the parentheses in
3536 * CREATE FUNCTION.
3537 */
3538Datum
3557
3558/*
3559 * pg_get_function_identity_arguments
3560 * Get a formatted list of arguments for a function.
3561 * This is everything that would go between the parentheses in
3562 * ALTER FUNCTION, etc. In particular, don't print defaults.
3563 */
3564Datum
3583
3584/*
3585 * pg_get_function_result
3586 * Get a nicely-formatted version of the result type of a function.
3587 * This is what would appear after RETURNS in CREATE FUNCTION.
3588 */
3589Datum
3614
3615/*
3616 * Guts of pg_get_function_result: append the function's return type
3617 * to the specified buffer.
3618 */
3619static void
3621{
3623 int ntabargs = 0;
3625
3627
3628 if (proc->proretset)
3629 {
3630 /* It might be a table function; try to print the arguments */
3631 appendStringInfoString(&rbuf, "TABLE(");
3633 if (ntabargs > 0)
3635 else
3637 }
3638
3639 if (ntabargs == 0)
3640 {
3641 /* Not a table function, so do the normal thing */
3642 if (proc->proretset)
3643 appendStringInfoString(&rbuf, "SETOF ");
3644 appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3645 }
3646
3647 appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3648}
3649
3650/*
3651 * Common code for pg_get_function_arguments and pg_get_function_result:
3652 * append the desired subset of arguments to buf. We print only TABLE
3653 * arguments when print_table_args is true, and all the others when it's false.
3654 * We print argument defaults only if print_defaults is true.
3655 * Function return value is the number of arguments printed.
3656 */
3657static int
3660{
3662 int numargs;
3663 Oid *argtypes;
3664 char **argnames;
3665 char *argmodes;
3666 int insertorderbyat = -1;
3667 int argsprinted;
3668 int inputargno;
3669 int nlackdefaults;
3670 List *argdefaults = NIL;
3672 int i;
3673
3674 numargs = get_func_arg_info(proctup,
3675 &argtypes, &argnames, &argmodes);
3676
3677 nlackdefaults = numargs;
3678 if (print_defaults && proc->pronargdefaults > 0)
3679 {
3681 bool isnull;
3682
3685 &isnull);
3686 if (!isnull)
3687 {
3688 char *str;
3689
3692 pfree(str);
3694 /* nlackdefaults counts only *input* arguments lacking defaults */
3695 nlackdefaults = proc->pronargs - list_length(argdefaults);
3696 }
3697 }
3698
3699 /* Check for special treatment of ordered-set aggregates */
3700 if (proc->prokind == PROKIND_AGGREGATE)
3701 {
3704
3707 elog(ERROR, "cache lookup failed for aggregate %u",
3708 proc->oid);
3710 if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3711 insertorderbyat = agg->aggnumdirectargs;
3713 }
3714
3715 argsprinted = 0;
3716 inputargno = 0;
3717 for (i = 0; i < numargs; i++)
3718 {
3719 Oid argtype = argtypes[i];
3720 char *argname = argnames ? argnames[i] : NULL;
3722 const char *modename;
3723 bool isinput;
3724
3725 switch (argmode)
3726 {
3727 case PROARGMODE_IN:
3728
3729 /*
3730 * For procedures, explicitly mark all argument modes, so as
3731 * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3732 */
3733 if (proc->prokind == PROKIND_PROCEDURE)
3734 modename = "IN ";
3735 else
3736 modename = "";
3737 isinput = true;
3738 break;
3739 case PROARGMODE_INOUT:
3740 modename = "INOUT ";
3741 isinput = true;
3742 break;
3743 case PROARGMODE_OUT:
3744 modename = "OUT ";
3745 isinput = false;
3746 break;
3748 modename = "VARIADIC ";
3749 isinput = true;
3750 break;
3751 case PROARGMODE_TABLE:
3752 modename = "";
3753 isinput = false;
3754 break;
3755 default:
3756 elog(ERROR, "invalid parameter mode '%c'", argmode);
3757 modename = NULL; /* keep compiler quiet */
3758 isinput = false;
3759 break;
3760 }
3761 if (isinput)
3762 inputargno++; /* this is a 1-based counter */
3763
3765 continue;
3766
3768 {
3769 if (argsprinted)
3771 appendStringInfoString(buf, "ORDER BY ");
3772 }
3773 else if (argsprinted)
3775
3777 if (argname && argname[0])
3778 appendStringInfo(buf, "%s ", quote_identifier(argname));
3781 {
3782 Node *expr;
3783
3785 expr = (Node *) lfirst(nextargdefault);
3787
3788 appendStringInfo(buf, " DEFAULT %s",
3789 deparse_expression(expr, NIL, false, false));
3790 }
3791 argsprinted++;
3792
3793 /* nasty hack: print the last arg twice for variadic ordered-set agg */
3794 if (argsprinted == insertorderbyat && i == numargs - 1)
3795 {
3796 i--;
3797 /* aggs shouldn't have defaults anyway, but just to be sure ... */
3798 print_defaults = false;
3799 }
3800 }
3801
3802 return argsprinted;
3803}
3804
3805static bool
3807{
3808 return (!argmodes
3812}
3813
3814/*
3815 * Append used transformed types to specified buffer
3816 */
3817static void
3819{
3820 Oid *trftypes;
3821 int ntypes;
3822
3823 ntypes = get_func_trftypes(proctup, &trftypes);
3824 if (ntypes > 0)
3825 {
3826 int i;
3827
3828 appendStringInfoString(buf, " TRANSFORM ");
3829 for (i = 0; i < ntypes; i++)
3830 {
3831 if (i != 0)
3833 appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3834 }
3836 }
3837}
3838
3839/*
3840 * Get textual representation of a function argument's default value. The
3841 * second argument of this function is the argument number among all arguments
3842 * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3843 * how information_schema.sql uses it.
3844 */
3845Datum
3847{
3848 Oid funcid = PG_GETARG_OID(0);
3851 Form_pg_proc proc;
3852 int numargs;
3853 Oid *argtypes;
3854 char **argnames;
3855 char *argmodes;
3856 int i;
3858 Node *node;
3859 char *str;
3860 int nth_inputarg;
3862 bool isnull;
3863 int nth_default;
3864
3868
3869 numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3871 {
3874 }
3875
3876 nth_inputarg = 0;
3877 for (i = 0; i < nth_arg; i++)
3879 nth_inputarg++;
3880
3883 &isnull);
3884 if (isnull)
3885 {
3888 }
3889
3892 pfree(str);
3893
3894 proc = (Form_pg_proc) GETSTRUCT(proctup);
3895
3896 /*
3897 * Calculate index into proargdefaults: proargdefaults corresponds to the
3898 * last N input arguments, where N = pronargdefaults.
3899 */
3900 nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3901
3903 {
3906 }
3908 str = deparse_expression(node, NIL, false, false);
3909
3911
3913}
3914
3915static void
3917{
3918 int numargs;
3919 Oid *argtypes;
3920 char **argnames;
3921 char *argmodes;
3922 deparse_namespace dpns = {0};
3923 Datum tmp;
3924 Node *n;
3925
3927 numargs = get_func_arg_info(proctup,
3928 &argtypes, &argnames, &argmodes);
3929 dpns.numargs = numargs;
3930 dpns.argnames = argnames;
3931
3934
3935 if (IsA(n, List))
3936 {
3937 List *stmts;
3938 ListCell *lc;
3939
3940 stmts = linitial(castNode(List, n));
3941
3942 appendStringInfoString(buf, "BEGIN ATOMIC\n");
3943
3944 foreach(lc, stmts)
3945 {
3946 Query *query = lfirst_node(Query, lc);
3947
3948 /* It seems advisable to get at least AccessShareLock on rels */
3949 AcquireRewriteLocks(query, false, false);
3950 get_query_def(query, buf, list_make1(&dpns), NULL, false,
3954 }
3955
3957 }
3958 else
3959 {
3960 Query *query = castNode(Query, n);
3961
3962 /* It seems advisable to get at least AccessShareLock on rels */
3963 AcquireRewriteLocks(query, false, false);
3964 get_query_def(query, buf, list_make1(&dpns), NULL, false,
3965 0, WRAP_COLUMN_DEFAULT, 0);
3966 }
3967}
3968
3969Datum
3971{
3972 Oid funcid = PG_GETARG_OID(0);
3975 bool isnull;
3976
3978
3979 /* Look up the function */
3983
3985 if (isnull)
3986 {
3989 }
3990
3992
3994
3996}
3997
3998
3999/*
4000 * deparse_expression - General utility for deparsing expressions
4001 *
4002 * calls deparse_expression_pretty with all prettyPrinting disabled
4003 */
4004char *
4006 bool forceprefix, bool showimplicit)
4007{
4009 showimplicit, 0, 0);
4010}
4011
4012/* ----------
4013 * deparse_expression_pretty - General utility for deparsing expressions
4014 *
4015 * expr is the node tree to be deparsed. It must be a transformed expression
4016 * tree (ie, not the raw output of gram.y).
4017 *
4018 * dpcontext is a list of deparse_namespace nodes representing the context
4019 * for interpreting Vars in the node tree. It can be NIL if no Vars are
4020 * expected.
4021 *
4022 * forceprefix is true to force all Vars to be prefixed with their table names.
4023 *
4024 * showimplicit is true to force all implicit casts to be shown explicitly.
4025 *
4026 * Tries to pretty up the output according to prettyFlags and startIndent.
4027 *
4028 * The result is a palloc'd string.
4029 * ----------
4030 */
4031static char *
4033 bool forceprefix, bool showimplicit,
4034 int prettyFlags, int startIndent)
4035{
4037 deparse_context context;
4038
4040 context.buf = &buf;
4041 context.namespaces = dpcontext;
4042 context.resultDesc = NULL;
4043 context.targetList = NIL;
4044 context.windowClause = NIL;
4045 context.varprefix = forceprefix;
4046 context.prettyFlags = prettyFlags;
4048 context.indentLevel = startIndent;
4049 context.colNamesVisible = true;
4050 context.inGroupBy = false;
4051 context.varInOrderBy = false;
4052 context.appendparents = NULL;
4053
4054 get_rule_expr(expr, &context, showimplicit);
4055
4056 return buf.data;
4057}
4058
4059/* ----------
4060 * deparse_context_for - Build deparse context for a single relation
4061 *
4062 * Given the reference name (alias) and OID of a relation, build deparsing
4063 * context for an expression referencing only that relation (as varno 1,
4064 * varlevelsup 0). This is sufficient for many uses of deparse_expression.
4065 * ----------
4066 */
4067List *
4068deparse_context_for(const char *aliasname, Oid relid)
4069{
4072
4074
4075 /* Build a minimal RTE for the rel */
4077 rte->rtekind = RTE_RELATION;
4078 rte->relid = relid;
4079 rte->relkind = RELKIND_RELATION; /* no need for exactness here */
4080 rte->rellockmode = AccessShareLock;
4081 rte->alias = makeAlias(aliasname, NIL);
4082 rte->eref = rte->alias;
4083 rte->lateral = false;
4084 rte->inh = false;
4085 rte->inFromCl = true;
4086
4087 /* Build one-element rtable */
4088 dpns->rtable = list_make1(rte);
4089 dpns->subplans = NIL;
4090 dpns->ctes = NIL;
4091 dpns->appendrels = NULL;
4094
4095 /* Return a one-deep namespace stack */
4096 return list_make1(dpns);
4097}
4098
4099/*
4100 * deparse_context_for_plan_tree - Build deparse context for a Plan tree
4101 *
4102 * When deparsing an expression in a Plan tree, we use the plan's rangetable
4103 * to resolve names of simple Vars. The initialization of column names for
4104 * this is rather expensive if the rangetable is large, and it'll be the same
4105 * for every expression in the Plan tree; so we do it just once and re-use
4106 * the result of this function for each expression. (Note that the result
4107 * is not usable until set_deparse_context_plan() is applied to it.)
4108 *
4109 * In addition to the PlannedStmt, pass the per-RTE alias names
4110 * assigned by a previous call to select_rtable_names_for_explain.
4111 */
4112List *
4114{
4116
4118
4119 /* Initialize fields that stay the same across the whole plan tree */
4120 dpns->rtable = pstmt->rtable;
4121 dpns->rtable_names = rtable_names;
4122 dpns->subplans = pstmt->subplans;
4123 dpns->ctes = NIL;
4124 if (pstmt->appendRelations)
4125 {
4126 /* Set up the array, indexed by child relid */
4127 int ntables = list_length(dpns->rtable);
4128 ListCell *lc;
4129
4130 dpns->appendrels = (AppendRelInfo **)
4131 palloc0((ntables + 1) * sizeof(AppendRelInfo *));
4132 foreach(lc, pstmt->appendRelations)
4133 {
4135 Index crelid = appinfo->child_relid;
4136
4137 Assert(crelid > 0 && crelid <= ntables);
4138 Assert(dpns->appendrels[crelid] == NULL);
4139 dpns->appendrels[crelid] = appinfo;
4140 }
4141 }
4142 else
4143 dpns->appendrels = NULL; /* don't need it */
4144
4145 /*
4146 * Set up column name aliases, ignoring any join RTEs; they don't matter
4147 * because plan trees don't contain any join alias Vars.
4148 */
4150
4151 /* Return a one-deep namespace stack */
4152 return list_make1(dpns);
4153}
4154
4155/*
4156 * set_deparse_context_plan - Specify Plan node containing expression
4157 *
4158 * When deparsing an expression in a Plan tree, we might have to resolve
4159 * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
4160 * provide the parent Plan node. Then OUTER_VAR and INNER_VAR references
4161 * can be resolved by drilling down into the left and right child plans.
4162 * Similarly, INDEX_VAR references can be resolved by reference to the
4163 * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
4164 * ForeignScan and CustomScan nodes. (Note that we don't currently support
4165 * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
4166 * for those, we can only deparse the indexqualorig fields, which won't
4167 * contain INDEX_VAR Vars.)
4168 *
4169 * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
4170 * the most-closely-nested first. This is needed to resolve PARAM_EXEC
4171 * Params. Note we assume that all the Plan nodes share the same rtable.
4172 *
4173 * For a ModifyTable plan, we might also need to resolve references to OLD/NEW
4174 * variables in the RETURNING list, so we copy the alias names of the OLD and
4175 * NEW rows from the ModifyTable plan node.
4176 *
4177 * Once this function has been called, deparse_expression() can be called on
4178 * subsidiary expression(s) of the specified Plan node. To deparse
4179 * expressions of a different Plan node in the same Plan tree, re-call this
4180 * function to identify the new parent Plan node.
4181 *
4182 * The result is the same List passed in; this is a notational convenience.
4183 */
4184List *
4186{
4188
4189 /* Should always have one-entry namespace list for Plan deparsing */
4192
4193 /* Set our attention on the specific plan node passed in */
4194 dpns->ancestors = ancestors;
4196
4197 /* For ModifyTable, set aliases for OLD and NEW in RETURNING */
4198 if (IsA(plan, ModifyTable))
4199 {
4200 dpns->ret_old_alias = ((ModifyTable *) plan)->returningOldAlias;
4201 dpns->ret_new_alias = ((ModifyTable *) plan)->returningNewAlias;
4202 }
4203
4204 return dpcontext;
4205}
4206
4207/*
4208 * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
4209 *
4210 * Determine the relation aliases we'll use during an EXPLAIN operation.
4211 * This is just a frontend to set_rtable_names. We have to expose the aliases
4212 * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
4213 */
4214List *
4216{
4218
4219 memset(&dpns, 0, sizeof(dpns));
4220 dpns.rtable = rtable;
4221 dpns.subplans = NIL;
4222 dpns.ctes = NIL;
4223 dpns.appendrels = NULL;
4225 /* We needn't bother computing column aliases yet */
4226
4227 return dpns.rtable_names;
4228}
4229
4230/*
4231 * set_rtable_names: select RTE aliases to be used in printing a query
4232 *
4233 * We fill in dpns->rtable_names with a list of names that is one-for-one with
4234 * the already-filled dpns->rtable list. Each RTE name is unique among those
4235 * in the new namespace plus any ancestor namespaces listed in
4236 * parent_namespaces.
4237 *
4238 * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
4239 *
4240 * Note that this function is only concerned with relation names, not column
4241 * names.
4242 */
4243static void
4246{
4248 HTAB *names_hash;
4250 bool found;
4251 int rtindex;
4252 ListCell *lc;
4253
4254 dpns->rtable_names = NIL;
4255 /* nothing more to do if empty rtable */
4256 if (dpns->rtable == NIL)
4257 return;
4258
4259 /*
4260 * We use a hash table to hold known names, so that this process is O(N)
4261 * not O(N^2) for N names.
4262 */
4263 hash_ctl.keysize = NAMEDATALEN;
4264 hash_ctl.entrysize = sizeof(NameHashEntry);
4266 names_hash = hash_create("set_rtable_names names",
4267 list_length(dpns->rtable),
4268 &hash_ctl,
4270
4271 /* Preload the hash table with names appearing in parent_namespaces */
4272 foreach(lc, parent_namespaces)
4273 {
4275 ListCell *lc2;
4276
4277 foreach(lc2, olddpns->rtable_names)
4278 {
4279 char *oldname = (char *) lfirst(lc2);
4280
4281 if (oldname == NULL)
4282 continue;
4283 hentry = (NameHashEntry *) hash_search(names_hash,
4284 oldname,
4285 HASH_ENTER,
4286 &found);
4287 /* we do not complain about duplicate names in parent namespaces */
4288 hentry->counter = 0;
4289 }
4290 }
4291
4292 /* Now we can scan the rtable */
4293 rtindex = 1;
4294 foreach(lc, dpns->rtable)
4295 {
4297 char *refname;
4298
4299 /* Just in case this takes an unreasonable amount of time ... */
4301
4302 if (rels_used && !bms_is_member(rtindex, rels_used))
4303 {
4304 /* Ignore unreferenced RTE */
4305 refname = NULL;
4306 }
4307 else if (rte->alias)
4308 {
4309 /* If RTE has a user-defined alias, prefer that */
4310 refname = rte->alias->aliasname;
4311 }
4312 else if (rte->rtekind == RTE_RELATION)
4313 {
4314 /* Use the current actual name of the relation */
4315 refname = get_rel_name(rte->relid);
4316 }
4317 else if (rte->rtekind == RTE_JOIN)
4318 {
4319 /* Unnamed join has no refname */
4320 refname = NULL;
4321 }
4322 else
4323 {
4324 /* Otherwise use whatever the parser assigned */
4325 refname = rte->eref->aliasname;
4326 }
4327
4328 /*
4329 * If the selected name isn't unique, append digits to make it so, and
4330 * make a new hash entry for it once we've got a unique name. For a
4331 * very long input name, we might have to truncate to stay within
4332 * NAMEDATALEN.
4333 */
4334 if (refname)
4335 {
4336 hentry = (NameHashEntry *) hash_search(names_hash,
4337 refname,
4338 HASH_ENTER,
4339 &found);
4340 if (found)
4341 {
4342 /* Name already in use, must choose a new one */
4343 int refnamelen = strlen(refname);
4344 char *modname = (char *) palloc(refnamelen + 16);
4346
4347 do
4348 {
4349 hentry->counter++;
4350 for (;;)
4351 {
4352 memcpy(modname, refname, refnamelen);
4353 sprintf(modname + refnamelen, "_%d", hentry->counter);
4354 if (strlen(modname) < NAMEDATALEN)
4355 break;
4356 /* drop chars from refname to keep all the digits */
4358 refnamelen - 1);
4359 }
4360 hentry2 = (NameHashEntry *) hash_search(names_hash,
4361 modname,
4362 HASH_ENTER,
4363 &found);
4364 } while (found);
4365 hentry2->counter = 0; /* init new hash entry */
4366 refname = modname;
4367 }
4368 else
4369 {
4370 /* Name not previously used, need only initialize hentry */
4371 hentry->counter = 0;
4372 }
4373 }
4374
4375 dpns->rtable_names = lappend(dpns->rtable_names, refname);
4376 rtindex++;
4377 }
4378
4379 hash_destroy(names_hash);
4380}
4381
4382/*
4383 * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
4384 *
4385 * For convenience, this is defined to initialize the deparse_namespace struct
4386 * from scratch.
4387 */
4388static void
4391{
4392 ListCell *lc;
4393 ListCell *lc2;
4394
4395 /* Initialize *dpns and fill rtable/ctes links */
4396 memset(dpns, 0, sizeof(deparse_namespace));
4397 dpns->rtable = query->rtable;
4398 dpns->subplans = NIL;
4399 dpns->ctes = query->cteList;
4400 dpns->appendrels = NULL;
4401 dpns->ret_old_alias = query->returningOldAlias;
4402 dpns->ret_new_alias = query->returningNewAlias;
4403
4404 /* Assign a unique relation alias to each RTE */
4406
4407 /* Initialize dpns->rtable_columns to contain zeroed structs */
4408 dpns->rtable_columns = NIL;
4409 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4410 dpns->rtable_columns = lappend(dpns->rtable_columns,
4411 palloc0(sizeof(deparse_columns)));
4412
4413 /* If it's a utility query, it won't have a jointree */
4414 if (query->jointree)
4415 {
4416 /* Detect whether global uniqueness of USING names is needed */
4417 dpns->unique_using =
4419
4420 /*
4421 * Select names for columns merged by USING, via a recursive pass over
4422 * the query jointree.
4423 */
4424 set_using_names(dpns, (Node *) query->jointree, NIL);
4425 }
4426
4427 /*
4428 * Now assign remaining column aliases for each RTE. We do this in a
4429 * linear scan of the rtable, so as to process RTEs whether or not they
4430 * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
4431 * etc). JOIN RTEs must be processed after their children, but this is
4432 * okay because they appear later in the rtable list than their children
4433 * (cf Asserts in identify_join_columns()).
4434 */
4435 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4436 {
4439
4440 if (rte->rtekind == RTE_JOIN)
4442 else
4444 }
4445}
4446
4447/*
4448 * set_simple_column_names: fill in column aliases for non-query situations
4449 *
4450 * This handles EXPLAIN and cases where we only have relation RTEs. Without
4451 * a join tree, we can't do anything smart about join RTEs, but we don't
4452 * need to, because EXPLAIN should never see join alias Vars anyway.
4453 * If we find a join RTE we'll just skip it, leaving its deparse_columns
4454 * struct all-zero. If somehow we try to deparse a join alias Var, we'll
4455 * error out cleanly because the struct's num_cols will be zero.
4456 */
4457static void
4459{
4460 ListCell *lc;
4461 ListCell *lc2;
4462
4463 /* Initialize dpns->rtable_columns to contain zeroed structs */
4464 dpns->rtable_columns = NIL;
4465 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4466 dpns->rtable_columns = lappend(dpns->rtable_columns,
4467 palloc0(sizeof(deparse_columns)));
4468
4469 /* Assign unique column aliases within each non-join RTE */
4470 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4471 {
4474
4475 if (rte->rtekind != RTE_JOIN)
4477 }
4478}
4479
4480/*
4481 * has_dangerous_join_using: search jointree for unnamed JOIN USING
4482 *
4483 * Merged columns of a JOIN USING may act differently from either of the input
4484 * columns, either because they are merged with COALESCE (in a FULL JOIN) or
4485 * because an implicit coercion of the underlying input column is required.
4486 * In such a case the column must be referenced as a column of the JOIN not as
4487 * a column of either input. And this is problematic if the join is unnamed
4488 * (alias-less): we cannot qualify the column's name with an RTE name, since
4489 * there is none. (Forcibly assigning an alias to the join is not a solution,
4490 * since that will prevent legal references to tables below the join.)
4491 * To ensure that every column in the query is unambiguously referenceable,
4492 * we must assign such merged columns names that are globally unique across
4493 * the whole query, aliasing other columns out of the way as necessary.
4494 *
4495 * Because the ensuing re-aliasing is fairly damaging to the readability of
4496 * the query, we don't do this unless we have to. So, we must pre-scan
4497 * the join tree to see if we have to, before starting set_using_names().
4498 */
4499static bool
4501{
4502 if (IsA(jtnode, RangeTblRef))
4503 {
4504 /* nothing to do here */
4505 }
4506 else if (IsA(jtnode, FromExpr))
4507 {
4508 FromExpr *f = (FromExpr *) jtnode;
4509 ListCell *lc;
4510
4511 foreach(lc, f->fromlist)
4512 {
4514 return true;
4515 }
4516 }
4517 else if (IsA(jtnode, JoinExpr))
4518 {
4519 JoinExpr *j = (JoinExpr *) jtnode;
4520
4521 /* Is it an unnamed JOIN with USING? */
4522 if (j->alias == NULL && j->usingClause)
4523 {
4524 /*
4525 * Yes, so check each join alias var to see if any of them are not
4526 * simple references to underlying columns. If so, we have a
4527 * dangerous situation and must pick unique aliases.
4528 */
4529 RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4530
4531 /* We need only examine the merged columns */
4532 for (int i = 0; i < jrte->joinmergedcols; i++)
4533 {
4534 Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4535
4536 if (!IsA(aliasvar, Var))
4537 return true;
4538 }
4539 }
4540
4541 /* Nope, but inspect children */
4542 if (has_dangerous_join_using(dpns, j->larg))
4543 return true;
4544 if (has_dangerous_join_using(dpns, j->rarg))
4545 return true;
4546 }
4547 else
4548 elog(ERROR, "unrecognized node type: %d",
4549 (int) nodeTag(jtnode));
4550 return false;
4551}
4552
4553/*
4554 * set_using_names: select column aliases to be used for merged USING columns
4555 *
4556 * We do this during a recursive descent of the query jointree.
4557 * dpns->unique_using must already be set to determine the global strategy.
4558 *
4559 * Column alias info is saved in the dpns->rtable_columns list, which is
4560 * assumed to be filled with pre-zeroed deparse_columns structs.
4561 *
4562 * parentUsing is a list of all USING aliases assigned in parent joins of
4563 * the current jointree node. (The passed-in list must not be modified.)
4564 *
4565 * Note that we do not use per-deparse_columns hash tables in this function.
4566 * The number of names that need to be assigned should be small enough that
4567 * we don't need to trouble with that.
4568 */
4569static void
4571{
4572 if (IsA(jtnode, RangeTblRef))
4573 {
4574 /* nothing to do now */
4575 }
4576 else if (IsA(jtnode, FromExpr))
4577 {
4578 FromExpr *f = (FromExpr *) jtnode;
4579 ListCell *lc;
4580
4581 foreach(lc, f->fromlist)
4582 set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4583 }
4584 else if (IsA(jtnode, JoinExpr))
4585 {
4586 JoinExpr *j = (JoinExpr *) jtnode;
4587 RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4589 int *leftattnos;
4590 int *rightattnos;
4593 int i;
4594 ListCell *lc;
4595
4596 /* Get info about the shape of the join */
4598 leftattnos = colinfo->leftattnos;
4599 rightattnos = colinfo->rightattnos;
4600
4601 /* Look up the not-yet-filled-in child deparse_columns structs */
4604
4605 /*
4606 * If this join is unnamed, then we cannot substitute new aliases at
4607 * this level, so any name requirements pushed down to here must be
4608 * pushed down again to the children.
4609 */
4610 if (rte->alias == NULL)
4611 {
4612 for (i = 0; i < colinfo->num_cols; i++)
4613 {
4614 char *colname = colinfo->colnames[i];
4615
4616 if (colname == NULL)
4617 continue;
4618
4619 /* Push down to left column, unless it's a system column */
4620 if (leftattnos[i] > 0)
4621 {
4623 leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4624 }
4625
4626 /* Same on the righthand side */
4627 if (rightattnos[i] > 0)
4628 {
4630 rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4631 }
4632 }
4633 }
4634
4635 /*
4636 * If there's a USING clause, select the USING column names and push
4637 * those names down to the children. We have two strategies:
4638 *
4639 * If dpns->unique_using is true, we force all USING names to be
4640 * unique across the whole query level. In principle we'd only need
4641 * the names of dangerous USING columns to be globally unique, but to
4642 * safely assign all USING names in a single pass, we have to enforce
4643 * the same uniqueness rule for all of them. However, if a USING
4644 * column's name has been pushed down from the parent, we should use
4645 * it as-is rather than making a uniqueness adjustment. This is
4646 * necessary when we're at an unnamed join, and it creates no risk of
4647 * ambiguity. Also, if there's a user-written output alias for a
4648 * merged column, we prefer to use that rather than the input name;
4649 * this simplifies the logic and seems likely to lead to less aliasing
4650 * overall.
4651 *
4652 * If dpns->unique_using is false, we only need USING names to be
4653 * unique within their own join RTE. We still need to honor
4654 * pushed-down names, though.
4655 *
4656 * Though significantly different in results, these two strategies are
4657 * implemented by the same code, with only the difference of whether
4658 * to put assigned names into dpns->using_names.
4659 */
4660 if (j->usingClause)
4661 {
4662 /* Copy the input parentUsing list so we don't modify it */
4663 parentUsing = list_copy(parentUsing);
4664
4665 /* USING names must correspond to the first join output columns */
4667 i = 0;
4668 foreach(lc, j->usingClause)
4669 {
4670 char *colname = strVal(lfirst(lc));
4671
4672 /* Assert it's a merged column */
4673 Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4674
4675 /* Adopt passed-down name if any, else select unique name */
4676 if (colinfo->colnames[i] != NULL)
4677 colname = colinfo->colnames[i];
4678 else
4679 {
4680 /* Prefer user-written output alias if any */
4681 if (rte->alias && i < list_length(rte->alias->colnames))
4682 colname = strVal(list_nth(rte->alias->colnames, i));
4683 /* Make it appropriately unique */
4684 colname = make_colname_unique(colname, dpns, colinfo);
4685 if (dpns->unique_using)
4686 dpns->using_names = lappend(dpns->using_names,
4687 colname);
4688 /* Save it as output column name, too */
4689 colinfo->colnames[i] = colname;
4690 }
4691
4692 /* Remember selected names for use later */
4693 colinfo->usingNames = lappend(colinfo->usingNames, colname);
4694 parentUsing = lappend(parentUsing, colname);
4695
4696 /* Push down to left column, unless it's a system column */
4697 if (leftattnos[i] > 0)
4698 {
4700 leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4701 }
4702
4703 /* Same on the righthand side */
4704 if (rightattnos[i] > 0)
4705 {
4707 rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4708 }
4709
4710 i++;
4711 }
4712 }
4713
4714 /* Mark child deparse_columns structs with correct parentUsing info */
4715 leftcolinfo->parentUsing = parentUsing;
4716 rightcolinfo->parentUsing = parentUsing;
4717
4718 /* Now recursively assign USING column names in children */
4719 set_using_names(dpns, j->larg, parentUsing);
4720 set_using_names(dpns, j->rarg, parentUsing);
4721 }
4722 else
4723 elog(ERROR, "unrecognized node type: %d",
4724 (int) nodeTag(jtnode));
4725}
4726
4727/*
4728 * set_relation_column_names: select column aliases for a non-join RTE
4729 *
4730 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4731 * If any colnames entries are already filled in, those override local
4732 * choices.
4733 */
4734static void
4737{
4738 int ncolumns;
4739 char **real_colnames;
4740 bool changed_any;
4741 int noldcolumns;
4742 int i;
4743 int j;
4744
4745 /*
4746 * Construct an array of the current "real" column names of the RTE.
4747 * real_colnames[] will be indexed by physical column number, with NULL
4748 * entries for dropped columns.
4749 */
4750 if (rte->rtekind == RTE_RELATION)
4751 {
4752 /* Relation --- look to the system catalogs for up-to-date info */
4753 Relation rel;
4754 TupleDesc tupdesc;
4755
4756 rel = relation_open(rte->relid, AccessShareLock);
4757 tupdesc = RelationGetDescr(rel);
4758
4759 ncolumns = tupdesc->natts;
4760 real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4761
4762 for (i = 0; i < ncolumns; i++)
4763 {
4764 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4765
4766 if (attr->attisdropped)
4767 real_colnames[i] = NULL;
4768 else
4769 real_colnames[i] = pstrdup(NameStr(attr->attname));
4770 }
4772 }
4773 else
4774 {
4775 /* Otherwise get the column names from eref or expandRTE() */
4776 List *colnames;
4777 ListCell *lc;
4778
4779 /*
4780 * Functions returning composites have the annoying property that some
4781 * of the composite type's columns might have been dropped since the
4782 * query was parsed. If possible, use expandRTE() to handle that
4783 * case, since it has the tedious logic needed to find out about
4784 * dropped columns. However, if we're explaining a plan, then we
4785 * don't have rte->functions because the planner thinks that won't be
4786 * needed later, and that breaks expandRTE(). So in that case we have
4787 * to rely on rte->eref, which may lead us to report a dropped
4788 * column's old name; that seems close enough for EXPLAIN's purposes.
4789 *
4790 * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4791 * which should be sufficiently up-to-date: no other RTE types can
4792 * have columns get dropped from under them after parsing.
4793 */
4794 if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
4795 {
4796 /* Since we're not creating Vars, rtindex etc. don't matter */
4798 true /* include dropped */ , &colnames, NULL);
4799 }
4800 else
4801 colnames = rte->eref->colnames;
4802
4803 ncolumns = list_length(colnames);
4804 real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4805
4806 i = 0;
4807 foreach(lc, colnames)
4808 {
4809 /*
4810 * If the column name we find here is an empty string, then it's a
4811 * dropped column, so change to NULL.
4812 */
4813 char *cname = strVal(lfirst(lc));
4814
4815 if (cname[0] == '\0')
4816 cname = NULL;
4818 i++;
4819 }
4820 }
4821
4822 /*
4823 * Ensure colinfo->colnames has a slot for each column. (It could be long
4824 * enough already, if we pushed down a name for the last column.) Note:
4825 * it's possible that there are now more columns than there were when the
4826 * query was parsed, ie colnames could be longer than rte->eref->colnames.
4827 * We must assign unique aliases to the new columns too, else there could
4828 * be unresolved conflicts when the view/rule is reloaded.
4829 */
4831 Assert(colinfo->num_cols == ncolumns);
4832
4833 /*
4834 * Make sufficiently large new_colnames and is_new_col arrays, too.
4835 *
4836 * Note: because we leave colinfo->num_new_cols zero until after the loop,
4837 * colname_is_unique will not consult that array, which is fine because it
4838 * would only be duplicate effort.
4839 */
4840 colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4841 colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4842
4843 /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4845
4846 /*
4847 * Scan the columns, select a unique alias for each one, and store it in
4848 * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4849 * entries for dropped columns, the latter omits them. Also mark
4850 * new_colnames entries as to whether they are new since parse time; this
4851 * is the case for entries beyond the length of rte->eref->colnames.
4852 */
4853 noldcolumns = list_length(rte->eref->colnames);
4854 changed_any = false;
4855 j = 0;
4856 for (i = 0; i < ncolumns; i++)
4857 {
4858 char *real_colname = real_colnames[i];
4859 char *colname = colinfo->colnames[i];
4860
4861 /* Skip dropped columns */
4862 if (real_colname == NULL)
4863 {
4864 Assert(colname == NULL); /* colnames[i] is already NULL */
4865 continue;
4866 }
4867
4868 /* If alias already assigned, that's what to use */
4869 if (colname == NULL)
4870 {
4871 /* If user wrote an alias, prefer that over real column name */
4872 if (rte->alias && i < list_length(rte->alias->colnames))
4873 colname = strVal(list_nth(rte->alias->colnames, i));
4874 else
4875 colname = real_colname;
4876
4877 /* Unique-ify and insert into colinfo */
4878 colname = make_colname_unique(colname, dpns, colinfo);
4879
4880 colinfo->colnames[i] = colname;
4881 add_to_names_hash(colinfo, colname);
4882 }
4883
4884 /* Put names of non-dropped columns in new_colnames[] too */
4885 colinfo->new_colnames[j] = colname;
4886 /* And mark them as new or not */
4887 colinfo->is_new_col[j] = (i >= noldcolumns);
4888 j++;
4889
4890 /* Remember if any assigned aliases differ from "real" name */
4891 if (!changed_any && strcmp(colname, real_colname) != 0)
4892 changed_any = true;
4893 }
4894
4895 /* We're now done needing the colinfo's names_hash */
4897
4898 /*
4899 * Set correct length for new_colnames[] array. (Note: if columns have
4900 * been added, colinfo->num_cols includes them, which is not really quite
4901 * right but is harmless, since any new columns must be at the end where
4902 * they won't affect varattnos of pre-existing columns.)
4903 */
4904 colinfo->num_new_cols = j;
4905
4906 /*
4907 * For a relation RTE, we need only print the alias column names if any
4908 * are different from the underlying "real" names. For a function RTE,
4909 * always emit a complete column alias list; this is to protect against
4910 * possible instability of the default column names (eg, from altering
4911 * parameter names). For tablefunc RTEs, we never print aliases, because
4912 * the column names are part of the clause itself. For other RTE types,
4913 * print if we changed anything OR if there were user-written column
4914 * aliases (since the latter would be part of the underlying "reality").
4915 */
4916 if (rte->rtekind == RTE_RELATION)
4917 colinfo->printaliases = changed_any;
4918 else if (rte->rtekind == RTE_FUNCTION)
4919 colinfo->printaliases = true;
4920 else if (rte->rtekind == RTE_TABLEFUNC)
4921 colinfo->printaliases = false;
4922 else if (rte->alias && rte->alias->colnames != NIL)
4923 colinfo->printaliases = true;
4924 else
4925 colinfo->printaliases = changed_any;
4926}
4927
4928/*
4929 * set_join_column_names: select column aliases for a join RTE
4930 *
4931 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4932 * If any colnames entries are already filled in, those override local
4933 * choices. Also, names for USING columns were already chosen by
4934 * set_using_names(). We further expect that column alias selection has been
4935 * completed for both input RTEs.
4936 */
4937static void
4940{
4943 bool changed_any;
4944 int noldcolumns;
4945 int nnewcolumns;
4948 int i;
4949 int j;
4950 int ic;
4951 int jc;
4952
4953 /* Look up the previously-filled-in child deparse_columns structs */
4956
4957 /*
4958 * Ensure colinfo->colnames has a slot for each column. (It could be long
4959 * enough already, if we pushed down a name for the last column.) Note:
4960 * it's possible that one or both inputs now have more columns than there
4961 * were when the query was parsed, but we'll deal with that below. We
4962 * only need entries in colnames for pre-existing columns.
4963 */
4964 noldcolumns = list_length(rte->eref->colnames);
4966 Assert(colinfo->num_cols == noldcolumns);
4967
4968 /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4970
4971 /*
4972 * Scan the join output columns, select an alias for each one, and store
4973 * it in colinfo->colnames. If there are USING columns, set_using_names()
4974 * already selected their names, so we can start the loop at the first
4975 * non-merged column.
4976 */
4977 changed_any = false;
4978 for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4979 {
4980 char *colname = colinfo->colnames[i];
4981 char *real_colname;
4982
4983 /* Join column must refer to at least one input column */
4984 Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4985
4986 /* Get the child column name */
4987 if (colinfo->leftattnos[i] > 0)
4988 real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4989 else if (colinfo->rightattnos[i] > 0)
4990 real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4991 else
4992 {
4993 /* We're joining system columns --- use eref name */
4994 real_colname = strVal(list_nth(rte->eref->colnames, i));
4995 }
4996
4997 /* If child col has been dropped, no need to assign a join colname */
4998 if (real_colname == NULL)
4999 {
5000 colinfo->colnames[i] = NULL;
5001 continue;
5002 }
5003
5004 /* In an unnamed join, just report child column names as-is */
5005 if (rte->alias == NULL)
5006 {
5007 colinfo->colnames[i] = real_colname;
5009 continue;
5010 }
5011
5012 /* If alias already assigned, that's what to use */
5013 if (colname == NULL)
5014 {
5015 /* If user wrote an alias, prefer that over real column name */
5016 if (rte->alias && i < list_length(rte->alias->colnames))
5017 colname = strVal(list_nth(rte->alias->colnames, i));
5018 else
5019 colname = real_colname;
5020
5021 /* Unique-ify and insert into colinfo */
5022 colname = make_colname_unique(colname, dpns, colinfo);
5023
5024 colinfo->colnames[i] = colname;
5025 add_to_names_hash(colinfo, colname);
5026 }
5027
5028 /* Remember if any assigned aliases differ from "real" name */
5029 if (!changed_any && strcmp(colname, real_colname) != 0)
5030 changed_any = true;
5031 }
5032
5033 /*
5034 * Calculate number of columns the join would have if it were re-parsed
5035 * now, and create storage for the new_colnames and is_new_col arrays.
5036 *
5037 * Note: colname_is_unique will be consulting new_colnames[] during the
5038 * loops below, so its not-yet-filled entries must be zeroes.
5039 */
5040 nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
5041 list_length(colinfo->usingNames);
5042 colinfo->num_new_cols = nnewcolumns;
5043 colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
5044 colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
5045
5046 /*
5047 * Generating the new_colnames array is a bit tricky since any new columns
5048 * added since parse time must be inserted in the right places. This code
5049 * must match the parser, which will order a join's columns as merged
5050 * columns first (in USING-clause order), then non-merged columns from the
5051 * left input (in attnum order), then non-merged columns from the right
5052 * input (ditto). If one of the inputs is itself a join, its columns will
5053 * be ordered according to the same rule, which means newly-added columns
5054 * might not be at the end. We can figure out what's what by consulting
5055 * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
5056 *
5057 * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
5058 * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
5059 * meanings for the current child RTE.
5060 */
5061
5062 /* Handle merged columns; they are first and can't be new */
5063 i = j = 0;
5064 while (i < noldcolumns &&
5065 colinfo->leftattnos[i] != 0 &&
5066 colinfo->rightattnos[i] != 0)
5067 {
5068 /* column name is already determined and known unique */
5069 colinfo->new_colnames[j] = colinfo->colnames[i];
5070 colinfo->is_new_col[j] = false;
5071
5072 /* build bitmapsets of child attnums of merged columns */
5073 if (colinfo->leftattnos[i] > 0)
5074 leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
5075 if (colinfo->rightattnos[i] > 0)
5077
5078 i++, j++;
5079 }
5080
5081 /* Handle non-merged left-child columns */
5082 ic = 0;
5083 for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
5084 {
5085 char *child_colname = leftcolinfo->new_colnames[jc];
5086
5087 if (!leftcolinfo->is_new_col[jc])
5088 {
5089 /* Advance ic to next non-dropped old column of left child */
5090 while (ic < leftcolinfo->num_cols &&
5091 leftcolinfo->colnames[ic] == NULL)
5092 ic++;
5093 Assert(ic < leftcolinfo->num_cols);
5094 ic++;
5095 /* If it is a merged column, we already processed it */
5097 continue;
5098 /* Else, advance i to the corresponding existing join column */
5099 while (i < colinfo->num_cols &&
5100 colinfo->colnames[i] == NULL)
5101 i++;
5102 Assert(i < colinfo->num_cols);
5103 Assert(ic == colinfo->leftattnos[i]);
5104 /* Use the already-assigned name of this column */
5105 colinfo->new_colnames[j] = colinfo->colnames[i];
5106 i++;
5107 }
5108 else
5109 {
5110 /*
5111 * Unique-ify the new child column name and assign, unless we're
5112 * in an unnamed join, in which case just copy
5113 */
5114 if (rte->alias != NULL)
5115 {
5116 colinfo->new_colnames[j] =
5118 if (!changed_any &&
5119 strcmp(colinfo->new_colnames[j], child_colname) != 0)
5120 changed_any = true;
5121 }
5122 else
5123 colinfo->new_colnames[j] = child_colname;
5124 add_to_names_hash(colinfo, colinfo->new_colnames[j]);
5125 }
5126
5127 colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
5128 j++;
5129 }
5130
5131 /* Handle non-merged right-child columns in exactly the same way */
5132 ic = 0;
5133 for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
5134 {
5135 char *child_colname = rightcolinfo->new_colnames[jc];
5136
5137 if (!rightcolinfo->is_new_col[jc])
5138 {
5139 /* Advance ic to next non-dropped old column of right child */
5140 while (ic < rightcolinfo->num_cols &&
5141 rightcolinfo->colnames[ic] == NULL)
5142 ic++;
5143 Assert(ic < rightcolinfo->num_cols);
5144 ic++;
5145 /* If it is a merged column, we already processed it */
5147 continue;
5148 /* Else, advance i to the corresponding existing join column */
5149 while (i < colinfo->num_cols &&
5150 colinfo->colnames[i] == NULL)
5151 i++;
5152 Assert(i < colinfo->num_cols);
5153 Assert(ic == colinfo->rightattnos[i]);
5154 /* Use the already-assigned name of this column */
5155 colinfo->new_colnames[j] = colinfo->colnames[i];
5156 i++;
5157 }
5158 else
5159 {
5160 /*
5161 * Unique-ify the new child column name and assign, unless we're
5162 * in an unnamed join, in which case just copy
5163 */
5164 if (rte->alias != NULL)
5165 {
5166 colinfo->new_colnames[j] =
5168 if (!changed_any &&
5169 strcmp(colinfo->new_colnames[j], child_colname) != 0)
5170 changed_any = true;
5171 }
5172 else
5173 colinfo->new_colnames[j] = child_colname;
5174 add_to_names_hash(colinfo, colinfo->new_colnames[j]);
5175 }
5176
5177 colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
5178 j++;
5179 }
5180
5181 /* Assert we processed the right number of columns */
5182#ifdef USE_ASSERT_CHECKING
5183 while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
5184 i++;
5185 Assert(i == colinfo->num_cols);
5186 Assert(j == nnewcolumns);
5187#endif
5188
5189 /* We're now done needing the colinfo's names_hash */
5191
5192 /*
5193 * For a named join, print column aliases if we changed any from the child
5194 * names. Unnamed joins cannot print aliases.
5195 */
5196 if (rte->alias != NULL)
5197 colinfo->printaliases = changed_any;
5198 else
5199 colinfo->printaliases = false;
5200}
5201
5202/*
5203 * colname_is_unique: is colname distinct from already-chosen column names?
5204 *
5205 * dpns is query-wide info, colinfo is for the column's RTE
5206 */
5207static bool
5210{
5211 int i;
5212 ListCell *lc;
5213
5214 /*
5215 * If we have a hash table, consult that instead of linearly scanning the
5216 * colinfo's strings.
5217 */
5218 if (colinfo->names_hash)
5219 {
5220 if (hash_search(colinfo->names_hash,
5221 colname,
5222 HASH_FIND,
5223 NULL) != NULL)
5224 return false;
5225 }
5226 else
5227 {
5228 /* Check against already-assigned column aliases within RTE */
5229 for (i = 0; i < colinfo->num_cols; i++)
5230 {
5231 char *oldname = colinfo->colnames[i];
5232
5233 if (oldname && strcmp(oldname, colname) == 0)
5234 return false;
5235 }
5236
5237 /*
5238 * If we're building a new_colnames array, check that too (this will
5239 * be partially but not completely redundant with the previous checks)
5240 */
5241 for (i = 0; i < colinfo->num_new_cols; i++)
5242 {
5243 char *oldname = colinfo->new_colnames[i];
5244
5245 if (oldname && strcmp(oldname, colname) == 0)
5246 return false;
5247 }
5248
5249 /*
5250 * Also check against names already assigned for parent-join USING
5251 * cols
5252 */
5253 foreach(lc, colinfo->parentUsing)
5254 {
5255 char *oldname = (char *) lfirst(lc);
5256
5257 if (strcmp(oldname, colname) == 0)
5258 return false;
5259 }
5260 }
5261
5262 /*
5263 * Also check against USING-column names that must be globally unique.
5264 * These are not hashed, but there should be few of them.
5265 */
5266 foreach(lc, dpns->using_names)
5267 {
5268 char *oldname = (char *) lfirst(lc);
5269
5270 if (strcmp(oldname, colname) == 0)
5271 return false;
5272 }
5273
5274 return true;
5275}
5276
5277/*
5278 * make_colname_unique: modify colname if necessary to make it unique
5279 *
5280 * dpns is query-wide info, colinfo is for the column's RTE
5281 */
5282static char *
5285{
5286 /*
5287 * If the selected name isn't unique, append digits to make it so. For a
5288 * very long input name, we might have to truncate to stay within
5289 * NAMEDATALEN.
5290 */
5291 if (!colname_is_unique(colname, dpns, colinfo))
5292 {
5293 int colnamelen = strlen(colname);
5294 char *modname = (char *) palloc(colnamelen + 16);
5295 int i = 0;
5296
5297 do
5298 {
5299 i++;
5300 for (;;)
5301 {
5302 memcpy(modname, colname, colnamelen);
5303 sprintf(modname + colnamelen, "_%d", i);
5304 if (strlen(modname) < NAMEDATALEN)
5305 break;
5306 /* drop chars from colname to keep all the digits */
5308 colnamelen - 1);
5309 }
5310 } while (!colname_is_unique(modname, dpns, colinfo));
5311 colname = modname;
5312 }
5313 return colname;
5314}
5315
5316/*
5317 * expand_colnames_array_to: make colinfo->colnames at least n items long
5318 *
5319 * Any added array entries are initialized to zero.
5320 */
5321static void
5323{
5324 if (n > colinfo->num_cols)
5325 {
5326 if (colinfo->colnames == NULL)
5327 colinfo->colnames = palloc0_array(char *, n);
5328 else
5329 colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
5330 colinfo->num_cols = n;
5331 }
5332}
5333
5334/*
5335 * build_colinfo_names_hash: optionally construct a hash table for colinfo
5336 */
5337static void
5339{
5341 int i;
5342 ListCell *lc;
5343
5344 /*
5345 * Use a hash table only for RTEs with at least 32 columns. (The cutoff
5346 * is somewhat arbitrary, but let's choose it so that this code does get
5347 * exercised in the regression tests.)
5348 */
5349 if (colinfo->num_cols < 32)
5350 return;
5351
5352 /*
5353 * Set up the hash table. The entries are just strings with no other
5354 * payload.
5355 */
5356 hash_ctl.keysize = NAMEDATALEN;
5357 hash_ctl.entrysize = NAMEDATALEN;
5359 colinfo->names_hash = hash_create("deparse_columns names",
5360 colinfo->num_cols + colinfo->num_new_cols,
5361 &hash_ctl,
5363
5364 /*
5365 * Preload the hash table with any names already present (these would have
5366 * come from set_using_names).
5367 */
5368 for (i = 0; i < colinfo->num_cols; i++)
5369 {
5370 char *oldname = colinfo->colnames[i];
5371
5372 if (oldname)
5374 }
5375
5376 for (i = 0; i < colinfo->num_new_cols; i++)
5377 {
5378 char *oldname = colinfo->new_colnames[i];
5379
5380 if (oldname)
5382 }
5383
5384 foreach(lc, colinfo->parentUsing)
5385 {
5386 char *oldname = (char *) lfirst(lc);
5387
5389 }
5390}
5391
5392/*
5393 * add_to_names_hash: add a string to the names_hash, if we're using one
5394 */
5395static void
5397{
5398 if (colinfo->names_hash)
5399 (void) hash_search(colinfo->names_hash,
5400 name,
5401 HASH_ENTER,
5402 NULL);
5403}
5404
5405/*
5406 * destroy_colinfo_names_hash: destroy hash table when done with it
5407 */
5408static void
5410{
5411 if (colinfo->names_hash)
5412 {
5413 hash_destroy(colinfo->names_hash);
5414 colinfo->names_hash = NULL;
5415 }
5416}
5417
5418/*
5419 * identify_join_columns: figure out where columns of a join come from
5420 *
5421 * Fills the join-specific fields of the colinfo struct, except for
5422 * usingNames which is filled later.
5423 */
5424static void
5427{
5428 int numjoincols;
5429 int jcolno;
5430 int rcolno;
5431 ListCell *lc;
5432
5433 /* Extract left/right child RT indexes */
5434 if (IsA(j->larg, RangeTblRef))
5435 colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
5436 else if (IsA(j->larg, JoinExpr))
5437 colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
5438 else
5439 elog(ERROR, "unrecognized node type in jointree: %d",
5440 (int) nodeTag(j->larg));
5441 if (IsA(j->rarg, RangeTblRef))
5442 colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
5443 else if (IsA(j->rarg, JoinExpr))
5444 colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
5445 else
5446 elog(ERROR, "unrecognized node type in jointree: %d",
5447 (int) nodeTag(j->rarg));
5448
5449 /* Assert children will be processed earlier than join in second pass */
5450 Assert(colinfo->leftrti < j->rtindex);
5451 Assert(colinfo->rightrti < j->rtindex);
5452
5453 /* Initialize result arrays with zeroes */
5454 numjoincols = list_length(jrte->joinaliasvars);
5455 Assert(numjoincols == list_length(jrte->eref->colnames));
5456 colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
5457 colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
5458
5459 /*
5460 * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
5461 * Recall that the column(s) merged due to USING are the first column(s)
5462 * of the join output. We need not do anything special while scanning
5463 * joinleftcols, but while scanning joinrightcols we must distinguish
5464 * merged from unmerged columns.
5465 */
5466 jcolno = 0;
5467 foreach(lc, jrte->joinleftcols)
5468 {
5469 int leftattno = lfirst_int(lc);
5470
5471 colinfo->leftattnos[jcolno++] = leftattno;
5472 }
5473 rcolno = 0;
5474 foreach(lc, jrte->joinrightcols)
5475 {
5476 int rightattno = lfirst_int(lc);
5477
5478 if (rcolno < jrte->joinmergedcols) /* merged column? */
5479 colinfo->rightattnos[rcolno] = rightattno;
5480 else
5481 colinfo->rightattnos[jcolno++] = rightattno;
5482 rcolno++;
5483 }
5485}
5486
5487/*
5488 * get_rtable_name: convenience function to get a previously assigned RTE alias
5489 *
5490 * The RTE must belong to the topmost namespace level in "context".
5491 */
5492static char *
5493get_rtable_name(int rtindex, deparse_context *context)
5494{
5496
5497 Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
5498 return (char *) list_nth(dpns->rtable_names, rtindex - 1);
5499}
5500
5501/*
5502 * set_deparse_plan: set up deparse_namespace to parse subexpressions
5503 * of a given Plan node
5504 *
5505 * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
5506 * and index_tlist fields. Caller must already have adjusted the ancestors
5507 * list if necessary. Note that the rtable, subplans, and ctes fields do
5508 * not need to change when shifting attention to different plan nodes in a
5509 * single plan tree.
5510 */
5511static void
5513{
5514 dpns->plan = plan;
5515
5516 /*
5517 * We special-case Append and MergeAppend to pretend that the first child
5518 * plan is the OUTER referent; we have to interpret OUTER Vars in their
5519 * tlists according to one of the children, and the first one is the most
5520 * natural choice.
5521 */
5522 if (IsA(plan, Append))
5523 dpns->outer_plan = linitial(((Append *) plan)->appendplans);
5524 else if (IsA(plan, MergeAppend))
5525 dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
5526 else
5527 dpns->outer_plan = outerPlan(plan);
5528
5529 if (dpns->outer_plan)
5530 dpns->outer_tlist = dpns->outer_plan->targetlist;
5531 else
5532 dpns->outer_tlist = NIL;
5533
5534 /*
5535 * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
5536 * use OUTER because that could someday conflict with the normal meaning.)
5537 * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
5538 * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
5539 * that as INNER referent.
5540 *
5541 * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
5542 * INNER referent. This is the join from the target relation to the data
5543 * source, and all INNER_VAR Vars in other parts of the query refer to its
5544 * targetlist.
5545 *
5546 * For ON CONFLICT DO SELECT/UPDATE we just need the inner tlist to point
5547 * to the excluded expression's tlist. (Similar to the SubqueryScan we
5548 * don't want to reuse OUTER, it's used for RETURNING in some modify table
5549 * cases, although not INSERT .. CONFLICT).
5550 */
5551 if (IsA(plan, SubqueryScan))
5552 dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
5553 else if (IsA(plan, CteScan))
5554 dpns->inner_plan = list_nth(dpns->subplans,
5555 ((CteScan *) plan)->ctePlanId - 1);
5556 else if (IsA(plan, WorkTableScan))
5557 dpns->inner_plan = find_recursive_union(dpns,
5558 (WorkTableScan *) plan);
5559 else if (IsA(plan, ModifyTable))
5560 {
5561 if (((ModifyTable *) plan)->operation == CMD_MERGE)
5562 dpns->inner_plan = outerPlan(plan);
5563 else
5564 dpns->inner_plan = plan;
5565 }
5566 else
5567 dpns->inner_plan = innerPlan(plan);
5568
5569 if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
5570 dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5571 else if (dpns->inner_plan)
5572 dpns->inner_tlist = dpns->inner_plan->targetlist;
5573 else
5574 dpns->inner_tlist = NIL;
5575
5576 /* Set up referent for INDEX_VAR Vars, if needed */
5577 if (IsA(plan, IndexOnlyScan))
5578 dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5579 else if (IsA(plan, ForeignScan))
5580 dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5581 else if (IsA(plan, CustomScan))
5582 dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5583 else
5584 dpns->index_tlist = NIL;
5585}
5586
5587/*
5588 * Locate the ancestor plan node that is the RecursiveUnion generating
5589 * the WorkTableScan's work table. We can match on wtParam, since that
5590 * should be unique within the plan tree.
5591 */
5592static Plan *
5594{
5595 ListCell *lc;
5596
5597 foreach(lc, dpns->ancestors)
5598 {
5599 Plan *ancestor = (Plan *) lfirst(lc);
5600
5601 if (IsA(ancestor, RecursiveUnion) &&
5602 ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5603 return ancestor;
5604 }
5605 elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5606 wtscan->wtParam);
5607 return NULL;
5608}
5609
5610/*
5611 * push_child_plan: temporarily transfer deparsing attention to a child plan
5612 *
5613 * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
5614 * deparse context in case the referenced expression itself uses
5615 * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
5616 * affecting levelsup issues (although in a Plan tree there really shouldn't
5617 * be any).
5618 *
5619 * Caller must provide a local deparse_namespace variable to save the
5620 * previous state for pop_child_plan.
5621 */
5622static void
5625{
5626 /* Save state for restoration later */
5627 *save_dpns = *dpns;
5628
5629 /* Link current plan node into ancestors list */
5630 dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5631
5632 /* Set attention on selected child */
5634}
5635
5636/*
5637 * pop_child_plan: undo the effects of push_child_plan
5638 */
5639static void
5641{
5642 List *ancestors;
5643
5644 /* Get rid of ancestors list cell added by push_child_plan */
5645 ancestors = list_delete_first(dpns->ancestors);
5646
5647 /* Restore fields changed by push_child_plan */
5648 *dpns = *save_dpns;
5649
5650 /* Make sure dpns->ancestors is right (may be unnecessary) */
5651 dpns->ancestors = ancestors;
5652}
5653
5654/*
5655 * push_ancestor_plan: temporarily transfer deparsing attention to an
5656 * ancestor plan
5657 *
5658 * When expanding a Param reference, we must adjust the deparse context
5659 * to match the plan node that contains the expression being printed;
5660 * otherwise we'd fail if that expression itself contains a Param or
5661 * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
5662 *
5663 * The target ancestor is conveniently identified by the ListCell holding it
5664 * in dpns->ancestors.
5665 *
5666 * Caller must provide a local deparse_namespace variable to save the
5667 * previous state for pop_ancestor_plan.
5668 */
5669static void
5672{
5674
5675 /* Save state for restoration later */
5676 *save_dpns = *dpns;
5677
5678 /* Build a new ancestor list with just this node's ancestors */
5679 dpns->ancestors =
5680 list_copy_tail(dpns->ancestors,
5681 list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5682
5683 /* Set attention on selected ancestor */
5685}
5686
5687/*
5688 * pop_ancestor_plan: undo the effects of push_ancestor_plan
5689 */
5690static void
5692{
5693 /* Free the ancestor list made in push_ancestor_plan */
5694 list_free(dpns->ancestors);
5695
5696 /* Restore fields changed by push_ancestor_plan */
5697 *dpns = *save_dpns;
5698}
5699
5700
5701/* ----------
5702 * make_ruledef - reconstruct the CREATE RULE command
5703 * for a given pg_rewrite tuple
5704 * ----------
5705 */
5706static void
5708 int prettyFlags)
5709{
5710 char *rulename;
5711 char ev_type;
5712 Oid ev_class;
5713 bool is_instead;
5714 char *ev_qual;
5715 char *ev_action;
5716 List *actions;
5719 int fno;
5720 Datum dat;
5721 bool isnull;
5722
5723 /*
5724 * Get the attribute values from the rules tuple
5725 */
5726 fno = SPI_fnumber(rulettc, "rulename");
5727 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5728 Assert(!isnull);
5729 rulename = NameStr(*(DatumGetName(dat)));
5730
5731 fno = SPI_fnumber(rulettc, "ev_type");
5732 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5733 Assert(!isnull);
5734 ev_type = DatumGetChar(dat);
5735
5736 fno = SPI_fnumber(rulettc, "ev_class");
5737 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5738 Assert(!isnull);
5740
5741 fno = SPI_fnumber(rulettc, "is_instead");
5742 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5743 Assert(!isnull);
5744 is_instead = DatumGetBool(dat);
5745
5746 fno = SPI_fnumber(rulettc, "ev_qual");
5748 Assert(ev_qual != NULL);
5749
5750 fno = SPI_fnumber(rulettc, "ev_action");
5752 Assert(ev_action != NULL);
5753 actions = (List *) stringToNode(ev_action);
5754 if (actions == NIL)
5755 elog(ERROR, "invalid empty ev_action list");
5756
5758
5759 /*
5760 * Build the rules definition text
5761 */
5762 appendStringInfo(buf, "CREATE RULE %s AS",
5763 quote_identifier(rulename));
5764
5765 if (prettyFlags & PRETTYFLAG_INDENT)
5766 appendStringInfoString(buf, "\n ON ");
5767 else
5768 appendStringInfoString(buf, " ON ");
5769
5770 /* The event the rule is fired for */
5771 switch (ev_type)
5772 {
5773 case '1':
5774 appendStringInfoString(buf, "SELECT");
5776 break;
5777
5778 case '2':
5779 appendStringInfoString(buf, "UPDATE");
5780 break;
5781
5782 case '3':
5783 appendStringInfoString(buf, "INSERT");
5784 break;
5785
5786 case '4':
5787 appendStringInfoString(buf, "DELETE");
5788 break;
5789
5790 default:
5791 ereport(ERROR,
5793 errmsg("rule \"%s\" has unsupported event type %d",
5794 rulename, ev_type)));
5795 break;
5796 }
5797
5798 /* The relation the rule is fired on */
5799 appendStringInfo(buf, " TO %s",
5800 (prettyFlags & PRETTYFLAG_SCHEMA) ?
5803
5804 /* If the rule has an event qualification, add it */
5805 if (strcmp(ev_qual, "<>") != 0)
5806 {
5807 Node *qual;
5808 Query *query;
5809 deparse_context context;
5811
5812 if (prettyFlags & PRETTYFLAG_INDENT)
5814 appendStringInfoString(buf, " WHERE ");
5815
5816 qual = stringToNode(ev_qual);
5817
5818 /*
5819 * We need to make a context for recognizing any Vars in the qual
5820 * (which can only be references to OLD and NEW). Use the rtable of
5821 * the first query in the action list for this purpose.
5822 */
5823 query = (Query *) linitial(actions);
5824
5825 /*
5826 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5827 * into the SELECT, and that's what we need to look at. (Ugly kluge
5828 * ... try to fix this when we redesign querytrees.)
5829 */
5830 query = getInsertSelectQuery(query, NULL);
5831
5832 /* Must acquire locks right away; see notes in get_query_def() */
5833 AcquireRewriteLocks(query, false, false);
5834
5835 context.buf = buf;
5836 context.namespaces = list_make1(&dpns);
5837 context.resultDesc = NULL;
5838 context.targetList = NIL;
5839 context.windowClause = NIL;
5840 context.varprefix = (list_length(query->rtable) != 1);
5841 context.prettyFlags = prettyFlags;
5843 context.indentLevel = PRETTYINDENT_STD;
5844 context.colNamesVisible = true;
5845 context.inGroupBy = false;
5846 context.varInOrderBy = false;
5847 context.appendparents = NULL;
5848
5849 set_deparse_for_query(&dpns, query, NIL);
5850
5851 get_rule_expr(qual, &context, false);
5852 }
5853
5854 appendStringInfoString(buf, " DO ");
5855
5856 /* The INSTEAD keyword (if so) */
5857 if (is_instead)
5858 appendStringInfoString(buf, "INSTEAD ");
5859
5860 /* Finally the rules actions */
5861 if (list_length(actions) > 1)
5862 {
5863 ListCell *action;
5864 Query *query;
5865
5867 foreach(action, actions)
5868 {
5869 query = (Query *) lfirst(action);
5870 get_query_def(query, buf, NIL, viewResultDesc, true,
5871 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5872 if (prettyFlags)
5874 else
5876 }
5878 }
5879 else
5880 {
5881 Query *query;
5882
5883 query = (Query *) linitial(actions);
5884 get_query_def(query, buf, NIL, viewResultDesc, true,
5885 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5887 }
5888
5890}
5891
5892
5893/* ----------
5894 * make_viewdef - reconstruct the SELECT part of a
5895 * view rewrite rule
5896 * ----------
5897 */
5898static void
5900 int prettyFlags, int wrapColumn)
5901{
5902 Query *query;
5903 char ev_type;
5904 Oid ev_class;
5905 bool is_instead;
5906 char *ev_qual;
5907 char *ev_action;
5908 List *actions;
5910 int fno;
5911 Datum dat;
5912 bool isnull;
5913
5914 /*
5915 * Get the attribute values from the rules tuple
5916 */
5917 fno = SPI_fnumber(rulettc, "ev_type");
5918 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5919 Assert(!isnull);
5920 ev_type = DatumGetChar(dat);
5921
5922 fno = SPI_fnumber(rulettc, "ev_class");
5923 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5924 Assert(!isnull);
5926
5927 fno = SPI_fnumber(rulettc, "is_instead");
5928 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5929 Assert(!isnull);
5930 is_instead = DatumGetBool(dat);
5931
5932 fno = SPI_fnumber(rulettc, "ev_qual");
5934 Assert(ev_qual != NULL);
5935
5936 fno = SPI_fnumber(rulettc, "ev_action");
5938 Assert(ev_action != NULL);
5939 actions = (List *) stringToNode(ev_action);
5940
5941 if (list_length(actions) != 1)
5942 {
5943 /* keep output buffer empty and leave */
5944 return;
5945 }
5946
5947 query = (Query *) linitial(actions);
5948
5949 if (ev_type != '1' || !is_instead ||
5950 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5951 {
5952 /* keep output buffer empty and leave */
5953 return;
5954 }
5955
5957
5959 prettyFlags, wrapColumn, 0);
5961
5963}
5964
5965
5966/* ----------
5967 * get_query_def - Parse back one query parsetree
5968 *
5969 * query: parsetree to be displayed
5970 * buf: output text is appended to buf
5971 * parentnamespace: list (initially empty) of outer-level deparse_namespace's
5972 * resultDesc: if not NULL, the output tuple descriptor for the view
5973 * represented by a SELECT query. We use the column names from it
5974 * to label SELECT output columns, in preference to names in the query
5975 * colNamesVisible: true if the surrounding context cares about the output
5976 * column names at all (as, for example, an EXISTS() context does not);
5977 * when false, we can suppress dummy column labels such as "?column?"
5978 * prettyFlags: bitmask of PRETTYFLAG_XXX options
5979 * wrapColumn: maximum line length, or -1 to disable wrapping
5980 * startIndent: initial indentation amount
5981 * ----------
5982 */
5983static void
5985 TupleDesc resultDesc, bool colNamesVisible,
5986 int prettyFlags, int wrapColumn, int startIndent)
5987{
5988 deparse_context context;
5990 int rtable_size;
5991
5992 /* Guard against excessively long or deeply-nested queries */
5995
5996 rtable_size = query->hasGroupRTE ?
5997 list_length(query->rtable) - 1 :
5998 list_length(query->rtable);
5999
6000 /*
6001 * Replace any Vars in the query's targetlist and havingQual that
6002 * reference GROUP outputs with the underlying grouping expressions.
6003 *
6004 * We can safely pass NULL for the root here. Preserving varnullingrels
6005 * makes no difference to the deparsed source text.
6006 */
6007 if (query->hasGroupRTE)
6008 {
6009 query->targetList = (List *)
6010 flatten_group_exprs(NULL, query, (Node *) query->targetList);
6011 query->havingQual =
6012 flatten_group_exprs(NULL, query, query->havingQual);
6013 }
6014
6015 /*
6016 * Before we begin to examine the query, acquire locks on referenced
6017 * relations, and fix up deleted columns in JOIN RTEs. This ensures
6018 * consistent results. Note we assume it's OK to scribble on the passed
6019 * querytree!
6020 *
6021 * We are only deparsing the query (we are not about to execute it), so we
6022 * only need AccessShareLock on the relations it mentions.
6023 */
6024 AcquireRewriteLocks(query, false, false);
6025
6026 context.buf = buf;
6028 context.resultDesc = NULL;
6029 context.targetList = NIL;
6030 context.windowClause = NIL;
6031 context.varprefix = (parentnamespace != NIL ||
6032 rtable_size != 1);
6033 context.prettyFlags = prettyFlags;
6034 context.wrapColumn = wrapColumn;
6035 context.indentLevel = startIndent;
6036 context.colNamesVisible = colNamesVisible;
6037 context.inGroupBy = false;
6038 context.varInOrderBy = false;
6039 context.appendparents = NULL;
6040
6042
6043 switch (query->commandType)
6044 {
6045 case CMD_SELECT:
6046 /* We set context.resultDesc only if it's a SELECT */
6047 context.resultDesc = resultDesc;
6048 get_select_query_def(query, &context);
6049 break;
6050
6051 case CMD_UPDATE:
6052 get_update_query_def(query, &context);
6053 break;
6054
6055 case CMD_INSERT:
6056 get_insert_query_def(query, &context);
6057 break;
6058
6059 case CMD_DELETE:
6060 get_delete_query_def(query, &context);
6061 break;
6062
6063 case CMD_MERGE:
6064 get_merge_query_def(query, &context);
6065 break;
6066
6067 case CMD_NOTHING:
6068 appendStringInfoString(buf, "NOTHING");
6069 break;
6070
6071 case CMD_UTILITY:
6072 get_utility_query_def(query, &context);
6073 break;
6074
6075 default:
6076 elog(ERROR, "unrecognized query command type: %d",
6077 query->commandType);
6078 break;
6079 }
6080}
6081
6082/* ----------
6083 * get_values_def - Parse back a VALUES list
6084 * ----------
6085 */
6086static void
6087get_values_def(List *values_lists, deparse_context *context)
6088{
6089 StringInfo buf = context->buf;
6090 bool first_list = true;
6091 ListCell *vtl;
6092
6093 appendStringInfoString(buf, "VALUES ");
6094
6095 foreach(vtl, values_lists)
6096 {
6097 List *sublist = (List *) lfirst(vtl);
6098 bool first_col = true;
6099 ListCell *lc;
6100
6101 if (first_list)
6102 first_list = false;
6103 else
6105
6107 foreach(lc, sublist)
6108 {
6109 Node *col = (Node *) lfirst(lc);
6110
6111 if (first_col)
6112 first_col = false;
6113 else
6115
6116 /*
6117 * Print the value. Whole-row Vars need special treatment.
6118 */
6119 get_rule_expr_toplevel(col, context, false);
6120 }
6122 }
6123}
6124
6125/* ----------
6126 * get_with_clause - Parse back a WITH clause
6127 * ----------
6128 */
6129static void
6131{
6132 StringInfo buf = context->buf;
6133 const char *sep;
6134 ListCell *l;
6135
6136 if (query->cteList == NIL)
6137 return;
6138
6139 if (PRETTY_INDENT(context))
6140 {
6141 context->indentLevel += PRETTYINDENT_STD;
6143 }
6144
6145 if (query->hasRecursive)
6146 sep = "WITH RECURSIVE ";
6147 else
6148 sep = "WITH ";
6149 foreach(l, query->cteList)
6150 {
6152
6155 if (cte->aliascolnames)
6156 {
6157 bool first = true;
6158 ListCell *col;
6159
6161 foreach(col, cte->aliascolnames)
6162 {
6163 if (first)
6164 first = false;
6165 else
6169 }
6171 }
6172 appendStringInfoString(buf, " AS ");
6173 switch (cte->ctematerialized)
6174 {
6176 break;
6178 appendStringInfoString(buf, "MATERIALIZED ");
6179 break;
6181 appendStringInfoString(buf, "NOT MATERIALIZED ");
6182 break;
6183 }
6185 if (PRETTY_INDENT(context))
6186 appendContextKeyword(context, "", 0, 0, 0);
6187 get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
6188 true,
6189 context->prettyFlags, context->wrapColumn,
6190 context->indentLevel);
6191 if (PRETTY_INDENT(context))
6192 appendContextKeyword(context, "", 0, 0, 0);
6194
6195 if (cte->search_clause)
6196 {
6197 bool first = true;
6198 ListCell *lc;
6199
6200 appendStringInfo(buf, " SEARCH %s FIRST BY ",
6201 cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
6202
6203 foreach(lc, cte->search_clause->search_col_list)
6204 {
6205 if (first)
6206 first = false;
6207 else
6211 }
6212
6213 appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
6214 }
6215
6216 if (cte->cycle_clause)
6217 {
6218 bool first = true;
6219 ListCell *lc;
6220
6221 appendStringInfoString(buf, " CYCLE ");
6222
6223 foreach(lc, cte->cycle_clause->cycle_col_list)
6224 {
6225 if (first)
6226 first = false;
6227 else
6231 }
6232
6233 appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
6234
6235 {
6236 Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
6237 Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
6238
6239 if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
6240 cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
6241 {
6242 appendStringInfoString(buf, " TO ");
6243 get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
6244 appendStringInfoString(buf, " DEFAULT ");
6245 get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
6246 }
6247 }
6248
6249 appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
6250 }
6251
6252 sep = ", ";
6253 }
6254
6255 if (PRETTY_INDENT(context))
6256 {
6257 context->indentLevel -= PRETTYINDENT_STD;
6258 appendContextKeyword(context, "", 0, 0, 0);
6259 }
6260 else
6262}
6263
6264/* ----------
6265 * get_select_query_def - Parse back a SELECT parsetree
6266 * ----------
6267 */
6268static void
6270{
6271 StringInfo buf = context->buf;
6272 bool force_colno;
6273 ListCell *l;
6274
6275 /* Insert the WITH clause if given */
6276 get_with_clause(query, context);
6277
6278 /* Subroutines may need to consult the SELECT targetlist and windowClause */
6279 context->targetList = query->targetList;
6280 context->windowClause = query->windowClause;
6281
6282 /*
6283 * If the Query node has a setOperations tree, then it's the top level of
6284 * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
6285 * fields are interesting in the top query itself.
6286 */
6287 if (query->setOperations)
6288 {
6289 get_setop_query(query->setOperations, query, context);
6290 /* ORDER BY clauses must be simple in this case */
6291 force_colno = true;
6292 }
6293 else
6294 {
6295 get_basic_select_query(query, context);
6296 force_colno = false;
6297 }
6298
6299 /* Add the ORDER BY clause if given */
6300 if (query->sortClause != NIL)
6301 {
6302 appendContextKeyword(context, " ORDER BY ",
6304 get_rule_orderby(query->sortClause, query->targetList,
6305 force_colno, context);
6306 }
6307
6308 /*
6309 * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
6310 * standard spelling of LIMIT.
6311 */
6312 if (query->limitOffset != NULL)
6313 {
6314 appendContextKeyword(context, " OFFSET ",
6316 get_rule_expr(query->limitOffset, context, false);
6317 }
6318 if (query->limitCount != NULL)
6319 {
6320 if (query->limitOption == LIMIT_OPTION_WITH_TIES)
6321 {
6322 /*
6323 * The limitCount arg is a c_expr, so it needs parens. Simple
6324 * literals and function expressions would not need parens, but
6325 * unfortunately it's hard to tell if the expression will be
6326 * printed as a simple literal like 123 or as a typecast
6327 * expression, like '-123'::int4. The grammar accepts the former
6328 * without quoting, but not the latter.
6329 */
6330 appendContextKeyword(context, " FETCH FIRST ",
6333 get_rule_expr(query->limitCount, context, false);
6335 appendStringInfoString(buf, " ROWS WITH TIES");
6336 }
6337 else
6338 {
6339 appendContextKeyword(context, " LIMIT ",
6341 if (IsA(query->limitCount, Const) &&
6342 ((Const *) query->limitCount)->constisnull)
6344 else
6345 get_rule_expr(query->limitCount, context, false);
6346 }
6347 }
6348
6349 /* Add FOR [KEY] UPDATE/SHARE clauses if present */
6350 if (query->hasForUpdate)
6351 {
6352 foreach(l, query->rowMarks)
6353 {
6354 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
6355
6356 /* don't print implicit clauses */
6357 if (rc->pushedDown)
6358 continue;
6359
6360 appendContextKeyword(context,
6363
6364 appendStringInfo(buf, " OF %s",
6366 context)));
6367 if (rc->waitPolicy == LockWaitError)
6368 appendStringInfoString(buf, " NOWAIT");
6369 else if (rc->waitPolicy == LockWaitSkip)
6370 appendStringInfoString(buf, " SKIP LOCKED");
6371 }
6372 }
6373}
6374
6375static char *
6377{
6378 switch (strength)
6379 {
6380 case LCS_NONE:
6381 /* we intentionally throw an error for LCS_NONE */
6382 elog(ERROR, "unrecognized LockClauseStrength %d",
6383 (int) strength);
6384 break;
6385 case LCS_FORKEYSHARE:
6386 return " FOR KEY SHARE";
6387 case LCS_FORSHARE:
6388 return " FOR SHARE";
6389 case LCS_FORNOKEYUPDATE:
6390 return " FOR NO KEY UPDATE";
6391 case LCS_FORUPDATE:
6392 return " FOR UPDATE";
6393 }
6394 return NULL; /* keep compiler quiet */
6395}
6396
6397/*
6398 * Detect whether query looks like SELECT ... FROM VALUES(),
6399 * with no need to rename the output columns of the VALUES RTE.
6400 * If so, return the VALUES RTE. Otherwise return NULL.
6401 */
6402static RangeTblEntry *
6404{
6405 RangeTblEntry *result = NULL;
6406 ListCell *lc;
6407
6408 /*
6409 * We want to detect a match even if the Query also contains OLD or NEW
6410 * rule RTEs. So the idea is to scan the rtable and see if there is only
6411 * one inFromCl RTE that is a VALUES RTE.
6412 */
6413 foreach(lc, query->rtable)
6414 {
6416
6417 if (rte->rtekind == RTE_VALUES && rte->inFromCl)
6418 {
6419 if (result)
6420 return NULL; /* multiple VALUES (probably not possible) */
6421 result = rte;
6422 }
6423 else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
6424 continue; /* ignore rule entries */
6425 else
6426 return NULL; /* something else -> not simple VALUES */
6427 }
6428
6429 /*
6430 * We don't need to check the targetlist in any great detail, because
6431 * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
6432 * appear inside auto-generated sub-queries with very restricted
6433 * structure. However, DefineView might have modified the tlist by
6434 * injecting new column aliases, or we might have some other column
6435 * aliases forced by a resultDesc. We can only simplify if the RTE's
6436 * column names match the names that get_target_list() would select.
6437 */
6438 if (result)
6439 {
6440 ListCell *lcn;
6441 int colno;
6442
6443 if (list_length(query->targetList) != list_length(result->eref->colnames))
6444 return NULL; /* this probably cannot happen */
6445 colno = 0;
6446 forboth(lc, query->targetList, lcn, result->eref->colnames)
6447 {
6449 char *cname = strVal(lfirst(lcn));
6450 char *colname;
6451
6452 if (tle->resjunk)
6453 return NULL; /* this probably cannot happen */
6454
6455 /* compute name that get_target_list would use for column */
6456 colno++;
6457 if (resultDesc && colno <= resultDesc->natts)
6458 colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6459 else
6460 colname = tle->resname;
6461
6462 /* does it match the VALUES RTE? */
6463 if (colname == NULL || strcmp(colname, cname) != 0)
6464 return NULL; /* column name has been changed */
6465 }
6466 }
6467
6468 return result;
6469}
6470
6471static void
6473{
6474 StringInfo buf = context->buf;
6476 char *sep;
6477 ListCell *l;
6478
6479 if (PRETTY_INDENT(context))
6480 {
6481 context->indentLevel += PRETTYINDENT_STD;
6483 }
6484
6485 /*
6486 * If the query looks like SELECT * FROM (VALUES ...), then print just the
6487 * VALUES part. This reverses what transformValuesClause() did at parse
6488 * time.
6489 */
6490 values_rte = get_simple_values_rte(query, context->resultDesc);
6491 if (values_rte)
6492 {
6493 get_values_def(values_rte->values_lists, context);
6494 return;
6495 }
6496
6497 /*
6498 * Build up the query string - first we say SELECT
6499 */
6500 if (query->isReturn)
6501 appendStringInfoString(buf, "RETURN");
6502 else
6503 appendStringInfoString(buf, "SELECT");
6504
6505 /* Add the DISTINCT clause if given */
6506 if (query->distinctClause != NIL)
6507 {
6508 if (query->hasDistinctOn)
6509 {
6510 appendStringInfoString(buf, " DISTINCT ON (");
6511 sep = "";
6512 foreach(l, query->distinctClause)
6513 {
6515
6517 get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList,
6518 false, context);
6519 sep = ", ";
6520 }
6522 }
6523 else
6524 appendStringInfoString(buf, " DISTINCT");
6525 }
6526
6527 /* Then we tell what to select (the targetlist) */
6528 get_target_list(query->targetList, context);
6529
6530 /* Add the FROM clause if needed */
6531 get_from_clause(query, " FROM ", context);
6532
6533 /* Add the WHERE clause if given */
6534 if (query->jointree->quals != NULL)
6535 {
6536 appendContextKeyword(context, " WHERE ",
6538 get_rule_expr(query->jointree->quals, context, false);
6539 }
6540
6541 /* Add the GROUP BY clause if given */
6542 if (query->groupClause != NULL || query->groupingSets != NULL)
6543 {
6544 bool save_ingroupby;
6545
6546 appendContextKeyword(context, " GROUP BY ",
6548 if (query->groupDistinct)
6549 appendStringInfoString(buf, "DISTINCT ");
6550
6551 save_ingroupby = context->inGroupBy;
6552 context->inGroupBy = true;
6553
6554 if (query->groupByAll)
6556 else if (query->groupingSets == NIL)
6557 {
6558 sep = "";
6559 foreach(l, query->groupClause)
6560 {
6562
6564 get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList,
6565 false, context);
6566 sep = ", ";
6567 }
6568 }
6569 else
6570 {
6571 sep = "";
6572 foreach(l, query->groupingSets)
6573 {
6574 GroupingSet *grp = lfirst(l);
6575
6577 get_rule_groupingset(grp, query->targetList, true, context);
6578 sep = ", ";
6579 }
6580 }
6581
6582 context->inGroupBy = save_ingroupby;
6583 }
6584
6585 /* Add the HAVING clause if given */
6586 if (query->havingQual != NULL)
6587 {
6588 appendContextKeyword(context, " HAVING ",
6590 get_rule_expr(query->havingQual, context, false);
6591 }
6592
6593 /* Add the WINDOW clause if needed */
6594 if (query->windowClause != NIL)
6595 get_rule_windowclause(query, context);
6596}
6597
6598/* ----------
6599 * get_target_list - Parse back a SELECT target list
6600 *
6601 * This is also used for RETURNING lists in INSERT/UPDATE/DELETE/MERGE.
6602 * ----------
6603 */
6604static void
6606{
6607 StringInfo buf = context->buf;
6609 bool last_was_multiline = false;
6610 char *sep;
6611 int colno;
6612 ListCell *l;
6613
6614 /* we use targetbuf to hold each TLE's text temporarily */
6616
6617 sep = " ";
6618 colno = 0;
6619 foreach(l, targetList)
6620 {
6622 char *colname;
6623 char *attname;
6624
6625 if (tle->resjunk)
6626 continue; /* ignore junk entries */
6627
6629 sep = ", ";
6630 colno++;
6631
6632 /*
6633 * Put the new field text into targetbuf so we can decide after we've
6634 * got it whether or not it needs to go on a new line.
6635 */
6637 context->buf = &targetbuf;
6638
6639 /*
6640 * We special-case Var nodes rather than using get_rule_expr. This is
6641 * needed because get_rule_expr will display a whole-row Var as
6642 * "foo.*", which is the preferred notation in most contexts, but at
6643 * the top level of a SELECT list it's not right (the parser will
6644 * expand that notation into multiple columns, yielding behavior
6645 * different from a whole-row Var). We need to call get_variable
6646 * directly so that we can tell it to do the right thing, and so that
6647 * we can get the attribute name which is the default AS label.
6648 */
6649 if (tle->expr && (IsA(tle->expr, Var)))
6650 {
6651 attname = get_variable((Var *) tle->expr, 0, true, context);
6652 }
6653 else
6654 {
6655 get_rule_expr((Node *) tle->expr, context, true);
6656
6657 /*
6658 * When colNamesVisible is true, we should always show the
6659 * assigned column name explicitly. Otherwise, show it only if
6660 * it's not FigureColname's fallback.
6661 */
6662 attname = context->colNamesVisible ? NULL : "?column?";
6663 }
6664
6665 /*
6666 * Figure out what the result column should be called. In the context
6667 * of a view, use the view's tuple descriptor (so as to pick up the
6668 * effects of any column RENAME that's been done on the view).
6669 * Otherwise, just use what we can find in the TLE.
6670 */
6671 if (context->resultDesc && colno <= context->resultDesc->natts)
6672 colname = NameStr(TupleDescAttr(context->resultDesc,
6673 colno - 1)->attname);
6674 else
6675 colname = tle->resname;
6676
6677 /* Show AS unless the column's name is correct as-is */
6678 if (colname) /* resname could be NULL */
6679 {
6680 if (attname == NULL || strcmp(attname, colname) != 0)
6681 appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6682 }
6683
6684 /* Restore context's output buffer */
6685 context->buf = buf;
6686
6687 /* Consider line-wrapping if enabled */
6688 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6689 {
6690 int leading_nl_pos;
6691
6692 /* Does the new field start with a new line? */
6693 if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
6694 leading_nl_pos = 0;
6695 else
6696 leading_nl_pos = -1;
6697
6698 /* If so, we shouldn't add anything */
6699 if (leading_nl_pos >= 0)
6700 {
6701 /* instead, remove any trailing spaces currently in buf */
6703 }
6704 else
6705 {
6706 char *trailing_nl;
6707
6708 /* Locate the start of the current line in the output buffer */
6709 trailing_nl = strrchr(buf->data, '\n');
6710 if (trailing_nl == NULL)
6711 trailing_nl = buf->data;
6712 else
6713 trailing_nl++;
6714
6715 /*
6716 * Add a newline, plus some indentation, if the new field is
6717 * not the first and either the new field would cause an
6718 * overflow or the last field used more than one line.
6719 */
6720 if (colno > 1 &&
6721 ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
6725 }
6726
6727 /* Remember this field's multiline status for next iteration */
6729 (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6730 }
6731
6732 /* Add the new field */
6734 }
6735
6736 /* clean up */
6737 pfree(targetbuf.data);
6738}
6739
6740static void
6742{
6743 StringInfo buf = context->buf;
6744
6745 if (query->returningList)
6746 {
6747 bool have_with = false;
6748
6749 appendContextKeyword(context, " RETURNING",
6751
6752 /* Add WITH (OLD/NEW) options, if they're not the defaults */
6753 if (query->returningOldAlias && strcmp(query->returningOldAlias, "old") != 0)
6754 {
6755 appendStringInfo(buf, " WITH (OLD AS %s",
6756 quote_identifier(query->returningOldAlias));
6757 have_with = true;
6758 }
6759 if (query->returningNewAlias && strcmp(query->returningNewAlias, "new") != 0)
6760 {
6761 if (have_with)
6762 appendStringInfo(buf, ", NEW AS %s",
6763 quote_identifier(query->returningNewAlias));
6764 else
6765 {
6766 appendStringInfo(buf, " WITH (NEW AS %s",
6767 quote_identifier(query->returningNewAlias));
6768 have_with = true;
6769 }
6770 }
6771 if (have_with)
6773
6774 /* Add the returning expressions themselves */
6775 get_target_list(query->returningList, context);
6776 }
6777}
6778
6779static void
6781{
6782 StringInfo buf = context->buf;
6783 bool need_paren;
6784
6785 /* Guard against excessively long or deeply-nested queries */
6788
6789 if (IsA(setOp, RangeTblRef))
6790 {
6792 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6793 Query *subquery = rte->subquery;
6794
6795 Assert(subquery != NULL);
6796
6797 /*
6798 * We need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y.
6799 * Also add parens if the leaf query contains its own set operations.
6800 * (That shouldn't happen unless one of the other clauses is also
6801 * present, see transformSetOperationTree; but let's be safe.)
6802 */
6803 need_paren = (subquery->cteList ||
6804 subquery->sortClause ||
6805 subquery->rowMarks ||
6806 subquery->limitOffset ||
6807 subquery->limitCount ||
6808 subquery->setOperations);
6809 if (need_paren)
6811 get_query_def(subquery, buf, context->namespaces,
6812 context->resultDesc, context->colNamesVisible,
6813 context->prettyFlags, context->wrapColumn,
6814 context->indentLevel);
6815 if (need_paren)
6817 }
6818 else if (IsA(setOp, SetOperationStmt))
6819 {
6821 int subindent;
6823
6824 /*
6825 * We force parens when nesting two SetOperationStmts, except when the
6826 * lefthand input is another setop of the same kind. Syntactically,
6827 * we could omit parens in rather more cases, but it seems best to use
6828 * parens to flag cases where the setop operator changes. If we use
6829 * parens, we also increase the indentation level for the child query.
6830 *
6831 * There are some cases in which parens are needed around a leaf query
6832 * too, but those are more easily handled at the next level down (see
6833 * code above).
6834 */
6835 if (IsA(op->larg, SetOperationStmt))
6836 {
6838
6839 if (op->op == lop->op && op->all == lop->all)
6840 need_paren = false;
6841 else
6842 need_paren = true;
6843 }
6844 else
6845 need_paren = false;
6846
6847 if (need_paren)
6848 {
6851 appendContextKeyword(context, "", subindent, 0, 0);
6852 }
6853 else
6854 subindent = 0;
6855
6856 get_setop_query(op->larg, query, context);
6857
6858 if (need_paren)
6859 appendContextKeyword(context, ") ", -subindent, 0, 0);
6860 else if (PRETTY_INDENT(context))
6861 appendContextKeyword(context, "", -subindent, 0, 0);
6862 else
6864
6865 switch (op->op)
6866 {
6867 case SETOP_UNION:
6868 appendStringInfoString(buf, "UNION ");
6869 break;
6870 case SETOP_INTERSECT:
6871 appendStringInfoString(buf, "INTERSECT ");
6872 break;
6873 case SETOP_EXCEPT:
6874 appendStringInfoString(buf, "EXCEPT ");
6875 break;
6876 default:
6877 elog(ERROR, "unrecognized set op: %d",
6878 (int) op->op);
6879 }
6880 if (op->all)
6881 appendStringInfoString(buf, "ALL ");
6882
6883 /* Always parenthesize if RHS is another setop */
6885
6886 /*
6887 * The indentation code here is deliberately a bit different from that
6888 * for the lefthand input, because we want the line breaks in
6889 * different places.
6890 */
6891 if (need_paren)
6892 {
6895 }
6896 else
6897 subindent = 0;
6898 appendContextKeyword(context, "", subindent, 0, 0);
6899
6900 /*
6901 * The output column names of the RHS sub-select don't matter.
6902 */
6904 context->colNamesVisible = false;
6905
6906 get_setop_query(op->rarg, query, context);
6907
6909
6910 if (PRETTY_INDENT(context))
6911 context->indentLevel -= subindent;
6912 if (need_paren)
6913 appendContextKeyword(context, ")", 0, 0, 0);
6914 }
6915 else
6916 {
6917 elog(ERROR, "unrecognized node type: %d",
6918 (int) nodeTag(setOp));
6919 }
6920}
6921
6922/*
6923 * Display a sort/group clause.
6924 *
6925 * Also returns the expression tree, so caller need not find it again.
6926 */
6927static Node *
6929 deparse_context *context)
6930{
6931 StringInfo buf = context->buf;
6933 Node *expr;
6934
6935 tle = get_sortgroupref_tle(ref, tlist);
6936 expr = (Node *) tle->expr;
6937
6938 /*
6939 * Use column-number form if requested by caller. Otherwise, if
6940 * expression is a constant, force it to be dumped with an explicit cast
6941 * as decoration --- this is because a simple integer constant is
6942 * ambiguous (and will be misinterpreted by findTargetlistEntrySQL92()) if
6943 * we dump it without any decoration. Similarly, if it's just a Var,
6944 * there is risk of misinterpretation if the column name is reassigned in
6945 * the SELECT list, so we may need to force table qualification. And, if
6946 * it's anything more complex than a simple Var, then force extra parens
6947 * around it, to ensure it can't be misinterpreted as a cube() or rollup()
6948 * construct.
6949 */
6950 if (force_colno)
6951 {
6952 Assert(!tle->resjunk);
6953 appendStringInfo(buf, "%d", tle->resno);
6954 }
6955 else if (!expr)
6956 /* do nothing, probably can't happen */ ;
6957 else if (IsA(expr, Const))
6958 get_const_expr((Const *) expr, context, 1);
6959 else if (IsA(expr, Var))
6960 {
6961 /* Tell get_variable to check for name conflict */
6962 bool save_varinorderby = context->varInOrderBy;
6963
6964 context->varInOrderBy = true;
6965 (void) get_variable((Var *) expr, 0, false, context);
6967 }
6968 else
6969 {
6970 /*
6971 * We must force parens for function-like expressions even if
6972 * PRETTY_PAREN is off, since those are the ones in danger of
6973 * misparsing. For other expressions we need to force them only if
6974 * PRETTY_PAREN is on, since otherwise the expression will output them
6975 * itself. (We can't skip the parens.)
6976 */
6977 bool need_paren = (PRETTY_PAREN(context)
6978 || IsA(expr, FuncExpr)
6979 || IsA(expr, Aggref)
6980 || IsA(expr, WindowFunc)
6981 || IsA(expr, JsonConstructorExpr));
6982
6983 if (need_paren)
6984 appendStringInfoChar(context->buf, '(');
6985 get_rule_expr(expr, context, true);
6986 if (need_paren)
6987 appendStringInfoChar(context->buf, ')');
6988 }
6989
6990 return expr;
6991}
6992
6993/*
6994 * Display a GroupingSet
6995 */
6996static void
6998 bool omit_parens, deparse_context *context)
6999{
7000 ListCell *l;
7001 StringInfo buf = context->buf;
7002 bool omit_child_parens = true;
7003 char *sep = "";
7004
7005 switch (gset->kind)
7006 {
7007 case GROUPING_SET_EMPTY:
7009 return;
7010
7012 {
7013 if (!omit_parens || list_length(gset->content) != 1)
7015
7016 foreach(l, gset->content)
7017 {
7018 Index ref = lfirst_int(l);
7019
7021 get_rule_sortgroupclause(ref, targetlist,
7022 false, context);
7023 sep = ", ";
7024 }
7025
7026 if (!omit_parens || list_length(gset->content) != 1)
7028 }
7029 return;
7030
7032 appendStringInfoString(buf, "ROLLUP(");
7033 break;
7034 case GROUPING_SET_CUBE:
7035 appendStringInfoString(buf, "CUBE(");
7036 break;
7037 case GROUPING_SET_SETS:
7038 appendStringInfoString(buf, "GROUPING SETS (");
7039 omit_child_parens = false;
7040 break;
7041 }
7042
7043 foreach(l, gset->content)
7044 {
7046 get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
7047 sep = ", ";
7048 }
7049
7051}
7052
7053/*
7054 * Display an ORDER BY list.
7055 */
7056static void
7058 bool force_colno, deparse_context *context)
7059{
7060 StringInfo buf = context->buf;
7061 const char *sep;
7062 ListCell *l;
7063
7064 sep = "";
7065 foreach(l, orderList)
7066 {
7068 Node *sortexpr;
7070 TypeCacheEntry *typentry;
7071
7073 sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
7074 force_colno, context);
7076 /* See whether operator is default < or > for datatype */
7077 typentry = lookup_type_cache(sortcoltype,
7079 if (srt->sortop == typentry->lt_opr)
7080 {
7081 /* ASC is default, so emit nothing for it */
7082 if (srt->nulls_first)
7083 appendStringInfoString(buf, " NULLS FIRST");
7084 }
7085 else if (srt->sortop == typentry->gt_opr)
7086 {
7087 appendStringInfoString(buf, " DESC");
7088 /* DESC defaults to NULLS FIRST */
7089 if (!srt->nulls_first)
7090 appendStringInfoString(buf, " NULLS LAST");
7091 }
7092 else
7093 {
7094 appendStringInfo(buf, " USING %s",
7097 sortcoltype));
7098 /* be specific to eliminate ambiguity */
7099 if (srt->nulls_first)
7100 appendStringInfoString(buf, " NULLS FIRST");
7101 else
7102 appendStringInfoString(buf, " NULLS LAST");
7103 }
7104 sep = ", ";
7105 }
7106}
7107
7108/*
7109 * Display a WINDOW clause.
7110 *
7111 * Note that the windowClause list might contain only anonymous window
7112 * specifications, in which case we should print nothing here.
7113 */
7114static void
7116{
7117 StringInfo buf = context->buf;
7118 const char *sep;
7119 ListCell *l;
7120
7121 sep = NULL;
7122 foreach(l, query->windowClause)
7123 {
7124 WindowClause *wc = (WindowClause *) lfirst(l);
7125
7126 if (wc->name == NULL)
7127 continue; /* ignore anonymous windows */
7128
7129 if (sep == NULL)
7130 appendContextKeyword(context, " WINDOW ",
7132 else
7134
7135 appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
7136
7137 get_rule_windowspec(wc, query->targetList, context);
7138
7139 sep = ", ";
7140 }
7141}
7142
7143/*
7144 * Display a window definition
7145 */
7146static void
7148 deparse_context *context)
7149{
7150 StringInfo buf = context->buf;
7151 bool needspace = false;
7152 const char *sep;
7153 ListCell *l;
7154
7156 if (wc->refname)
7157 {
7159 needspace = true;
7160 }
7161 /* partition clauses are always inherited, so only print if no refname */
7162 if (wc->partitionClause && !wc->refname)
7163 {
7164 if (needspace)
7166 appendStringInfoString(buf, "PARTITION BY ");
7167 sep = "";
7168 foreach(l, wc->partitionClause)
7169 {
7171
7173 get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
7174 false, context);
7175 sep = ", ";
7176 }
7177 needspace = true;
7178 }
7179 /* print ordering clause only if not inherited */
7180 if (wc->orderClause && !wc->copiedOrder)
7181 {
7182 if (needspace)
7184 appendStringInfoString(buf, "ORDER BY ");
7185 get_rule_orderby(wc->orderClause, targetList, false, context);
7186 needspace = true;
7187 }
7188 /* framing clause is never inherited, so print unless it's default */
7190 {
7191 if (needspace)
7194 wc->startOffset, wc->endOffset,
7195 context);
7196 }
7198}
7199
7200/*
7201 * Append the description of a window's framing options to context->buf
7202 */
7203static void
7205 Node *startOffset, Node *endOffset,
7206 deparse_context *context)
7207{
7208 StringInfo buf = context->buf;
7209
7210 if (frameOptions & FRAMEOPTION_NONDEFAULT)
7211 {
7212 if (frameOptions & FRAMEOPTION_RANGE)
7213 appendStringInfoString(buf, "RANGE ");
7214 else if (frameOptions & FRAMEOPTION_ROWS)
7215 appendStringInfoString(buf, "ROWS ");
7216 else if (frameOptions & FRAMEOPTION_GROUPS)
7217 appendStringInfoString(buf, "GROUPS ");
7218 else
7219 Assert(false);
7220 if (frameOptions & FRAMEOPTION_BETWEEN)
7221 appendStringInfoString(buf, "BETWEEN ");
7222 if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
7223 appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
7224 else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW)
7225 appendStringInfoString(buf, "CURRENT ROW ");
7226 else if (frameOptions & FRAMEOPTION_START_OFFSET)
7227 {
7228 get_rule_expr(startOffset, context, false);
7229 if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
7230 appendStringInfoString(buf, " PRECEDING ");
7231 else if (frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
7232 appendStringInfoString(buf, " FOLLOWING ");
7233 else
7234 Assert(false);
7235 }
7236 else
7237 Assert(false);
7238 if (frameOptions & FRAMEOPTION_BETWEEN)
7239 {
7240 appendStringInfoString(buf, "AND ");
7241 if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
7242 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
7243 else if (frameOptions & FRAMEOPTION_END_CURRENT_ROW)
7244 appendStringInfoString(buf, "CURRENT ROW ");
7245 else if (frameOptions & FRAMEOPTION_END_OFFSET)
7246 {
7247 get_rule_expr(endOffset, context, false);
7248 if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
7249 appendStringInfoString(buf, " PRECEDING ");
7250 else if (frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
7251 appendStringInfoString(buf, " FOLLOWING ");
7252 else
7253 Assert(false);
7254 }
7255 else
7256 Assert(false);
7257 }
7258 if (frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
7259 appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
7260 else if (frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
7261 appendStringInfoString(buf, "EXCLUDE GROUP ");
7262 else if (frameOptions & FRAMEOPTION_EXCLUDE_TIES)
7263 appendStringInfoString(buf, "EXCLUDE TIES ");
7264 /* we will now have a trailing space; remove it */
7265 buf->data[--(buf->len)] = '\0';
7266 }
7267}
7268
7269/*
7270 * Return the description of a window's framing options as a palloc'd string
7271 */
7272char *
7274 Node *startOffset, Node *endOffset,
7275 List *dpcontext, bool forceprefix)
7276{
7278 deparse_context context;
7279
7281 context.buf = &buf;
7282 context.namespaces = dpcontext;
7283 context.resultDesc = NULL;
7284 context.targetList = NIL;
7285 context.windowClause = NIL;
7286 context.varprefix = forceprefix;
7287 context.prettyFlags = 0;
7289 context.indentLevel = 0;
7290 context.colNamesVisible = true;
7291 context.inGroupBy = false;
7292 context.varInOrderBy = false;
7293 context.appendparents = NULL;
7294
7295 get_window_frame_options(frameOptions, startOffset, endOffset, &context);
7296
7297 return buf.data;
7298}
7299
7300/* ----------
7301 * get_insert_query_def - Parse back an INSERT parsetree
7302 * ----------
7303 */
7304static void
7306{
7307 StringInfo buf = context->buf;
7311 char *sep;
7312 ListCell *l;
7314
7315 /* Insert the WITH clause if given */
7316 get_with_clause(query, context);
7317
7318 /*
7319 * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
7320 * single RTE for the SELECT or VALUES. Plain VALUES has neither.
7321 */
7322 foreach(l, query->rtable)
7323 {
7324 rte = (RangeTblEntry *) lfirst(l);
7325
7326 if (rte->rtekind == RTE_SUBQUERY)
7327 {
7328 if (select_rte)
7329 elog(ERROR, "too many subquery RTEs in INSERT");
7330 select_rte = rte;
7331 }
7332
7333 if (rte->rtekind == RTE_VALUES)
7334 {
7335 if (values_rte)
7336 elog(ERROR, "too many values RTEs in INSERT");
7337 values_rte = rte;
7338 }
7339 }
7340 if (select_rte && values_rte)
7341 elog(ERROR, "both subquery and values RTEs in INSERT");
7342
7343 /*
7344 * Start the query with INSERT INTO relname
7345 */
7346 rte = rt_fetch(query->resultRelation, query->rtable);
7347 Assert(rte->rtekind == RTE_RELATION);
7348
7349 if (PRETTY_INDENT(context))
7350 {
7351 context->indentLevel += PRETTYINDENT_STD;
7353 }
7354 appendStringInfo(buf, "INSERT INTO %s",
7355 generate_relation_name(rte->relid, NIL));
7356
7357 /* Print the relation alias, if needed; INSERT requires explicit AS */
7358 get_rte_alias(rte, query->resultRelation, true, context);
7359
7360 /* always want a space here */
7362
7363 /*
7364 * Add the insert-column-names list. Any indirection decoration needed on
7365 * the column names can be inferred from the top targetlist.
7366 */
7368 sep = "";
7369 if (query->targetList)
7371 foreach(l, query->targetList)
7372 {
7374
7375 if (tle->resjunk)
7376 continue; /* ignore junk entries */
7377
7379 sep = ", ";
7380
7381 /*
7382 * Put out name of target column; look in the catalogs, not at
7383 * tle->resname, since resname will fail to track RENAME.
7384 */
7387 tle->resno,
7388 false)));
7389
7390 /*
7391 * Print any indirection needed (subfields or subscripts), and strip
7392 * off the top-level nodes representing the indirection assignments.
7393 * Add the stripped expressions to strippedexprs. (If it's a
7394 * single-VALUES statement, the stripped expressions are the VALUES to
7395 * print below. Otherwise they're just Vars and not really
7396 * interesting.)
7397 */
7399 processIndirection((Node *) tle->expr,
7400 context));
7401 }
7402 if (query->targetList)
7404
7405 if (query->override)
7406 {
7407 if (query->override == OVERRIDING_SYSTEM_VALUE)
7408 appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
7409 else if (query->override == OVERRIDING_USER_VALUE)
7410 appendStringInfoString(buf, "OVERRIDING USER VALUE ");
7411 }
7412
7413 if (select_rte)
7414 {
7415 /* Add the SELECT */
7416 get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
7417 false,
7418 context->prettyFlags, context->wrapColumn,
7419 context->indentLevel);
7420 }
7421 else if (values_rte)
7422 {
7423 /* Add the multi-VALUES expression lists */
7424 get_values_def(values_rte->values_lists, context);
7425 }
7426 else if (strippedexprs)
7427 {
7428 /* Add the single-VALUES expression list */
7429 appendContextKeyword(context, "VALUES (",
7431 get_rule_list_toplevel(strippedexprs, context, false);
7433 }
7434 else
7435 {
7436 /* No expressions, so it must be DEFAULT VALUES */
7437 appendStringInfoString(buf, "DEFAULT VALUES");
7438 }
7439
7440 /* Add ON CONFLICT if present */
7441 if (query->onConflict)
7442 {
7444
7445 appendStringInfoString(buf, " ON CONFLICT");
7446
7447 if (confl->arbiterElems)
7448 {
7449 /* Add the single-VALUES expression list */
7451 get_rule_expr((Node *) confl->arbiterElems, context, false);
7453
7454 /* Add a WHERE clause (for partial indexes) if given */
7455 if (confl->arbiterWhere != NULL)
7456 {
7457 bool save_varprefix;
7458
7459 /*
7460 * Force non-prefixing of Vars, since parser assumes that they
7461 * belong to target relation. WHERE clause does not use
7462 * InferenceElem, so this is separately required.
7463 */
7464 save_varprefix = context->varprefix;
7465 context->varprefix = false;
7466
7467 appendContextKeyword(context, " WHERE ",
7469 get_rule_expr(confl->arbiterWhere, context, false);
7470
7471 context->varprefix = save_varprefix;
7472 }
7473 }
7474 else if (OidIsValid(confl->constraint))
7475 {
7476 char *constraint = get_constraint_name(confl->constraint);
7477
7478 if (!constraint)
7479 elog(ERROR, "cache lookup failed for constraint %u",
7480 confl->constraint);
7481 appendStringInfo(buf, " ON CONSTRAINT %s",
7482 quote_identifier(constraint));
7483 }
7484
7485 if (confl->action == ONCONFLICT_NOTHING)
7486 {
7487 appendStringInfoString(buf, " DO NOTHING");
7488 }
7489 else if (confl->action == ONCONFLICT_UPDATE)
7490 {
7491 appendStringInfoString(buf, " DO UPDATE SET ");
7492 /* Deparse targetlist */
7493 get_update_query_targetlist_def(query, confl->onConflictSet,
7494 context, rte);
7495
7496 /* Add a WHERE clause if given */
7497 if (confl->onConflictWhere != NULL)
7498 {
7499 appendContextKeyword(context, " WHERE ",
7501 get_rule_expr(confl->onConflictWhere, context, false);
7502 }
7503 }
7504 else
7505 {
7506 Assert(confl->action == ONCONFLICT_SELECT);
7507 appendStringInfoString(buf, " DO SELECT");
7508
7509 /* Add FOR [KEY] UPDATE/SHARE clause if present */
7510 if (confl->lockStrength != LCS_NONE)
7512
7513 /* Add a WHERE clause if given */
7514 if (confl->onConflictWhere != NULL)
7515 {
7516 appendContextKeyword(context, " WHERE ",
7518 get_rule_expr(confl->onConflictWhere, context, false);
7519 }
7520 }
7521 }
7522
7523 /* Add RETURNING if present */
7524 if (query->returningList)
7525 get_returning_clause(query, context);
7526}
7527
7528
7529/* ----------
7530 * get_update_query_def - Parse back an UPDATE parsetree
7531 * ----------
7532 */
7533static void
7535{
7536 StringInfo buf = context->buf;
7538
7539 /* Insert the WITH clause if given */
7540 get_with_clause(query, context);
7541
7542 /*
7543 * Start the query with UPDATE relname SET
7544 */
7545 rte = rt_fetch(query->resultRelation, query->rtable);
7546 Assert(rte->rtekind == RTE_RELATION);
7547 if (PRETTY_INDENT(context))
7548 {
7550 context->indentLevel += PRETTYINDENT_STD;
7551 }
7552 appendStringInfo(buf, "UPDATE %s%s",
7554 generate_relation_name(rte->relid, NIL));
7555
7556 /* Print the relation alias, if needed */
7557 get_rte_alias(rte, query->resultRelation, false, context);
7558
7559 appendStringInfoString(buf, " SET ");
7560
7561 /* Deparse targetlist */
7562 get_update_query_targetlist_def(query, query->targetList, context, rte);
7563
7564 /* Add the FROM clause if needed */
7565 get_from_clause(query, " FROM ", context);
7566
7567 /* Add a WHERE clause if given */
7568 if (query->jointree->quals != NULL)
7569 {
7570 appendContextKeyword(context, " WHERE ",
7572 get_rule_expr(query->jointree->quals, context, false);
7573 }
7574
7575 /* Add RETURNING if present */
7576 if (query->returningList)
7577 get_returning_clause(query, context);
7578}
7579
7580
7581/* ----------
7582 * get_update_query_targetlist_def - Parse back an UPDATE targetlist
7583 * ----------
7584 */
7585static void
7588{
7589 StringInfo buf = context->buf;
7590 ListCell *l;
7593 const char *sep;
7596
7597 /*
7598 * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
7599 * into a list. We expect them to appear, in ID order, in resjunk tlist
7600 * entries.
7601 */
7602 ma_sublinks = NIL;
7603 if (query->hasSubLinks) /* else there can't be any */
7604 {
7605 foreach(l, targetList)
7606 {
7608
7609 if (tle->resjunk && IsA(tle->expr, SubLink))
7610 {
7611 SubLink *sl = (SubLink *) tle->expr;
7612
7613 if (sl->subLinkType == MULTIEXPR_SUBLINK)
7614 {
7616 Assert(sl->subLinkId == list_length(ma_sublinks));
7617 }
7618 }
7619 }
7620 }
7624
7625 /* Add the comma separated list of 'attname = value' */
7626 sep = "";
7627 foreach(l, targetList)
7628 {
7630 Node *expr;
7631
7632 if (tle->resjunk)
7633 continue; /* ignore junk entries */
7634
7635 /* Emit separator (OK whether we're in multiassignment or not) */
7637 sep = ", ";
7638
7639 /*
7640 * Check to see if we're starting a multiassignment group: if so,
7641 * output a left paren.
7642 */
7643 if (next_ma_cell != NULL && cur_ma_sublink == NULL)
7644 {
7645 /*
7646 * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
7647 * Param. That could be buried under FieldStores and
7648 * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
7649 * and underneath those there could be an implicit type coercion.
7650 * Because we would ignore implicit type coercions anyway, we
7651 * don't need to be as careful as processIndirection() is about
7652 * descending past implicit CoerceToDomains.
7653 */
7654 expr = (Node *) tle->expr;
7655 while (expr)
7656 {
7657 if (IsA(expr, FieldStore))
7658 {
7659 FieldStore *fstore = (FieldStore *) expr;
7660
7661 expr = (Node *) linitial(fstore->newvals);
7662 }
7663 else if (IsA(expr, SubscriptingRef))
7664 {
7665 SubscriptingRef *sbsref = (SubscriptingRef *) expr;
7666
7667 if (sbsref->refassgnexpr == NULL)
7668 break;
7669
7670 expr = (Node *) sbsref->refassgnexpr;
7671 }
7672 else if (IsA(expr, CoerceToDomain))
7673 {
7675
7676 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
7677 break;
7678 expr = (Node *) cdomain->arg;
7679 }
7680 else
7681 break;
7682 }
7683 expr = strip_implicit_coercions(expr);
7684
7685 if (expr && IsA(expr, Param) &&
7686 ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
7687 {
7691 Assert(((Param *) expr)->paramid ==
7692 ((cur_ma_sublink->subLinkId << 16) | 1));
7694 }
7695 }
7696
7697 /*
7698 * Put out name of target column; look in the catalogs, not at
7699 * tle->resname, since resname will fail to track RENAME.
7700 */
7703 tle->resno,
7704 false)));
7705
7706 /*
7707 * Print any indirection needed (subfields or subscripts), and strip
7708 * off the top-level nodes representing the indirection assignments.
7709 */
7710 expr = processIndirection((Node *) tle->expr, context);
7711
7712 /*
7713 * If we're in a multiassignment, skip printing anything more, unless
7714 * this is the last column; in which case, what we print should be the
7715 * sublink, not the Param.
7716 */
7717 if (cur_ma_sublink != NULL)
7718 {
7719 if (--remaining_ma_columns > 0)
7720 continue; /* not the last column of multiassignment */
7722 expr = (Node *) cur_ma_sublink;
7724 }
7725
7727
7728 get_rule_expr(expr, context, false);
7729 }
7730}
7731
7732
7733/* ----------
7734 * get_delete_query_def - Parse back a DELETE parsetree
7735 * ----------
7736 */
7737static void
7739{
7740 StringInfo buf = context->buf;
7742
7743 /* Insert the WITH clause if given */
7744 get_with_clause(query, context);
7745
7746 /*
7747 * Start the query with DELETE FROM relname
7748 */
7749 rte = rt_fetch(query->resultRelation, query->rtable);
7750 Assert(rte->rtekind == RTE_RELATION);
7751 if (PRETTY_INDENT(context))
7752 {
7754 context->indentLevel += PRETTYINDENT_STD;
7755 }
7756 appendStringInfo(buf, "DELETE FROM %s%s",
7758 generate_relation_name(rte->relid, NIL));
7759
7760 /* Print the relation alias, if needed */
7761 get_rte_alias(rte, query->resultRelation, false, context);
7762
7763 /* Add the USING clause if given */
7764 get_from_clause(query, " USING ", context);
7765
7766 /* Add a WHERE clause if given */
7767 if (query->jointree->quals != NULL)
7768 {
7769 appendContextKeyword(context, " WHERE ",
7771 get_rule_expr(query->jointree->quals, context, false);
7772 }
7773
7774 /* Add RETURNING if present */
7775 if (query->returningList)
7776 get_returning_clause(query, context);
7777}
7778
7779
7780/* ----------
7781 * get_merge_query_def - Parse back a MERGE parsetree
7782 * ----------
7783 */
7784static void
7786{
7787 StringInfo buf = context->buf;
7789 ListCell *lc;
7791
7792 /* Insert the WITH clause if given */
7793 get_with_clause(query, context);
7794
7795 /*
7796 * Start the query with MERGE INTO relname
7797 */
7798 rte = rt_fetch(query->resultRelation, query->rtable);
7799 Assert(rte->rtekind == RTE_RELATION);
7800 if (PRETTY_INDENT(context))
7801 {
7803 context->indentLevel += PRETTYINDENT_STD;
7804 }
7805 appendStringInfo(buf, "MERGE INTO %s%s",
7807 generate_relation_name(rte->relid, NIL));
7808
7809 /* Print the relation alias, if needed */
7810 get_rte_alias(rte, query->resultRelation, false, context);
7811
7812 /* Print the source relation and join clause */
7813 get_from_clause(query, " USING ", context);
7814 appendContextKeyword(context, " ON ",
7816 get_rule_expr(query->mergeJoinCondition, context, false);
7817
7818 /*
7819 * Test for any NOT MATCHED BY SOURCE actions. If there are none, then
7820 * any NOT MATCHED BY TARGET actions are output as "WHEN NOT MATCHED", per
7821 * SQL standard. Otherwise, we have a non-SQL-standard query, so output
7822 * "BY SOURCE" / "BY TARGET" qualifiers for all NOT MATCHED actions, to be
7823 * more explicit.
7824 */
7825 haveNotMatchedBySource = false;
7826 foreach(lc, query->mergeActionList)
7827 {
7829
7830 if (action->matchKind == MERGE_WHEN_NOT_MATCHED_BY_SOURCE)
7831 {
7833 break;
7834 }
7835 }
7836
7837 /* Print each merge action */
7838 foreach(lc, query->mergeActionList)
7839 {
7841
7842 appendContextKeyword(context, " WHEN ",
7844 switch (action->matchKind)
7845 {
7846 case MERGE_WHEN_MATCHED:
7847 appendStringInfoString(buf, "MATCHED");
7848 break;
7850 appendStringInfoString(buf, "NOT MATCHED BY SOURCE");
7851 break;
7854 appendStringInfoString(buf, "NOT MATCHED BY TARGET");
7855 else
7856 appendStringInfoString(buf, "NOT MATCHED");
7857 break;
7858 default:
7859 elog(ERROR, "unrecognized matchKind: %d",
7860 (int) action->matchKind);
7861 }
7862
7863 if (action->qual)
7864 {
7865 appendContextKeyword(context, " AND ",
7867 get_rule_expr(action->qual, context, false);
7868 }
7869 appendContextKeyword(context, " THEN ",
7871
7872 if (action->commandType == CMD_INSERT)
7873 {
7874 /* This generally matches get_insert_query_def() */
7876 const char *sep = "";
7877 ListCell *lc2;
7878
7879 appendStringInfoString(buf, "INSERT");
7880
7881 if (action->targetList)
7883 foreach(lc2, action->targetList)
7884 {
7886
7887 Assert(!tle->resjunk);
7888
7890 sep = ", ";
7891
7894 tle->resno,
7895 false)));
7897 processIndirection((Node *) tle->expr,
7898 context));
7899 }
7900 if (action->targetList)
7902
7903 if (action->override)
7904 {
7905 if (action->override == OVERRIDING_SYSTEM_VALUE)
7906 appendStringInfoString(buf, " OVERRIDING SYSTEM VALUE");
7907 else if (action->override == OVERRIDING_USER_VALUE)
7908 appendStringInfoString(buf, " OVERRIDING USER VALUE");
7909 }
7910
7911 if (strippedexprs)
7912 {
7913 appendContextKeyword(context, " VALUES (",
7915 get_rule_list_toplevel(strippedexprs, context, false);
7917 }
7918 else
7919 appendStringInfoString(buf, " DEFAULT VALUES");
7920 }
7921 else if (action->commandType == CMD_UPDATE)
7922 {
7923 appendStringInfoString(buf, "UPDATE SET ");
7924 get_update_query_targetlist_def(query, action->targetList,
7925 context, rte);
7926 }
7927 else if (action->commandType == CMD_DELETE)
7928 appendStringInfoString(buf, "DELETE");
7929 else if (action->commandType == CMD_NOTHING)
7930 appendStringInfoString(buf, "DO NOTHING");
7931 }
7932
7933 /* Add RETURNING if present */
7934 if (query->returningList)
7935 get_returning_clause(query, context);
7936}
7937
7938
7939/* ----------
7940 * get_utility_query_def - Parse back a UTILITY parsetree
7941 * ----------
7942 */
7943static void
7945{
7946 StringInfo buf = context->buf;
7947
7948 if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7949 {
7950 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7951
7952 appendContextKeyword(context, "",
7953 0, PRETTYINDENT_STD, 1);
7954 appendStringInfo(buf, "NOTIFY %s",
7955 quote_identifier(stmt->conditionname));
7956 if (stmt->payload)
7957 {
7959 simple_quote_literal(buf, stmt->payload);
7960 }
7961 }
7962 else
7963 {
7964 /* Currently only NOTIFY utility commands can appear in rules */
7965 elog(ERROR, "unexpected utility statement type");
7966 }
7967}
7968
7969
7970/*
7971 * Parse back a graph label expression
7972 */
7973static void
7975{
7976 StringInfo buf = context->buf;
7977
7979
7980 switch (nodeTag(label_expr))
7981 {
7982 case T_GraphLabelRef:
7983 {
7985
7987 break;
7988 }
7989
7990 case T_BoolExpr:
7991 {
7993 ListCell *lc;
7994 bool first = true;
7995
7996 Assert(be->boolop == OR_EXPR);
7997
7998 foreach(lc, be->args)
7999 {
8000 if (!first)
8001 {
8002 if (be->boolop == OR_EXPR)
8004 }
8005 else
8006 first = false;
8007 get_graph_label_expr(lfirst(lc), context);
8008 }
8009
8010 break;
8011 }
8012
8013 default:
8014 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(label_expr));
8015 break;
8016 }
8017}
8018
8019/*
8020 * Parse back a path pattern expression
8021 */
8022static void
8024{
8025 StringInfo buf = context->buf;
8026 ListCell *lc;
8027
8028 foreach(lc, path_pattern_expr)
8029 {
8031 const char *sep = "";
8032
8033 switch (gep->kind)
8034 {
8035 case VERTEX_PATTERN:
8037 break;
8038 case EDGE_PATTERN_LEFT:
8040 break;
8041 case EDGE_PATTERN_RIGHT:
8042 case EDGE_PATTERN_ANY:
8044 break;
8045 case PAREN_EXPR:
8047 break;
8048 }
8049
8050 if (gep->variable)
8051 {
8053 sep = " ";
8054 }
8055
8056 if (gep->labelexpr)
8057 {
8060 get_graph_label_expr(gep->labelexpr, context);
8061 sep = " ";
8062 }
8063
8064 if (gep->subexpr)
8065 {
8067 get_path_pattern_expr_def(gep->subexpr, context);
8068 sep = " ";
8069 }
8070
8071 if (gep->whereClause)
8072 {
8074 appendStringInfoString(buf, "WHERE ");
8075 get_rule_expr(gep->whereClause, context, false);
8076 }
8077
8078 switch (gep->kind)
8079 {
8080 case VERTEX_PATTERN:
8082 break;
8083 case EDGE_PATTERN_LEFT:
8084 case EDGE_PATTERN_ANY:
8086 break;
8087 case EDGE_PATTERN_RIGHT:
8089 break;
8090 case PAREN_EXPR:
8092 break;
8093 }
8094
8095 if (gep->quantifier)
8096 {
8097 int lower = linitial_int(gep->quantifier);
8098 int upper = lsecond_int(gep->quantifier);
8099
8100 appendStringInfo(buf, "{%d,%d}", lower, upper);
8101 }
8102 }
8103}
8104
8105/*
8106 * Parse back a graph pattern
8107 */
8108static void
8110{
8111 StringInfo buf = context->buf;
8112 ListCell *lc;
8113 bool first = true;
8114
8115 foreach(lc, graph_pattern->path_pattern_list)
8116 {
8118
8119 if (!first)
8121 else
8122 first = false;
8123
8125 }
8126
8127 if (graph_pattern->whereClause)
8128 {
8129 appendStringInfoString(buf, "WHERE ");
8130 get_rule_expr(graph_pattern->whereClause, context, false);
8131 }
8132}
8133
8134/*
8135 * Display a Var appropriately.
8136 *
8137 * In some cases (currently only when recursing into an unnamed join)
8138 * the Var's varlevelsup has to be interpreted with respect to a context
8139 * above the current one; levelsup indicates the offset.
8140 *
8141 * If istoplevel is true, the Var is at the top level of a SELECT's
8142 * targetlist, which means we need special treatment of whole-row Vars.
8143 * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
8144 * dirty hack to prevent "tab.*" from being expanded into multiple columns.
8145 * (The parser will strip the useless coercion, so no inefficiency is added in
8146 * dump and reload.) We used to print just "tab" in such cases, but that is
8147 * ambiguous and will yield the wrong result if "tab" is also a plain column
8148 * name in the query.
8149 *
8150 * Returns the attname of the Var, or NULL if the Var has no attname (because
8151 * it is a whole-row Var or a subplan output reference).
8152 */
8153static char *
8154get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
8155{
8156 StringInfo buf = context->buf;
8159 int netlevelsup;
8161 int varno;
8162 AttrNumber varattno;
8164 char *refname;
8165 char *attname;
8166 bool need_prefix;
8167
8168 /* Find appropriate nesting depth */
8169 netlevelsup = var->varlevelsup + levelsup;
8170 if (netlevelsup >= list_length(context->namespaces))
8171 elog(ERROR, "bogus varlevelsup: %d offset %d",
8172 var->varlevelsup, levelsup);
8174 netlevelsup);
8175
8176 /*
8177 * If we have a syntactic referent for the Var, and we're working from a
8178 * parse tree, prefer to use the syntactic referent. Otherwise, fall back
8179 * on the semantic referent. (Forcing use of the semantic referent when
8180 * printing plan trees is a design choice that's perhaps more motivated by
8181 * backwards compatibility than anything else. But it does have the
8182 * advantage of making plans more explicit.)
8183 */
8184 if (var->varnosyn > 0 && dpns->plan == NULL)
8185 {
8186 varno = var->varnosyn;
8187 varattno = var->varattnosyn;
8188 }
8189 else
8190 {
8191 varno = var->varno;
8192 varattno = var->varattno;
8193 }
8194
8195 /*
8196 * Try to find the relevant RTE in this rtable. In a plan tree, it's
8197 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
8198 * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
8199 * find the aliases previously assigned for this RTE.
8200 */
8201 if (varno >= 1 && varno <= list_length(dpns->rtable))
8202 {
8203 /*
8204 * We might have been asked to map child Vars to some parent relation.
8205 */
8206 if (context->appendparents && dpns->appendrels)
8207 {
8208 int pvarno = varno;
8209 AttrNumber pvarattno = varattno;
8210 AppendRelInfo *appinfo = dpns->appendrels[pvarno];
8211 bool found = false;
8212
8213 /* Only map up to inheritance parents, not UNION ALL appendrels */
8214 while (appinfo &&
8215 rt_fetch(appinfo->parent_relid,
8216 dpns->rtable)->rtekind == RTE_RELATION)
8217 {
8218 found = false;
8219 if (pvarattno > 0) /* system columns stay as-is */
8220 {
8221 if (pvarattno > appinfo->num_child_cols)
8222 break; /* safety check */
8223 pvarattno = appinfo->parent_colnos[pvarattno - 1];
8224 if (pvarattno == 0)
8225 break; /* Var is local to child */
8226 }
8227
8229 found = true;
8230
8231 /* If the parent is itself a child, continue up. */
8232 Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
8233 appinfo = dpns->appendrels[pvarno];
8234 }
8235
8236 /*
8237 * If we found an ancestral rel, and that rel is included in
8238 * appendparents, print that column not the original one.
8239 */
8240 if (found && bms_is_member(pvarno, context->appendparents))
8241 {
8242 varno = pvarno;
8243 varattno = pvarattno;
8244 }
8245 }
8246
8247 rte = rt_fetch(varno, dpns->rtable);
8248
8249 /* might be returning old/new column value */
8251 refname = dpns->ret_old_alias;
8252 else if (var->varreturningtype == VAR_RETURNING_NEW)
8253 refname = dpns->ret_new_alias;
8254 else
8255 refname = (char *) list_nth(dpns->rtable_names, varno - 1);
8256
8258 attnum = varattno;
8259 }
8260 else
8261 {
8262 resolve_special_varno((Node *) var, context,
8264 return NULL;
8265 }
8266
8267 /*
8268 * The planner will sometimes emit Vars referencing resjunk elements of a
8269 * subquery's target list (this is currently only possible if it chooses
8270 * to generate a "physical tlist" for a SubqueryScan or CteScan node).
8271 * Although we prefer to print subquery-referencing Vars using the
8272 * subquery's alias, that's not possible for resjunk items since they have
8273 * no alias. So in that case, drill down to the subplan and print the
8274 * contents of the referenced tlist item. This works because in a plan
8275 * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
8276 * we'll have set dpns->inner_plan to reference the child plan node.
8277 */
8278 if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
8279 attnum > list_length(rte->eref->colnames) &&
8280 dpns->inner_plan)
8281 {
8284
8285 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8286 if (!tle)
8287 elog(ERROR, "invalid attnum %d for relation \"%s\"",
8288 attnum, rte->eref->aliasname);
8289
8290 Assert(netlevelsup == 0);
8291 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8292
8293 /*
8294 * Force parentheses because our caller probably assumed a Var is a
8295 * simple expression.
8296 */
8297 if (!IsA(tle->expr, Var))
8299 get_rule_expr((Node *) tle->expr, context, true);
8300 if (!IsA(tle->expr, Var))
8302
8304 return NULL;
8305 }
8306
8307 /*
8308 * If it's an unnamed join, look at the expansion of the alias variable.
8309 * If it's a simple reference to one of the input vars, then recursively
8310 * print the name of that var instead. When it's not a simple reference,
8311 * we have to just print the unqualified join column name. (This can only
8312 * happen with "dangerous" merged columns in a JOIN USING; we took pains
8313 * previously to make the unqualified column name unique in such cases.)
8314 *
8315 * This wouldn't work in decompiling plan trees, because we don't store
8316 * joinaliasvars lists after planning; but a plan tree should never
8317 * contain a join alias variable.
8318 */
8319 if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
8320 {
8321 if (rte->joinaliasvars == NIL)
8322 elog(ERROR, "cannot decompile join alias var in plan tree");
8323 if (attnum > 0)
8324 {
8325 Var *aliasvar;
8326
8327 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
8328 /* we intentionally don't strip implicit coercions here */
8329 if (aliasvar && IsA(aliasvar, Var))
8330 {
8331 return get_variable(aliasvar, var->varlevelsup + levelsup,
8332 istoplevel, context);
8333 }
8334 }
8335
8336 /*
8337 * Unnamed join has no refname. (Note: since it's unnamed, there is
8338 * no way the user could have referenced it to create a whole-row Var
8339 * for it. So we don't have to cover that case below.)
8340 */
8341 Assert(refname == NULL);
8342 }
8343
8345 attname = NULL;
8346 else if (attnum > 0)
8347 {
8348 /* Get column name to use from the colinfo struct */
8349 if (attnum > colinfo->num_cols)
8350 elog(ERROR, "invalid attnum %d for relation \"%s\"",
8351 attnum, rte->eref->aliasname);
8352 attname = colinfo->colnames[attnum - 1];
8353
8354 /*
8355 * If we find a Var referencing a dropped column, it seems better to
8356 * print something (anything) than to fail. In general this should
8357 * not happen, but it used to be possible for some cases involving
8358 * functions returning named composite types, and perhaps there are
8359 * still bugs out there.
8360 */
8361 if (attname == NULL)
8362 attname = "?dropped?column?";
8363 }
8364 else
8365 {
8366 /* System column - name is fixed, get it from the catalog */
8368 }
8369
8370 need_prefix = (context->varprefix || attname == NULL ||
8372
8373 /*
8374 * If we're considering a plain Var in an ORDER BY (but not GROUP BY)
8375 * clause, we may need to add a table-name prefix to prevent
8376 * findTargetlistEntrySQL92 from misinterpreting the name as an
8377 * output-column name. To avoid cluttering the output with unnecessary
8378 * prefixes, do so only if there is a name match to a SELECT tlist item
8379 * that is different from the Var.
8380 */
8381 if (context->varInOrderBy && !context->inGroupBy && !need_prefix)
8382 {
8383 int colno = 0;
8384
8386 {
8387 char *colname;
8388
8389 if (tle->resjunk)
8390 continue; /* ignore junk entries */
8391 colno++;
8392
8393 /* This must match colname-choosing logic in get_target_list() */
8394 if (context->resultDesc && colno <= context->resultDesc->natts)
8395 colname = NameStr(TupleDescAttr(context->resultDesc,
8396 colno - 1)->attname);
8397 else
8398 colname = tle->resname;
8399
8400 if (colname && strcmp(colname, attname) == 0 &&
8401 !equal(var, tle->expr))
8402 {
8403 need_prefix = true;
8404 break;
8405 }
8406 }
8407 }
8408
8409 if (refname && need_prefix)
8410 {
8413 }
8414 if (attname)
8416 else
8417 {
8419 if (istoplevel)
8420 appendStringInfo(buf, "::%s",
8421 format_type_with_typemod(var->vartype,
8422 var->vartypmod));
8423 }
8424
8425 return attname;
8426}
8427
8428/*
8429 * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
8430 * routine is actually a callback for resolve_special_varno, which handles
8431 * finding the correct TargetEntry. We get the expression contained in that
8432 * TargetEntry and just need to deparse it, a job we can throw back on
8433 * get_rule_expr.
8434 */
8435static void
8436get_special_variable(Node *node, deparse_context *context, void *callback_arg)
8437{
8438 StringInfo buf = context->buf;
8439
8440 /*
8441 * For a non-Var referent, force parentheses because our caller probably
8442 * assumed a Var is a simple expression.
8443 */
8444 if (!IsA(node, Var))
8446 get_rule_expr(node, context, true);
8447 if (!IsA(node, Var))
8449}
8450
8451/*
8452 * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
8453 * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
8454 * invoke the callback provided.
8455 */
8456static void
8458 rsv_callback callback, void *callback_arg)
8459{
8460 Var *var;
8462
8463 /* This function is recursive, so let's be paranoid. */
8465
8466 /* If it's not a Var, invoke the callback. */
8467 if (!IsA(node, Var))
8468 {
8469 (*callback) (node, context, callback_arg);
8470 return;
8471 }
8472
8473 /* Find appropriate nesting depth */
8474 var = (Var *) node;
8476 var->varlevelsup);
8477
8478 /*
8479 * If varno is special, recurse. (Don't worry about varnosyn; if we're
8480 * here, we already decided not to use that.)
8481 */
8482 if (var->varno == OUTER_VAR && dpns->outer_tlist)
8483 {
8487
8488 tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
8489 if (!tle)
8490 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
8491
8492 /*
8493 * If we're descending to the first child of an Append or MergeAppend,
8494 * update appendparents. This will affect deparsing of all Vars
8495 * appearing within the eventually-resolved subexpression.
8496 */
8498
8499 if (IsA(dpns->plan, Append))
8500 context->appendparents = bms_union(context->appendparents,
8501 ((Append *) dpns->plan)->apprelids);
8502 else if (IsA(dpns->plan, MergeAppend))
8503 context->appendparents = bms_union(context->appendparents,
8504 ((MergeAppend *) dpns->plan)->apprelids);
8505
8506 push_child_plan(dpns, dpns->outer_plan, &save_dpns);
8507 resolve_special_varno((Node *) tle->expr, context,
8508 callback, callback_arg);
8511 return;
8512 }
8513 else if (var->varno == INNER_VAR && dpns->inner_tlist)
8514 {
8517
8518 tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
8519 if (!tle)
8520 elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
8521
8522 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8523 resolve_special_varno((Node *) tle->expr, context,
8524 callback, callback_arg);
8526 return;
8527 }
8528 else if (var->varno == INDEX_VAR && dpns->index_tlist)
8529 {
8531
8532 tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
8533 if (!tle)
8534 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
8535
8536 resolve_special_varno((Node *) tle->expr, context,
8537 callback, callback_arg);
8538 return;
8539 }
8540 else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
8541 elog(ERROR, "bogus varno: %d", var->varno);
8542
8543 /* Not special. Just invoke the callback. */
8544 (*callback) (node, context, callback_arg);
8545}
8546
8547/*
8548 * Get the name of a field of an expression of composite type. The
8549 * expression is usually a Var, but we handle other cases too.
8550 *
8551 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
8552 *
8553 * This is fairly straightforward when the expression has a named composite
8554 * type; we need only look up the type in the catalogs. However, the type
8555 * could also be RECORD. Since no actual table or view column is allowed to
8556 * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
8557 * or to a subquery output. We drill down to find the ultimate defining
8558 * expression and attempt to infer the field name from it. We ereport if we
8559 * can't determine the name.
8560 *
8561 * Similarly, a PARAM of type RECORD has to refer to some expression of
8562 * a determinable composite type.
8563 */
8564static const char *
8566 int levelsup, deparse_context *context)
8567{
8570 int netlevelsup;
8572 int varno;
8573 AttrNumber varattno;
8575 Node *expr;
8576
8577 /*
8578 * If it's a RowExpr that was expanded from a whole-row Var, use the
8579 * column names attached to it. (We could let get_expr_result_tupdesc()
8580 * handle this, but it's much cheaper to just pull out the name we need.)
8581 */
8582 if (IsA(var, RowExpr))
8583 {
8584 RowExpr *r = (RowExpr *) var;
8585
8586 if (fieldno > 0 && fieldno <= list_length(r->colnames))
8587 return strVal(list_nth(r->colnames, fieldno - 1));
8588 }
8589
8590 /*
8591 * If it's a Param of type RECORD, try to find what the Param refers to.
8592 */
8593 if (IsA(var, Param))
8594 {
8595 Param *param = (Param *) var;
8597
8598 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8599 if (expr)
8600 {
8601 /* Found a match, so recurse to decipher the field name */
8603 const char *result;
8604
8606 result = get_name_for_var_field((Var *) expr, fieldno,
8607 0, context);
8609 return result;
8610 }
8611 }
8612
8613 /*
8614 * If it's a Var of type RECORD, we have to find what the Var refers to;
8615 * if not, we can use get_expr_result_tupdesc().
8616 */
8617 if (!IsA(var, Var) ||
8618 var->vartype != RECORDOID)
8619 {
8620 tupleDesc = get_expr_result_tupdesc((Node *) var, false);
8621 /* Got the tupdesc, so we can extract the field name */
8624 }
8625
8626 /* Find appropriate nesting depth */
8627 netlevelsup = var->varlevelsup + levelsup;
8628 if (netlevelsup >= list_length(context->namespaces))
8629 elog(ERROR, "bogus varlevelsup: %d offset %d",
8630 var->varlevelsup, levelsup);
8632 netlevelsup);
8633
8634 /*
8635 * If we have a syntactic referent for the Var, and we're working from a
8636 * parse tree, prefer to use the syntactic referent. Otherwise, fall back
8637 * on the semantic referent. (See comments in get_variable().)
8638 */
8639 if (var->varnosyn > 0 && dpns->plan == NULL)
8640 {
8641 varno = var->varnosyn;
8642 varattno = var->varattnosyn;
8643 }
8644 else
8645 {
8646 varno = var->varno;
8647 varattno = var->varattno;
8648 }
8649
8650 /*
8651 * Try to find the relevant RTE in this rtable. In a plan tree, it's
8652 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
8653 * down into the subplans, or INDEX_VAR, which is resolved similarly.
8654 *
8655 * Note: unlike get_variable and resolve_special_varno, we need not worry
8656 * about inheritance mapping: a child Var should have the same datatype as
8657 * its parent, and here we're really only interested in the Var's type.
8658 */
8659 if (varno >= 1 && varno <= list_length(dpns->rtable))
8660 {
8661 rte = rt_fetch(varno, dpns->rtable);
8662 attnum = varattno;
8663 }
8664 else if (varno == OUTER_VAR && dpns->outer_tlist)
8665 {
8668 const char *result;
8669
8670 tle = get_tle_by_resno(dpns->outer_tlist, varattno);
8671 if (!tle)
8672 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
8673
8674 Assert(netlevelsup == 0);
8675 push_child_plan(dpns, dpns->outer_plan, &save_dpns);
8676
8677 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8678 levelsup, context);
8679
8681 return result;
8682 }
8683 else if (varno == INNER_VAR && dpns->inner_tlist)
8684 {
8687 const char *result;
8688
8689 tle = get_tle_by_resno(dpns->inner_tlist, varattno);
8690 if (!tle)
8691 elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
8692
8693 Assert(netlevelsup == 0);
8694 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8695
8696 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8697 levelsup, context);
8698
8700 return result;
8701 }
8702 else if (varno == INDEX_VAR && dpns->index_tlist)
8703 {
8705 const char *result;
8706
8707 tle = get_tle_by_resno(dpns->index_tlist, varattno);
8708 if (!tle)
8709 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
8710
8711 Assert(netlevelsup == 0);
8712
8713 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8714 levelsup, context);
8715
8716 return result;
8717 }
8718 else
8719 {
8720 elog(ERROR, "bogus varno: %d", varno);
8721 return NULL; /* keep compiler quiet */
8722 }
8723
8725 {
8726 /* Var is whole-row reference to RTE, so select the right field */
8728 }
8729
8730 /*
8731 * This part has essentially the same logic as the parser's
8732 * expandRecordVariable() function, but we are dealing with a different
8733 * representation of the input context, and we only need one field name
8734 * not a TupleDesc. Also, we need special cases for finding subquery and
8735 * CTE subplans when deparsing Plan trees.
8736 */
8737 expr = (Node *) var; /* default if we can't drill down */
8738
8739 switch (rte->rtekind)
8740 {
8741 case RTE_RELATION:
8742 case RTE_VALUES:
8744 case RTE_GRAPH_TABLE:
8745 case RTE_RESULT:
8746
8747 /*
8748 * This case should not occur: a column of a table, values list,
8749 * or ENR shouldn't have type RECORD. Fall through and fail (most
8750 * likely) at the bottom.
8751 */
8752 break;
8753 case RTE_SUBQUERY:
8754 /* Subselect-in-FROM: examine sub-select's output expr */
8755 {
8756 if (rte->subquery)
8757 {
8758 TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
8759 attnum);
8760
8761 if (ste == NULL || ste->resjunk)
8762 elog(ERROR, "subquery %s does not have attribute %d",
8763 rte->eref->aliasname, attnum);
8764 expr = (Node *) ste->expr;
8765 if (IsA(expr, Var))
8766 {
8767 /*
8768 * Recurse into the sub-select to see what its Var
8769 * refers to. We have to build an additional level of
8770 * namespace to keep in step with varlevelsup in the
8771 * subselect; furthermore, the subquery RTE might be
8772 * from an outer query level, in which case the
8773 * namespace for the subselect must have that outer
8774 * level as parent namespace.
8775 */
8776 List *save_nslist = context->namespaces;
8779 const char *result;
8780
8782 netlevelsup);
8783
8784 set_deparse_for_query(&mydpns, rte->subquery,
8786
8788
8789 result = get_name_for_var_field((Var *) expr, fieldno,
8790 0, context);
8791
8792 context->namespaces = save_nslist;
8793
8794 return result;
8795 }
8796 /* else fall through to inspect the expression */
8797 }
8798 else
8799 {
8800 /*
8801 * We're deparsing a Plan tree so we don't have complete
8802 * RTE entries (in particular, rte->subquery is NULL). But
8803 * the only place we'd normally see a Var directly
8804 * referencing a SUBQUERY RTE is in a SubqueryScan plan
8805 * node, and we can look into the child plan's tlist
8806 * instead. An exception occurs if the subquery was
8807 * proven empty and optimized away: then we'd find such a
8808 * Var in a childless Result node, and there's nothing in
8809 * the plan tree that would let us figure out what it had
8810 * originally referenced. In that case, fall back on
8811 * printing "fN", analogously to the default column names
8812 * for RowExprs.
8813 */
8816 const char *result;
8817
8818 if (!dpns->inner_plan)
8819 {
8820 char *dummy_name = palloc(32);
8821
8822 Assert(dpns->plan && IsA(dpns->plan, Result));
8823 snprintf(dummy_name, 32, "f%d", fieldno);
8824 return dummy_name;
8825 }
8826 Assert(dpns->plan && IsA(dpns->plan, SubqueryScan));
8827
8828 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8829 if (!tle)
8830 elog(ERROR, "bogus varattno for subquery var: %d",
8831 attnum);
8832 Assert(netlevelsup == 0);
8833 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8834
8835 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8836 levelsup, context);
8837
8839 return result;
8840 }
8841 }
8842 break;
8843 case RTE_JOIN:
8844 /* Join RTE --- recursively inspect the alias variable */
8845 if (rte->joinaliasvars == NIL)
8846 elog(ERROR, "cannot decompile join alias var in plan tree");
8847 Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
8848 expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
8849 Assert(expr != NULL);
8850 /* we intentionally don't strip implicit coercions here */
8851 if (IsA(expr, Var))
8852 return get_name_for_var_field((Var *) expr, fieldno,
8853 var->varlevelsup + levelsup,
8854 context);
8855 /* else fall through to inspect the expression */
8856 break;
8857 case RTE_FUNCTION:
8858 case RTE_TABLEFUNC:
8859
8860 /*
8861 * We couldn't get here unless a function is declared with one of
8862 * its result columns as RECORD, which is not allowed.
8863 */
8864 break;
8865 case RTE_CTE:
8866 /* CTE reference: examine subquery's output expr */
8867 {
8868 CommonTableExpr *cte = NULL;
8869 Index ctelevelsup;
8870 ListCell *lc;
8871
8872 /*
8873 * Try to find the referenced CTE using the namespace stack.
8874 */
8875 ctelevelsup = rte->ctelevelsup + netlevelsup;
8876 if (ctelevelsup >= list_length(context->namespaces))
8877 lc = NULL;
8878 else
8879 {
8881
8883 list_nth(context->namespaces, ctelevelsup);
8884 foreach(lc, ctedpns->ctes)
8885 {
8886 cte = (CommonTableExpr *) lfirst(lc);
8887 if (strcmp(cte->ctename, rte->ctename) == 0)
8888 break;
8889 }
8890 }
8891 if (lc != NULL)
8892 {
8893 Query *ctequery = (Query *) cte->ctequery;
8895 attnum);
8896
8897 if (ste == NULL || ste->resjunk)
8898 elog(ERROR, "CTE %s does not have attribute %d",
8899 rte->eref->aliasname, attnum);
8900 expr = (Node *) ste->expr;
8901 if (IsA(expr, Var))
8902 {
8903 /*
8904 * Recurse into the CTE to see what its Var refers to.
8905 * We have to build an additional level of namespace
8906 * to keep in step with varlevelsup in the CTE;
8907 * furthermore it could be an outer CTE (compare
8908 * SUBQUERY case above).
8909 */
8910 List *save_nslist = context->namespaces;
8913 const char *result;
8914
8916 ctelevelsup);
8917
8918 set_deparse_for_query(&mydpns, ctequery,
8920
8922
8923 result = get_name_for_var_field((Var *) expr, fieldno,
8924 0, context);
8925
8926 context->namespaces = save_nslist;
8927
8928 return result;
8929 }
8930 /* else fall through to inspect the expression */
8931 }
8932 else
8933 {
8934 /*
8935 * We're deparsing a Plan tree so we don't have a CTE
8936 * list. But the only places we'd normally see a Var
8937 * directly referencing a CTE RTE are in CteScan or
8938 * WorkTableScan plan nodes. For those cases,
8939 * set_deparse_plan arranged for dpns->inner_plan to be
8940 * the plan node that emits the CTE or RecursiveUnion
8941 * result, and we can look at its tlist instead. As
8942 * above, this can fail if the CTE has been proven empty,
8943 * in which case fall back to "fN".
8944 */
8947 const char *result;
8948
8949 if (!dpns->inner_plan)
8950 {
8951 char *dummy_name = palloc(32);
8952
8953 Assert(dpns->plan && IsA(dpns->plan, Result));
8954 snprintf(dummy_name, 32, "f%d", fieldno);
8955 return dummy_name;
8956 }
8957 Assert(dpns->plan && (IsA(dpns->plan, CteScan) ||
8958 IsA(dpns->plan, WorkTableScan)));
8959
8960 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8961 if (!tle)
8962 elog(ERROR, "bogus varattno for subquery var: %d",
8963 attnum);
8964 Assert(netlevelsup == 0);
8965 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8966
8967 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8968 levelsup, context);
8969
8971 return result;
8972 }
8973 }
8974 break;
8975 case RTE_GROUP:
8976
8977 /*
8978 * We couldn't get here: any Vars that reference the RTE_GROUP RTE
8979 * should have been replaced with the underlying grouping
8980 * expressions.
8981 */
8982 break;
8983 }
8984
8985 /*
8986 * We now have an expression we can't expand any more, so see if
8987 * get_expr_result_tupdesc() can do anything with it.
8988 */
8989 tupleDesc = get_expr_result_tupdesc(expr, false);
8990 /* Got the tupdesc, so we can extract the field name */
8993}
8994
8995/*
8996 * Try to find the referenced expression for a PARAM_EXEC Param that might
8997 * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
8998 *
8999 * If successful, return the expression and set *dpns_p and *ancestor_cell_p
9000 * appropriately for calling push_ancestor_plan(). If no referent can be
9001 * found, return NULL.
9002 */
9003static Node *
9006{
9007 /* Initialize output parameters to prevent compiler warnings */
9008 *dpns_p = NULL;
9010
9011 /*
9012 * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
9013 * SubPlan argument. This will necessarily be in some ancestor of the
9014 * current expression's Plan node.
9015 */
9016 if (param->paramkind == PARAM_EXEC)
9017 {
9020 ListCell *lc;
9021
9022 dpns = (deparse_namespace *) linitial(context->namespaces);
9023 child_plan = dpns->plan;
9024
9025 foreach(lc, dpns->ancestors)
9026 {
9027 Node *ancestor = (Node *) lfirst(lc);
9028 ListCell *lc2;
9029
9030 /*
9031 * NestLoops transmit params to their inner child only.
9032 */
9033 if (IsA(ancestor, NestLoop) &&
9035 {
9037
9038 foreach(lc2, nl->nestParams)
9039 {
9041
9042 if (nlp->paramno == param->paramid)
9043 {
9044 /* Found a match, so return it */
9045 *dpns_p = dpns;
9047 return (Node *) nlp->paramval;
9048 }
9049 }
9050 }
9051
9052 /*
9053 * If ancestor is a SubPlan, check the arguments it provides.
9054 */
9055 if (IsA(ancestor, SubPlan))
9056 {
9057 SubPlan *subplan = (SubPlan *) ancestor;
9058 ListCell *lc3;
9059 ListCell *lc4;
9060
9061 forboth(lc3, subplan->parParam, lc4, subplan->args)
9062 {
9063 int paramid = lfirst_int(lc3);
9064 Node *arg = (Node *) lfirst(lc4);
9065
9066 if (paramid == param->paramid)
9067 {
9068 /*
9069 * Found a match, so return it. But, since Vars in
9070 * the arg are to be evaluated in the surrounding
9071 * context, we have to point to the next ancestor item
9072 * that is *not* a SubPlan.
9073 */
9074 ListCell *rest;
9075
9076 for_each_cell(rest, dpns->ancestors,
9077 lnext(dpns->ancestors, lc))
9078 {
9079 Node *ancestor2 = (Node *) lfirst(rest);
9080
9081 if (!IsA(ancestor2, SubPlan))
9082 {
9083 *dpns_p = dpns;
9085 return arg;
9086 }
9087 }
9088 elog(ERROR, "SubPlan cannot be outermost ancestor");
9089 }
9090 }
9091
9092 /* SubPlan isn't a kind of Plan, so skip the rest */
9093 continue;
9094 }
9095
9096 /*
9097 * We need not consider the ancestor's initPlan list, since
9098 * initplans never have any parParams.
9099 */
9100
9101 /* No luck, crawl up to next ancestor */
9102 child_plan = (Plan *) ancestor;
9103 }
9104 }
9105
9106 /* No referent found */
9107 return NULL;
9108}
9109
9110/*
9111 * Try to find a subplan/initplan that emits the value for a PARAM_EXEC Param.
9112 *
9113 * If successful, return the generating subplan/initplan and set *column_p
9114 * to the subplan's 0-based output column number.
9115 * Otherwise, return NULL.
9116 */
9117static SubPlan *
9119{
9120 /* Initialize output parameter to prevent compiler warnings */
9121 *column_p = 0;
9122
9123 /*
9124 * If it's a PARAM_EXEC parameter, search the current plan node as well as
9125 * ancestor nodes looking for a subplan or initplan that emits the value
9126 * for the Param. It could appear in the setParams of an initplan or
9127 * MULTIEXPR_SUBLINK subplan, or in the paramIds of an ancestral SubPlan.
9128 */
9129 if (param->paramkind == PARAM_EXEC)
9130 {
9131 SubPlan *result;
9133 ListCell *lc;
9134
9135 dpns = (deparse_namespace *) linitial(context->namespaces);
9136
9137 /* First check the innermost plan node's initplans */
9138 result = find_param_generator_initplan(param, dpns->plan, column_p);
9139 if (result)
9140 return result;
9141
9142 /*
9143 * The plan's targetlist might contain MULTIEXPR_SUBLINK SubPlans,
9144 * which can be referenced by Params elsewhere in the targetlist.
9145 * (Such Params should always be in the same targetlist, so there's no
9146 * need to do this work at upper plan nodes.)
9147 */
9148 foreach_node(TargetEntry, tle, dpns->plan->targetlist)
9149 {
9150 if (tle->expr && IsA(tle->expr, SubPlan))
9151 {
9152 SubPlan *subplan = (SubPlan *) tle->expr;
9153
9154 if (subplan->subLinkType == MULTIEXPR_SUBLINK)
9155 {
9156 foreach_int(paramid, subplan->setParam)
9157 {
9158 if (paramid == param->paramid)
9159 {
9160 /* Found a match, so return it. */
9161 *column_p = foreach_current_index(paramid);
9162 return subplan;
9163 }
9164 }
9165 }
9166 }
9167 }
9168
9169 /* No luck, so check the ancestor nodes */
9170 foreach(lc, dpns->ancestors)
9171 {
9172 Node *ancestor = (Node *) lfirst(lc);
9173
9174 /*
9175 * If ancestor is a SubPlan, check the paramIds it provides.
9176 */
9177 if (IsA(ancestor, SubPlan))
9178 {
9179 SubPlan *subplan = (SubPlan *) ancestor;
9180
9181 foreach_int(paramid, subplan->paramIds)
9182 {
9183 if (paramid == param->paramid)
9184 {
9185 /* Found a match, so return it. */
9186 *column_p = foreach_current_index(paramid);
9187 return subplan;
9188 }
9189 }
9190
9191 /* SubPlan isn't a kind of Plan, so skip the rest */
9192 continue;
9193 }
9194
9195 /*
9196 * Otherwise, it's some kind of Plan node, so check its initplans.
9197 */
9198 result = find_param_generator_initplan(param, (Plan *) ancestor,
9199 column_p);
9200 if (result)
9201 return result;
9202
9203 /* No luck, crawl up to next ancestor */
9204 }
9205 }
9206
9207 /* No generator found */
9208 return NULL;
9209}
9210
9211/*
9212 * Subroutine for find_param_generator: search one Plan node's initplans
9213 */
9214static SubPlan *
9216{
9217 foreach_node(SubPlan, subplan, plan->initPlan)
9218 {
9219 foreach_int(paramid, subplan->setParam)
9220 {
9221 if (paramid == param->paramid)
9222 {
9223 /* Found a match, so return it. */
9224 *column_p = foreach_current_index(paramid);
9225 return subplan;
9226 }
9227 }
9228 }
9229 return NULL;
9230}
9231
9232/*
9233 * Display a Param appropriately.
9234 */
9235static void
9237{
9238 Node *expr;
9241 SubPlan *subplan;
9242 int column;
9243
9244 /*
9245 * If it's a PARAM_EXEC parameter, try to locate the expression from which
9246 * the parameter was computed. This stanza handles only cases in which
9247 * the Param represents an input to the subplan we are currently in.
9248 */
9249 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
9250 if (expr)
9251 {
9252 /* Found a match, so print it */
9254 bool save_varprefix;
9255 bool need_paren;
9256
9257 /* Switch attention to the ancestor plan node */
9259
9260 /*
9261 * Force prefixing of Vars, since they won't belong to the relation
9262 * being scanned in the original plan node.
9263 */
9264 save_varprefix = context->varprefix;
9265 context->varprefix = true;
9266
9267 /*
9268 * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
9269 * upper-level Param, which wouldn't need extra parentheses.
9270 * Otherwise, insert parens to ensure the expression looks atomic.
9271 */
9272 need_paren = !(IsA(expr, Var) ||
9273 IsA(expr, Aggref) ||
9274 IsA(expr, GroupingFunc) ||
9275 IsA(expr, Param));
9276 if (need_paren)
9277 appendStringInfoChar(context->buf, '(');
9278
9279 get_rule_expr(expr, context, false);
9280
9281 if (need_paren)
9282 appendStringInfoChar(context->buf, ')');
9283
9284 context->varprefix = save_varprefix;
9285
9287
9288 return;
9289 }
9290
9291 /*
9292 * Alternatively, maybe it's a subplan output, which we print as a
9293 * reference to the subplan. (We could drill down into the subplan and
9294 * print the relevant targetlist expression, but that has been deemed too
9295 * confusing since it would violate normal SQL scope rules. Also, we're
9296 * relying on this reference to show that the testexpr containing the
9297 * Param has anything to do with that subplan at all.)
9298 */
9299 subplan = find_param_generator(param, context, &column);
9300 if (subplan)
9301 {
9302 const char *nameprefix;
9303
9304 if (subplan->isInitPlan)
9305 nameprefix = "InitPlan ";
9306 else
9307 nameprefix = "SubPlan ";
9308
9309 appendStringInfo(context->buf, "(%s%s%s).col%d",
9310 subplan->useHashTable ? "hashed " : "",
9311 nameprefix,
9312 subplan->plan_name, column + 1);
9313
9314 return;
9315 }
9316
9317 /*
9318 * If it's an external parameter, see if the outermost namespace provides
9319 * function argument names.
9320 */
9321 if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
9322 {
9323 dpns = llast(context->namespaces);
9324 if (dpns->argnames &&
9325 param->paramid > 0 &&
9326 param->paramid <= dpns->numargs)
9327 {
9328 char *argname = dpns->argnames[param->paramid - 1];
9329
9330 if (argname)
9331 {
9332 bool should_qualify = false;
9333 ListCell *lc;
9334
9335 /*
9336 * Qualify the parameter name if there are any other deparse
9337 * namespaces with range tables. This avoids qualifying in
9338 * trivial cases like "RETURN a + b", but makes it safe in all
9339 * other cases.
9340 */
9341 foreach(lc, context->namespaces)
9342 {
9344
9345 if (depns->rtable_names != NIL)
9346 {
9347 should_qualify = true;
9348 break;
9349 }
9350 }
9351 if (should_qualify)
9352 {
9353 appendStringInfoString(context->buf, quote_identifier(dpns->funcname));
9354 appendStringInfoChar(context->buf, '.');
9355 }
9356
9357 appendStringInfoString(context->buf, quote_identifier(argname));
9358 return;
9359 }
9360 }
9361 }
9362
9363 /*
9364 * Not PARAM_EXEC, or couldn't find referent: just print $N.
9365 *
9366 * It's a bug if we get here for anything except PARAM_EXTERN Params, but
9367 * in production builds printing $N seems more useful than failing.
9368 */
9369 Assert(param->paramkind == PARAM_EXTERN);
9370
9371 appendStringInfo(context->buf, "$%d", param->paramid);
9372}
9373
9374/*
9375 * get_simple_binary_op_name
9376 *
9377 * helper function for isSimpleNode
9378 * will return single char binary operator name, or NULL if it's not
9379 */
9380static const char *
9382{
9383 List *args = expr->args;
9384
9385 if (list_length(args) == 2)
9386 {
9387 /* binary operator */
9388 Node *arg1 = (Node *) linitial(args);
9389 Node *arg2 = (Node *) lsecond(args);
9390 const char *op;
9391
9393 if (strlen(op) == 1)
9394 return op;
9395 }
9396 return NULL;
9397}
9398
9399
9400/*
9401 * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
9402 *
9403 * true : simple in the context of parent node's type
9404 * false : not simple
9405 */
9406static bool
9407isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
9408{
9409 if (!node)
9410 return false;
9411
9412 switch (nodeTag(node))
9413 {
9414 case T_Var:
9415 case T_Const:
9416 case T_Param:
9418 case T_SetToDefault:
9419 case T_CurrentOfExpr:
9420 /* single words: always simple */
9421 return true;
9422
9423 case T_SubscriptingRef:
9424 case T_ArrayExpr:
9425 case T_RowExpr:
9426 case T_CoalesceExpr:
9427 case T_MinMaxExpr:
9428 case T_SQLValueFunction:
9429 case T_XmlExpr:
9430 case T_NextValueExpr:
9431 case T_NullIfExpr:
9432 case T_Aggref:
9433 case T_GroupingFunc:
9434 case T_WindowFunc:
9435 case T_MergeSupportFunc:
9436 case T_FuncExpr:
9438 case T_JsonExpr:
9439 /* function-like: name(..) or name[..] */
9440 return true;
9441
9442 /* CASE keywords act as parentheses */
9443 case T_CaseExpr:
9444 return true;
9445
9446 case T_FieldSelect:
9447
9448 /*
9449 * appears simple since . has top precedence, unless parent is
9450 * T_FieldSelect itself!
9451 */
9452 return !IsA(parentNode, FieldSelect);
9453
9454 case T_FieldStore:
9455
9456 /*
9457 * treat like FieldSelect (probably doesn't matter)
9458 */
9459 return !IsA(parentNode, FieldStore);
9460
9461 case T_CoerceToDomain:
9462 /* maybe simple, check args */
9463 return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
9464 node, prettyFlags);
9465 case T_RelabelType:
9466 return isSimpleNode((Node *) ((RelabelType *) node)->arg,
9467 node, prettyFlags);
9468 case T_CoerceViaIO:
9469 return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
9470 node, prettyFlags);
9471 case T_ArrayCoerceExpr:
9472 return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
9473 node, prettyFlags);
9475 return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
9476 node, prettyFlags);
9477 case T_ReturningExpr:
9478 return isSimpleNode((Node *) ((ReturningExpr *) node)->retexpr,
9479 node, prettyFlags);
9480
9481 case T_OpExpr:
9482 {
9483 /* depends on parent node type; needs further checking */
9484 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
9485 {
9486 const char *op;
9487 const char *parentOp;
9488 bool is_lopriop;
9489 bool is_hipriop;
9490 bool is_lopriparent;
9491 bool is_hipriparent;
9492
9493 op = get_simple_binary_op_name((OpExpr *) node);
9494 if (!op)
9495 return false;
9496
9497 /* We know only the basic operators + - and * / % */
9498 is_lopriop = (strchr("+-", *op) != NULL);
9499 is_hipriop = (strchr("*/%", *op) != NULL);
9500 if (!(is_lopriop || is_hipriop))
9501 return false;
9502
9504 if (!parentOp)
9505 return false;
9506
9507 is_lopriparent = (strchr("+-", *parentOp) != NULL);
9508 is_hipriparent = (strchr("*/%", *parentOp) != NULL);
9510 return false;
9511
9513 return true; /* op binds tighter than parent */
9514
9516 return false;
9517
9518 /*
9519 * Operators are same priority --- can skip parens only if
9520 * we have (a - b) - c, not a - (b - c).
9521 */
9522 if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
9523 return true;
9524
9525 return false;
9526 }
9527 /* else do the same stuff as for T_SubLink et al. */
9528 }
9530
9531 case T_SubLink:
9532 case T_NullTest:
9533 case T_BooleanTest:
9534 case T_DistinctExpr:
9535 case T_JsonIsPredicate:
9536 switch (nodeTag(parentNode))
9537 {
9538 case T_FuncExpr:
9539 {
9540 /* special handling for casts and COERCE_SQL_SYNTAX */
9541 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
9542
9543 if (type == COERCE_EXPLICIT_CAST ||
9546 return false;
9547 return true; /* own parentheses */
9548 }
9549 case T_BoolExpr: /* lower precedence */
9550 case T_SubscriptingRef: /* other separators */
9551 case T_ArrayExpr: /* other separators */
9552 case T_RowExpr: /* other separators */
9553 case T_CoalesceExpr: /* own parentheses */
9554 case T_MinMaxExpr: /* own parentheses */
9555 case T_XmlExpr: /* own parentheses */
9556 case T_NullIfExpr: /* other separators */
9557 case T_Aggref: /* own parentheses */
9558 case T_GroupingFunc: /* own parentheses */
9559 case T_WindowFunc: /* own parentheses */
9560 case T_CaseExpr: /* other separators */
9561 return true;
9562 default:
9563 return false;
9564 }
9565
9566 case T_BoolExpr:
9567 switch (nodeTag(parentNode))
9568 {
9569 case T_BoolExpr:
9570 if (prettyFlags & PRETTYFLAG_PAREN)
9571 {
9574
9575 type = ((BoolExpr *) node)->boolop;
9576 parentType = ((BoolExpr *) parentNode)->boolop;
9577 switch (type)
9578 {
9579 case NOT_EXPR:
9580 case AND_EXPR:
9582 return true;
9583 break;
9584 case OR_EXPR:
9585 if (parentType == OR_EXPR)
9586 return true;
9587 break;
9588 }
9589 }
9590 return false;
9591 case T_FuncExpr:
9592 {
9593 /* special handling for casts and COERCE_SQL_SYNTAX */
9594 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
9595
9596 if (type == COERCE_EXPLICIT_CAST ||
9599 return false;
9600 return true; /* own parentheses */
9601 }
9602 case T_SubscriptingRef: /* other separators */
9603 case T_ArrayExpr: /* other separators */
9604 case T_RowExpr: /* other separators */
9605 case T_CoalesceExpr: /* own parentheses */
9606 case T_MinMaxExpr: /* own parentheses */
9607 case T_XmlExpr: /* own parentheses */
9608 case T_NullIfExpr: /* other separators */
9609 case T_Aggref: /* own parentheses */
9610 case T_GroupingFunc: /* own parentheses */
9611 case T_WindowFunc: /* own parentheses */
9612 case T_CaseExpr: /* other separators */
9613 case T_JsonExpr: /* own parentheses */
9614 return true;
9615 default:
9616 return false;
9617 }
9618
9619 case T_JsonValueExpr:
9620 /* maybe simple, check args */
9621 return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
9622 node, prettyFlags);
9623
9624 default:
9625 break;
9626 }
9627 /* those we don't know: in dubio complexo */
9628 return false;
9629}
9630
9631
9632/*
9633 * appendContextKeyword - append a keyword to buffer
9634 *
9635 * If prettyPrint is enabled, perform a line break, and adjust indentation.
9636 * Otherwise, just append the keyword.
9637 */
9638static void
9640 int indentBefore, int indentAfter, int indentPlus)
9641{
9642 StringInfo buf = context->buf;
9643
9644 if (PRETTY_INDENT(context))
9645 {
9646 int indentAmount;
9647
9648 context->indentLevel += indentBefore;
9649
9650 /* remove any trailing spaces currently in the buffer ... */
9652 /* ... then add a newline and some spaces */
9654
9655 if (context->indentLevel < PRETTYINDENT_LIMIT)
9656 indentAmount = Max(context->indentLevel, 0) + indentPlus;
9657 else
9658 {
9659 /*
9660 * If we're indented more than PRETTYINDENT_LIMIT characters, try
9661 * to conserve horizontal space by reducing the per-level
9662 * indentation. For best results the scale factor here should
9663 * divide all the indent amounts that get added to indentLevel
9664 * (PRETTYINDENT_STD, etc). It's important that the indentation
9665 * not grow unboundedly, else deeply-nested trees use O(N^2)
9666 * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
9667 */
9669 (context->indentLevel - PRETTYINDENT_LIMIT) /
9670 (PRETTYINDENT_STD / 2);
9672 /* scale/wrap logic affects indentLevel, but not indentPlus */
9674 }
9676
9678
9679 context->indentLevel += indentAfter;
9680 if (context->indentLevel < 0)
9681 context->indentLevel = 0;
9682 }
9683 else
9685}
9686
9687/*
9688 * removeStringInfoSpaces - delete trailing spaces from a buffer.
9689 *
9690 * Possibly this should move to stringinfo.c at some point.
9691 */
9692static void
9694{
9695 while (str->len > 0 && str->data[str->len - 1] == ' ')
9696 str->data[--(str->len)] = '\0';
9697}
9698
9699
9700/*
9701 * get_rule_expr_paren - deparse expr using get_rule_expr,
9702 * embracing the string with parentheses if necessary for prettyPrint.
9703 *
9704 * Never embrace if prettyFlags=0, because it's done in the calling node.
9705 *
9706 * Any node that does *not* embrace its argument node by sql syntax (with
9707 * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
9708 * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
9709 * added.
9710 */
9711static void
9714{
9715 bool need_paren;
9716
9717 need_paren = PRETTY_PAREN(context) &&
9718 !isSimpleNode(node, parentNode, context->prettyFlags);
9719
9720 if (need_paren)
9721 appendStringInfoChar(context->buf, '(');
9722
9723 get_rule_expr(node, context, showimplicit);
9724
9725 if (need_paren)
9726 appendStringInfoChar(context->buf, ')');
9727}
9728
9729static void
9731 const char *on)
9732{
9733 /*
9734 * The order of array elements must correspond to the order of
9735 * JsonBehaviorType members.
9736 */
9737 const char *behavior_names[] =
9738 {
9739 " NULL",
9740 " ERROR",
9741 " EMPTY",
9742 " TRUE",
9743 " FALSE",
9744 " UNKNOWN",
9745 " EMPTY ARRAY",
9746 " EMPTY OBJECT",
9747 " DEFAULT "
9748 };
9749
9750 if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
9751 elog(ERROR, "invalid json behavior type: %d", behavior->btype);
9752
9753 appendStringInfoString(context->buf, behavior_names[behavior->btype]);
9754
9755 if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
9756 get_rule_expr(behavior->expr, context, false);
9757
9758 appendStringInfo(context->buf, " ON %s", on);
9759}
9760
9761/*
9762 * get_json_expr_options
9763 *
9764 * Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and
9765 * JSON_TABLE columns.
9766 */
9767static void
9770{
9771 if (jsexpr->op == JSON_QUERY_OP)
9772 {
9773 if (jsexpr->wrapper == JSW_CONDITIONAL)
9774 appendStringInfoString(context->buf, " WITH CONDITIONAL WRAPPER");
9775 else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
9776 appendStringInfoString(context->buf, " WITH UNCONDITIONAL WRAPPER");
9777 /* The default */
9778 else if (jsexpr->wrapper == JSW_NONE || jsexpr->wrapper == JSW_UNSPEC)
9779 appendStringInfoString(context->buf, " WITHOUT WRAPPER");
9780
9781 if (jsexpr->omit_quotes)
9782 appendStringInfoString(context->buf, " OMIT QUOTES");
9783 /* The default */
9784 else
9785 appendStringInfoString(context->buf, " KEEP QUOTES");
9786 }
9787
9788 if (jsexpr->on_empty && jsexpr->on_empty->btype != default_behavior)
9789 get_json_behavior(jsexpr->on_empty, context, "EMPTY");
9790
9791 if (jsexpr->on_error && jsexpr->on_error->btype != default_behavior)
9792 get_json_behavior(jsexpr->on_error, context, "ERROR");
9793}
9794
9795/* ----------
9796 * get_rule_expr - Parse back an expression
9797 *
9798 * Note: showimplicit determines whether we display any implicit cast that
9799 * is present at the top of the expression tree. It is a passed argument,
9800 * not a field of the context struct, because we change the value as we
9801 * recurse down into the expression. In general we suppress implicit casts
9802 * when the result type is known with certainty (eg, the arguments of an
9803 * OR must be boolean). We display implicit casts for arguments of functions
9804 * and operators, since this is needed to be certain that the same function
9805 * or operator will be chosen when the expression is re-parsed.
9806 * ----------
9807 */
9808static void
9810 bool showimplicit)
9811{
9812 StringInfo buf = context->buf;
9813
9814 if (node == NULL)
9815 return;
9816
9817 /* Guard against excessively long or deeply-nested queries */
9820
9821 /*
9822 * Each level of get_rule_expr must emit an indivisible term
9823 * (parenthesized if necessary) to ensure result is reparsed into the same
9824 * expression tree. The only exception is that when the input is a List,
9825 * we emit the component items comma-separated with no surrounding
9826 * decoration; this is convenient for most callers.
9827 */
9828 switch (nodeTag(node))
9829 {
9830 case T_Var:
9831 (void) get_variable((Var *) node, 0, false, context);
9832 break;
9833
9834 case T_Const:
9835 get_const_expr((Const *) node, context, 0);
9836 break;
9837
9838 case T_Param:
9839 get_parameter((Param *) node, context);
9840 break;
9841
9842 case T_Aggref:
9843 get_agg_expr((Aggref *) node, context, (Aggref *) node);
9844 break;
9845
9846 case T_GroupingFunc:
9847 {
9848 GroupingFunc *gexpr = (GroupingFunc *) node;
9849
9850 appendStringInfoString(buf, "GROUPING(");
9851 get_rule_expr((Node *) gexpr->args, context, true);
9853 }
9854 break;
9855
9856 case T_WindowFunc:
9857 get_windowfunc_expr((WindowFunc *) node, context);
9858 break;
9859
9860 case T_MergeSupportFunc:
9861 appendStringInfoString(buf, "MERGE_ACTION()");
9862 break;
9863
9864 case T_SubscriptingRef:
9865 {
9866 SubscriptingRef *sbsref = (SubscriptingRef *) node;
9867 bool need_parens;
9868
9869 /*
9870 * If the argument is a CaseTestExpr, we must be inside a
9871 * FieldStore, ie, we are assigning to an element of an array
9872 * within a composite column. Since we already punted on
9873 * displaying the FieldStore's target information, just punt
9874 * here too, and display only the assignment source
9875 * expression.
9876 */
9877 if (IsA(sbsref->refexpr, CaseTestExpr))
9878 {
9879 Assert(sbsref->refassgnexpr);
9880 get_rule_expr((Node *) sbsref->refassgnexpr,
9881 context, showimplicit);
9882 break;
9883 }
9884
9885 /*
9886 * Parenthesize the argument unless it's a simple Var or a
9887 * FieldSelect. (In particular, if it's another
9888 * SubscriptingRef, we *must* parenthesize to avoid
9889 * confusion.)
9890 */
9891 need_parens = !IsA(sbsref->refexpr, Var) &&
9892 !IsA(sbsref->refexpr, FieldSelect);
9893 if (need_parens)
9895 get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
9896 if (need_parens)
9898
9899 /*
9900 * If there's a refassgnexpr, we want to print the node in the
9901 * format "container[subscripts] := refassgnexpr". This is
9902 * not legal SQL, so decompilation of INSERT or UPDATE
9903 * statements should always use processIndirection as part of
9904 * the statement-level syntax. We should only see this when
9905 * EXPLAIN tries to print the targetlist of a plan resulting
9906 * from such a statement.
9907 */
9908 if (sbsref->refassgnexpr)
9909 {
9910 Node *refassgnexpr;
9911
9912 /*
9913 * Use processIndirection to print this node's subscripts
9914 * as well as any additional field selections or
9915 * subscripting in immediate descendants. It returns the
9916 * RHS expr that is actually being "assigned".
9917 */
9918 refassgnexpr = processIndirection(node, context);
9919 appendStringInfoString(buf, " := ");
9920 get_rule_expr(refassgnexpr, context, showimplicit);
9921 }
9922 else
9923 {
9924 /* Just an ordinary container fetch, so print subscripts */
9925 printSubscripts(sbsref, context);
9926 }
9927 }
9928 break;
9929
9930 case T_FuncExpr:
9931 get_func_expr((FuncExpr *) node, context, showimplicit);
9932 break;
9933
9934 case T_NamedArgExpr:
9935 {
9936 NamedArgExpr *na = (NamedArgExpr *) node;
9937
9938 appendStringInfo(buf, "%s => ", quote_identifier(na->name));
9939 get_rule_expr((Node *) na->arg, context, showimplicit);
9940 }
9941 break;
9942
9943 case T_OpExpr:
9944 get_oper_expr((OpExpr *) node, context);
9945 break;
9946
9947 case T_DistinctExpr:
9948 {
9949 DistinctExpr *expr = (DistinctExpr *) node;
9950 List *args = expr->args;
9951 Node *arg1 = (Node *) linitial(args);
9952 Node *arg2 = (Node *) lsecond(args);
9953
9954 if (!PRETTY_PAREN(context))
9956 get_rule_expr_paren(arg1, context, true, node);
9957 appendStringInfoString(buf, " IS DISTINCT FROM ");
9958 get_rule_expr_paren(arg2, context, true, node);
9959 if (!PRETTY_PAREN(context))
9961 }
9962 break;
9963
9964 case T_NullIfExpr:
9965 {
9966 NullIfExpr *nullifexpr = (NullIfExpr *) node;
9967
9968 appendStringInfoString(buf, "NULLIF(");
9969 get_rule_expr((Node *) nullifexpr->args, context, true);
9971 }
9972 break;
9973
9975 {
9976 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
9977 List *args = expr->args;
9978 Node *arg1 = (Node *) linitial(args);
9979 Node *arg2 = (Node *) lsecond(args);
9980
9981 if (!PRETTY_PAREN(context))
9983 get_rule_expr_paren(arg1, context, true, node);
9984 appendStringInfo(buf, " %s %s (",
9986 exprType(arg1),
9988 expr->useOr ? "ANY" : "ALL");
9989 get_rule_expr_paren(arg2, context, true, node);
9990
9991 /*
9992 * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
9993 * a bare sub-SELECT. Since we're here, the sub-SELECT must
9994 * be meant as a scalar sub-SELECT yielding an array value to
9995 * be used in ScalarArrayOpExpr; but the grammar will
9996 * preferentially interpret such a construct as an ANY/ALL
9997 * SubLink. To prevent misparsing the output that way, insert
9998 * a dummy coercion (which will be stripped by parse analysis,
9999 * so no inefficiency is added in dump and reload). This is
10000 * indeed most likely what the user wrote to get the construct
10001 * accepted in the first place.
10002 */
10003 if (IsA(arg2, SubLink) &&
10004 ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
10005 appendStringInfo(buf, "::%s",
10007 exprTypmod(arg2)));
10009 if (!PRETTY_PAREN(context))
10011 }
10012 break;
10013
10014 case T_BoolExpr:
10015 {
10016 BoolExpr *expr = (BoolExpr *) node;
10017 Node *first_arg = linitial(expr->args);
10018 ListCell *arg;
10019
10020 switch (expr->boolop)
10021 {
10022 case AND_EXPR:
10023 if (!PRETTY_PAREN(context))
10026 false, node);
10027 for_each_from(arg, expr->args, 1)
10028 {
10029 appendStringInfoString(buf, " AND ");
10030 get_rule_expr_paren((Node *) lfirst(arg), context,
10031 false, node);
10032 }
10033 if (!PRETTY_PAREN(context))
10035 break;
10036
10037 case OR_EXPR:
10038 if (!PRETTY_PAREN(context))
10041 false, node);
10042 for_each_from(arg, expr->args, 1)
10043 {
10044 appendStringInfoString(buf, " OR ");
10045 get_rule_expr_paren((Node *) lfirst(arg), context,
10046 false, node);
10047 }
10048 if (!PRETTY_PAREN(context))
10050 break;
10051
10052 case NOT_EXPR:
10053 if (!PRETTY_PAREN(context))
10055 appendStringInfoString(buf, "NOT ");
10057 false, node);
10058 if (!PRETTY_PAREN(context))
10060 break;
10061
10062 default:
10063 elog(ERROR, "unrecognized boolop: %d",
10064 (int) expr->boolop);
10065 }
10066 }
10067 break;
10068
10069 case T_SubLink:
10070 get_sublink_expr((SubLink *) node, context);
10071 break;
10072
10073 case T_SubPlan:
10074 {
10075 SubPlan *subplan = (SubPlan *) node;
10076
10077 /*
10078 * We cannot see an already-planned subplan in rule deparsing,
10079 * only while EXPLAINing a query plan. We don't try to
10080 * reconstruct the original SQL, just reference the subplan
10081 * that appears elsewhere in EXPLAIN's result. It does seem
10082 * useful to show the subLinkType and testexpr (if any), and
10083 * we also note whether the subplan will be hashed.
10084 */
10085 switch (subplan->subLinkType)
10086 {
10087 case EXISTS_SUBLINK:
10088 appendStringInfoString(buf, "EXISTS(");
10089 Assert(subplan->testexpr == NULL);
10090 break;
10091 case ALL_SUBLINK:
10092 appendStringInfoString(buf, "(ALL ");
10093 Assert(subplan->testexpr != NULL);
10094 break;
10095 case ANY_SUBLINK:
10096 appendStringInfoString(buf, "(ANY ");
10097 Assert(subplan->testexpr != NULL);
10098 break;
10099 case ROWCOMPARE_SUBLINK:
10100 /* Parenthesizing the testexpr seems sufficient */
10102 Assert(subplan->testexpr != NULL);
10103 break;
10104 case EXPR_SUBLINK:
10105 /* No need to decorate these subplan references */
10107 Assert(subplan->testexpr == NULL);
10108 break;
10109 case MULTIEXPR_SUBLINK:
10110 /* MULTIEXPR isn't executed in the normal way */
10111 appendStringInfoString(buf, "(rescan ");
10112 Assert(subplan->testexpr == NULL);
10113 break;
10114 case ARRAY_SUBLINK:
10115 appendStringInfoString(buf, "ARRAY(");
10116 Assert(subplan->testexpr == NULL);
10117 break;
10118 case CTE_SUBLINK:
10119 /* This case is unreachable within expressions */
10120 appendStringInfoString(buf, "CTE(");
10121 Assert(subplan->testexpr == NULL);
10122 break;
10123 }
10124
10125 if (subplan->testexpr != NULL)
10126 {
10128
10129 /*
10130 * Push SubPlan into ancestors list while deparsing
10131 * testexpr, so that we can handle PARAM_EXEC references
10132 * to the SubPlan's paramIds. (This makes it look like
10133 * the SubPlan is an "ancestor" of the current plan node,
10134 * which is a little weird, but it does no harm.) In this
10135 * path, we don't need to mention the SubPlan explicitly,
10136 * because the referencing Params will show its existence.
10137 */
10138 dpns = (deparse_namespace *) linitial(context->namespaces);
10139 dpns->ancestors = lcons(subplan, dpns->ancestors);
10140
10141 get_rule_expr(subplan->testexpr, context, showimplicit);
10143
10144 dpns->ancestors = list_delete_first(dpns->ancestors);
10145 }
10146 else
10147 {
10148 const char *nameprefix;
10149
10150 /* No referencing Params, so show the SubPlan's name */
10151 if (subplan->isInitPlan)
10152 nameprefix = "InitPlan ";
10153 else
10154 nameprefix = "SubPlan ";
10155 if (subplan->useHashTable)
10156 appendStringInfo(buf, "hashed %s%s)",
10157 nameprefix, subplan->plan_name);
10158 else
10159 appendStringInfo(buf, "%s%s)",
10160 nameprefix, subplan->plan_name);
10161 }
10162 }
10163 break;
10164
10166 {
10168 ListCell *lc;
10169
10170 /*
10171 * This case cannot be reached in normal usage, since no
10172 * AlternativeSubPlan can appear either in parsetrees or
10173 * finished plan trees. We keep it just in case somebody
10174 * wants to use this code to print planner data structures.
10175 */
10176 appendStringInfoString(buf, "(alternatives: ");
10177 foreach(lc, asplan->subplans)
10178 {
10179 SubPlan *splan = lfirst_node(SubPlan, lc);
10180 const char *nameprefix;
10181
10182 if (splan->isInitPlan)
10183 nameprefix = "InitPlan ";
10184 else
10185 nameprefix = "SubPlan ";
10186 if (splan->useHashTable)
10187 appendStringInfo(buf, "hashed %s%s", nameprefix,
10188 splan->plan_name);
10189 else
10191 splan->plan_name);
10192 if (lnext(asplan->subplans, lc))
10193 appendStringInfoString(buf, " or ");
10194 }
10196 }
10197 break;
10198
10199 case T_FieldSelect:
10200 {
10201 FieldSelect *fselect = (FieldSelect *) node;
10202 Node *arg = (Node *) fselect->arg;
10203 int fno = fselect->fieldnum;
10204 const char *fieldname;
10205 bool need_parens;
10206
10207 /*
10208 * Parenthesize the argument unless it's a SubscriptingRef or
10209 * another FieldSelect. Note in particular that it would be
10210 * WRONG to not parenthesize a Var argument; simplicity is not
10211 * the issue here, having the right number of names is.
10212 */
10214 !IsA(arg, FieldSelect);
10215 if (need_parens)
10217 get_rule_expr(arg, context, true);
10218 if (need_parens)
10220
10221 /*
10222 * Get and print the field name.
10223 */
10224 fieldname = get_name_for_var_field((Var *) arg, fno,
10225 0, context);
10226 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
10227 }
10228 break;
10229
10230 case T_FieldStore:
10231 {
10232 FieldStore *fstore = (FieldStore *) node;
10233 bool need_parens;
10234
10235 /*
10236 * There is no good way to represent a FieldStore as real SQL,
10237 * so decompilation of INSERT or UPDATE statements should
10238 * always use processIndirection as part of the
10239 * statement-level syntax. We should only get here when
10240 * EXPLAIN tries to print the targetlist of a plan resulting
10241 * from such a statement. The plan case is even harder than
10242 * ordinary rules would be, because the planner tries to
10243 * collapse multiple assignments to the same field or subfield
10244 * into one FieldStore; so we can see a list of target fields
10245 * not just one, and the arguments could be FieldStores
10246 * themselves. We don't bother to try to print the target
10247 * field names; we just print the source arguments, with a
10248 * ROW() around them if there's more than one. This isn't
10249 * terribly complete, but it's probably good enough for
10250 * EXPLAIN's purposes; especially since anything more would be
10251 * either hopelessly confusing or an even poorer
10252 * representation of what the plan is actually doing.
10253 */
10254 need_parens = (list_length(fstore->newvals) != 1);
10255 if (need_parens)
10256 appendStringInfoString(buf, "ROW(");
10257 get_rule_expr((Node *) fstore->newvals, context, showimplicit);
10258 if (need_parens)
10260 }
10261 break;
10262
10263 case T_RelabelType:
10264 {
10265 RelabelType *relabel = (RelabelType *) node;
10266 Node *arg = (Node *) relabel->arg;
10267
10268 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
10269 !showimplicit)
10270 {
10271 /* don't show the implicit cast */
10272 get_rule_expr_paren(arg, context, false, node);
10273 }
10274 else
10275 {
10276 get_coercion_expr(arg, context,
10277 relabel->resulttype,
10278 relabel->resulttypmod,
10279 node);
10280 }
10281 }
10282 break;
10283
10284 case T_CoerceViaIO:
10285 {
10286 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
10287 Node *arg = (Node *) iocoerce->arg;
10288
10289 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
10290 !showimplicit)
10291 {
10292 /* don't show the implicit cast */
10293 get_rule_expr_paren(arg, context, false, node);
10294 }
10295 else
10296 {
10297 get_coercion_expr(arg, context,
10298 iocoerce->resulttype,
10299 -1,
10300 node);
10301 }
10302 }
10303 break;
10304
10305 case T_ArrayCoerceExpr:
10306 {
10308 Node *arg = (Node *) acoerce->arg;
10309
10310 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
10311 !showimplicit)
10312 {
10313 /* don't show the implicit cast */
10314 get_rule_expr_paren(arg, context, false, node);
10315 }
10316 else
10317 {
10318 get_coercion_expr(arg, context,
10319 acoerce->resulttype,
10320 acoerce->resulttypmod,
10321 node);
10322 }
10323 }
10324 break;
10325
10327 {
10329 Node *arg = (Node *) convert->arg;
10330
10331 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
10332 !showimplicit)
10333 {
10334 /* don't show the implicit cast */
10335 get_rule_expr_paren(arg, context, false, node);
10336 }
10337 else
10338 {
10339 get_coercion_expr(arg, context,
10340 convert->resulttype, -1,
10341 node);
10342 }
10343 }
10344 break;
10345
10346 case T_CollateExpr:
10347 {
10348 CollateExpr *collate = (CollateExpr *) node;
10349 Node *arg = (Node *) collate->arg;
10350
10351 if (!PRETTY_PAREN(context))
10353 get_rule_expr_paren(arg, context, showimplicit, node);
10354 appendStringInfo(buf, " COLLATE %s",
10356 if (!PRETTY_PAREN(context))
10358 }
10359 break;
10360
10361 case T_CaseExpr:
10362 {
10363 CaseExpr *caseexpr = (CaseExpr *) node;
10364 ListCell *temp;
10365
10366 appendContextKeyword(context, "CASE",
10367 0, PRETTYINDENT_VAR, 0);
10368 if (caseexpr->arg)
10369 {
10371 get_rule_expr((Node *) caseexpr->arg, context, true);
10372 }
10373 foreach(temp, caseexpr->args)
10374 {
10376 Node *w = (Node *) when->expr;
10377
10378 if (caseexpr->arg)
10379 {
10380 /*
10381 * The parser should have produced WHEN clauses of the
10382 * form "CaseTestExpr = RHS", possibly with an
10383 * implicit coercion inserted above the CaseTestExpr.
10384 * For accurate decompilation of rules it's essential
10385 * that we show just the RHS. However in an
10386 * expression that's been through the optimizer, the
10387 * WHEN clause could be almost anything (since the
10388 * equality operator could have been expanded into an
10389 * inline function). If we don't recognize the form
10390 * of the WHEN clause, just punt and display it as-is.
10391 */
10392 if (IsA(w, OpExpr))
10393 {
10394 List *args = ((OpExpr *) w)->args;
10395
10396 if (list_length(args) == 2 &&
10398 CaseTestExpr))
10399 w = (Node *) lsecond(args);
10400 }
10401 }
10402
10403 if (!PRETTY_INDENT(context))
10405 appendContextKeyword(context, "WHEN ",
10406 0, 0, 0);
10407 get_rule_expr(w, context, false);
10408 appendStringInfoString(buf, " THEN ");
10409 get_rule_expr((Node *) when->result, context, true);
10410 }
10411 if (!PRETTY_INDENT(context))
10413 appendContextKeyword(context, "ELSE ",
10414 0, 0, 0);
10415 get_rule_expr((Node *) caseexpr->defresult, context, true);
10416 if (!PRETTY_INDENT(context))
10418 appendContextKeyword(context, "END",
10419 -PRETTYINDENT_VAR, 0, 0);
10420 }
10421 break;
10422
10423 case T_CaseTestExpr:
10424 {
10425 /*
10426 * Normally we should never get here, since for expressions
10427 * that can contain this node type we attempt to avoid
10428 * recursing to it. But in an optimized expression we might
10429 * be unable to avoid that (see comments for CaseExpr). If we
10430 * do see one, print it as CASE_TEST_EXPR.
10431 */
10432 appendStringInfoString(buf, "CASE_TEST_EXPR");
10433 }
10434 break;
10435
10436 case T_ArrayExpr:
10437 {
10438 ArrayExpr *arrayexpr = (ArrayExpr *) node;
10439
10440 appendStringInfoString(buf, "ARRAY[");
10441 get_rule_expr((Node *) arrayexpr->elements, context, true);
10443
10444 /*
10445 * If the array isn't empty, we assume its elements are
10446 * coerced to the desired type. If it's empty, though, we
10447 * need an explicit coercion to the array type.
10448 */
10449 if (arrayexpr->elements == NIL)
10450 appendStringInfo(buf, "::%s",
10451 format_type_with_typemod(arrayexpr->array_typeid, -1));
10452 }
10453 break;
10454
10455 case T_RowExpr:
10456 {
10457 RowExpr *rowexpr = (RowExpr *) node;
10458 TupleDesc tupdesc = NULL;
10459 ListCell *arg;
10460 int i;
10461 char *sep;
10462
10463 /*
10464 * If it's a named type and not RECORD, we may have to skip
10465 * dropped columns and/or claim there are NULLs for added
10466 * columns.
10467 */
10468 if (rowexpr->row_typeid != RECORDOID)
10469 {
10470 tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
10471 Assert(list_length(rowexpr->args) <= tupdesc->natts);
10472 }
10473
10474 /*
10475 * SQL99 allows "ROW" to be omitted when there is more than
10476 * one column, but for simplicity we always print it.
10477 */
10478 appendStringInfoString(buf, "ROW(");
10479 sep = "";
10480 i = 0;
10481 foreach(arg, rowexpr->args)
10482 {
10483 Node *e = (Node *) lfirst(arg);
10484
10485 if (tupdesc == NULL ||
10487 {
10489 /* Whole-row Vars need special treatment here */
10490 get_rule_expr_toplevel(e, context, true);
10491 sep = ", ";
10492 }
10493 i++;
10494 }
10495 if (tupdesc != NULL)
10496 {
10497 while (i < tupdesc->natts)
10498 {
10499 if (!TupleDescCompactAttr(tupdesc, i)->attisdropped)
10500 {
10502 appendStringInfoString(buf, "NULL");
10503 sep = ", ";
10504 }
10505 i++;
10506 }
10507
10508 ReleaseTupleDesc(tupdesc);
10509 }
10511 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
10512 appendStringInfo(buf, "::%s",
10513 format_type_with_typemod(rowexpr->row_typeid, -1));
10514 }
10515 break;
10516
10517 case T_RowCompareExpr:
10518 {
10520
10521 /*
10522 * SQL99 allows "ROW" to be omitted when there is more than
10523 * one column, but for simplicity we always print it. Within
10524 * a ROW expression, whole-row Vars need special treatment, so
10525 * use get_rule_list_toplevel.
10526 */
10527 appendStringInfoString(buf, "(ROW(");
10528 get_rule_list_toplevel(rcexpr->largs, context, true);
10529
10530 /*
10531 * We assume that the name of the first-column operator will
10532 * do for all the rest too. This is definitely open to
10533 * failure, eg if some but not all operators were renamed
10534 * since the construct was parsed, but there seems no way to
10535 * be perfect.
10536 */
10537 appendStringInfo(buf, ") %s ROW(",
10539 exprType(linitial(rcexpr->largs)),
10540 exprType(linitial(rcexpr->rargs))));
10541 get_rule_list_toplevel(rcexpr->rargs, context, true);
10543 }
10544 break;
10545
10546 case T_CoalesceExpr:
10547 {
10549
10550 appendStringInfoString(buf, "COALESCE(");
10551 get_rule_expr((Node *) coalesceexpr->args, context, true);
10553 }
10554 break;
10555
10556 case T_MinMaxExpr:
10557 {
10558 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
10559
10560 switch (minmaxexpr->op)
10561 {
10562 case IS_GREATEST:
10563 appendStringInfoString(buf, "GREATEST(");
10564 break;
10565 case IS_LEAST:
10566 appendStringInfoString(buf, "LEAST(");
10567 break;
10568 }
10569 get_rule_expr((Node *) minmaxexpr->args, context, true);
10571 }
10572 break;
10573
10574 case T_SQLValueFunction:
10575 {
10576 SQLValueFunction *svf = (SQLValueFunction *) node;
10577
10578 /*
10579 * Note: this code knows that typmod for time, timestamp, and
10580 * timestamptz just prints as integer.
10581 */
10582 switch (svf->op)
10583 {
10584 case SVFOP_CURRENT_DATE:
10585 appendStringInfoString(buf, "CURRENT_DATE");
10586 break;
10587 case SVFOP_CURRENT_TIME:
10588 appendStringInfoString(buf, "CURRENT_TIME");
10589 break;
10591 appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
10592 break;
10594 appendStringInfoString(buf, "CURRENT_TIMESTAMP");
10595 break;
10597 appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
10598 svf->typmod);
10599 break;
10600 case SVFOP_LOCALTIME:
10601 appendStringInfoString(buf, "LOCALTIME");
10602 break;
10603 case SVFOP_LOCALTIME_N:
10604 appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
10605 break;
10607 appendStringInfoString(buf, "LOCALTIMESTAMP");
10608 break;
10610 appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
10611 svf->typmod);
10612 break;
10613 case SVFOP_CURRENT_ROLE:
10614 appendStringInfoString(buf, "CURRENT_ROLE");
10615 break;
10616 case SVFOP_CURRENT_USER:
10617 appendStringInfoString(buf, "CURRENT_USER");
10618 break;
10619 case SVFOP_USER:
10620 appendStringInfoString(buf, "USER");
10621 break;
10622 case SVFOP_SESSION_USER:
10623 appendStringInfoString(buf, "SESSION_USER");
10624 break;
10626 appendStringInfoString(buf, "CURRENT_CATALOG");
10627 break;
10629 appendStringInfoString(buf, "CURRENT_SCHEMA");
10630 break;
10631 }
10632 }
10633 break;
10634
10635 case T_XmlExpr:
10636 {
10637 XmlExpr *xexpr = (XmlExpr *) node;
10638 bool needcomma = false;
10639 ListCell *arg;
10640 ListCell *narg;
10641 Const *con;
10642
10643 switch (xexpr->op)
10644 {
10645 case IS_XMLCONCAT:
10646 appendStringInfoString(buf, "XMLCONCAT(");
10647 break;
10648 case IS_XMLELEMENT:
10649 appendStringInfoString(buf, "XMLELEMENT(");
10650 break;
10651 case IS_XMLFOREST:
10652 appendStringInfoString(buf, "XMLFOREST(");
10653 break;
10654 case IS_XMLPARSE:
10655 appendStringInfoString(buf, "XMLPARSE(");
10656 break;
10657 case IS_XMLPI:
10658 appendStringInfoString(buf, "XMLPI(");
10659 break;
10660 case IS_XMLROOT:
10661 appendStringInfoString(buf, "XMLROOT(");
10662 break;
10663 case IS_XMLSERIALIZE:
10664 appendStringInfoString(buf, "XMLSERIALIZE(");
10665 break;
10666 case IS_DOCUMENT:
10667 break;
10668 }
10669 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
10670 {
10671 if (xexpr->xmloption == XMLOPTION_DOCUMENT)
10672 appendStringInfoString(buf, "DOCUMENT ");
10673 else
10674 appendStringInfoString(buf, "CONTENT ");
10675 }
10676 if (xexpr->name)
10677 {
10678 appendStringInfo(buf, "NAME %s",
10680 needcomma = true;
10681 }
10682 if (xexpr->named_args)
10683 {
10684 if (xexpr->op != IS_XMLFOREST)
10685 {
10686 if (needcomma)
10688 appendStringInfoString(buf, "XMLATTRIBUTES(");
10689 needcomma = false;
10690 }
10691 forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
10692 {
10693 Node *e = (Node *) lfirst(arg);
10694 char *argname = strVal(lfirst(narg));
10695
10696 if (needcomma)
10698 get_rule_expr(e, context, true);
10699 appendStringInfo(buf, " AS %s",
10701 needcomma = true;
10702 }
10703 if (xexpr->op != IS_XMLFOREST)
10705 }
10706 if (xexpr->args)
10707 {
10708 if (needcomma)
10710 switch (xexpr->op)
10711 {
10712 case IS_XMLCONCAT:
10713 case IS_XMLELEMENT:
10714 case IS_XMLFOREST:
10715 case IS_XMLPI:
10716 case IS_XMLSERIALIZE:
10717 /* no extra decoration needed */
10718 get_rule_expr((Node *) xexpr->args, context, true);
10719 break;
10720 case IS_XMLPARSE:
10721 Assert(list_length(xexpr->args) == 2);
10722
10723 get_rule_expr((Node *) linitial(xexpr->args),
10724 context, true);
10725
10726 con = lsecond_node(Const, xexpr->args);
10727 Assert(!con->constisnull);
10728 if (DatumGetBool(con->constvalue))
10730 " PRESERVE WHITESPACE");
10731 else
10733 " STRIP WHITESPACE");
10734 break;
10735 case IS_XMLROOT:
10736 Assert(list_length(xexpr->args) == 3);
10737
10738 get_rule_expr((Node *) linitial(xexpr->args),
10739 context, true);
10740
10741 appendStringInfoString(buf, ", VERSION ");
10742 con = (Const *) lsecond(xexpr->args);
10743 if (IsA(con, Const) &&
10744 con->constisnull)
10745 appendStringInfoString(buf, "NO VALUE");
10746 else
10747 get_rule_expr((Node *) con, context, false);
10748
10749 con = lthird_node(Const, xexpr->args);
10750 if (con->constisnull)
10751 /* suppress STANDALONE NO VALUE */ ;
10752 else
10753 {
10754 switch (DatumGetInt32(con->constvalue))
10755 {
10756 case XML_STANDALONE_YES:
10758 ", STANDALONE YES");
10759 break;
10760 case XML_STANDALONE_NO:
10762 ", STANDALONE NO");
10763 break;
10766 ", STANDALONE NO VALUE");
10767 break;
10768 default:
10769 break;
10770 }
10771 }
10772 break;
10773 case IS_DOCUMENT:
10774 get_rule_expr_paren((Node *) xexpr->args, context, false, node);
10775 break;
10776 }
10777 }
10778 if (xexpr->op == IS_XMLSERIALIZE)
10779 {
10780 appendStringInfo(buf, " AS %s",
10781 format_type_with_typemod(xexpr->type,
10782 xexpr->typmod));
10783 if (xexpr->indent)
10784 appendStringInfoString(buf, " INDENT");
10785 else
10786 appendStringInfoString(buf, " NO INDENT");
10787 }
10788
10789 if (xexpr->op == IS_DOCUMENT)
10790 appendStringInfoString(buf, " IS DOCUMENT");
10791 else
10793 }
10794 break;
10795
10796 case T_NullTest:
10797 {
10798 NullTest *ntest = (NullTest *) node;
10799
10800 if (!PRETTY_PAREN(context))
10802 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
10803
10804 /*
10805 * For scalar inputs, we prefer to print as IS [NOT] NULL,
10806 * which is shorter and traditional. If it's a rowtype input
10807 * but we're applying a scalar test, must print IS [NOT]
10808 * DISTINCT FROM NULL to be semantically correct.
10809 */
10810 if (ntest->argisrow ||
10811 !type_is_rowtype(exprType((Node *) ntest->arg)))
10812 {
10813 switch (ntest->nulltesttype)
10814 {
10815 case IS_NULL:
10816 appendStringInfoString(buf, " IS NULL");
10817 break;
10818 case IS_NOT_NULL:
10819 appendStringInfoString(buf, " IS NOT NULL");
10820 break;
10821 default:
10822 elog(ERROR, "unrecognized nulltesttype: %d",
10823 (int) ntest->nulltesttype);
10824 }
10825 }
10826 else
10827 {
10828 switch (ntest->nulltesttype)
10829 {
10830 case IS_NULL:
10831 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
10832 break;
10833 case IS_NOT_NULL:
10834 appendStringInfoString(buf, " IS DISTINCT FROM NULL");
10835 break;
10836 default:
10837 elog(ERROR, "unrecognized nulltesttype: %d",
10838 (int) ntest->nulltesttype);
10839 }
10840 }
10841 if (!PRETTY_PAREN(context))
10843 }
10844 break;
10845
10846 case T_BooleanTest:
10847 {
10848 BooleanTest *btest = (BooleanTest *) node;
10849
10850 if (!PRETTY_PAREN(context))
10852 get_rule_expr_paren((Node *) btest->arg, context, false, node);
10853 switch (btest->booltesttype)
10854 {
10855 case IS_TRUE:
10856 appendStringInfoString(buf, " IS TRUE");
10857 break;
10858 case IS_NOT_TRUE:
10859 appendStringInfoString(buf, " IS NOT TRUE");
10860 break;
10861 case IS_FALSE:
10862 appendStringInfoString(buf, " IS FALSE");
10863 break;
10864 case IS_NOT_FALSE:
10865 appendStringInfoString(buf, " IS NOT FALSE");
10866 break;
10867 case IS_UNKNOWN:
10868 appendStringInfoString(buf, " IS UNKNOWN");
10869 break;
10870 case IS_NOT_UNKNOWN:
10871 appendStringInfoString(buf, " IS NOT UNKNOWN");
10872 break;
10873 default:
10874 elog(ERROR, "unrecognized booltesttype: %d",
10875 (int) btest->booltesttype);
10876 }
10877 if (!PRETTY_PAREN(context))
10879 }
10880 break;
10881
10882 case T_CoerceToDomain:
10883 {
10885 Node *arg = (Node *) ctest->arg;
10886
10887 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
10888 !showimplicit)
10889 {
10890 /* don't show the implicit cast */
10891 get_rule_expr(arg, context, false);
10892 }
10893 else
10894 {
10895 get_coercion_expr(arg, context,
10896 ctest->resulttype,
10897 ctest->resulttypmod,
10898 node);
10899 }
10900 }
10901 break;
10902
10904 appendStringInfoString(buf, "VALUE");
10905 break;
10906
10907 case T_SetToDefault:
10908 appendStringInfoString(buf, "DEFAULT");
10909 break;
10910
10911 case T_CurrentOfExpr:
10912 {
10913 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
10914
10915 if (cexpr->cursor_name)
10916 appendStringInfo(buf, "CURRENT OF %s",
10918 else
10919 appendStringInfo(buf, "CURRENT OF $%d",
10920 cexpr->cursor_param);
10921 }
10922 break;
10923
10924 case T_NextValueExpr:
10925 {
10927
10928 /*
10929 * This isn't exactly nextval(), but that seems close enough
10930 * for EXPLAIN's purposes.
10931 */
10932 appendStringInfoString(buf, "nextval(");
10935 NIL));
10937 }
10938 break;
10939
10940 case T_InferenceElem:
10941 {
10942 InferenceElem *iexpr = (InferenceElem *) node;
10943 bool save_varprefix;
10944 bool need_parens;
10945
10946 /*
10947 * InferenceElem can only refer to target relation, so a
10948 * prefix is not useful, and indeed would cause parse errors.
10949 */
10950 save_varprefix = context->varprefix;
10951 context->varprefix = false;
10952
10953 /*
10954 * Parenthesize the element unless it's a simple Var or a bare
10955 * function call. Follows pg_get_indexdef_worker().
10956 */
10957 need_parens = !IsA(iexpr->expr, Var);
10958 if (IsA(iexpr->expr, FuncExpr) &&
10959 ((FuncExpr *) iexpr->expr)->funcformat ==
10961 need_parens = false;
10962
10963 if (need_parens)
10965 get_rule_expr((Node *) iexpr->expr,
10966 context, false);
10967 if (need_parens)
10969
10970 context->varprefix = save_varprefix;
10971
10972 if (iexpr->infercollid)
10973 appendStringInfo(buf, " COLLATE %s",
10974 generate_collation_name(iexpr->infercollid));
10975
10976 /* Add the operator class name, if not default */
10977 if (iexpr->inferopclass)
10978 {
10979 Oid inferopclass = iexpr->inferopclass;
10981
10982 get_opclass_name(inferopclass, inferopcinputtype, buf);
10983 }
10984 }
10985 break;
10986
10987 case T_ReturningExpr:
10988 {
10990
10991 /*
10992 * We cannot see a ReturningExpr in rule deparsing, only while
10993 * EXPLAINing a query plan (ReturningExpr nodes are only ever
10994 * adding during query rewriting). Just display the expression
10995 * returned (an expanded view column).
10996 */
10997 get_rule_expr((Node *) retExpr->retexpr, context, showimplicit);
10998 }
10999 break;
11000
11002 {
11004 ListCell *cell;
11005 char *sep;
11006
11007 if (spec->is_default)
11008 {
11009 appendStringInfoString(buf, "DEFAULT");
11010 break;
11011 }
11012
11013 switch (spec->strategy)
11014 {
11016 Assert(spec->modulus > 0 && spec->remainder >= 0);
11017 Assert(spec->modulus > spec->remainder);
11018
11019 appendStringInfoString(buf, "FOR VALUES");
11020 appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
11021 spec->modulus, spec->remainder);
11022 break;
11023
11025 Assert(spec->listdatums != NIL);
11026
11027 appendStringInfoString(buf, "FOR VALUES IN (");
11028 sep = "";
11029 foreach(cell, spec->listdatums)
11030 {
11031 Const *val = lfirst_node(Const, cell);
11032
11034 get_const_expr(val, context, -1);
11035 sep = ", ";
11036 }
11037
11039 break;
11040
11042 Assert(spec->lowerdatums != NIL &&
11043 spec->upperdatums != NIL &&
11044 list_length(spec->lowerdatums) ==
11045 list_length(spec->upperdatums));
11046
11047 appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
11048 get_range_partbound_string(spec->lowerdatums),
11049 get_range_partbound_string(spec->upperdatums));
11050 break;
11051
11052 default:
11053 elog(ERROR, "unrecognized partition strategy: %d",
11054 (int) spec->strategy);
11055 break;
11056 }
11057 }
11058 break;
11059
11060 case T_JsonValueExpr:
11061 {
11062 JsonValueExpr *jve = (JsonValueExpr *) node;
11063
11064 get_rule_expr((Node *) jve->raw_expr, context, false);
11065 get_json_format(jve->format, context->buf);
11066 }
11067 break;
11068
11070 get_json_constructor((JsonConstructorExpr *) node, context, false);
11071 break;
11072
11073 case T_JsonIsPredicate:
11074 {
11075 JsonIsPredicate *pred = (JsonIsPredicate *) node;
11076
11077 if (!PRETTY_PAREN(context))
11078 appendStringInfoChar(context->buf, '(');
11079
11080 get_rule_expr_paren(pred->expr, context, true, node);
11081
11082 appendStringInfoString(context->buf, " IS JSON");
11083
11084 /* TODO: handle FORMAT clause */
11085
11086 switch (pred->item_type)
11087 {
11088 case JS_TYPE_SCALAR:
11089 appendStringInfoString(context->buf, " SCALAR");
11090 break;
11091 case JS_TYPE_ARRAY:
11092 appendStringInfoString(context->buf, " ARRAY");
11093 break;
11094 case JS_TYPE_OBJECT:
11095 appendStringInfoString(context->buf, " OBJECT");
11096 break;
11097 default:
11098 break;
11099 }
11100
11101 if (pred->unique_keys)
11102 appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
11103
11104 if (!PRETTY_PAREN(context))
11105 appendStringInfoChar(context->buf, ')');
11106 }
11107 break;
11108
11109 case T_JsonExpr:
11110 {
11111 JsonExpr *jexpr = (JsonExpr *) node;
11112
11113 switch (jexpr->op)
11114 {
11115 case JSON_EXISTS_OP:
11116 appendStringInfoString(buf, "JSON_EXISTS(");
11117 break;
11118 case JSON_QUERY_OP:
11119 appendStringInfoString(buf, "JSON_QUERY(");
11120 break;
11121 case JSON_VALUE_OP:
11122 appendStringInfoString(buf, "JSON_VALUE(");
11123 break;
11124 default:
11125 elog(ERROR, "unrecognized JsonExpr op: %d",
11126 (int) jexpr->op);
11127 }
11128
11129 get_rule_expr(jexpr->formatted_expr, context, showimplicit);
11130
11132
11133 get_json_path_spec(jexpr->path_spec, context, showimplicit);
11134
11135 if (jexpr->passing_values)
11136 {
11137 ListCell *lc1,
11138 *lc2;
11139 bool needcomma = false;
11140
11141 appendStringInfoString(buf, " PASSING ");
11142
11143 forboth(lc1, jexpr->passing_names,
11144 lc2, jexpr->passing_values)
11145 {
11146 if (needcomma)
11148 needcomma = true;
11149
11150 get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
11151 appendStringInfo(buf, " AS %s",
11153 }
11154 }
11155
11156 if (jexpr->op != JSON_EXISTS_OP ||
11157 jexpr->returning->typid != BOOLOID)
11158 get_json_returning(jexpr->returning, context->buf,
11159 jexpr->op == JSON_QUERY_OP);
11160
11162 jexpr->op != JSON_EXISTS_OP ?
11165
11167 }
11168 break;
11169
11170 case T_List:
11171 {
11172 char *sep;
11173 ListCell *l;
11174
11175 sep = "";
11176 foreach(l, (List *) node)
11177 {
11179 get_rule_expr((Node *) lfirst(l), context, showimplicit);
11180 sep = ", ";
11181 }
11182 }
11183 break;
11184
11185 case T_TableFunc:
11186 get_tablefunc((TableFunc *) node, context, showimplicit);
11187 break;
11188
11189 case T_GraphPropertyRef:
11190 {
11192
11194 break;
11195 }
11196
11197 default:
11198 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
11199 break;
11200 }
11201}
11202
11203/*
11204 * get_rule_expr_toplevel - Parse back a toplevel expression
11205 *
11206 * Same as get_rule_expr(), except that if the expr is just a Var, we pass
11207 * istoplevel = true not false to get_variable(). This causes whole-row Vars
11208 * to get printed with decoration that will prevent expansion of "*".
11209 * We need to use this in contexts such as ROW() and VALUES(), where the
11210 * parser would expand "foo.*" appearing at top level. (In principle we'd
11211 * use this in get_target_list() too, but that has additional worries about
11212 * whether to print AS, so it needs to invoke get_variable() directly anyway.)
11213 */
11214static void
11216 bool showimplicit)
11217{
11218 if (node && IsA(node, Var))
11219 (void) get_variable((Var *) node, 0, true, context);
11220 else
11221 get_rule_expr(node, context, showimplicit);
11222}
11223
11224/*
11225 * get_rule_list_toplevel - Parse back a list of toplevel expressions
11226 *
11227 * Apply get_rule_expr_toplevel() to each element of a List.
11228 *
11229 * This adds commas between the expressions, but caller is responsible
11230 * for printing surrounding decoration.
11231 */
11232static void
11234 bool showimplicit)
11235{
11236 const char *sep;
11237 ListCell *lc;
11238
11239 sep = "";
11240 foreach(lc, lst)
11241 {
11242 Node *e = (Node *) lfirst(lc);
11243
11244 appendStringInfoString(context->buf, sep);
11246 sep = ", ";
11247 }
11248}
11249
11250/*
11251 * get_rule_expr_funccall - Parse back a function-call expression
11252 *
11253 * Same as get_rule_expr(), except that we guarantee that the output will
11254 * look like a function call, or like one of the things the grammar treats as
11255 * equivalent to a function call (see the func_expr_windowless production).
11256 * This is needed in places where the grammar uses func_expr_windowless and
11257 * you can't substitute a parenthesized a_expr. If what we have isn't going
11258 * to look like a function call, wrap it in a dummy CAST() expression, which
11259 * will satisfy the grammar --- and, indeed, is likely what the user wrote to
11260 * produce such a thing.
11261 */
11262static void
11264 bool showimplicit)
11265{
11266 if (looks_like_function(node))
11267 get_rule_expr(node, context, showimplicit);
11268 else
11269 {
11270 StringInfo buf = context->buf;
11271
11272 appendStringInfoString(buf, "CAST(");
11273 /* no point in showing any top-level implicit cast */
11274 get_rule_expr(node, context, false);
11275 appendStringInfo(buf, " AS %s)",
11277 exprTypmod(node)));
11278 }
11279}
11280
11281/*
11282 * Helper function to identify node types that satisfy func_expr_windowless.
11283 * If in doubt, "false" is always a safe answer.
11284 */
11285static bool
11287{
11288 if (node == NULL)
11289 return false; /* probably shouldn't happen */
11290 switch (nodeTag(node))
11291 {
11292 case T_FuncExpr:
11293 /* OK, unless it's going to deparse as a cast */
11294 return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
11295 ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
11296 case T_NullIfExpr:
11297 case T_CoalesceExpr:
11298 case T_MinMaxExpr:
11299 case T_SQLValueFunction:
11300 case T_XmlExpr:
11301 case T_JsonExpr:
11302 /* these are all accepted by func_expr_common_subexpr */
11303 return true;
11304 default:
11305 break;
11306 }
11307 return false;
11308}
11309
11310
11311/*
11312 * get_oper_expr - Parse back an OpExpr node
11313 */
11314static void
11316{
11317 StringInfo buf = context->buf;
11318 Oid opno = expr->opno;
11319 List *args = expr->args;
11320
11321 if (!PRETTY_PAREN(context))
11323 if (list_length(args) == 2)
11324 {
11325 /* binary operator */
11326 Node *arg1 = (Node *) linitial(args);
11327 Node *arg2 = (Node *) lsecond(args);
11328
11329 get_rule_expr_paren(arg1, context, true, (Node *) expr);
11330 appendStringInfo(buf, " %s ",
11332 exprType(arg1),
11333 exprType(arg2)));
11334 get_rule_expr_paren(arg2, context, true, (Node *) expr);
11335 }
11336 else
11337 {
11338 /* prefix operator */
11339 Node *arg = (Node *) linitial(args);
11340
11341 appendStringInfo(buf, "%s ",
11343 InvalidOid,
11344 exprType(arg)));
11345 get_rule_expr_paren(arg, context, true, (Node *) expr);
11346 }
11347 if (!PRETTY_PAREN(context))
11349}
11350
11351/*
11352 * get_func_expr - Parse back a FuncExpr node
11353 */
11354static void
11356 bool showimplicit)
11357{
11358 StringInfo buf = context->buf;
11359 Oid funcoid = expr->funcid;
11360 Oid argtypes[FUNC_MAX_ARGS];
11361 int nargs;
11362 List *argnames;
11363 bool use_variadic;
11364 ListCell *l;
11365
11366 /*
11367 * If the function call came from an implicit coercion, then just show the
11368 * first argument --- unless caller wants to see implicit coercions.
11369 */
11370 if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
11371 {
11372 get_rule_expr_paren((Node *) linitial(expr->args), context,
11373 false, (Node *) expr);
11374 return;
11375 }
11376
11377 /*
11378 * If the function call came from a cast, then show the first argument
11379 * plus an explicit cast operation.
11380 */
11381 if (expr->funcformat == COERCE_EXPLICIT_CAST ||
11382 expr->funcformat == COERCE_IMPLICIT_CAST)
11383 {
11384 Node *arg = linitial(expr->args);
11385 Oid rettype = expr->funcresulttype;
11387
11388 /* Get the typmod if this is a length-coercion function */
11390
11391 get_coercion_expr(arg, context,
11392 rettype, coercedTypmod,
11393 (Node *) expr);
11394
11395 return;
11396 }
11397
11398 /*
11399 * If the function was called using one of the SQL spec's random special
11400 * syntaxes, try to reproduce that. If we don't recognize the function,
11401 * fall through.
11402 */
11403 if (expr->funcformat == COERCE_SQL_SYNTAX)
11404 {
11405 if (get_func_sql_syntax(expr, context))
11406 return;
11407 }
11408
11409 /*
11410 * Normal function: display as proname(args). First we need to extract
11411 * the argument datatypes.
11412 */
11413 if (list_length(expr->args) > FUNC_MAX_ARGS)
11414 ereport(ERROR,
11416 errmsg("too many arguments")));
11417 nargs = 0;
11418 argnames = NIL;
11419 foreach(l, expr->args)
11420 {
11421 Node *arg = (Node *) lfirst(l);
11422
11423 if (IsA(arg, NamedArgExpr))
11424 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
11425 argtypes[nargs] = exprType(arg);
11426 nargs++;
11427 }
11428
11429 appendStringInfo(buf, "%s(",
11431 argnames, argtypes,
11432 expr->funcvariadic,
11433 &use_variadic,
11434 context->inGroupBy));
11435 nargs = 0;
11436 foreach(l, expr->args)
11437 {
11438 if (nargs++ > 0)
11440 if (use_variadic && lnext(expr->args, l) == NULL)
11441 appendStringInfoString(buf, "VARIADIC ");
11442 get_rule_expr((Node *) lfirst(l), context, true);
11443 }
11445}
11446
11447/*
11448 * get_agg_expr - Parse back an Aggref node
11449 */
11450static void
11453{
11454 get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
11455 false);
11456}
11457
11458/*
11459 * get_agg_expr_helper - subroutine for get_agg_expr and
11460 * get_json_agg_constructor
11461 */
11462static void
11464 Aggref *original_aggref, const char *funcname,
11465 const char *options, bool is_json_objectagg)
11466{
11467 StringInfo buf = context->buf;
11468 Oid argtypes[FUNC_MAX_ARGS];
11469 int nargs;
11470 bool use_variadic = false;
11471
11472 /*
11473 * For a combining aggregate, we look up and deparse the corresponding
11474 * partial aggregate instead. This is necessary because our input
11475 * argument list has been replaced; the new argument list always has just
11476 * one element, which will point to a partial Aggref that supplies us with
11477 * transition states to combine.
11478 */
11479 if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
11480 {
11482
11483 Assert(list_length(aggref->args) == 1);
11484 tle = linitial_node(TargetEntry, aggref->args);
11485 resolve_special_varno((Node *) tle->expr, context,
11487 return;
11488 }
11489
11490 /*
11491 * Mark as PARTIAL, if appropriate. We look to the original aggref so as
11492 * to avoid printing this when recursing from the code just above.
11493 */
11495 appendStringInfoString(buf, "PARTIAL ");
11496
11497 /* Extract the argument types as seen by the parser */
11498 nargs = get_aggregate_argtypes(aggref, argtypes);
11499
11500 if (!funcname)
11501 funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
11502 argtypes, aggref->aggvariadic,
11503 &use_variadic,
11504 context->inGroupBy);
11505
11506 /* Print the aggregate name, schema-qualified if needed */
11507 appendStringInfo(buf, "%s(%s", funcname,
11508 (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
11509
11510 if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
11511 {
11512 /*
11513 * Ordered-set aggregates do not use "*" syntax. Also, we needn't
11514 * worry about inserting VARIADIC. So we can just dump the direct
11515 * args as-is.
11516 */
11517 Assert(!aggref->aggvariadic);
11518 get_rule_expr((Node *) aggref->aggdirectargs, context, true);
11519 Assert(aggref->aggorder != NIL);
11520 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
11521 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
11522 }
11523 else
11524 {
11525 /* aggstar can be set only in zero-argument aggregates */
11526 if (aggref->aggstar)
11528 else
11529 {
11530 ListCell *l;
11531 int i;
11532
11533 i = 0;
11534 foreach(l, aggref->args)
11535 {
11537 Node *arg = (Node *) tle->expr;
11538
11540 if (tle->resjunk)
11541 continue;
11542 if (i++ > 0)
11543 {
11545 {
11546 /*
11547 * the ABSENT ON NULL and WITH UNIQUE args are printed
11548 * separately, so ignore them here
11549 */
11550 if (i > 2)
11551 break;
11552
11554 }
11555 else
11557 }
11558 if (use_variadic && i == nargs)
11559 appendStringInfoString(buf, "VARIADIC ");
11560 get_rule_expr(arg, context, true);
11561 }
11562 }
11563
11564 if (aggref->aggorder != NIL)
11565 {
11566 appendStringInfoString(buf, " ORDER BY ");
11567 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
11568 }
11569 }
11570
11571 if (options)
11573
11574 if (aggref->aggfilter != NULL)
11575 {
11576 appendStringInfoString(buf, ") FILTER (WHERE ");
11577 get_rule_expr((Node *) aggref->aggfilter, context, false);
11578 }
11579
11581}
11582
11583/*
11584 * This is a helper function for get_agg_expr(). It's used when we deparse
11585 * a combining Aggref; resolve_special_varno locates the corresponding partial
11586 * Aggref and then calls this.
11587 */
11588static void
11589get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
11590{
11591 Aggref *aggref;
11592 Aggref *original_aggref = callback_arg;
11593
11594 if (!IsA(node, Aggref))
11595 elog(ERROR, "combining Aggref does not point to an Aggref");
11596
11597 aggref = (Aggref *) node;
11598 get_agg_expr(aggref, context, original_aggref);
11599}
11600
11601/*
11602 * get_windowfunc_expr - Parse back a WindowFunc node
11603 */
11604static void
11606{
11607 get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
11608}
11609
11610
11611/*
11612 * get_windowfunc_expr_helper - subroutine for get_windowfunc_expr and
11613 * get_json_agg_constructor
11614 */
11615static void
11617 const char *funcname, const char *options,
11618 bool is_json_objectagg)
11619{
11620 StringInfo buf = context->buf;
11621 Oid argtypes[FUNC_MAX_ARGS];
11622 int nargs;
11623 List *argnames;
11624 ListCell *l;
11625
11626 if (list_length(wfunc->args) > FUNC_MAX_ARGS)
11627 ereport(ERROR,
11629 errmsg("too many arguments")));
11630 nargs = 0;
11631 argnames = NIL;
11632 foreach(l, wfunc->args)
11633 {
11634 Node *arg = (Node *) lfirst(l);
11635
11636 if (IsA(arg, NamedArgExpr))
11637 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
11638 argtypes[nargs] = exprType(arg);
11639 nargs++;
11640 }
11641
11642 if (!funcname)
11643 funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
11644 argtypes, false, NULL,
11645 context->inGroupBy);
11646
11647 appendStringInfo(buf, "%s(", funcname);
11648
11649 /* winstar can be set only in zero-argument aggregates */
11650 if (wfunc->winstar)
11652 else
11653 {
11655 {
11656 get_rule_expr((Node *) linitial(wfunc->args), context, false);
11658 get_rule_expr((Node *) lsecond(wfunc->args), context, false);
11659 }
11660 else
11661 get_rule_expr((Node *) wfunc->args, context, true);
11662 }
11663
11664 if (options)
11666
11667 if (wfunc->aggfilter != NULL)
11668 {
11669 appendStringInfoString(buf, ") FILTER (WHERE ");
11670 get_rule_expr((Node *) wfunc->aggfilter, context, false);
11671 }
11672
11674
11675 if (wfunc->ignore_nulls == PARSER_IGNORE_NULLS)
11676 appendStringInfoString(buf, "IGNORE NULLS ");
11677
11678 appendStringInfoString(buf, "OVER ");
11679
11680 if (context->windowClause)
11681 {
11682 /* Query-decompilation case: search the windowClause list */
11683 foreach(l, context->windowClause)
11684 {
11685 WindowClause *wc = (WindowClause *) lfirst(l);
11686
11687 if (wc->winref == wfunc->winref)
11688 {
11689 if (wc->name)
11691 else
11692 get_rule_windowspec(wc, context->targetList, context);
11693 break;
11694 }
11695 }
11696 if (l == NULL)
11697 elog(ERROR, "could not find window clause for winref %u",
11698 wfunc->winref);
11699 }
11700 else
11701 {
11702 /*
11703 * In EXPLAIN, search the namespace stack for a matching WindowAgg
11704 * node (probably it's always the first entry), and print winname.
11705 */
11706 foreach(l, context->namespaces)
11707 {
11709
11710 if (dpns->plan && IsA(dpns->plan, WindowAgg))
11711 {
11713
11714 if (wagg->winref == wfunc->winref)
11715 {
11717 break;
11718 }
11719 }
11720 }
11721 if (l == NULL)
11722 elog(ERROR, "could not find window clause for winref %u",
11723 wfunc->winref);
11724 }
11725}
11726
11727/*
11728 * get_func_sql_syntax - Parse back a SQL-syntax function call
11729 *
11730 * Returns true if we successfully deparsed, false if we did not
11731 * recognize the function.
11732 */
11733static bool
11735{
11736 StringInfo buf = context->buf;
11737 Oid funcoid = expr->funcid;
11738
11739 switch (funcoid)
11740 {
11747 /* AT TIME ZONE ... note reversed argument order */
11749 get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
11750 (Node *) expr);
11751 appendStringInfoString(buf, " AT TIME ZONE ");
11752 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11753 (Node *) expr);
11755 return true;
11756
11759 case F_TIMEZONE_TIMETZ:
11760 /* AT LOCAL */
11762 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11763 (Node *) expr);
11764 appendStringInfoString(buf, " AT LOCAL)");
11765 return true;
11766
11780 /* (x1, x2) OVERLAPS (y1, y2) */
11782 get_rule_expr((Node *) linitial(expr->args), context, false);
11784 get_rule_expr((Node *) lsecond(expr->args), context, false);
11785 appendStringInfoString(buf, ") OVERLAPS (");
11786 get_rule_expr((Node *) lthird(expr->args), context, false);
11788 get_rule_expr((Node *) lfourth(expr->args), context, false);
11790 return true;
11791
11798 /* EXTRACT (x FROM y) */
11799 appendStringInfoString(buf, "EXTRACT(");
11800 {
11801 Const *con = (Const *) linitial(expr->args);
11802
11803 Assert(IsA(con, Const) &&
11804 con->consttype == TEXTOID &&
11805 !con->constisnull);
11807 }
11808 appendStringInfoString(buf, " FROM ");
11809 get_rule_expr((Node *) lsecond(expr->args), context, false);
11811 return true;
11812
11813 case F_IS_NORMALIZED:
11814 /* IS xxx NORMALIZED */
11816 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11817 (Node *) expr);
11819 if (list_length(expr->args) == 2)
11820 {
11821 Const *con = (Const *) lsecond(expr->args);
11822
11823 Assert(IsA(con, Const) &&
11824 con->consttype == TEXTOID &&
11825 !con->constisnull);
11826 appendStringInfo(buf, " %s",
11827 TextDatumGetCString(con->constvalue));
11828 }
11829 appendStringInfoString(buf, " NORMALIZED)");
11830 return true;
11831
11832 case F_PG_COLLATION_FOR:
11833 /* COLLATION FOR */
11834 appendStringInfoString(buf, "COLLATION FOR (");
11835 get_rule_expr((Node *) linitial(expr->args), context, false);
11837 return true;
11838
11839 case F_NORMALIZE:
11840 /* NORMALIZE() */
11841 appendStringInfoString(buf, "NORMALIZE(");
11842 get_rule_expr((Node *) linitial(expr->args), context, false);
11843 if (list_length(expr->args) == 2)
11844 {
11845 Const *con = (Const *) lsecond(expr->args);
11846
11847 Assert(IsA(con, Const) &&
11848 con->consttype == TEXTOID &&
11849 !con->constisnull);
11850 appendStringInfo(buf, ", %s",
11851 TextDatumGetCString(con->constvalue));
11852 }
11854 return true;
11855
11862 /* OVERLAY() */
11863 appendStringInfoString(buf, "OVERLAY(");
11864 get_rule_expr((Node *) linitial(expr->args), context, false);
11865 appendStringInfoString(buf, " PLACING ");
11866 get_rule_expr((Node *) lsecond(expr->args), context, false);
11867 appendStringInfoString(buf, " FROM ");
11868 get_rule_expr((Node *) lthird(expr->args), context, false);
11869 if (list_length(expr->args) == 4)
11870 {
11871 appendStringInfoString(buf, " FOR ");
11872 get_rule_expr((Node *) lfourth(expr->args), context, false);
11873 }
11875 return true;
11876
11877 case F_POSITION_BIT_BIT:
11880 /* POSITION() ... extra parens since args are b_expr not a_expr */
11881 appendStringInfoString(buf, "POSITION((");
11882 get_rule_expr((Node *) lsecond(expr->args), context, false);
11883 appendStringInfoString(buf, ") IN (");
11884 get_rule_expr((Node *) linitial(expr->args), context, false);
11886 return true;
11887
11894 /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
11895 appendStringInfoString(buf, "SUBSTRING(");
11896 get_rule_expr((Node *) linitial(expr->args), context, false);
11897 appendStringInfoString(buf, " FROM ");
11898 get_rule_expr((Node *) lsecond(expr->args), context, false);
11899 if (list_length(expr->args) == 3)
11900 {
11901 appendStringInfoString(buf, " FOR ");
11902 get_rule_expr((Node *) lthird(expr->args), context, false);
11903 }
11905 return true;
11906
11908 /* SUBSTRING SIMILAR/ESCAPE */
11909 appendStringInfoString(buf, "SUBSTRING(");
11910 get_rule_expr((Node *) linitial(expr->args), context, false);
11911 appendStringInfoString(buf, " SIMILAR ");
11912 get_rule_expr((Node *) lsecond(expr->args), context, false);
11913 appendStringInfoString(buf, " ESCAPE ");
11914 get_rule_expr((Node *) lthird(expr->args), context, false);
11916 return true;
11917
11919 case F_BTRIM_TEXT:
11920 case F_BTRIM_TEXT_TEXT:
11921 /* TRIM() */
11922 appendStringInfoString(buf, "TRIM(BOTH");
11923 if (list_length(expr->args) == 2)
11924 {
11926 get_rule_expr((Node *) lsecond(expr->args), context, false);
11927 }
11928 appendStringInfoString(buf, " FROM ");
11929 get_rule_expr((Node *) linitial(expr->args), context, false);
11931 return true;
11932
11934 case F_LTRIM_TEXT:
11935 case F_LTRIM_TEXT_TEXT:
11936 /* TRIM() */
11937 appendStringInfoString(buf, "TRIM(LEADING");
11938 if (list_length(expr->args) == 2)
11939 {
11941 get_rule_expr((Node *) lsecond(expr->args), context, false);
11942 }
11943 appendStringInfoString(buf, " FROM ");
11944 get_rule_expr((Node *) linitial(expr->args), context, false);
11946 return true;
11947
11949 case F_RTRIM_TEXT:
11950 case F_RTRIM_TEXT_TEXT:
11951 /* TRIM() */
11952 appendStringInfoString(buf, "TRIM(TRAILING");
11953 if (list_length(expr->args) == 2)
11954 {
11956 get_rule_expr((Node *) lsecond(expr->args), context, false);
11957 }
11958 appendStringInfoString(buf, " FROM ");
11959 get_rule_expr((Node *) linitial(expr->args), context, false);
11961 return true;
11962
11963 case F_SYSTEM_USER:
11964 appendStringInfoString(buf, "SYSTEM_USER");
11965 return true;
11966
11967 case F_XMLEXISTS:
11968 /* XMLEXISTS ... extra parens because args are c_expr */
11969 appendStringInfoString(buf, "XMLEXISTS((");
11970 get_rule_expr((Node *) linitial(expr->args), context, false);
11971 appendStringInfoString(buf, ") PASSING (");
11972 get_rule_expr((Node *) lsecond(expr->args), context, false);
11974 return true;
11975 }
11976 return false;
11977}
11978
11979/* ----------
11980 * get_coercion_expr
11981 *
11982 * Make a string representation of a value coerced to a specific type
11983 * ----------
11984 */
11985static void
11987 Oid resulttype, int32 resulttypmod,
11989{
11990 StringInfo buf = context->buf;
11991
11992 /*
11993 * Since parse_coerce.c doesn't immediately collapse application of
11994 * length-coercion functions to constants, what we'll typically see in
11995 * such cases is a Const with typmod -1 and a length-coercion function
11996 * right above it. Avoid generating redundant output. However, beware of
11997 * suppressing casts when the user actually wrote something like
11998 * 'foo'::text::char(3).
11999 *
12000 * Note: it might seem that we are missing the possibility of needing to
12001 * print a COLLATE clause for such a Const. However, a Const could only
12002 * have nondefault collation in a post-constant-folding tree, in which the
12003 * length coercion would have been folded too. See also the special
12004 * handling of CollateExpr in coerce_to_target_type(): any collation
12005 * marking will be above the coercion node, not below it.
12006 */
12007 if (arg && IsA(arg, Const) &&
12008 ((Const *) arg)->consttype == resulttype &&
12009 ((Const *) arg)->consttypmod == -1)
12010 {
12011 /* Show the constant without normal ::typename decoration */
12012 get_const_expr((Const *) arg, context, -1);
12013 }
12014 else
12015 {
12016 if (!PRETTY_PAREN(context))
12018 get_rule_expr_paren(arg, context, false, parentNode);
12019 if (!PRETTY_PAREN(context))
12021 }
12022
12023 /*
12024 * Never emit resulttype(arg) functional notation. A pg_proc entry could
12025 * take precedence, and a resulttype in pg_temp would require schema
12026 * qualification that format_type_with_typemod() would usually omit. We've
12027 * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
12028 * would work fine.
12029 */
12030 appendStringInfo(buf, "::%s",
12032}
12033
12034/* ----------
12035 * get_const_expr
12036 *
12037 * Make a string representation of a Const
12038 *
12039 * showtype can be -1 to never show "::typename" decoration, or +1 to always
12040 * show it, or 0 to show it only if the constant wouldn't be assumed to be
12041 * the right type by default.
12042 *
12043 * If the Const's collation isn't default for its type, show that too.
12044 * We mustn't do this when showtype is -1 (since that means the caller will
12045 * print "::typename", and we can't put a COLLATE clause in between). It's
12046 * caller's responsibility that collation isn't missed in such cases.
12047 * ----------
12048 */
12049static void
12051{
12052 StringInfo buf = context->buf;
12053 Oid typoutput;
12054 bool typIsVarlena;
12055 char *extval;
12056 bool needlabel = false;
12057
12058 if (constval->constisnull)
12059 {
12060 /*
12061 * Always label the type of a NULL constant to prevent misdecisions
12062 * about type when reparsing.
12063 */
12064 appendStringInfoString(buf, "NULL");
12065 if (showtype >= 0)
12066 {
12067 appendStringInfo(buf, "::%s",
12069 constval->consttypmod));
12070 get_const_collation(constval, context);
12071 }
12072 return;
12073 }
12074
12075 getTypeOutputInfo(constval->consttype,
12076 &typoutput, &typIsVarlena);
12077
12078 extval = OidOutputFunctionCall(typoutput, constval->constvalue);
12079
12080 switch (constval->consttype)
12081 {
12082 case INT4OID:
12083
12084 /*
12085 * INT4 can be printed without any decoration, unless it is
12086 * negative; in that case print it as '-nnn'::integer to ensure
12087 * that the output will re-parse as a constant, not as a constant
12088 * plus operator. In most cases we could get away with printing
12089 * (-nnn) instead, because of the way that gram.y handles negative
12090 * literals; but that doesn't work for INT_MIN, and it doesn't
12091 * seem that much prettier anyway.
12092 */
12093 if (extval[0] != '-')
12095 else
12096 {
12097 appendStringInfo(buf, "'%s'", extval);
12098 needlabel = true; /* we must attach a cast */
12099 }
12100 break;
12101
12102 case NUMERICOID:
12103
12104 /*
12105 * NUMERIC can be printed without quotes if it looks like a float
12106 * constant (not an integer, and not Infinity or NaN) and doesn't
12107 * have a leading sign (for the same reason as for INT4).
12108 */
12109 if (isdigit((unsigned char) extval[0]) &&
12110 strcspn(extval, "eE.") != strlen(extval))
12111 {
12113 }
12114 else
12115 {
12116 appendStringInfo(buf, "'%s'", extval);
12117 needlabel = true; /* we must attach a cast */
12118 }
12119 break;
12120
12121 case BOOLOID:
12122 if (strcmp(extval, "t") == 0)
12123 appendStringInfoString(buf, "true");
12124 else
12125 appendStringInfoString(buf, "false");
12126 break;
12127
12128 default:
12130 break;
12131 }
12132
12133 pfree(extval);
12134
12135 if (showtype < 0)
12136 return;
12137
12138 /*
12139 * For showtype == 0, append ::typename unless the constant will be
12140 * implicitly typed as the right type when it is read in.
12141 *
12142 * XXX this code has to be kept in sync with the behavior of the parser,
12143 * especially make_const.
12144 */
12145 switch (constval->consttype)
12146 {
12147 case BOOLOID:
12148 case UNKNOWNOID:
12149 /* These types can be left unlabeled */
12150 needlabel = false;
12151 break;
12152 case INT4OID:
12153 /* We determined above whether a label is needed */
12154 break;
12155 case NUMERICOID:
12156
12157 /*
12158 * Float-looking constants will be typed as numeric, which we
12159 * checked above; but if there's a nondefault typmod we need to
12160 * show it.
12161 */
12162 needlabel |= (constval->consttypmod >= 0);
12163 break;
12164 default:
12165 needlabel = true;
12166 break;
12167 }
12168 if (needlabel || showtype > 0)
12169 appendStringInfo(buf, "::%s",
12171 constval->consttypmod));
12172
12173 get_const_collation(constval, context);
12174}
12175
12176/*
12177 * helper for get_const_expr: append COLLATE if needed
12178 */
12179static void
12181{
12182 StringInfo buf = context->buf;
12183
12184 if (OidIsValid(constval->constcollid))
12185 {
12186 Oid typcollation = get_typcollation(constval->consttype);
12187
12188 if (constval->constcollid != typcollation)
12189 {
12190 appendStringInfo(buf, " COLLATE %s",
12191 generate_collation_name(constval->constcollid));
12192 }
12193 }
12194}
12195
12196/*
12197 * get_json_path_spec - Parse back a JSON path specification
12198 */
12199static void
12201{
12202 if (IsA(path_spec, Const))
12203 get_const_expr((Const *) path_spec, context, -1);
12204 else
12205 get_rule_expr(path_spec, context, showimplicit);
12206}
12207
12208/*
12209 * get_json_format - Parse back a JsonFormat node
12210 */
12211static void
12213{
12214 if (format->format_type == JS_FORMAT_DEFAULT)
12215 return;
12216
12218 format->format_type == JS_FORMAT_JSONB ?
12219 " FORMAT JSONB" : " FORMAT JSON");
12220
12221 if (format->encoding != JS_ENC_DEFAULT)
12222 {
12223 const char *encoding;
12224
12225 encoding =
12226 format->encoding == JS_ENC_UTF16 ? "UTF16" :
12227 format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
12228
12229 appendStringInfo(buf, " ENCODING %s", encoding);
12230 }
12231}
12232
12233/*
12234 * get_json_returning - Parse back a JsonReturning structure
12235 */
12236static void
12239{
12240 if (!OidIsValid(returning->typid))
12241 return;
12242
12243 appendStringInfo(buf, " RETURNING %s",
12245 returning->typmod));
12246
12248 returning->format->format_type !=
12249 (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
12250 get_json_format(returning->format, buf);
12251}
12252
12253/*
12254 * get_json_constructor - Parse back a JsonConstructorExpr node
12255 */
12256static void
12258 bool showimplicit)
12259{
12260 StringInfo buf = context->buf;
12261 const char *funcname;
12262 bool is_json_object;
12263 int curridx;
12264 ListCell *lc;
12265
12266 if (ctor->type == JSCTOR_JSON_OBJECTAGG)
12267 {
12268 get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
12269 return;
12270 }
12271 else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
12272 {
12273 get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
12274 return;
12275 }
12276
12277 switch (ctor->type)
12278 {
12279 case JSCTOR_JSON_OBJECT:
12280 funcname = "JSON_OBJECT";
12281 break;
12282 case JSCTOR_JSON_ARRAY:
12283 funcname = "JSON_ARRAY";
12284 break;
12285 case JSCTOR_JSON_PARSE:
12286 funcname = "JSON";
12287 break;
12288 case JSCTOR_JSON_SCALAR:
12289 funcname = "JSON_SCALAR";
12290 break;
12292 funcname = "JSON_SERIALIZE";
12293 break;
12294 default:
12295 elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
12296 }
12297
12298 appendStringInfo(buf, "%s(", funcname);
12299
12301 foreach(lc, ctor->args)
12302 {
12304 if (curridx > 0)
12305 {
12306 const char *sep;
12307
12308 sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
12310 }
12311
12312 get_rule_expr((Node *) lfirst(lc), context, true);
12313 }
12314
12317}
12318
12319/*
12320 * Append options, if any, to the JSON constructor being deparsed
12321 */
12322static void
12324{
12325 if (ctor->absent_on_null)
12326 {
12327 if (ctor->type == JSCTOR_JSON_OBJECT ||
12328 ctor->type == JSCTOR_JSON_OBJECTAGG)
12329 appendStringInfoString(buf, " ABSENT ON NULL");
12330 }
12331 else
12332 {
12333 if (ctor->type == JSCTOR_JSON_ARRAY ||
12334 ctor->type == JSCTOR_JSON_ARRAYAGG)
12335 appendStringInfoString(buf, " NULL ON NULL");
12336 }
12337
12338 if (ctor->unique)
12339 appendStringInfoString(buf, " WITH UNIQUE KEYS");
12340
12341 /*
12342 * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
12343 * support one.
12344 */
12345 if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
12346 get_json_returning(ctor->returning, buf, true);
12347}
12348
12349/*
12350 * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
12351 */
12352static void
12354 const char *funcname, bool is_json_objectagg)
12355{
12357
12360
12361 if (IsA(ctor->func, Aggref))
12362 get_agg_expr_helper((Aggref *) ctor->func, context,
12363 (Aggref *) ctor->func,
12365 else if (IsA(ctor->func, WindowFunc))
12366 get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
12367 funcname, options.data,
12369 else
12370 elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
12371 nodeTag(ctor->func));
12372}
12373
12374/*
12375 * simple_quote_literal - Format a string as a SQL literal, append to buf
12376 */
12377static void
12379{
12380 const char *valptr;
12381
12382 /*
12383 * We always form the string literal according to standard SQL rules.
12384 */
12386 for (valptr = val; *valptr; valptr++)
12387 {
12388 char ch = *valptr;
12389
12390 if (SQL_STR_DOUBLE(ch, false))
12393 }
12395}
12396
12397
12398/* ----------
12399 * get_sublink_expr - Parse back a sublink
12400 * ----------
12401 */
12402static void
12404{
12405 StringInfo buf = context->buf;
12406 Query *query = (Query *) (sublink->subselect);
12407 char *opname = NULL;
12408 bool need_paren;
12409
12410 if (sublink->subLinkType == ARRAY_SUBLINK)
12411 appendStringInfoString(buf, "ARRAY(");
12412 else
12414
12415 /*
12416 * Note that we print the name of only the first operator, when there are
12417 * multiple combining operators. This is an approximation that could go
12418 * wrong in various scenarios (operators in different schemas, renamed
12419 * operators, etc) but there is not a whole lot we can do about it, since
12420 * the syntax allows only one operator to be shown.
12421 */
12422 if (sublink->testexpr)
12423 {
12424 if (IsA(sublink->testexpr, OpExpr))
12425 {
12426 /* single combining operator */
12427 OpExpr *opexpr = (OpExpr *) sublink->testexpr;
12428
12429 get_rule_expr(linitial(opexpr->args), context, true);
12431 exprType(linitial(opexpr->args)),
12432 exprType(lsecond(opexpr->args)));
12433 }
12434 else if (IsA(sublink->testexpr, BoolExpr))
12435 {
12436 /* multiple combining operators, = or <> cases */
12437 char *sep;
12438 ListCell *l;
12439
12441 sep = "";
12442 foreach(l, ((BoolExpr *) sublink->testexpr)->args)
12443 {
12444 OpExpr *opexpr = lfirst_node(OpExpr, l);
12445
12447 get_rule_expr(linitial(opexpr->args), context, true);
12448 if (!opname)
12450 exprType(linitial(opexpr->args)),
12451 exprType(lsecond(opexpr->args)));
12452 sep = ", ";
12453 }
12455 }
12456 else if (IsA(sublink->testexpr, RowCompareExpr))
12457 {
12458 /* multiple combining operators, < <= > >= cases */
12460
12462 get_rule_expr((Node *) rcexpr->largs, context, true);
12464 exprType(linitial(rcexpr->largs)),
12465 exprType(linitial(rcexpr->rargs)));
12467 }
12468 else
12469 elog(ERROR, "unrecognized testexpr type: %d",
12470 (int) nodeTag(sublink->testexpr));
12471 }
12472
12473 need_paren = true;
12474
12475 switch (sublink->subLinkType)
12476 {
12477 case EXISTS_SUBLINK:
12478 appendStringInfoString(buf, "EXISTS ");
12479 break;
12480
12481 case ANY_SUBLINK:
12482 if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
12483 appendStringInfoString(buf, " IN ");
12484 else
12485 appendStringInfo(buf, " %s ANY ", opname);
12486 break;
12487
12488 case ALL_SUBLINK:
12489 appendStringInfo(buf, " %s ALL ", opname);
12490 break;
12491
12492 case ROWCOMPARE_SUBLINK:
12493 appendStringInfo(buf, " %s ", opname);
12494 break;
12495
12496 case EXPR_SUBLINK:
12497 case MULTIEXPR_SUBLINK:
12498 case ARRAY_SUBLINK:
12499 need_paren = false;
12500 break;
12501
12502 case CTE_SUBLINK: /* shouldn't occur in a SubLink */
12503 default:
12504 elog(ERROR, "unrecognized sublink type: %d",
12505 (int) sublink->subLinkType);
12506 break;
12507 }
12508
12509 if (need_paren)
12511
12512 get_query_def(query, buf, context->namespaces, NULL, false,
12513 context->prettyFlags, context->wrapColumn,
12514 context->indentLevel);
12515
12516 if (need_paren)
12518 else
12520}
12521
12522
12523/* ----------
12524 * get_xmltable - Parse back a XMLTABLE function
12525 * ----------
12526 */
12527static void
12529{
12530 StringInfo buf = context->buf;
12531
12532 appendStringInfoString(buf, "XMLTABLE(");
12533
12534 if (tf->ns_uris != NIL)
12535 {
12536 ListCell *lc1,
12537 *lc2;
12538 bool first = true;
12539
12540 appendStringInfoString(buf, "XMLNAMESPACES (");
12541 forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
12542 {
12543 Node *expr = (Node *) lfirst(lc1);
12545
12546 if (!first)
12548 else
12549 first = false;
12550
12551 if (ns_node != NULL)
12552 {
12553 get_rule_expr(expr, context, showimplicit);
12554 appendStringInfo(buf, " AS %s",
12556 }
12557 else
12558 {
12559 appendStringInfoString(buf, "DEFAULT ");
12560 get_rule_expr(expr, context, showimplicit);
12561 }
12562 }
12564 }
12565
12567 get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
12568 appendStringInfoString(buf, ") PASSING (");
12569 get_rule_expr((Node *) tf->docexpr, context, showimplicit);
12571
12572 if (tf->colexprs != NIL)
12573 {
12574 ListCell *l1;
12575 ListCell *l2;
12576 ListCell *l3;
12577 ListCell *l4;
12578 ListCell *l5;
12579 int colnum = 0;
12580
12581 appendStringInfoString(buf, " COLUMNS ");
12582 forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
12583 l4, tf->colexprs, l5, tf->coldefexprs)
12584 {
12585 char *colname = strVal(lfirst(l1));
12586 Oid typid = lfirst_oid(l2);
12587 int32 typmod = lfirst_int(l3);
12588 Node *colexpr = (Node *) lfirst(l4);
12589 Node *coldefexpr = (Node *) lfirst(l5);
12590 bool ordinality = (tf->ordinalitycol == colnum);
12591 bool notnull = bms_is_member(colnum, tf->notnulls);
12592
12593 if (colnum > 0)
12595 colnum++;
12596
12597 appendStringInfo(buf, "%s %s", quote_identifier(colname),
12598 ordinality ? "FOR ORDINALITY" :
12599 format_type_with_typemod(typid, typmod));
12600 if (ordinality)
12601 continue;
12602
12603 if (coldefexpr != NULL)
12604 {
12605 appendStringInfoString(buf, " DEFAULT (");
12606 get_rule_expr((Node *) coldefexpr, context, showimplicit);
12608 }
12609 if (colexpr != NULL)
12610 {
12611 appendStringInfoString(buf, " PATH (");
12612 get_rule_expr((Node *) colexpr, context, showimplicit);
12614 }
12615 if (notnull)
12616 appendStringInfoString(buf, " NOT NULL");
12617 }
12618 }
12619
12621}
12622
12623/*
12624 * get_json_table_nested_columns - Parse back nested JSON_TABLE columns
12625 */
12626static void
12628 deparse_context *context, bool showimplicit,
12629 bool needcomma)
12630{
12632 {
12634
12635 if (needcomma)
12636 appendStringInfoChar(context->buf, ',');
12637
12638 appendStringInfoChar(context->buf, ' ');
12639 appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
12640 get_const_expr(scan->path->value, context, -1);
12641 appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
12642 get_json_table_columns(tf, scan, context, showimplicit);
12643 }
12644 else if (IsA(plan, JsonTableSiblingJoin))
12645 {
12647
12649 needcomma);
12651 true);
12652 }
12653}
12654
12655/*
12656 * get_json_table_columns - Parse back JSON_TABLE columns
12657 */
12658static void
12660 deparse_context *context,
12661 bool showimplicit)
12662{
12663 StringInfo buf = context->buf;
12668 int colnum = 0;
12669
12671 appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
12672
12673 if (PRETTY_INDENT(context))
12674 context->indentLevel += PRETTYINDENT_VAR;
12675
12676 forfour(lc_colname, tf->colnames,
12677 lc_coltype, tf->coltypes,
12678 lc_coltypmod, tf->coltypmods,
12679 lc_colvalexpr, tf->colvalexprs)
12680 {
12681 char *colname = strVal(lfirst(lc_colname));
12682 JsonExpr *colexpr;
12683 Oid typid;
12684 int32 typmod;
12685 bool ordinality;
12687
12688 typid = lfirst_oid(lc_coltype);
12689 typmod = lfirst_int(lc_coltypmod);
12691
12692 /* Skip columns that don't belong to this scan. */
12693 if (scan->colMin < 0 || colnum < scan->colMin)
12694 {
12695 colnum++;
12696 continue;
12697 }
12698 if (colnum > scan->colMax)
12699 break;
12700
12701 if (colnum > scan->colMin)
12703
12704 colnum++;
12705
12706 ordinality = !colexpr;
12707
12708 appendContextKeyword(context, "", 0, 0, 0);
12709
12710 appendStringInfo(buf, "%s %s", quote_identifier(colname),
12711 ordinality ? "FOR ORDINALITY" :
12712 format_type_with_typemod(typid, typmod));
12713 if (ordinality)
12714 continue;
12715
12716 /*
12717 * Set default_behavior to guide get_json_expr_options() on whether to
12718 * emit the ON ERROR / EMPTY clauses.
12719 */
12720 if (colexpr->op == JSON_EXISTS_OP)
12721 {
12722 appendStringInfoString(buf, " EXISTS");
12724 }
12725 else
12726 {
12727 if (colexpr->op == JSON_QUERY_OP)
12728 {
12729 char typcategory;
12730 bool typispreferred;
12731
12733
12736 colexpr->format->format_type == JS_FORMAT_JSONB ?
12737 " FORMAT JSONB" : " FORMAT JSON");
12738 }
12739
12741 }
12742
12743 appendStringInfoString(buf, " PATH ");
12744
12745 get_json_path_spec(colexpr->path_spec, context, showimplicit);
12746
12747 get_json_expr_options(colexpr, context, default_behavior);
12748 }
12749
12750 if (scan->child)
12752 scan->colMin >= 0);
12753
12754 if (PRETTY_INDENT(context))
12755 context->indentLevel -= PRETTYINDENT_VAR;
12756
12757 appendContextKeyword(context, ")", 0, 0, 0);
12758}
12759
12760/* ----------
12761 * get_json_table - Parse back a JSON_TABLE function
12762 * ----------
12763 */
12764static void
12766{
12767 StringInfo buf = context->buf;
12770
12771 appendStringInfoString(buf, "JSON_TABLE(");
12772
12773 if (PRETTY_INDENT(context))
12774 context->indentLevel += PRETTYINDENT_VAR;
12775
12776 appendContextKeyword(context, "", 0, 0, 0);
12777
12778 get_rule_expr(jexpr->formatted_expr, context, showimplicit);
12779
12781
12782 get_const_expr(root->path->value, context, -1);
12783
12784 appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
12785
12786 if (jexpr->passing_values)
12787 {
12788 ListCell *lc1,
12789 *lc2;
12790 bool needcomma = false;
12791
12793 appendContextKeyword(context, "PASSING ", 0, 0, 0);
12794
12795 if (PRETTY_INDENT(context))
12796 context->indentLevel += PRETTYINDENT_VAR;
12797
12798 forboth(lc1, jexpr->passing_names,
12799 lc2, jexpr->passing_values)
12800 {
12801 if (needcomma)
12803 needcomma = true;
12804
12805 appendContextKeyword(context, "", 0, 0, 0);
12806
12807 get_rule_expr((Node *) lfirst(lc2), context, false);
12808 appendStringInfo(buf, " AS %s",
12810 );
12811 }
12812
12813 if (PRETTY_INDENT(context))
12814 context->indentLevel -= PRETTYINDENT_VAR;
12815 }
12816
12817 get_json_table_columns(tf, castNode(JsonTablePathScan, tf->plan), context,
12818 showimplicit);
12819
12820 if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY_ARRAY)
12821 get_json_behavior(jexpr->on_error, context, "ERROR");
12822
12823 if (PRETTY_INDENT(context))
12824 context->indentLevel -= PRETTYINDENT_VAR;
12825
12826 appendContextKeyword(context, ")", 0, 0, 0);
12827}
12828
12829/* ----------
12830 * get_tablefunc - Parse back a table function
12831 * ----------
12832 */
12833static void
12835{
12836 /* XMLTABLE and JSON_TABLE are the only existing implementations. */
12837
12838 if (tf->functype == TFT_XMLTABLE)
12839 get_xmltable(tf, context, showimplicit);
12840 else if (tf->functype == TFT_JSON_TABLE)
12841 get_json_table(tf, context, showimplicit);
12842}
12843
12844/* ----------
12845 * get_from_clause - Parse back a FROM clause
12846 *
12847 * "prefix" is the keyword that denotes the start of the list of FROM
12848 * elements. It is FROM when used to parse back SELECT and UPDATE, but
12849 * is USING when parsing back DELETE.
12850 * ----------
12851 */
12852static void
12853get_from_clause(Query *query, const char *prefix, deparse_context *context)
12854{
12855 StringInfo buf = context->buf;
12856 bool first = true;
12857 ListCell *l;
12858
12859 /*
12860 * We use the query's jointree as a guide to what to print. However, we
12861 * must ignore auto-added RTEs that are marked not inFromCl. (These can
12862 * only appear at the top level of the jointree, so it's sufficient to
12863 * check here.) This check also ensures we ignore the rule pseudo-RTEs
12864 * for NEW and OLD.
12865 */
12866 foreach(l, query->jointree->fromlist)
12867 {
12868 Node *jtnode = (Node *) lfirst(l);
12869
12870 if (IsA(jtnode, RangeTblRef))
12871 {
12872 int varno = ((RangeTblRef *) jtnode)->rtindex;
12873 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12874
12875 if (!rte->inFromCl)
12876 continue;
12877 }
12878
12879 if (first)
12880 {
12881 appendContextKeyword(context, prefix,
12883 first = false;
12884
12885 get_from_clause_item(jtnode, query, context);
12886 }
12887 else
12888 {
12890
12892
12893 /*
12894 * Put the new FROM item's text into itembuf so we can decide
12895 * after we've got it whether or not it needs to go on a new line.
12896 */
12898 context->buf = &itembuf;
12899
12900 get_from_clause_item(jtnode, query, context);
12901
12902 /* Restore context's output buffer */
12903 context->buf = buf;
12904
12905 /* Consider line-wrapping if enabled */
12906 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
12907 {
12908 /* Does the new item start with a new line? */
12909 if (itembuf.len > 0 && itembuf.data[0] == '\n')
12910 {
12911 /* If so, we shouldn't add anything */
12912 /* instead, remove any trailing spaces currently in buf */
12914 }
12915 else
12916 {
12917 char *trailing_nl;
12918
12919 /* Locate the start of the current line in the buffer */
12920 trailing_nl = strrchr(buf->data, '\n');
12921 if (trailing_nl == NULL)
12922 trailing_nl = buf->data;
12923 else
12924 trailing_nl++;
12925
12926 /*
12927 * Add a newline, plus some indentation, if the new item
12928 * would cause an overflow.
12929 */
12930 if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
12934 }
12935 }
12936
12937 /* Add the new item */
12939
12940 /* clean up */
12941 pfree(itembuf.data);
12942 }
12943 }
12944}
12945
12946static void
12948{
12949 StringInfo buf = context->buf;
12951
12952 if (IsA(jtnode, RangeTblRef))
12953 {
12954 int varno = ((RangeTblRef *) jtnode)->rtindex;
12955 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12958
12959 if (rte->lateral)
12960 appendStringInfoString(buf, "LATERAL ");
12961
12962 /* Print the FROM item proper */
12963 switch (rte->rtekind)
12964 {
12965 case RTE_RELATION:
12966 /* Normal relation RTE */
12967 appendStringInfo(buf, "%s%s",
12970 context->namespaces));
12971 break;
12972 case RTE_SUBQUERY:
12973 /* Subquery RTE */
12975 get_query_def(rte->subquery, buf, context->namespaces, NULL,
12976 true,
12977 context->prettyFlags, context->wrapColumn,
12978 context->indentLevel);
12980 break;
12981 case RTE_FUNCTION:
12982 /* Function RTE */
12983 rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
12984
12985 /*
12986 * Omit ROWS FROM() syntax for just one function, unless it
12987 * has both a coldeflist and WITH ORDINALITY. If it has both,
12988 * we must use ROWS FROM() syntax to avoid ambiguity about
12989 * whether the coldeflist includes the ordinality column.
12990 */
12991 if (list_length(rte->functions) == 1 &&
12992 (rtfunc1->funccolnames == NIL || !rte->funcordinality))
12993 {
12994 get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
12995 /* we'll print the coldeflist below, if it has one */
12996 }
12997 else
12998 {
12999 bool all_unnest;
13000 ListCell *lc;
13001
13002 /*
13003 * If all the function calls in the list are to unnest,
13004 * and none need a coldeflist, then collapse the list back
13005 * down to UNNEST(args). (If we had more than one
13006 * built-in unnest function, this would get more
13007 * difficult.)
13008 *
13009 * XXX This is pretty ugly, since it makes not-terribly-
13010 * future-proof assumptions about what the parser would do
13011 * with the output; but the alternative is to emit our
13012 * nonstandard ROWS FROM() notation for what might have
13013 * been a perfectly spec-compliant multi-argument
13014 * UNNEST().
13015 */
13016 all_unnest = true;
13017 foreach(lc, rte->functions)
13018 {
13020
13021 if (!IsA(rtfunc->funcexpr, FuncExpr) ||
13022 ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
13023 rtfunc->funccolnames != NIL)
13024 {
13025 all_unnest = false;
13026 break;
13027 }
13028 }
13029
13030 if (all_unnest)
13031 {
13032 List *allargs = NIL;
13033
13034 foreach(lc, rte->functions)
13035 {
13037 List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
13038
13039 allargs = list_concat(allargs, args);
13040 }
13041
13042 appendStringInfoString(buf, "UNNEST(");
13043 get_rule_expr((Node *) allargs, context, true);
13045 }
13046 else
13047 {
13048 int funcno = 0;
13049
13050 appendStringInfoString(buf, "ROWS FROM(");
13051 foreach(lc, rte->functions)
13052 {
13054
13055 if (funcno > 0)
13057 get_rule_expr_funccall(rtfunc->funcexpr, context, true);
13058 if (rtfunc->funccolnames != NIL)
13059 {
13060 /* Reconstruct the column definition list */
13061 appendStringInfoString(buf, " AS ");
13063 NULL,
13064 context);
13065 }
13066 funcno++;
13067 }
13069 }
13070 /* prevent printing duplicate coldeflist below */
13071 rtfunc1 = NULL;
13072 }
13073 if (rte->funcordinality)
13074 appendStringInfoString(buf, " WITH ORDINALITY");
13075 break;
13076 case RTE_TABLEFUNC:
13077 get_tablefunc(rte->tablefunc, context, true);
13078 break;
13079 case RTE_GRAPH_TABLE:
13080 appendStringInfoString(buf, "GRAPH_TABLE (");
13082 appendStringInfoString(buf, " MATCH ");
13083 get_graph_pattern_def(rte->graph_pattern, context);
13084 appendStringInfoString(buf, " COLUMNS (");
13085 {
13086 ListCell *lc;
13087 bool first = true;
13088
13089 foreach(lc, rte->graph_table_columns)
13090 {
13092 deparse_context context = {0};
13093
13094 if (!first)
13096 else
13097 first = false;
13098
13099 context.buf = buf;
13100
13101 get_rule_expr((Node *) te->expr, &context, false);
13102 appendStringInfoString(buf, " AS ");
13104 }
13105 }
13108 break;
13109 case RTE_VALUES:
13110 /* Values list RTE */
13112 get_values_def(rte->values_lists, context);
13114 break;
13115 case RTE_CTE:
13117 break;
13118 default:
13119 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
13120 break;
13121 }
13122
13123 /* Print the relation alias, if needed */
13124 get_rte_alias(rte, varno, false, context);
13125
13126 /* Print the column definitions or aliases, if needed */
13127 if (rtfunc1 && rtfunc1->funccolnames != NIL)
13128 {
13129 /* Reconstruct the columndef list, which is also the aliases */
13131 }
13132 else
13133 {
13134 /* Else print column aliases as needed */
13136 }
13137
13138 /* Tablesample clause must go after any alias */
13139 if (rte->rtekind == RTE_RELATION && rte->tablesample)
13140 get_tablesample_def(rte->tablesample, context);
13141 }
13142 else if (IsA(jtnode, JoinExpr))
13143 {
13144 JoinExpr *j = (JoinExpr *) jtnode;
13147
13148 need_paren_on_right = PRETTY_PAREN(context) &&
13149 !IsA(j->rarg, RangeTblRef) &&
13150 !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
13151
13152 if (!PRETTY_PAREN(context) || j->alias != NULL)
13154
13155 get_from_clause_item(j->larg, query, context);
13156
13157 switch (j->jointype)
13158 {
13159 case JOIN_INNER:
13160 if (j->quals)
13161 appendContextKeyword(context, " JOIN ",
13165 else
13166 appendContextKeyword(context, " CROSS JOIN ",
13170 break;
13171 case JOIN_LEFT:
13172 appendContextKeyword(context, " LEFT JOIN ",
13176 break;
13177 case JOIN_FULL:
13178 appendContextKeyword(context, " FULL JOIN ",
13182 break;
13183 case JOIN_RIGHT:
13184 appendContextKeyword(context, " RIGHT JOIN ",
13188 break;
13189 default:
13190 elog(ERROR, "unrecognized join type: %d",
13191 (int) j->jointype);
13192 }
13193
13196 get_from_clause_item(j->rarg, query, context);
13199
13200 if (j->usingClause)
13201 {
13202 ListCell *lc;
13203 bool first = true;
13204
13205 appendStringInfoString(buf, " USING (");
13206 /* Use the assigned names, not what's in usingClause */
13207 foreach(lc, colinfo->usingNames)
13208 {
13209 char *colname = (char *) lfirst(lc);
13210
13211 if (first)
13212 first = false;
13213 else
13216 }
13218
13219 if (j->join_using_alias)
13220 appendStringInfo(buf, " AS %s",
13221 quote_identifier(j->join_using_alias->aliasname));
13222 }
13223 else if (j->quals)
13224 {
13225 appendStringInfoString(buf, " ON ");
13226 if (!PRETTY_PAREN(context))
13228 get_rule_expr(j->quals, context, false);
13229 if (!PRETTY_PAREN(context))
13231 }
13232 else if (j->jointype != JOIN_INNER)
13233 {
13234 /* If we didn't say CROSS JOIN above, we must provide an ON */
13235 appendStringInfoString(buf, " ON TRUE");
13236 }
13237
13238 if (!PRETTY_PAREN(context) || j->alias != NULL)
13240
13241 /* Yes, it's correct to put alias after the right paren ... */
13242 if (j->alias != NULL)
13243 {
13244 /*
13245 * Note that it's correct to emit an alias clause if and only if
13246 * there was one originally. Otherwise we'd be converting a named
13247 * join to unnamed or vice versa, which creates semantic
13248 * subtleties we don't want. However, we might print a different
13249 * alias name than was there originally.
13250 */
13251 appendStringInfo(buf, " %s",
13253 context)));
13255 }
13256 }
13257 else
13258 elog(ERROR, "unrecognized node type: %d",
13259 (int) nodeTag(jtnode));
13260}
13261
13262/*
13263 * get_rte_alias - print the relation's alias, if needed
13264 *
13265 * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
13266 */
13267static void
13269 deparse_context *context)
13270{
13272 char *refname = get_rtable_name(varno, context);
13274 bool printalias = false;
13275
13276 if (rte->alias != NULL)
13277 {
13278 /* Always print alias if user provided one */
13279 printalias = true;
13280 }
13281 else if (colinfo->printaliases)
13282 {
13283 /* Always print alias if we need to print column aliases */
13284 printalias = true;
13285 }
13286 else if (rte->rtekind == RTE_RELATION)
13287 {
13288 /*
13289 * No need to print alias if it's same as relation name (this would
13290 * normally be the case, but not if set_rtable_names had to resolve a
13291 * conflict).
13292 */
13293 if (strcmp(refname, get_relation_name(rte->relid)) != 0)
13294 printalias = true;
13295 }
13296 else if (rte->rtekind == RTE_FUNCTION)
13297 {
13298 /*
13299 * For a function RTE, always print alias. This covers possible
13300 * renaming of the function and/or instability of the FigureColname
13301 * rules for things that aren't simple functions. Note we'd need to
13302 * force it anyway for the columndef list case.
13303 */
13304 printalias = true;
13305 }
13306 else if (rte->rtekind == RTE_SUBQUERY ||
13307 rte->rtekind == RTE_VALUES)
13308 {
13309 /*
13310 * For a subquery, always print alias. This makes the output
13311 * SQL-spec-compliant, even though we allow such aliases to be omitted
13312 * on input.
13313 */
13314 printalias = true;
13315 }
13316 else if (rte->rtekind == RTE_CTE)
13317 {
13318 /*
13319 * No need to print alias if it's same as CTE name (this would
13320 * normally be the case, but not if set_rtable_names had to resolve a
13321 * conflict).
13322 */
13323 if (strcmp(refname, rte->ctename) != 0)
13324 printalias = true;
13325 }
13326
13327 if (printalias)
13328 appendStringInfo(context->buf, "%s%s",
13329 use_as ? " AS " : " ",
13330 quote_identifier(refname));
13331}
13332
13333/*
13334 * get_column_alias_list - print column alias list for an RTE
13335 *
13336 * Caller must already have printed the relation's alias name.
13337 */
13338static void
13340{
13341 StringInfo buf = context->buf;
13342 int i;
13343 bool first = true;
13344
13345 /* Don't print aliases if not needed */
13346 if (!colinfo->printaliases)
13347 return;
13348
13349 for (i = 0; i < colinfo->num_new_cols; i++)
13350 {
13351 char *colname = colinfo->new_colnames[i];
13352
13353 if (first)
13354 {
13356 first = false;
13357 }
13358 else
13361 }
13362 if (!first)
13364}
13365
13366/*
13367 * get_from_clause_coldeflist - reproduce FROM clause coldeflist
13368 *
13369 * When printing a top-level coldeflist (which is syntactically also the
13370 * relation's column alias list), use column names from colinfo. But when
13371 * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
13372 * original coldeflist's names, which are available in rtfunc->funccolnames.
13373 * Pass NULL for colinfo to select the latter behavior.
13374 *
13375 * The coldeflist is appended immediately (no space) to buf. Caller is
13376 * responsible for ensuring that an alias or AS is present before it.
13377 */
13378static void
13381 deparse_context *context)
13382{
13383 StringInfo buf = context->buf;
13384 ListCell *l1;
13385 ListCell *l2;
13386 ListCell *l3;
13387 ListCell *l4;
13388 int i;
13389
13391
13392 i = 0;
13393 forfour(l1, rtfunc->funccoltypes,
13394 l2, rtfunc->funccoltypmods,
13395 l3, rtfunc->funccolcollations,
13396 l4, rtfunc->funccolnames)
13397 {
13398 Oid atttypid = lfirst_oid(l1);
13399 int32 atttypmod = lfirst_int(l2);
13400 Oid attcollation = lfirst_oid(l3);
13401 char *attname;
13402
13403 if (colinfo)
13404 attname = colinfo->colnames[i];
13405 else
13406 attname = strVal(lfirst(l4));
13407
13408 Assert(attname); /* shouldn't be any dropped columns here */
13409
13410 if (i > 0)
13412 appendStringInfo(buf, "%s %s",
13415 if (OidIsValid(attcollation) &&
13416 attcollation != get_typcollation(atttypid))
13417 appendStringInfo(buf, " COLLATE %s",
13418 generate_collation_name(attcollation));
13419
13420 i++;
13421 }
13422
13424}
13425
13426/*
13427 * get_tablesample_def - print a TableSampleClause
13428 */
13429static void
13431{
13432 StringInfo buf = context->buf;
13433 Oid argtypes[1];
13434 int nargs;
13435 ListCell *l;
13436
13437 /*
13438 * We should qualify the handler's function name if it wouldn't be
13439 * resolved by lookup in the current search path.
13440 */
13441 argtypes[0] = INTERNALOID;
13442 appendStringInfo(buf, " TABLESAMPLE %s (",
13443 generate_function_name(tablesample->tsmhandler, 1,
13444 NIL, argtypes,
13445 false, NULL, false));
13446
13447 nargs = 0;
13448 foreach(l, tablesample->args)
13449 {
13450 if (nargs++ > 0)
13452 get_rule_expr((Node *) lfirst(l), context, false);
13453 }
13455
13456 if (tablesample->repeatable != NULL)
13457 {
13458 appendStringInfoString(buf, " REPEATABLE (");
13459 get_rule_expr((Node *) tablesample->repeatable, context, false);
13461 }
13462}
13463
13464/*
13465 * get_opclass_name - fetch name of an index operator class
13466 *
13467 * The opclass name is appended (after a space) to buf.
13468 *
13469 * Output is suppressed if the opclass is the default for the given
13470 * actual_datatype. (If you don't want this behavior, just pass
13471 * InvalidOid for actual_datatype.)
13472 */
13473static void
13476{
13479 char *opcname;
13480 char *nspname;
13481
13484 elog(ERROR, "cache lookup failed for opclass %u", opclass);
13486
13488 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
13489 {
13490 /* Okay, we need the opclass name. Do we need to qualify it? */
13491 opcname = NameStr(opcrec->opcname);
13492 if (OpclassIsVisible(opclass))
13494 else
13495 {
13496 nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
13497 appendStringInfo(buf, " %s.%s",
13498 quote_identifier(nspname),
13500 }
13501 }
13503}
13504
13505/*
13506 * generate_opclass_name
13507 * Compute the name to display for an opclass specified by OID
13508 *
13509 * The result includes all necessary quoting and schema-prefixing.
13510 */
13511char *
13513{
13515
13517 get_opclass_name(opclass, InvalidOid, &buf);
13518
13519 return &buf.data[1]; /* get_opclass_name() prepends space */
13520}
13521
13522/*
13523 * processIndirection - take care of array and subfield assignment
13524 *
13525 * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
13526 * appear in the input, printing them as decoration for the base column
13527 * name (which we assume the caller just printed). We might also need to
13528 * strip CoerceToDomain nodes, but only ones that appear above assignment
13529 * nodes.
13530 *
13531 * Returns the subexpression that's to be assigned.
13532 */
13533static Node *
13535{
13536 StringInfo buf = context->buf;
13538
13539 for (;;)
13540 {
13541 if (node == NULL)
13542 break;
13543 if (IsA(node, FieldStore))
13544 {
13545 FieldStore *fstore = (FieldStore *) node;
13546 Oid typrelid;
13547 char *fieldname;
13548
13549 /* lookup tuple type */
13550 typrelid = get_typ_typrelid(fstore->resulttype);
13551 if (!OidIsValid(typrelid))
13552 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
13553 format_type_be(fstore->resulttype));
13554
13555 /*
13556 * Print the field name. There should only be one target field in
13557 * stored rules. There could be more than that in executable
13558 * target lists, but this function cannot be used for that case.
13559 */
13560 Assert(list_length(fstore->fieldnums) == 1);
13561 fieldname = get_attname(typrelid,
13562 linitial_int(fstore->fieldnums), false);
13563 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
13564
13565 /*
13566 * We ignore arg since it should be an uninteresting reference to
13567 * the target column or subcolumn.
13568 */
13569 node = (Node *) linitial(fstore->newvals);
13570 }
13571 else if (IsA(node, SubscriptingRef))
13572 {
13573 SubscriptingRef *sbsref = (SubscriptingRef *) node;
13574
13575 if (sbsref->refassgnexpr == NULL)
13576 break;
13577
13578 printSubscripts(sbsref, context);
13579
13580 /*
13581 * We ignore refexpr since it should be an uninteresting reference
13582 * to the target column or subcolumn.
13583 */
13584 node = (Node *) sbsref->refassgnexpr;
13585 }
13586 else if (IsA(node, CoerceToDomain))
13587 {
13588 cdomain = (CoerceToDomain *) node;
13589 /* If it's an explicit domain coercion, we're done */
13590 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
13591 break;
13592 /* Tentatively descend past the CoerceToDomain */
13593 node = (Node *) cdomain->arg;
13594 }
13595 else
13596 break;
13597 }
13598
13599 /*
13600 * If we descended past a CoerceToDomain whose argument turned out not to
13601 * be a FieldStore or array assignment, back up to the CoerceToDomain.
13602 * (This is not enough to be fully correct if there are nested implicit
13603 * CoerceToDomains, but such cases shouldn't ever occur.)
13604 */
13605 if (cdomain && node == (Node *) cdomain->arg)
13606 node = (Node *) cdomain;
13607
13608 return node;
13609}
13610
13611static void
13613{
13614 StringInfo buf = context->buf;
13617
13618 lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
13619 foreach(uplist_item, sbsref->refupperindexpr)
13620 {
13622 if (lowlist_item)
13623 {
13624 /* If subexpression is NULL, get_rule_expr prints nothing */
13625 get_rule_expr((Node *) lfirst(lowlist_item), context, false);
13628 }
13629 /* If subexpression is NULL, get_rule_expr prints nothing */
13630 get_rule_expr((Node *) lfirst(uplist_item), context, false);
13632 }
13633}
13634
13635/*
13636 * quote_identifier - Quote an identifier only if needed
13637 *
13638 * When quotes are needed, we palloc the required space; slightly
13639 * space-wasteful but well worth it for notational simplicity.
13640 */
13641const char *
13643{
13644 /*
13645 * Can avoid quoting if ident starts with a lowercase letter or underscore
13646 * and contains only lowercase letters, digits, and underscores, *and* is
13647 * not any SQL keyword. Otherwise, supply quotes.
13648 */
13649 int nquotes = 0;
13650 bool safe;
13651 const char *ptr;
13652 char *result;
13653 char *optr;
13654
13655 /*
13656 * would like to use <ctype.h> macros here, but they might yield unwanted
13657 * locale-specific results...
13658 */
13659 safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
13660
13661 for (ptr = ident; *ptr; ptr++)
13662 {
13663 char ch = *ptr;
13664
13665 if ((ch >= 'a' && ch <= 'z') ||
13666 (ch >= '0' && ch <= '9') ||
13667 (ch == '_'))
13668 {
13669 /* okay */
13670 }
13671 else
13672 {
13673 safe = false;
13674 if (ch == '"')
13675 nquotes++;
13676 }
13677 }
13678
13680 safe = false;
13681
13682 if (safe)
13683 {
13684 /*
13685 * Check for keyword. We quote keywords except for unreserved ones.
13686 * (In some cases we could avoid quoting a col_name or type_func_name
13687 * keyword, but it seems much harder than it's worth to tell that.)
13688 *
13689 * Note: ScanKeywordLookup() does case-insensitive comparison, but
13690 * that's fine, since we already know we have all-lower-case.
13691 */
13693
13695 safe = false;
13696 }
13697
13698 if (safe)
13699 return ident; /* no change needed */
13700
13701 result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
13702
13703 optr = result;
13704 *optr++ = '"';
13705 for (ptr = ident; *ptr; ptr++)
13706 {
13707 char ch = *ptr;
13708
13709 if (ch == '"')
13710 *optr++ = '"';
13711 *optr++ = ch;
13712 }
13713 *optr++ = '"';
13714 *optr = '\0';
13715
13716 return result;
13717}
13718
13719/*
13720 * quote_qualified_identifier - Quote a possibly-qualified identifier
13721 *
13722 * Return a name of the form qualifier.ident, or just ident if qualifier
13723 * is NULL, quoting each component if necessary. The result is palloc'd.
13724 */
13725char *
13727 const char *ident)
13728{
13730
13732 if (qualifier)
13735 return buf.data;
13736}
13737
13738/*
13739 * get_relation_name
13740 * Get the unqualified name of a relation specified by OID
13741 *
13742 * This differs from the underlying get_rel_name() function in that it will
13743 * throw error instead of silently returning NULL if the OID is bad.
13744 */
13745static char *
13747{
13748 char *relname = get_rel_name(relid);
13749
13750 if (!relname)
13751 elog(ERROR, "cache lookup failed for relation %u", relid);
13752 return relname;
13753}
13754
13755/*
13756 * generate_relation_name
13757 * Compute the name to display for a relation specified by OID
13758 *
13759 * The result includes all necessary quoting and schema-prefixing.
13760 *
13761 * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
13762 * We will forcibly qualify the relation name if it equals any CTE name
13763 * visible in the namespace list.
13764 */
13765static char *
13767{
13768 HeapTuple tp;
13770 bool need_qual;
13772 char *relname;
13773 char *nspname;
13774 char *result;
13775
13777 if (!HeapTupleIsValid(tp))
13778 elog(ERROR, "cache lookup failed for relation %u", relid);
13780 relname = NameStr(reltup->relname);
13781
13782 /* Check for conflicting CTE name */
13783 need_qual = false;
13784 foreach(nslist, namespaces)
13785 {
13788
13789 foreach(ctlist, dpns->ctes)
13790 {
13792
13793 if (strcmp(cte->ctename, relname) == 0)
13794 {
13795 need_qual = true;
13796 break;
13797 }
13798 }
13799 if (need_qual)
13800 break;
13801 }
13802
13803 /* Otherwise, qualify the name if not visible in search path */
13804 if (!need_qual)
13805 need_qual = !RelationIsVisible(relid);
13806
13807 if (need_qual)
13808 nspname = get_namespace_name_or_temp(reltup->relnamespace);
13809 else
13810 nspname = NULL;
13811
13812 result = quote_qualified_identifier(nspname, relname);
13813
13814 ReleaseSysCache(tp);
13815
13816 return result;
13817}
13818
13819/*
13820 * generate_qualified_relation_name
13821 * Compute the name to display for a relation specified by OID
13822 *
13823 * As above, but unconditionally schema-qualify the name.
13824 */
13825static char *
13827{
13828 HeapTuple tp;
13830 char *relname;
13831 char *nspname;
13832 char *result;
13833
13835 if (!HeapTupleIsValid(tp))
13836 elog(ERROR, "cache lookup failed for relation %u", relid);
13838 relname = NameStr(reltup->relname);
13839
13840 nspname = get_namespace_name_or_temp(reltup->relnamespace);
13841 if (!nspname)
13842 elog(ERROR, "cache lookup failed for namespace %u",
13843 reltup->relnamespace);
13844
13845 result = quote_qualified_identifier(nspname, relname);
13846
13847 ReleaseSysCache(tp);
13848
13849 return result;
13850}
13851
13852/*
13853 * generate_function_name
13854 * Compute the name to display for a function specified by OID,
13855 * given that it is being called with the specified actual arg names and
13856 * types. (Those matter because of ambiguous-function resolution rules.)
13857 *
13858 * If we're dealing with a potentially variadic function (in practice, this
13859 * means a FuncExpr or Aggref, not some other way of calling a function), then
13860 * has_variadic must specify whether variadic arguments have been merged,
13861 * and *use_variadic_p will be set to indicate whether to print VARIADIC in
13862 * the output. For non-FuncExpr cases, has_variadic should be false and
13863 * use_variadic_p can be NULL.
13864 *
13865 * inGroupBy must be true if we're deparsing a GROUP BY clause.
13866 *
13867 * The result includes all necessary quoting and schema-prefixing.
13868 */
13869static char *
13870generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
13871 bool has_variadic, bool *use_variadic_p,
13872 bool inGroupBy)
13873{
13874 char *result;
13877 char *proname;
13878 bool use_variadic;
13879 char *nspname;
13881 int fgc_flags;
13882 Oid p_funcid;
13883 Oid p_rettype;
13884 bool p_retset;
13885 int p_nvargs;
13886 Oid p_vatype;
13888 bool force_qualify = false;
13889
13892 elog(ERROR, "cache lookup failed for function %u", funcid);
13894 proname = NameStr(procform->proname);
13895
13896 /*
13897 * Due to parser hacks to avoid needing to reserve CUBE, we need to force
13898 * qualification of some function names within GROUP BY.
13899 */
13900 if (inGroupBy)
13901 {
13902 if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
13903 force_qualify = true;
13904 }
13905
13906 /*
13907 * Determine whether VARIADIC should be printed. We must do this first
13908 * since it affects the lookup rules in func_get_detail().
13909 *
13910 * We always print VARIADIC if the function has a merged variadic-array
13911 * argument. Note that this is always the case for functions taking a
13912 * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
13913 * and printed the array elements as separate arguments, the call could
13914 * match a newer non-VARIADIC function.
13915 */
13916 if (use_variadic_p)
13917 {
13918 /* Parser should not have set funcvariadic unless fn is variadic */
13919 Assert(!has_variadic || OidIsValid(procform->provariadic));
13922 }
13923 else
13924 {
13926 use_variadic = false;
13927 }
13928
13929 /*
13930 * The idea here is to schema-qualify only if the parser would fail to
13931 * resolve the correct function given the unqualified func name with the
13932 * specified argtypes and VARIADIC flag. But if we already decided to
13933 * force qualification, then we can skip the lookup and pretend we didn't
13934 * find it.
13935 */
13936 if (!force_qualify)
13938 NIL, argnames, nargs, argtypes,
13939 !use_variadic, true, false,
13940 &fgc_flags,
13944 else
13945 {
13948 }
13949
13950 if ((p_result == FUNCDETAIL_NORMAL ||
13953 p_funcid == funcid)
13954 nspname = NULL;
13955 else
13956 nspname = get_namespace_name_or_temp(procform->pronamespace);
13957
13958 result = quote_qualified_identifier(nspname, proname);
13959
13961
13962 return result;
13963}
13964
13965/*
13966 * generate_operator_name
13967 * Compute the name to display for an operator specified by OID,
13968 * given that it is being called with the specified actual arg types.
13969 * (Arg types matter because of ambiguous-operator resolution rules.
13970 * Pass InvalidOid for unused arg of a unary operator.)
13971 *
13972 * The result includes all necessary quoting and schema-prefixing,
13973 * plus the OPERATOR() decoration needed to use a qualified operator name
13974 * in an expression.
13975 */
13976static char *
13978{
13982 char *oprname;
13983 char *nspname;
13985
13987
13990 elog(ERROR, "cache lookup failed for operator %u", operid);
13992 oprname = NameStr(operform->oprname);
13993
13994 /*
13995 * The idea here is to schema-qualify only if the parser would fail to
13996 * resolve the correct operator given the unqualified op name with the
13997 * specified argtypes.
13998 */
13999 switch (operform->oprkind)
14000 {
14001 case 'b':
14003 true, -1);
14004 break;
14005 case 'l':
14007 true, -1);
14008 break;
14009 default:
14010 elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
14011 p_result = NULL; /* keep compiler quiet */
14012 break;
14013 }
14014
14015 if (p_result != NULL && oprid(p_result) == operid)
14016 nspname = NULL;
14017 else
14018 {
14019 nspname = get_namespace_name_or_temp(operform->oprnamespace);
14020 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
14021 }
14022
14023 appendStringInfoString(&buf, oprname);
14024
14025 if (nspname)
14027
14028 if (p_result != NULL)
14030
14032
14033 return buf.data;
14034}
14035
14036/*
14037 * generate_operator_clause --- generate a binary-operator WHERE clause
14038 *
14039 * This is used for internally-generated-and-executed SQL queries, where
14040 * precision is essential and readability is secondary. The basic
14041 * requirement is to append "leftop op rightop" to buf, where leftop and
14042 * rightop are given as strings and are assumed to yield types leftoptype
14043 * and rightoptype; the operator is identified by OID. The complexity
14044 * comes from needing to be sure that the parser will select the desired
14045 * operator when the query is parsed. We always name the operator using
14046 * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
14047 * We have to emit casts too, if either input isn't already the input type
14048 * of the operator; else we are at the mercy of the parser's heuristics for
14049 * ambiguous-operator resolution. The caller must ensure that leftop and
14050 * rightop are suitable arguments for a cast operation; it's best to insert
14051 * parentheses if they aren't just variables or parameters.
14052 */
14053void
14055 const char *leftop, Oid leftoptype,
14056 Oid opoid,
14057 const char *rightop, Oid rightoptype)
14058{
14061 char *oprname;
14062 char *nspname;
14063
14066 elog(ERROR, "cache lookup failed for operator %u", opoid);
14068 Assert(operform->oprkind == 'b');
14069 oprname = NameStr(operform->oprname);
14070
14071 nspname = get_namespace_name(operform->oprnamespace);
14072
14074 if (leftoptype != operform->oprleft)
14075 add_cast_to(buf, operform->oprleft);
14076 appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
14077 appendStringInfoString(buf, oprname);
14078 appendStringInfo(buf, ") %s", rightop);
14079 if (rightoptype != operform->oprright)
14080 add_cast_to(buf, operform->oprright);
14081
14083}
14084
14085/*
14086 * Add a cast specification to buf. We spell out the type name the hard way,
14087 * intentionally not using format_type_be(). This is to avoid corner cases
14088 * for CHARACTER, BIT, and perhaps other types, where specifying the type
14089 * using SQL-standard syntax results in undesirable data truncation. By
14090 * doing it this way we can be certain that the cast will have default (-1)
14091 * target typmod.
14092 */
14093static void
14095{
14098 char *typname;
14099 char *nspname;
14100
14103 elog(ERROR, "cache lookup failed for type %u", typid);
14105
14106 typname = NameStr(typform->typname);
14107 nspname = get_namespace_name_or_temp(typform->typnamespace);
14108
14109 appendStringInfo(buf, "::%s.%s",
14111
14113}
14114
14115/*
14116 * generate_qualified_type_name
14117 * Compute the name to display for a type specified by OID
14118 *
14119 * This is different from format_type_be() in that we unconditionally
14120 * schema-qualify the name. That also means no special syntax for
14121 * SQL-standard type names ... although in current usage, this should
14122 * only get used for domains, so such cases wouldn't occur anyway.
14123 */
14124static char *
14126{
14127 HeapTuple tp;
14129 char *typname;
14130 char *nspname;
14131 char *result;
14132
14134 if (!HeapTupleIsValid(tp))
14135 elog(ERROR, "cache lookup failed for type %u", typid);
14137 typname = NameStr(typtup->typname);
14138
14139 nspname = get_namespace_name_or_temp(typtup->typnamespace);
14140 if (!nspname)
14141 elog(ERROR, "cache lookup failed for namespace %u",
14142 typtup->typnamespace);
14143
14144 result = quote_qualified_identifier(nspname, typname);
14145
14146 ReleaseSysCache(tp);
14147
14148 return result;
14149}
14150
14151/*
14152 * generate_collation_name
14153 * Compute the name to display for a collation specified by OID
14154 *
14155 * The result includes all necessary quoting and schema-prefixing.
14156 */
14157char *
14159{
14160 HeapTuple tp;
14162 char *collname;
14163 char *nspname;
14164 char *result;
14165
14167 if (!HeapTupleIsValid(tp))
14168 elog(ERROR, "cache lookup failed for collation %u", collid);
14170 collname = NameStr(colltup->collname);
14171
14173 nspname = get_namespace_name_or_temp(colltup->collnamespace);
14174 else
14175 nspname = NULL;
14176
14177 result = quote_qualified_identifier(nspname, collname);
14178
14179 ReleaseSysCache(tp);
14180
14181 return result;
14182}
14183
14184/*
14185 * Given a C string, produce a TEXT datum.
14186 *
14187 * We assume that the input was palloc'd and may be freed.
14188 */
14189static text *
14191{
14192 text *result;
14193
14194 result = cstring_to_text(str);
14195 pfree(str);
14196 return result;
14197}
14198
14199/*
14200 * Generate a C string representing a relation options from text[] datum.
14201 */
14202static void
14204{
14205 Datum *options;
14206 int noptions;
14207 int i;
14208
14210 &options, NULL, &noptions);
14211
14212 for (i = 0; i < noptions; i++)
14213 {
14215 char *name;
14216 char *separator;
14217 char *value;
14218
14219 /*
14220 * Each array element should have the form name=value. If the "=" is
14221 * missing for some reason, treat it like an empty value.
14222 */
14223 name = option;
14224 separator = strchr(option, '=');
14225 if (separator)
14226 {
14227 *separator = '\0';
14228 value = separator + 1;
14229 }
14230 else
14231 value = "";
14232
14233 if (i > 0)
14236
14237 /*
14238 * In general we need to quote the value; but to avoid unnecessary
14239 * clutter, do not quote if it is an identifier that would not need
14240 * quoting. (We could also allow numbers, but that is a bit trickier
14241 * than it looks --- for example, are leading zeroes significant? We
14242 * don't want to assume very much here about what custom reloptions
14243 * might mean.)
14244 */
14247 else
14249
14250 pfree(option);
14251 }
14252}
14253
14254/*
14255 * Generate a C string representing a relation's reloptions, or NULL if none.
14256 */
14257static char *
14259{
14260 char *result = NULL;
14261 HeapTuple tuple;
14262 Datum reloptions;
14263 bool isnull;
14264
14265 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
14266 if (!HeapTupleIsValid(tuple))
14267 elog(ERROR, "cache lookup failed for relation %u", relid);
14268
14269 reloptions = SysCacheGetAttr(RELOID, tuple,
14270 Anum_pg_class_reloptions, &isnull);
14271 if (!isnull)
14272 {
14274
14276 get_reloptions(&buf, reloptions);
14277
14278 result = buf.data;
14279 }
14280
14281 ReleaseSysCache(tuple);
14282
14283 return result;
14284}
14285
14286/*
14287 * get_range_partbound_string
14288 * A C string representation of one range partition bound
14289 */
14290char *
14292{
14293 deparse_context context;
14295 ListCell *cell;
14296 char *sep;
14297
14299 memset(&context, 0, sizeof(deparse_context));
14300 context.buf = &buf;
14301
14303 sep = "";
14304 foreach(cell, bound_datums)
14305 {
14306 PartitionRangeDatum *datum =
14308
14311 appendStringInfoString(&buf, "MINVALUE");
14312 else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
14313 appendStringInfoString(&buf, "MAXVALUE");
14314 else
14315 {
14316 Const *val = castNode(Const, datum->value);
14317
14318 get_const_expr(val, &context, -1);
14319 }
14320 sep = ", ";
14321 }
14323
14324 return buf.data;
14325}
const IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition amapi.c:33
#define ARR_NDIM(a)
Definition array.h:290
#define ARR_DATA_PTR(a)
Definition array.h:322
#define DatumGetArrayTypeP(X)
Definition array.h:261
#define ARR_ELEMTYPE(a)
Definition array.h:292
#define ARR_DIMS(a)
Definition array.h:294
#define ARR_HASNULL(a)
Definition array.h:291
#define ARR_LBOUND(a)
Definition array.h:296
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Datum array_ref(ArrayType *array, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
int16 AttrNumber
Definition attnum.h:21
#define InvalidAttrNumber
Definition attnum.h:23
char * get_tablespace_name(Oid spc_oid)
Bitmapset * bms_make_singleton(int x)
Definition bitmapset.c:216
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:412
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:251
#define bms_is_empty(a)
Definition bitmapset.h:118
#define TextDatumGetCString(d)
Definition builtins.h:99
#define NameStr(name)
Definition c.h:837
uint16 bits16
Definition c.h:626
NameData * Name
Definition c.h:835
#define Max(x, y)
Definition c.h:1087
#define Assert(condition)
Definition c.h:945
int16_t int16
Definition c.h:613
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition c.h:1254
int32_t int32
Definition c.h:614
#define lengthof(array)
Definition c.h:875
unsigned int Index
Definition c.h:700
float float4
Definition c.h:715
#define pg_fallthrough
Definition c.h:152
#define OidIsValid(objectId)
Definition c.h:860
Oid collid
const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS]
Definition keywords.c:29
@ DEPENDENCY_AUTO
Definition dependency.h:34
@ DEPENDENCY_INTERNAL
Definition dependency.h:35
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
void hash_destroy(HTAB *hashp)
Definition dynahash.c:865
Datum arg
Definition elog.c:1322
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define palloc0_object(type)
Definition fe_memutils.h:75
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition fmgr.c:1764
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define DatumGetByteaPP(X)
Definition fmgr.h:292
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_RETURN_TEXT_P(x)
Definition fmgr.h:374
#define PG_RETURN_NAME(x)
Definition fmgr.h:365
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_GETARG_BOOL(n)
Definition fmgr.h:274
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
char * format_type_with_typemod(Oid type_oid, int32 typemod)
char * format_type_be(Oid type_oid)
int get_func_trftypes(HeapTuple procTup, Oid **p_trftypes)
Definition funcapi.c:1478
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition funcapi.c:1382
TupleDesc get_expr_result_tupdesc(Node *expr, bool noError)
Definition funcapi.c:553
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
int GetConfigOptionFlags(const char *name, bool missing_ok)
Definition guc.c:4348
#define GUC_LIST_QUOTE
Definition guc.h:215
const char * str
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition heaptuple.c:456
#define HASH_STRINGS
Definition hsearch.h:96
@ HASH_FIND
Definition hsearch.h:113
@ HASH_ENTER
Definition hsearch.h:114
#define HASH_CONTEXT
Definition hsearch.h:102
#define HASH_ELEM
Definition hsearch.h:95
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static void * GETSTRUCT(const HeapTupleData *tuple)
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
#define stmt
#define ident
#define funcname
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2369
long val
Definition informix.c:689
static struct @174 value
static char * encoding
Definition initdb.c:139
int b
Definition isn.c:74
int a
Definition isn.c:73
int j
Definition isn.c:78
int i
Definition isn.c:77
PGDLLIMPORT const ScanKeywordList ScanKeywords
#define UNRESERVED_KEYWORD
Definition keywords.h:20
int ScanKeywordLookup(const char *str, const ScanKeywordList *keywords)
Definition kwlookup.c:38
List * lappend(List *list, void *datum)
Definition list.c:339
void list_sort(List *list, list_sort_comparator cmp)
Definition list.c:1674
List * list_copy_tail(const List *oldlist, int nskip)
Definition list.c:1613
List * list_delete_first(List *list)
Definition list.c:943
List * list_concat(List *list1, const List *list2)
Definition list.c:561
List * list_copy(const List *oldlist)
Definition list.c:1573
List * lcons(void *datum, List *list)
Definition list.c:495
void list_free(List *list)
Definition list.c:1546
#define NoLock
Definition lockdefs.h:34
#define AccessShareLock
Definition lockdefs.h:36
@ LockWaitSkip
Definition lockoptions.h:42
@ LockWaitError
Definition lockoptions.h:44
LockClauseStrength
Definition lockoptions.h:22
@ LCS_FORUPDATE
Definition lockoptions.h:28
@ LCS_NONE
Definition lockoptions.h:23
@ LCS_FORSHARE
Definition lockoptions.h:26
@ LCS_FORKEYSHARE
Definition lockoptions.h:25
@ LCS_FORNOKEYUPDATE
Definition lockoptions.h:27
char * get_rel_name(Oid relid)
Definition lsyscache.c:2148
char * get_propgraph_property_name(Oid propoid)
Definition lsyscache.c:3959
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:977
Oid get_opclass_input_type(Oid opclass)
Definition lsyscache.c:1384
bool type_is_rowtype(Oid typid)
Definition lsyscache.c:2877
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3129
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1089
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2223
Oid get_typcollation(Oid typid)
Definition lsyscache.c:3278
char * get_language_name(Oid langoid, bool missing_ok)
Definition lsyscache.c:1333
char * get_namespace_name_or_temp(Oid nspid)
Definition lsyscache.c:3612
char * get_propgraph_label_name(Oid labeloid)
Definition lsyscache.c:3941
char * get_constraint_name(Oid conoid)
Definition lsyscache.c:1227
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:946
Oid get_rel_tablespace(Oid relid)
Definition lsyscache.c:2274
Oid get_typ_typrelid(Oid typid)
Definition lsyscache.c:2953
Oid get_base_element_type(Oid typid)
Definition lsyscache.c:3054
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3588
void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
Definition lsyscache.c:2932
void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod, Oid *collid)
Definition lsyscache.c:1062
Alias * makeAlias(const char *aliasname, List *colnames)
Definition makefuncs.c:438
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1211
char * pstrdup(const char *in)
Definition mcxt.c:1781
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc0(Size size)
Definition mcxt.c:1417
void * palloc(Size size)
Definition mcxt.c:1387
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
Datum namein(PG_FUNCTION_ARGS)
Definition name.c:48
bool CollationIsVisible(Oid collid)
Definition namespace.c:2476
bool RelationIsVisible(Oid relid)
Definition namespace.c:914
bool OpclassIsVisible(Oid opcid)
Definition namespace.c:2223
RangeVar * makeRangeVarFromNameList(const List *names)
Definition namespace.c:3626
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition namespace.h:98
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition nodeFuncs.c:562
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
Node * strip_implicit_coercions(Node *node)
Definition nodeFuncs.c:710
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition nodes.h:396
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define nodeTag(nodeptr)
Definition nodes.h:139
#define DO_AGGSPLIT_COMBINE(as)
Definition nodes.h:395
@ ONCONFLICT_SELECT
Definition nodes.h:431
@ ONCONFLICT_UPDATE
Definition nodes.h:430
@ ONCONFLICT_NOTHING
Definition nodes.h:429
@ CMD_MERGE
Definition nodes.h:279
@ CMD_UTILITY
Definition nodes.h:280
@ CMD_INSERT
Definition nodes.h:277
@ CMD_DELETE
Definition nodes.h:278
@ CMD_UPDATE
Definition nodes.h:276
@ CMD_SELECT
Definition nodes.h:275
@ CMD_NOTHING
Definition nodes.h:282
@ LIMIT_OPTION_WITH_TIES
Definition nodes.h:443
#define makeNode(_type_)
Definition nodes.h:161
#define castNode(_type_, nodeptr)
Definition nodes.h:182
@ JOIN_FULL
Definition nodes.h:305
@ JOIN_INNER
Definition nodes.h:303
@ JOIN_RIGHT
Definition nodes.h:306
@ JOIN_LEFT
Definition nodes.h:304
static char * errmsg
Datum lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
#define repalloc0_array(pointer, type, oldcount, count)
Definition palloc.h:109
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition parse_agg.c:2112
FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, bool include_out_arguments, int *fgc_flags, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, Oid **true_typeids, List **argdefaults)
FuncDetailCode
Definition parse_func.h:23
@ FUNCDETAIL_NORMAL
Definition parse_func.h:26
@ FUNCDETAIL_WINDOWFUNC
Definition parse_func.h:29
@ FUNCDETAIL_NOTFOUND
Definition parse_func.h:24
@ FUNCDETAIL_AGGREGATE
Definition parse_func.h:28
Operator left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
Definition parse_oper.c:522
Oid oprid(Operator op)
Definition parse_oper.c:240
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition parse_oper.c:372
char * get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, VarReturningType returning_type, int location, bool include_dropped, List **colnames, List **colvars)
#define FRAMEOPTION_END_CURRENT_ROW
Definition parsenodes.h:619
#define FRAMEOPTION_END_OFFSET
Definition parsenodes.h:630
#define FRAMEOPTION_EXCLUDE_CURRENT_ROW
Definition parsenodes.h:624
@ GROUPING_SET_CUBE
@ GROUPING_SET_SIMPLE
@ GROUPING_SET_ROLLUP
@ GROUPING_SET_SETS
@ GROUPING_SET_EMPTY
#define FKCONSTR_ACTION_RESTRICT
@ SETOP_INTERSECT
@ SETOP_UNION
@ SETOP_EXCEPT
#define FRAMEOPTION_END_OFFSET_PRECEDING
Definition parsenodes.h:621
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition parsenodes.h:614
#define GetCTETargetList(cte)
#define FKCONSTR_ACTION_SETDEFAULT
@ PARTITION_STRATEGY_HASH
Definition parsenodes.h:916
@ PARTITION_STRATEGY_LIST
Definition parsenodes.h:914
@ PARTITION_STRATEGY_RANGE
Definition parsenodes.h:915
#define FRAMEOPTION_START_CURRENT_ROW
Definition parsenodes.h:618
#define FKCONSTR_MATCH_SIMPLE
@ RTE_JOIN
@ RTE_CTE
@ RTE_NAMEDTUPLESTORE
@ RTE_VALUES
@ RTE_SUBQUERY
@ RTE_RESULT
@ RTE_FUNCTION
@ RTE_TABLEFUNC
@ RTE_GROUP
@ RTE_GRAPH_TABLE
@ RTE_RELATION
#define FRAMEOPTION_START_OFFSET
Definition parsenodes.h:628
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition parsenodes.h:968
@ PARTITION_RANGE_DATUM_MINVALUE
Definition parsenodes.h:966
@ EDGE_PATTERN_RIGHT
@ VERTEX_PATTERN
@ EDGE_PATTERN_LEFT
@ PAREN_EXPR
@ EDGE_PATTERN_ANY
#define FKCONSTR_MATCH_PARTIAL
#define FRAMEOPTION_END_OFFSET_FOLLOWING
Definition parsenodes.h:623
#define FRAMEOPTION_EXCLUDE_TIES
Definition parsenodes.h:626
#define FRAMEOPTION_RANGE
Definition parsenodes.h:610
#define FRAMEOPTION_EXCLUDE_GROUP
Definition parsenodes.h:625
#define FKCONSTR_ACTION_CASCADE
#define FRAMEOPTION_GROUPS
Definition parsenodes.h:612
#define FRAMEOPTION_BETWEEN
Definition parsenodes.h:613
#define FKCONSTR_ACTION_SETNULL
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING
Definition parsenodes.h:617
#define FRAMEOPTION_START_OFFSET_PRECEDING
Definition parsenodes.h:620
#define FRAMEOPTION_START_OFFSET_FOLLOWING
Definition parsenodes.h:622
#define FRAMEOPTION_NONDEFAULT
Definition parsenodes.h:609
#define FKCONSTR_MATCH_FULL
#define FKCONSTR_ACTION_NOACTION
#define FRAMEOPTION_ROWS
Definition parsenodes.h:611
@ CTEMaterializeNever
@ CTEMaterializeAlways
@ CTEMaterializeDefault
#define rt_fetch(rangetable_index, rangetable)
Definition parsetree.h:31
Expr * get_partition_qual_relid(Oid relid)
Definition partcache.c:299
END_CATALOG_STRUCT typedef FormData_pg_aggregate * Form_pg_aggregate
END_CATALOG_STRUCT typedef FormData_pg_am * Form_pg_am
Definition pg_am.h:52
NameData attname
int16 attnum
FormData_pg_attribute * Form_pg_attribute
END_CATALOG_STRUCT typedef FormData_pg_authid * Form_pg_authid
Definition pg_authid.h:60
static char format
NameData relname
Definition pg_class.h:40
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
END_CATALOG_STRUCT typedef FormData_pg_collation * Form_pg_collation
#define NAMEDATALEN
#define FUNC_MAX_ARGS
AttrNumber extractNotNullColumn(HeapTuple constrTup)
END_CATALOG_STRUCT typedef FormData_pg_constraint * Form_pg_constraint
const void * data
END_CATALOG_STRUCT typedef FormData_pg_depend * Form_pg_depend
Definition pg_depend.h:76
END_CATALOG_STRUCT typedef FormData_pg_index * Form_pg_index
Definition pg_index.h:74
#define lfirst(lc)
Definition pg_list.h:172
#define llast(l)
Definition pg_list.h:198
#define lfirst_node(type, lc)
Definition pg_list.h:176
static int list_length(const List *l)
Definition pg_list.h:152
#define linitial_node(type, l)
Definition pg_list.h:181
#define NIL
Definition pg_list.h:68
#define lsecond_node(type, l)
Definition pg_list.h:186
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:518
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
#define lfirst_int(lc)
Definition pg_list.h:173
#define lthird(l)
Definition pg_list.h:188
#define list_make1(x1)
Definition pg_list.h:212
#define linitial_int(l)
Definition pg_list.h:179
#define foreach_ptr(type, var, lst)
Definition pg_list.h:469
#define for_each_cell(cell, lst, initcell)
Definition pg_list.h:438
#define for_each_from(cell, lst, N)
Definition pg_list.h:414
static void * list_nth(const List *list, int n)
Definition pg_list.h:299
#define lsecond_int(l)
Definition pg_list.h:184
#define linitial(l)
Definition pg_list.h:178
#define lsecond(l)
Definition pg_list.h:183
#define foreach_node(type, var, lst)
Definition pg_list.h:496
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition pg_list.h:575
static ListCell * list_head(const List *l)
Definition pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:343
#define lfourth(l)
Definition pg_list.h:193
#define linitial_oid(l)
Definition pg_list.h:180
#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5)
Definition pg_list.h:588
#define lfirst_oid(lc)
Definition pg_list.h:174
#define list_make2(x1, x2)
Definition pg_list.h:214
#define foreach_int(var, lst)
Definition pg_list.h:470
static int list_cell_number(const List *l, const ListCell *c)
Definition pg_list.h:333
#define lthird_node(type, l)
Definition pg_list.h:191
END_CATALOG_STRUCT typedef FormData_pg_opclass * Form_pg_opclass
Definition pg_opclass.h:87
END_CATALOG_STRUCT typedef FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:87
END_CATALOG_STRUCT typedef FormData_pg_partitioned_table * Form_pg_partitioned_table
END_CATALOG_STRUCT typedef FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:140
NameData proname
Definition pg_proc.h:37
END_CATALOG_STRUCT typedef FormData_pg_propgraph_element * Form_pg_propgraph_element
END_CATALOG_STRUCT typedef FormData_pg_propgraph_element_label * Form_pg_propgraph_element_label
END_CATALOG_STRUCT typedef FormData_pg_propgraph_label_property * Form_pg_propgraph_label_property
static size_t noptions
#define plan(x)
Definition pg_regress.c:161
END_CATALOG_STRUCT typedef FormData_pg_statistic_ext * Form_pg_statistic_ext
static char buf[DEFAULT_XLOG_SEG_SIZE]
END_CATALOG_STRUCT typedef FormData_pg_trigger * Form_pg_trigger
Definition pg_trigger.h:84
END_CATALOG_STRUCT typedef FormData_pg_type * Form_pg_type
Definition pg_type.h:265
NameData typname
Definition pg_type.h:43
#define innerPlan(node)
Definition plannodes.h:264
#define outerPlan(node)
Definition plannodes.h:265
#define sprintf
Definition port.h:262
#define snprintf
Definition port.h:260
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Name DatumGetName(Datum X)
Definition postgres.h:380
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
static char DatumGetChar(Datum X)
Definition postgres.h:122
static Datum CStringGetDatum(const char *X)
Definition postgres.h:370
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
static int16 DatumGetInt16(Datum X)
Definition postgres.h:162
static int32 DatumGetInt32(Datum X)
Definition postgres.h:202
#define InvalidOid
unsigned int Oid
e
static int fb(int x)
char string[11]
@ IS_NOT_TRUE
Definition primnodes.h:2003
@ IS_NOT_FALSE
Definition primnodes.h:2003
@ IS_NOT_UNKNOWN
Definition primnodes.h:2003
@ IS_TRUE
Definition primnodes.h:2003
@ IS_UNKNOWN
Definition primnodes.h:2003
@ IS_FALSE
Definition primnodes.h:2003
@ ARRAY_SUBLINK
Definition primnodes.h:1036
@ ANY_SUBLINK
Definition primnodes.h:1032
@ MULTIEXPR_SUBLINK
Definition primnodes.h:1035
@ CTE_SUBLINK
Definition primnodes.h:1037
@ EXPR_SUBLINK
Definition primnodes.h:1034
@ ROWCOMPARE_SUBLINK
Definition primnodes.h:1033
@ ALL_SUBLINK
Definition primnodes.h:1031
@ EXISTS_SUBLINK
Definition primnodes.h:1030
@ JS_FORMAT_JSONB
Definition primnodes.h:1666
@ JS_FORMAT_DEFAULT
Definition primnodes.h:1664
@ JS_FORMAT_JSON
Definition primnodes.h:1665
@ IS_LEAST
Definition primnodes.h:1529
@ IS_GREATEST
Definition primnodes.h:1528
@ TFT_XMLTABLE
Definition primnodes.h:101
@ TFT_JSON_TABLE
Definition primnodes.h:102
BoolExprType
Definition primnodes.h:963
@ AND_EXPR
Definition primnodes.h:964
@ OR_EXPR
Definition primnodes.h:964
@ NOT_EXPR
Definition primnodes.h:964
@ JS_ENC_DEFAULT
Definition primnodes.h:1652
@ JS_ENC_UTF32
Definition primnodes.h:1655
@ JS_ENC_UTF16
Definition primnodes.h:1654
@ XMLOPTION_DOCUMENT
Definition primnodes.h:1618
@ SVFOP_CURRENT_CATALOG
Definition primnodes.h:1575
@ SVFOP_LOCALTIME_N
Definition primnodes.h:1568
@ SVFOP_CURRENT_TIMESTAMP
Definition primnodes.h:1565
@ SVFOP_LOCALTIME
Definition primnodes.h:1567
@ SVFOP_CURRENT_TIMESTAMP_N
Definition primnodes.h:1566
@ SVFOP_CURRENT_ROLE
Definition primnodes.h:1571
@ SVFOP_USER
Definition primnodes.h:1573
@ SVFOP_CURRENT_SCHEMA
Definition primnodes.h:1576
@ SVFOP_LOCALTIMESTAMP_N
Definition primnodes.h:1570
@ SVFOP_CURRENT_DATE
Definition primnodes.h:1562
@ SVFOP_CURRENT_TIME_N
Definition primnodes.h:1564
@ SVFOP_CURRENT_TIME
Definition primnodes.h:1563
@ SVFOP_LOCALTIMESTAMP
Definition primnodes.h:1569
@ SVFOP_CURRENT_USER
Definition primnodes.h:1572
@ SVFOP_SESSION_USER
Definition primnodes.h:1574
@ PARAM_MULTIEXPR
Definition primnodes.h:388
@ PARAM_EXTERN
Definition primnodes.h:385
@ PARAM_EXEC
Definition primnodes.h:386
@ JSW_UNCONDITIONAL
Definition primnodes.h:1780
@ JSW_CONDITIONAL
Definition primnodes.h:1779
@ JSW_UNSPEC
Definition primnodes.h:1777
@ JSW_NONE
Definition primnodes.h:1778
#define PARSER_IGNORE_NULLS
Definition primnodes.h:590
@ IS_DOCUMENT
Definition primnodes.h:1613
@ IS_XMLFOREST
Definition primnodes.h:1608
@ IS_XMLCONCAT
Definition primnodes.h:1606
@ IS_XMLPI
Definition primnodes.h:1610
@ IS_XMLPARSE
Definition primnodes.h:1609
@ IS_XMLSERIALIZE
Definition primnodes.h:1612
@ IS_XMLROOT
Definition primnodes.h:1611
@ IS_XMLELEMENT
Definition primnodes.h:1607
@ VAR_RETURNING_OLD
Definition primnodes.h:258
@ VAR_RETURNING_NEW
Definition primnodes.h:259
@ VAR_RETURNING_DEFAULT
Definition primnodes.h:257
JsonBehaviorType
Definition primnodes.h:1791
@ JSON_BEHAVIOR_DEFAULT
Definition primnodes.h:1800
@ JSON_BEHAVIOR_FALSE
Definition primnodes.h:1796
@ JSON_BEHAVIOR_NULL
Definition primnodes.h:1792
@ JSON_BEHAVIOR_EMPTY_ARRAY
Definition primnodes.h:1798
@ JSON_QUERY_OP
Definition primnodes.h:1830
@ JSON_EXISTS_OP
Definition primnodes.h:1829
@ JSON_VALUE_OP
Definition primnodes.h:1831
CoercionForm
Definition primnodes.h:766
@ COERCE_SQL_SYNTAX
Definition primnodes.h:770
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:769
@ COERCE_EXPLICIT_CAST
Definition primnodes.h:768
@ COERCE_EXPLICIT_CALL
Definition primnodes.h:767
@ OVERRIDING_SYSTEM_VALUE
Definition primnodes.h:31
@ OVERRIDING_USER_VALUE
Definition primnodes.h:30
@ IS_NULL
Definition primnodes.h:1979
@ IS_NOT_NULL
Definition primnodes.h:1979
@ JS_TYPE_ARRAY
Definition primnodes.h:1750
@ JS_TYPE_OBJECT
Definition primnodes.h:1749
@ JS_TYPE_SCALAR
Definition primnodes.h:1751
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition primnodes.h:2025
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition primnodes.h:2024
@ MERGE_WHEN_MATCHED
Definition primnodes.h:2023
#define OUTER_VAR
Definition primnodes.h:244
@ JSCTOR_JSON_SERIALIZE
Definition primnodes.h:1722
@ JSCTOR_JSON_ARRAYAGG
Definition primnodes.h:1719
@ JSCTOR_JSON_PARSE
Definition primnodes.h:1720
@ JSCTOR_JSON_OBJECT
Definition primnodes.h:1716
@ JSCTOR_JSON_SCALAR
Definition primnodes.h:1721
@ JSCTOR_JSON_ARRAY
Definition primnodes.h:1717
@ JSCTOR_JSON_OBJECTAGG
Definition primnodes.h:1718
#define INNER_VAR
Definition primnodes.h:243
#define INDEX_VAR
Definition primnodes.h:245
tree ctl root
Definition radixtree.h:1857
void * stringToNode(const char *str)
Definition read.c:90
#define RelationGetDescr(relation)
Definition rel.h:540
#define RelationGetRelationName(relation)
Definition rel.h:548
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
#define ViewSelectRuleName
Datum pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:894
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags, int wrapColumn)
Definition ruleutils.c:5899
static void removeStringInfoSpaces(StringInfo str)
Definition ruleutils.c:9693
static bool looks_like_function(Node *node)
Datum pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:2452
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition ruleutils.c:5493
Datum pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
Definition ruleutils.c:725
static int decompile_column_index_array(Datum column_index_array, Oid relId, bool withPeriod, StringInfo buf)
Definition ruleutils.c:2977
static void make_propgraphdef_labels(StringInfo buf, Oid elid, const char *elalias, Oid elrelid)
Definition ruleutils.c:1795
static void set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition ruleutils.c:4735
static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
Definition ruleutils.c:9639
List * deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
Definition ruleutils.c:4113
char * pg_get_statisticsobjdef_string(Oid statextid)
Definition ruleutils.c:1983
Datum pg_get_indexdef_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:1207
static void set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
Definition ruleutils.c:4570
static Plan * find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
Definition ruleutils.c:5593
static text * string_to_text(char *str)
static void get_values_def(List *values_lists, deparse_context *context)
Definition ruleutils.c:6087
#define PRETTYINDENT_LIMIT
Definition ruleutils.c:90
Datum pg_get_viewdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:687
static char * make_colname_unique(char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
Definition ruleutils.c:5283
static void get_json_behavior(JsonBehavior *behavior, deparse_context *context, const char *on)
Definition ruleutils.c:9730
static const char * get_simple_binary_op_name(OpExpr *expr)
Definition ruleutils.c:9381
static void get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
Datum pg_get_constraintdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:2502
static void set_deparse_for_query(deparse_namespace *dpns, Query *query, List *parent_namespaces)
Definition ruleutils.c:4389
static void print_function_trftypes(StringInfo buf, HeapTuple proctup)
Definition ruleutils.c:3818
void(* rsv_callback)(Node *node, deparse_context *context, void *callback_arg)
Definition ruleutils.c:330
#define PRETTYINDENT_STD
Definition ruleutils.c:86
static void get_graph_label_expr(Node *label_expr, deparse_context *context)
Definition ruleutils.c:7974
char * quote_qualified_identifier(const char *qualifier, const char *ident)
static void get_setop_query(Node *setOp, Query *query, deparse_context *context)
Definition ruleutils.c:6780
#define PRETTYINDENT_JOIN
Definition ruleutils.c:87
static bool is_input_argument(int nth, const char *argmodes)
Definition ruleutils.c:3806
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
Definition ruleutils.c:5984
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Datum pg_get_functiondef(PG_FUNCTION_ARGS)
Definition ruleutils.c:3283
Datum pg_get_function_result(PG_FUNCTION_ARGS)
Definition ruleutils.c:3590
Datum pg_get_indexdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:1187
static void get_sublink_expr(SubLink *sublink, deparse_context *context)
static const char * get_name_for_var_field(Var *var, int fieldno, int levelsup, deparse_context *context)
Definition ruleutils.c:8565
static char * get_lock_clause_strength(LockClauseStrength strength)
Definition ruleutils.c:6376
static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as, deparse_context *context)
#define only_marker(rte)
Definition ruleutils.c:559
Datum pg_get_function_arg_default(PG_FUNCTION_ARGS)
Definition ruleutils.c:3846
static void get_parameter(Param *param, deparse_context *context)
Definition ruleutils.c:9236
static void build_colinfo_names_hash(deparse_columns *colinfo)
Definition ruleutils.c:5338
Datum pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
Definition ruleutils.c:2194
static void get_delete_query_def(Query *query, deparse_context *context)
Definition ruleutils.c:7738
Datum pg_get_ruledef(PG_FUNCTION_ARGS)
Definition ruleutils.c:569
static void get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan, deparse_context *context, bool showimplicit)
#define PRETTYFLAG_INDENT
Definition ruleutils.c:94
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Datum pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)
Definition ruleutils.c:1993
Datum pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:1965
static void add_to_names_hash(deparse_columns *colinfo, const char *name)
Definition ruleutils.c:5396
static void simple_quote_literal(StringInfo buf, const char *val)
static bool colname_is_unique(const char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
Definition ruleutils.c:5208
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
char * pg_get_partkeydef_columns(Oid relid, bool pretty)
Definition ruleutils.c:2280
static void get_from_clause(Query *query, const char *prefix, deparse_context *context)
List * deparse_context_for(const char *aliasname, Oid relid)
Definition ruleutils.c:4068
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Datum pg_get_partkeydef(PG_FUNCTION_ARGS)
Definition ruleutils.c:2265
static char * generate_qualified_relation_name(Oid relid)
static void set_simple_column_names(deparse_namespace *dpns)
Definition ruleutils.c:4458
static void get_json_expr_options(JsonExpr *jsexpr, deparse_context *context, JsonBehaviorType default_behavior)
Definition ruleutils.c:9768
char * pg_get_indexdef_columns(Oid indexrelid, bool pretty)
Definition ruleutils.c:1244
#define PRETTY_INDENT(context)
Definition ruleutils.c:107
#define PRETTYFLAG_PAREN
Definition ruleutils.c:93
static void get_rule_groupingset(GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context)
Definition ruleutils.c:6997
static int propdata_by_name_cmp(const ListCell *a, const ListCell *b)
Definition ruleutils.c:1863
char * pg_get_indexdef_columns_extended(Oid indexrelid, bits16 flags)
Definition ruleutils.c:1258
static char * pg_get_indexdef_worker(Oid indexrelid, int colno, const Oid *excludeOps, bool attrsOnly, bool keysOnly, bool showTblSpc, bool inherits, int prettyFlags, bool missing_ok)
Definition ruleutils.c:1279
static char * pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, int prettyFlags, bool missing_ok)
Definition ruleutils.c:2549
static void get_rule_expr_funccall(Node *node, deparse_context *context, bool showimplicit)
static char * generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, bool has_variadic, bool *use_variadic_p, bool inGroupBy)
static void expand_colnames_array_to(deparse_columns *colinfo, int n)
Definition ruleutils.c:5322
static void get_returning_clause(Query *query, deparse_context *context)
Definition ruleutils.c:6741
List * set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
Definition ruleutils.c:4185
static SubPlan * find_param_generator(Param *param, deparse_context *context, int *column_p)
Definition ruleutils.c:9118
static void add_cast_to(StringInfo buf, Oid typid)
static void get_special_variable(Node *node, deparse_context *context, void *callback_arg)
Definition ruleutils.c:8436
static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context, const char *funcname, const char *options, bool is_json_objectagg)
static void get_rule_list_toplevel(List *lst, deparse_context *context, bool showimplicit)
static char * pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
Definition ruleutils.c:2010
#define deparse_columns_fetch(rangetable_index, dpns)
Definition ruleutils.c:317
static void get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context, bool showimplicit)
static const char *const query_getrulebyoid
Definition ruleutils.c:339
static void get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
static SubPlan * find_param_generator_initplan(Param *param, Plan *plan, int *column_p)
Definition ruleutils.c:9215
static void pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition ruleutils.c:5691
static void get_window_frame_options(int frameOptions, Node *startOffset, Node *endOffset, deparse_context *context)
Definition ruleutils.c:7204
static void get_rule_expr_paren(Node *node, deparse_context *context, bool showimplicit, Node *parentNode)
Definition ruleutils.c:9712
bool quote_all_identifiers
Definition ruleutils.c:344
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
static void get_const_collation(Const *constval, deparse_context *context)
static void get_target_list(List *targetList, deparse_context *context)
Definition ruleutils.c:6605
static SPIPlanPtr plan_getrulebyoid
Definition ruleutils.c:338
static void get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan, deparse_context *context, bool showimplicit, bool needcomma)
static char * deparse_expression_pretty(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
Definition ruleutils.c:4032
Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:587
char * pg_get_indexdef_string(Oid indexrelid)
Definition ruleutils.c:1234
static void get_insert_query_def(Query *query, deparse_context *context)
Definition ruleutils.c:7305
char * pg_get_querydef(Query *query, bool pretty)
Definition ruleutils.c:1597
static void print_function_sqlbody(StringInfo buf, HeapTuple proctup)
Definition ruleutils.c:3916
static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
Definition ruleutils.c:4500
const char * quote_identifier(const char *ident)
static Node * get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context)
Definition ruleutils.c:6928
static char * pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
Definition ruleutils.c:798
static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns)
Definition ruleutils.c:5670
static SPIPlanPtr plan_getviewrule
Definition ruleutils.c:340
#define WRAP_COLUMN_DEFAULT
Definition ruleutils.c:103
static char * flatten_reloptions(Oid relid)
static text * pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
Definition ruleutils.c:3066
static Node * processIndirection(Node *node, deparse_context *context)
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
#define PRETTY_PAREN(context)
Definition ruleutils.c:106
Datum pg_get_triggerdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:880
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition ruleutils.c:4215
Datum pg_get_function_sqlbody(PG_FUNCTION_ARGS)
Definition ruleutils.c:3970
static void get_path_pattern_expr_def(List *path_pattern_expr, deparse_context *context)
Definition ruleutils.c:8023
Datum pg_get_expr(PG_FUNCTION_ARGS)
Definition ruleutils.c:3031
static char * generate_qualified_type_name(Oid typid)
static void get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
static void get_utility_query_def(Query *query, deparse_context *context)
Definition ruleutils.c:7944
static char * get_relation_name(Oid relid)
Datum pg_get_expr_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:3048
static int list_oid_str_pair_cmp_by_str(const ListCell *p1, const ListCell *p2)
Definition ruleutils.c:1782
static void get_rule_windowclause(Query *query, deparse_context *context)
Definition ruleutils.c:7115
static void get_rule_windowspec(WindowClause *wc, List *targetList, deparse_context *context)
Definition ruleutils.c:7147
static void get_json_returning(JsonReturning *returning, StringInfo buf, bool json_format_by_default)
Datum pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:770
static Node * find_param_referent(Param *param, deparse_context *context, deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
Definition ruleutils.c:9004
static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context)
Definition ruleutils.c:7057
static void pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition ruleutils.c:5640
char * generate_collation_name(Oid collid)
static void get_graph_pattern_def(GraphPattern *graph_pattern, deparse_context *context)
Definition ruleutils.c:8109
char * pg_get_constraintdef_command(Oid constraintId)
Definition ruleutils.c:2540
char * pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
Definition ruleutils.c:2484
static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition ruleutils.c:4938
Datum pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:2519
static void make_propgraphdef_properties(StringInfo buf, Oid ellabelid, Oid elrelid)
Definition ruleutils.c:1879
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
Definition ruleutils.c:4244
char * get_window_frame_options_for_explain(int frameOptions, Node *startOffset, Node *endOffset, List *dpcontext, bool forceprefix)
Definition ruleutils.c:7273
static void get_update_query_targetlist_def(Query *query, List *targetList, deparse_context *context, RangeTblEntry *rte)
Definition ruleutils.c:7586
static void get_rule_expr(Node *node, deparse_context *context, bool showimplicit)
Definition ruleutils.c:9809
Datum pg_get_viewdef_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:706
static char * pg_get_partkeydef_worker(Oid relid, int prettyFlags, bool attrsOnly, bool missing_ok)
Definition ruleutils.c:2293
static void get_oper_expr(OpExpr *expr, deparse_context *context)
Datum pg_get_propgraphdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:1616
Datum pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
Definition ruleutils.c:3565
static char * pg_get_triggerdef_worker(Oid trigid, bool pretty)
Definition ruleutils.c:909
#define GET_PRETTY_FLAGS(pretty)
Definition ruleutils.c:98
static void get_reloptions(StringInfo buf, Datum reloptions)
static void get_func_expr(FuncExpr *expr, deparse_context *context, bool showimplicit)
static void get_const_expr(Const *constval, deparse_context *context, int showtype)
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition ruleutils.c:4005
void generate_operator_clause(StringInfo buf, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype)
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
Definition ruleutils.c:5707
static const char *const query_getviewrule
Definition ruleutils.c:341
static char * pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
Definition ruleutils.c:606
static int print_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults)
Definition ruleutils.c:3658
static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte, deparse_columns *colinfo)
Definition ruleutils.c:5425
static void print_function_rettype(StringInfo buf, HeapTuple proctup)
Definition ruleutils.c:3620
char * generate_opclass_name(Oid opclass)
static void set_deparse_plan(deparse_namespace *dpns, Plan *plan)
Definition ruleutils.c:5512
static void make_propgraphdef_elements(StringInfo buf, Oid pgrelid, char pgekind)
Definition ruleutils.c:1658
static void get_merge_query_def(Query *query, deparse_context *context)
Definition ruleutils.c:7785
static void resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
Definition ruleutils.c:8457
static void get_json_format(JsonFormat *format, StringInfo buf)
char * get_range_partbound_string(List *bound_datums)
static void get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
static void get_rule_expr_toplevel(Node *node, deparse_context *context, bool showimplicit)
static RangeTblEntry * get_simple_values_rte(Query *query, TupleDesc resultDesc)
Definition ruleutils.c:6403
static void get_coercion_expr(Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
static void push_child_plan(deparse_namespace *dpns, Plan *plan, deparse_namespace *save_dpns)
Definition ruleutils.c:5623
static void get_update_query_def(Query *query, deparse_context *context)
Definition ruleutils.c:7534
static void get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
static void get_basic_select_query(Query *query, deparse_context *context)
Definition ruleutils.c:6472
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
Definition ruleutils.c:9407
static void get_with_clause(Query *query, deparse_context *context)
Definition ruleutils.c:6130
#define PRETTYINDENT_VAR
Definition ruleutils.c:88
static void destroy_colinfo_names_hash(deparse_columns *colinfo)
Definition ruleutils.c:5409
static char * generate_relation_name(Oid relid, List *namespaces)
static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
static char * get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
Definition ruleutils.c:8154
Datum pg_get_serial_sequence(PG_FUNCTION_ARGS)
Definition ruleutils.c:3189
static char * generate_operator_name(Oid operid, Oid arg1, Oid arg2)
static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
Datum pg_get_function_arguments(PG_FUNCTION_ARGS)
Definition ruleutils.c:3539
static void get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
#define PRETTYFLAG_SCHEMA
Definition ruleutils.c:95
static void get_select_query_def(Query *query, deparse_context *context)
Definition ruleutils.c:6269
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Datum pg_get_viewdef_name(PG_FUNCTION_ARGS)
Definition ruleutils.c:745
Datum pg_get_userbyid(PG_FUNCTION_ARGS)
Definition ruleutils.c:3151
static void get_agg_expr_helper(Aggref *aggref, deparse_context *context, Aggref *original_aggref, const char *funcname, const char *options, bool is_json_objectagg)
#define RULE_INDEXDEF_PRETTY
Definition ruleutils.h:24
#define RULE_INDEXDEF_KEYS_ONLY
Definition ruleutils.h:25
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c:272
void UnregisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:866
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:824
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Definition spi.c:1176
uint64 SPI_processed
Definition spi.c:45
SPITupleTable * SPI_tuptable
Definition spi.c:46
int SPI_execute_plan(SPIPlanPtr plan, const Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition spi.c:673
int SPI_connect(void)
Definition spi.c:95
int SPI_finish(void)
Definition spi.c:183
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition spi.c:861
int SPI_keepplan(SPIPlanPtr plan)
Definition spi.c:977
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition spi.c:1221
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition spi.c:1253
#define SPI_OK_FINISH
Definition spi.h:83
#define SPI_OK_SELECT
Definition spi.h:86
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:88
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:47
void check_stack_depth(void)
Definition stack_depth.c:95
#define BTEqualStrategyNumber
Definition stratnum.h:31
void resetStringInfo(StringInfo str)
Definition stringinfo.c:126
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition stringinfo.c:281
void appendStringInfoSpaces(StringInfo str, int count)
Definition stringinfo.c:260
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Oid aggfnoid
Definition primnodes.h:464
List * aggdistinct
Definition primnodes.h:494
List * aggdirectargs
Definition primnodes.h:485
List * args
Definition primnodes.h:488
Expr * aggfilter
Definition primnodes.h:497
List * aggorder
Definition primnodes.h:491
Index parent_relid
Definition pathnodes.h:3288
BoolExprType boolop
Definition primnodes.h:972
List * args
Definition primnodes.h:973
CTEMaterialize ctematerialized
bool attisdropped
Definition tupdesc.h:78
Oid consttype
Definition primnodes.h:330
char * cursor_name
Definition primnodes.h:2125
List * newvals
Definition primnodes.h:1194
Node * quals
Definition primnodes.h:2384
List * fromlist
Definition primnodes.h:2383
Oid funcid
Definition primnodes.h:783
List * args
Definition primnodes.h:801
Node * whereClause
List * path_pattern_list
JsonBehaviorType btype
Definition primnodes.h:1817
JsonBehavior * on_empty
Definition primnodes.h:1866
JsonFormat * format
Definition primnodes.h:1853
Node * path_spec
Definition primnodes.h:1856
JsonWrapper wrapper
Definition primnodes.h:1877
JsonExprOp op
Definition primnodes.h:1844
JsonBehavior * on_error
Definition primnodes.h:1867
bool omit_quotes
Definition primnodes.h:1880
JsonFormatType format_type
Definition primnodes.h:1677
JsonValueType item_type
Definition primnodes.h:1763
JsonFormat * format
Definition primnodes.h:1689
JsonTablePath * path
Definition primnodes.h:1925
JsonTablePlan * child
Definition primnodes.h:1934
Const * value
Definition primnodes.h:1898
JsonTablePlan * rplan
Definition primnodes.h:1955
JsonTablePlan * lplan
Definition primnodes.h:1954
Definition pg_list.h:54
Definition nodes.h:135
Oid opno
Definition primnodes.h:851
List * args
Definition primnodes.h:869
int paramid
Definition primnodes.h:397
ParamKind paramkind
Definition primnodes.h:396
PartitionRangeDatumKind kind
Definition parsenodes.h:975
List * appendRelations
Definition plannodes.h:125
List * subplans
Definition plannodes.h:130
List * rtable
Definition plannodes.h:107
List * rowMarks
Definition parsenodes.h:234
bool groupDistinct
Definition parsenodes.h:217
Node * mergeJoinCondition
Definition parsenodes.h:196
Node * limitCount
Definition parsenodes.h:231
FromExpr * jointree
Definition parsenodes.h:182
List * returningList
Definition parsenodes.h:214
Node * setOperations
Definition parsenodes.h:236
List * cteList
Definition parsenodes.h:173
OnConflictExpr * onConflict
Definition parsenodes.h:203
List * groupClause
Definition parsenodes.h:216
Node * havingQual
Definition parsenodes.h:222
List * rtable
Definition parsenodes.h:175
Node * limitOffset
Definition parsenodes.h:230
CmdType commandType
Definition parsenodes.h:121
LimitOption limitOption
Definition parsenodes.h:232
Node * utilityStmt
Definition parsenodes.h:141
List * mergeActionList
Definition parsenodes.h:185
List * windowClause
Definition parsenodes.h:224
List * targetList
Definition parsenodes.h:198
List * groupingSets
Definition parsenodes.h:220
bool groupByAll
Definition parsenodes.h:218
List * distinctClause
Definition parsenodes.h:226
List * sortClause
Definition parsenodes.h:228
List * args
Definition primnodes.h:1449
LockClauseStrength strength
LockWaitPolicy waitPolicy
TupleDesc tupdesc
Definition spi.h:25
HeapTuple * vals
Definition spi.h:26
SQLValueFunctionOp op
Definition primnodes.h:1582
SetOperation op
Definition value.h:64
char * plan_name
Definition primnodes.h:1105
List * args
Definition primnodes.h:1125
List * paramIds
Definition primnodes.h:1101
bool isInitPlan
Definition primnodes.h:1112
bool useHashTable
Definition primnodes.h:1113
Node * testexpr
Definition primnodes.h:1100
List * parParam
Definition primnodes.h:1124
List * setParam
Definition primnodes.h:1122
SubLinkType subLinkType
Definition primnodes.h:1098
Expr * refassgnexpr
Definition primnodes.h:736
List * refupperindexpr
Definition primnodes.h:726
List * reflowerindexpr
Definition primnodes.h:732
Node * docexpr
Definition primnodes.h:121
Node * rowexpr
Definition primnodes.h:123
List * colexprs
Definition primnodes.h:133
TableFuncType functype
Definition primnodes.h:115
Expr * expr
Definition primnodes.h:2265
AttrNumber varattno
Definition primnodes.h:275
int varno
Definition primnodes.h:270
VarReturningType varreturningtype
Definition primnodes.h:298
Index varlevelsup
Definition primnodes.h:295
Node * startOffset
List * partitionClause
Node * endOffset
List * orderClause
List * args
Definition primnodes.h:606
Index winref
Definition primnodes.h:612
Expr * aggfilter
Definition primnodes.h:608
int ignore_nulls
Definition primnodes.h:618
List * args
Definition primnodes.h:1634
bool indent
Definition primnodes.h:1638
List * named_args
Definition primnodes.h:1630
XmlExprOp op
Definition primnodes.h:1626
List * parentUsing
Definition ruleutils.c:281
HTAB * names_hash
Definition ruleutils.c:313
char ** new_colnames
Definition ruleutils.c:274
char ** colnames
Definition ruleutils.c:257
List * usingNames
Definition ruleutils.c:304
bool * is_new_col
Definition ruleutils.c:275
TupleDesc resultDesc
Definition ruleutils.c:121
StringInfo buf
Definition ruleutils.c:119
List * targetList
Definition ruleutils.c:122
List * namespaces
Definition ruleutils.c:120
List * windowClause
Definition ruleutils.c:123
Bitmapset * appendparents
Definition ruleutils.c:131
AppendRelInfo ** appendrels
Definition ruleutils.c:174
List * rtable_columns
Definition ruleutils.c:171
Definition c.h:832
Definition c.h:817
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition c.h:824
Definition c.h:778
Definition type.h:89
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition tlist.c:354
int count_nonjunk_tlist_entries(List *tlist)
Definition tlist.c:195
#define ReleaseTupleDesc(tupdesc)
Definition tupdesc.h:238
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:193
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition typcache.c:1947
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#define TYPECACHE_GT_OPR
Definition typcache.h:140
#define TYPECACHE_LT_OPR
Definition typcache.h:139
String * makeString(char *str)
Definition value.c:63
#define strVal(v)
Definition value.h:82
Node * flatten_group_exprs(PlannerInfo *root, Query *query, Node *node)
Definition var.c:999
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition var.c:114
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
text * cstring_to_text_with_len(const char *s, int len)
Definition varlena.c:196
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition varlena.c:3025
text * cstring_to_text(const char *s)
Definition varlena.c:184
char * text_to_cstring(const text *t)
Definition varlena.c:217
List * textToQualifiedNameList(text *textval)
Definition varlena.c:2719
const char * type
const char * name
char * map_xml_name_to_sql_identifier(const char *name)
Definition xml.c:2474
@ XML_STANDALONE_NO_VALUE
Definition xml.h:29
@ XML_STANDALONE_YES
Definition xml.h:27
@ XML_STANDALONE_NO
Definition xml.h:28
static void convert(const int_fast32_t val, char *const buf)
Definition zic.c:1980