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