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 get_json_agg_constructor_expr(Node *node, deparse_context *context,
516 void *callback_arg);
517static void simple_quote_literal(StringInfo buf, const char *val);
518static void get_sublink_expr(SubLink *sublink, deparse_context *context);
519static void get_tablefunc(TableFunc *tf, deparse_context *context,
520 bool showimplicit);
521static void get_from_clause(Query *query, const char *prefix,
522 deparse_context *context);
523static void get_from_clause_item(Node *jtnode, Query *query,
524 deparse_context *context);
525static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
526 deparse_context *context);
528 deparse_context *context);
529static void get_for_portion_of(ForPortionOfExpr *forPortionOf,
530 deparse_context *context);
533 deparse_context *context);
534static void get_tablesample_def(TableSampleClause *tablesample,
535 deparse_context *context);
536static void get_opclass_name(Oid opclass, Oid actual_datatype,
538static Node *processIndirection(Node *node, deparse_context *context);
539static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
540static char *get_relation_name(Oid relid);
541static char *generate_relation_name(Oid relid, List *namespaces);
542static char *generate_qualified_relation_name(Oid relid);
543static char *generate_function_name(Oid funcid, int nargs,
544 List *argnames, Oid *argtypes,
545 bool has_variadic, bool *use_variadic_p,
546 bool inGroupBy);
548static void add_cast_to(StringInfo buf, Oid typid);
549static char *generate_qualified_type_name(Oid typid);
550static text *string_to_text(char *str);
551static char *flatten_reloptions(Oid relid);
552void get_reloptions(StringInfo buf, Datum reloptions);
553static void get_json_path_spec(Node *path_spec, deparse_context *context,
554 bool showimplicit);
556 deparse_context *context,
557 bool showimplicit);
559 deparse_context *context,
560 bool showimplicit,
561 bool needcomma);
562
563#define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
564
565
566/* ----------
567 * pg_get_ruledef - Do it all and return a text
568 * that could be used as a statement
569 * to recreate the rule
570 * ----------
571 */
572Datum
574{
576 int prettyFlags;
577 char *res;
578
579 prettyFlags = PRETTYFLAG_INDENT;
580
581 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
582
583 if (res == NULL)
585
587}
588
589
590Datum
592{
594 bool pretty = PG_GETARG_BOOL(1);
595 int prettyFlags;
596 char *res;
597
598 prettyFlags = GET_PRETTY_FLAGS(pretty);
599
600 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
601
602 if (res == NULL)
604
606}
607
608
609static char *
611{
612 Datum args[1];
613 char nulls[1];
614 int spirc;
618
619 /*
620 * Do this first so that string is alloc'd in outer context not SPI's.
621 */
623
624 /*
625 * Connect to SPI manager
626 */
627 SPI_connect();
628
629 /*
630 * On the first call prepare the plan to lookup pg_rewrite. We read
631 * pg_rewrite over the SPI manager instead of using the syscache to be
632 * checked for read access on pg_rewrite.
633 */
634 if (plan_getrulebyoid == NULL)
635 {
636 Oid argtypes[1];
638
639 argtypes[0] = OIDOID;
640 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
641 if (plan == NULL)
642 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
645 }
646
647 /*
648 * Get the pg_rewrite tuple for this rule
649 */
650 args[0] = ObjectIdGetDatum(ruleoid);
651 nulls[0] = ' ';
652 spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
653 if (spirc != SPI_OK_SELECT)
654 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
655 if (SPI_processed != 1)
656 {
657 /*
658 * There is no tuple data available here, just keep the output buffer
659 * empty.
660 */
661 }
662 else
663 {
664 /*
665 * Get the rule's definition and put it into executor's memory
666 */
669 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
670 }
671
672 /*
673 * Disconnect from SPI manager
674 */
675 if (SPI_finish() != SPI_OK_FINISH)
676 elog(ERROR, "SPI_finish failed");
677
678 if (buf.len == 0)
679 return NULL;
680
681 return buf.data;
682}
683
684
685/* ----------
686 * pg_get_viewdef - Mainly the same thing, but we
687 * only return the SELECT part of a view
688 * ----------
689 */
690Datum
692{
693 /* By OID */
694 Oid viewoid = PG_GETARG_OID(0);
695 int prettyFlags;
696 char *res;
697
698 prettyFlags = PRETTYFLAG_INDENT;
699
700 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
701
702 if (res == NULL)
704
706}
707
708
709Datum
711{
712 /* By OID */
713 Oid viewoid = PG_GETARG_OID(0);
714 bool pretty = PG_GETARG_BOOL(1);
715 int prettyFlags;
716 char *res;
717
718 prettyFlags = GET_PRETTY_FLAGS(pretty);
719
720 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
721
722 if (res == NULL)
724
726}
727
728Datum
730{
731 /* By OID */
732 Oid viewoid = PG_GETARG_OID(0);
733 int wrap = PG_GETARG_INT32(1);
734 int prettyFlags;
735 char *res;
736
737 /* calling this implies we want pretty printing */
738 prettyFlags = GET_PRETTY_FLAGS(true);
739
740 res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
741
742 if (res == NULL)
744
746}
747
748Datum
750{
751 /* By qualified name */
753 int prettyFlags;
755 Oid viewoid;
756 char *res;
757
758 prettyFlags = PRETTYFLAG_INDENT;
759
760 /* Look up view name. Can't lock it - we might not have privileges. */
762 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
763
764 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
765
766 if (res == NULL)
768
770}
771
772
773Datum
775{
776 /* By qualified name */
778 bool pretty = PG_GETARG_BOOL(1);
779 int prettyFlags;
781 Oid viewoid;
782 char *res;
783
784 prettyFlags = GET_PRETTY_FLAGS(pretty);
785
786 /* Look up view name. Can't lock it - we might not have privileges. */
788 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
789
790 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
791
792 if (res == NULL)
794
796}
797
798/*
799 * Common code for by-OID and by-name variants of pg_get_viewdef
800 */
801static char *
802pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
803{
804 Datum args[2];
805 char nulls[2];
806 int spirc;
810
811 /*
812 * Do this first so that string is alloc'd in outer context not SPI's.
813 */
815
816 /*
817 * Connect to SPI manager
818 */
819 SPI_connect();
820
821 /*
822 * On the first call prepare the plan to lookup pg_rewrite. We read
823 * pg_rewrite over the SPI manager instead of using the syscache to be
824 * checked for read access on pg_rewrite.
825 */
826 if (plan_getviewrule == NULL)
827 {
828 Oid argtypes[2];
830
831 argtypes[0] = OIDOID;
832 argtypes[1] = NAMEOID;
833 plan = SPI_prepare(query_getviewrule, 2, argtypes);
834 if (plan == NULL)
835 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
838 }
839
840 /*
841 * Get the pg_rewrite tuple for the view's SELECT rule
842 */
843 args[0] = ObjectIdGetDatum(viewoid);
845 nulls[0] = ' ';
846 nulls[1] = ' ';
847 spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
848 if (spirc != SPI_OK_SELECT)
849 elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
850 if (SPI_processed != 1)
851 {
852 /*
853 * There is no tuple data available here, just keep the output buffer
854 * empty.
855 */
856 }
857 else
858 {
859 /*
860 * Get the rule's definition and put it into executor's memory
861 */
864 make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
865 }
866
867 /*
868 * Disconnect from SPI manager
869 */
870 if (SPI_finish() != SPI_OK_FINISH)
871 elog(ERROR, "SPI_finish failed");
872
873 if (buf.len == 0)
874 return NULL;
875
876 return buf.data;
877}
878
879/* ----------
880 * pg_get_triggerdef - Get the definition of a trigger
881 * ----------
882 */
883Datum
885{
887 char *res;
888
889 res = pg_get_triggerdef_worker(trigid, false);
890
891 if (res == NULL)
893
895}
896
897Datum
899{
901 bool pretty = PG_GETARG_BOOL(1);
902 char *res;
903
905
906 if (res == NULL)
908
910}
911
912static char *
914{
919 ScanKeyData skey[1];
921 int findx = 0;
922 char *tgname;
923 char *tgoldtable;
924 char *tgnewtable;
925 Datum value;
926 bool isnull;
927
928 /*
929 * Fetch the pg_trigger tuple by the Oid of the trigger
930 */
932
933 ScanKeyInit(&skey[0],
937
939 NULL, 1, skey);
940
942
944 {
947 return NULL;
948 }
949
951
952 /*
953 * Start the trigger definition. Note that the trigger's name should never
954 * be schema-qualified, but the trigger rel's name may be.
955 */
957
958 tgname = NameStr(trigrec->tgname);
959 appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
960 OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
961 quote_identifier(tgname));
962
963 if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
964 appendStringInfoString(&buf, "BEFORE");
965 else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
966 appendStringInfoString(&buf, "AFTER");
967 else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
968 appendStringInfoString(&buf, "INSTEAD OF");
969 else
970 elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
971
972 if (TRIGGER_FOR_INSERT(trigrec->tgtype))
973 {
974 appendStringInfoString(&buf, " INSERT");
975 findx++;
976 }
977 if (TRIGGER_FOR_DELETE(trigrec->tgtype))
978 {
979 if (findx > 0)
980 appendStringInfoString(&buf, " OR DELETE");
981 else
982 appendStringInfoString(&buf, " DELETE");
983 findx++;
984 }
985 if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
986 {
987 if (findx > 0)
988 appendStringInfoString(&buf, " OR UPDATE");
989 else
990 appendStringInfoString(&buf, " UPDATE");
991 findx++;
992 /* tgattr is first var-width field, so OK to access directly */
993 if (trigrec->tgattr.dim1 > 0)
994 {
995 int i;
996
997 appendStringInfoString(&buf, " OF ");
998 for (i = 0; i < trigrec->tgattr.dim1; i++)
999 {
1000 char *attname;
1001
1002 if (i > 0)
1004 attname = get_attname(trigrec->tgrelid,
1005 trigrec->tgattr.values[i], false);
1007 }
1008 }
1009 }
1010 if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
1011 {
1012 if (findx > 0)
1013 appendStringInfoString(&buf, " OR TRUNCATE");
1014 else
1015 appendStringInfoString(&buf, " TRUNCATE");
1016 findx++;
1017 }
1018
1019 /*
1020 * In non-pretty mode, always schema-qualify the target table name for
1021 * safety. In pretty mode, schema-qualify only if not visible.
1022 */
1023 appendStringInfo(&buf, " ON %s ",
1024 pretty ?
1027
1028 if (OidIsValid(trigrec->tgconstraint))
1029 {
1030 if (OidIsValid(trigrec->tgconstrrelid))
1031 appendStringInfo(&buf, "FROM %s ",
1032 generate_relation_name(trigrec->tgconstrrelid, NIL));
1033 if (!trigrec->tgdeferrable)
1034 appendStringInfoString(&buf, "NOT ");
1035 appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
1036 if (trigrec->tginitdeferred)
1037 appendStringInfoString(&buf, "DEFERRED ");
1038 else
1039 appendStringInfoString(&buf, "IMMEDIATE ");
1040 }
1041
1043 tgrel->rd_att, &isnull);
1044 if (!isnull)
1045 tgoldtable = NameStr(*DatumGetName(value));
1046 else
1047 tgoldtable = NULL;
1049 tgrel->rd_att, &isnull);
1050 if (!isnull)
1051 tgnewtable = NameStr(*DatumGetName(value));
1052 else
1053 tgnewtable = NULL;
1054 if (tgoldtable != NULL || tgnewtable != NULL)
1055 {
1056 appendStringInfoString(&buf, "REFERENCING ");
1057 if (tgoldtable != NULL)
1058 appendStringInfo(&buf, "OLD TABLE AS %s ",
1059 quote_identifier(tgoldtable));
1060 if (tgnewtable != NULL)
1061 appendStringInfo(&buf, "NEW TABLE AS %s ",
1062 quote_identifier(tgnewtable));
1063 }
1064
1065 if (TRIGGER_FOR_ROW(trigrec->tgtype))
1066 appendStringInfoString(&buf, "FOR EACH ROW ");
1067 else
1068 appendStringInfoString(&buf, "FOR EACH STATEMENT ");
1069
1070 /* If the trigger has a WHEN qualification, add that */
1072 tgrel->rd_att, &isnull);
1073 if (!isnull)
1074 {
1075 Node *qual;
1076 char relkind;
1077 deparse_context context;
1081
1082 appendStringInfoString(&buf, "WHEN (");
1083
1085
1086 relkind = get_rel_relkind(trigrec->tgrelid);
1087
1088 /* Build minimal OLD and NEW RTEs for the rel */
1090 oldrte->rtekind = RTE_RELATION;
1091 oldrte->relid = trigrec->tgrelid;
1092 oldrte->relkind = relkind;
1093 oldrte->rellockmode = AccessShareLock;
1094 oldrte->alias = makeAlias("old", NIL);
1095 oldrte->eref = oldrte->alias;
1096 oldrte->lateral = false;
1097 oldrte->inh = false;
1098 oldrte->inFromCl = true;
1099
1101 newrte->rtekind = RTE_RELATION;
1102 newrte->relid = trigrec->tgrelid;
1103 newrte->relkind = relkind;
1104 newrte->rellockmode = AccessShareLock;
1105 newrte->alias = makeAlias("new", NIL);
1106 newrte->eref = newrte->alias;
1107 newrte->lateral = false;
1108 newrte->inh = false;
1109 newrte->inFromCl = true;
1110
1111 /* Build two-element rtable */
1112 memset(&dpns, 0, sizeof(dpns));
1113 dpns.rtable = list_make2(oldrte, newrte);
1114 dpns.subplans = NIL;
1115 dpns.ctes = NIL;
1116 dpns.appendrels = NULL;
1119
1120 /* Set up context with one-deep namespace stack */
1121 context.buf = &buf;
1122 context.namespaces = list_make1(&dpns);
1123 context.resultDesc = NULL;
1124 context.targetList = NIL;
1125 context.windowClause = NIL;
1126 context.varprefix = true;
1129 context.indentLevel = PRETTYINDENT_STD;
1130 context.colNamesVisible = true;
1131 context.inGroupBy = false;
1132 context.varInOrderBy = false;
1133 context.appendparents = NULL;
1134
1135 get_rule_expr(qual, &context, false);
1136
1138 }
1139
1140 appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
1142 NIL, NULL,
1143 false, NULL, false));
1144
1145 if (trigrec->tgnargs > 0)
1146 {
1147 char *p;
1148 int i;
1149
1151 tgrel->rd_att, &isnull);
1152 if (isnull)
1153 elog(ERROR, "tgargs is null for trigger %u", trigid);
1154 p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1155 for (i = 0; i < trigrec->tgnargs; i++)
1156 {
1157 if (i > 0)
1160 /* advance p to next string embedded in tgargs */
1161 while (*p)
1162 p++;
1163 p++;
1164 }
1165 }
1166
1167 /* We deliberately do not put semi-colon at end */
1169
1170 /* Clean up */
1172
1174
1175 return buf.data;
1176}
1177
1178/* ----------
1179 * pg_get_indexdef - Get the definition of an index
1180 *
1181 * In the extended version, there is a colno argument as well as pretty bool.
1182 * if colno == 0, we want a complete index definition.
1183 * if colno > 0, we only want the Nth index key's variable or expression.
1184 *
1185 * Note that the SQL-function versions of this omit any info about the
1186 * index tablespace; this is intentional because pg_dump wants it that way.
1187 * However pg_get_indexdef_string() includes the index tablespace.
1188 * ----------
1189 */
1190Datum
1192{
1193 Oid indexrelid = PG_GETARG_OID(0);
1194 int prettyFlags;
1195 char *res;
1196
1197 prettyFlags = PRETTYFLAG_INDENT;
1198
1199 res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1200 false, false,
1201 false, false,
1202 prettyFlags, true);
1203
1204 if (res == NULL)
1206
1208}
1209
1210Datum
1212{
1213 Oid indexrelid = PG_GETARG_OID(0);
1214 int32 colno = PG_GETARG_INT32(1);
1215 bool pretty = PG_GETARG_BOOL(2);
1216 int prettyFlags;
1217 char *res;
1218
1219 prettyFlags = GET_PRETTY_FLAGS(pretty);
1220
1221 res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1222 colno != 0, false,
1223 false, false,
1224 prettyFlags, true);
1225
1226 if (res == NULL)
1228
1230}
1231
1232/*
1233 * Internal version for use by ALTER TABLE.
1234 * Includes a tablespace clause in the result.
1235 * Returns a palloc'd C string; no pretty-printing.
1236 */
1237char *
1239{
1240 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1241 false, false,
1242 true, true,
1243 0, false);
1244}
1245
1246/* Internal version that just reports the key-column definitions */
1247char *
1249{
1250 int prettyFlags;
1251
1252 prettyFlags = GET_PRETTY_FLAGS(pretty);
1253
1254 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1255 true, true,
1256 false, false,
1257 prettyFlags, false);
1258}
1259
1260/* Internal version, extensible with flags to control its behavior */
1261char *
1263{
1264 bool pretty = ((flags & RULE_INDEXDEF_PRETTY) != 0);
1265 bool keys_only = ((flags & RULE_INDEXDEF_KEYS_ONLY) != 0);
1266 int prettyFlags;
1267
1268 prettyFlags = GET_PRETTY_FLAGS(pretty);
1269
1270 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1271 true, keys_only,
1272 false, false,
1273 prettyFlags, false);
1274}
1275
1276/*
1277 * Internal workhorse to decompile an index definition.
1278 *
1279 * This is now used for exclusion constraints as well: if excludeOps is not
1280 * NULL then it points to an array of exclusion operator OIDs.
1281 */
1282static char *
1283pg_get_indexdef_worker(Oid indexrelid, int colno,
1284 const Oid *excludeOps,
1285 bool attrsOnly, bool keysOnly,
1286 bool showTblSpc, bool inherits,
1287 int prettyFlags, bool missing_ok)
1288{
1289 /* might want a separate isConstraint parameter later */
1290 bool isConstraint = (excludeOps != NULL);
1298 List *indexprs;
1300 List *context;
1301 Oid indrelid;
1302 int keyno;
1310 char *str;
1311 char *sep;
1312
1313 /*
1314 * Fetch the pg_index tuple by the Oid of the index
1315 */
1318 {
1319 if (missing_ok)
1320 return NULL;
1321 elog(ERROR, "cache lookup failed for index %u", indexrelid);
1322 }
1324
1325 indrelid = idxrec->indrelid;
1326 Assert(indexrelid == idxrec->indexrelid);
1327
1328 /* Must get indcollation, indclass, and indoption the hard way */
1332
1336
1340
1341 /*
1342 * Fetch the pg_class tuple of the index relation
1343 */
1346 elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1348
1349 /*
1350 * Fetch the pg_am tuple of the index' access method
1351 */
1353 if (!HeapTupleIsValid(ht_am))
1354 elog(ERROR, "cache lookup failed for access method %u",
1355 idxrelrec->relam);
1357
1358 /* Fetch the index AM's API struct */
1359 amroutine = GetIndexAmRoutine(amrec->amhandler);
1360
1361 /*
1362 * Get the index expressions, if any. (NOTE: we do not use the relcache
1363 * versions of the expressions and predicate, because we want to display
1364 * non-const-folded expressions.)
1365 */
1367 {
1369 char *exprsString;
1370
1376 }
1377 else
1378 indexprs = NIL;
1379
1381
1383
1384 /*
1385 * Start the index definition. Note that the index's name should never be
1386 * schema-qualified, but the indexed rel's name may be.
1387 */
1389
1390 if (!attrsOnly)
1391 {
1392 if (!isConstraint)
1393 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
1394 idxrec->indisunique ? "UNIQUE " : "",
1397 && !inherits ? "ONLY " : "",
1398 (prettyFlags & PRETTYFLAG_SCHEMA) ?
1401 quote_identifier(NameStr(amrec->amname)));
1402 else /* currently, must be EXCLUDE constraint */
1403 appendStringInfo(&buf, "EXCLUDE USING %s (",
1404 quote_identifier(NameStr(amrec->amname)));
1405 }
1406
1407 /*
1408 * Report the indexed attributes
1409 */
1410 sep = "";
1411 for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1412 {
1413 AttrNumber attnum = idxrec->indkey.values[keyno];
1416
1417 /*
1418 * Ignore non-key attributes if told to.
1419 */
1420 if (keysOnly && keyno >= idxrec->indnkeyatts)
1421 break;
1422
1423 /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1424 if (!colno && keyno == idxrec->indnkeyatts)
1425 {
1426 appendStringInfoString(&buf, ") INCLUDE (");
1427 sep = "";
1428 }
1429
1430 if (!colno)
1432 sep = ", ";
1433
1434 if (attnum != 0)
1435 {
1436 /* Simple index column */
1437 char *attname;
1439
1441 if (!colno || colno == keyno + 1)
1446 }
1447 else
1448 {
1449 /* expressional index */
1450 Node *indexkey;
1451
1452 if (indexpr_item == NULL)
1453 elog(ERROR, "too few entries in indexprs list");
1456 /* Deparse */
1457 str = deparse_expression_pretty(indexkey, context, false, false,
1458 prettyFlags, 0);
1459 if (!colno || colno == keyno + 1)
1460 {
1461 /* Need parens if it's not a bare function call */
1464 else
1465 appendStringInfo(&buf, "(%s)", str);
1466 }
1469 }
1470
1471 /* Print additional decoration for (selected) key columns */
1473 (!colno || colno == keyno + 1))
1474 {
1475 int16 opt = indoption->values[keyno];
1476 Oid indcoll = indcollation->values[keyno];
1477 Datum attoptions = get_attoptions(indexrelid, keyno + 1);
1478 bool has_options = attoptions != (Datum) 0;
1479
1480 /* Add collation, if not default for column */
1482 appendStringInfo(&buf, " COLLATE %s",
1484
1485 /* Add the operator class name, if not default */
1486 get_opclass_name(indclass->values[keyno],
1488
1489 if (has_options)
1490 {
1492 get_reloptions(&buf, attoptions);
1494 }
1495
1496 /* Add options if relevant */
1497 if (amroutine->amcanorder)
1498 {
1499 /* if it supports sort ordering, report DESC and NULLS opts */
1500 if (opt & INDOPTION_DESC)
1501 {
1502 appendStringInfoString(&buf, " DESC");
1503 /* NULLS FIRST is the default in this case */
1504 if (!(opt & INDOPTION_NULLS_FIRST))
1505 appendStringInfoString(&buf, " NULLS LAST");
1506 }
1507 else
1508 {
1509 if (opt & INDOPTION_NULLS_FIRST)
1510 appendStringInfoString(&buf, " NULLS FIRST");
1511 }
1512 }
1513
1514 /* Add the exclusion operator if relevant */
1515 if (excludeOps != NULL)
1516 appendStringInfo(&buf, " WITH %s",
1518 keycoltype,
1519 keycoltype));
1520 }
1521 }
1522
1523 if (!attrsOnly)
1524 {
1526
1527 if (idxrec->indnullsnotdistinct)
1528 appendStringInfoString(&buf, " NULLS NOT DISTINCT");
1529
1530 /*
1531 * If it has options, append "WITH (options)"
1532 */
1533 str = flatten_reloptions(indexrelid);
1534 if (str)
1535 {
1536 appendStringInfo(&buf, " WITH (%s)", str);
1537 pfree(str);
1538 }
1539
1540 /*
1541 * Print tablespace, but only if requested
1542 */
1543 if (showTblSpc)
1544 {
1545 Oid tblspc;
1546
1547 tblspc = get_rel_tablespace(indexrelid);
1548 if (OidIsValid(tblspc))
1549 {
1550 if (isConstraint)
1551 appendStringInfoString(&buf, " USING INDEX");
1552 appendStringInfo(&buf, " TABLESPACE %s",
1554 }
1555 }
1556
1557 /*
1558 * If it's a partial index, decompile and append the predicate
1559 */
1561 {
1562 Node *node;
1564 char *predString;
1565
1566 /* Convert text string to node tree */
1570 node = (Node *) stringToNode(predString);
1572
1573 /* Deparse */
1574 str = deparse_expression_pretty(node, context, false, false,
1575 prettyFlags, 0);
1576 if (isConstraint)
1577 appendStringInfo(&buf, " WHERE (%s)", str);
1578 else
1579 appendStringInfo(&buf, " WHERE %s", str);
1580 }
1581 }
1582
1583 /* Clean up */
1587
1588 return buf.data;
1589}
1590
1591/* ----------
1592 * pg_get_querydef
1593 *
1594 * Public entry point to deparse one query parsetree.
1595 * The pretty flags are determined by GET_PRETTY_FLAGS(pretty).
1596 *
1597 * The result is a palloc'd C string.
1598 * ----------
1599 */
1600char *
1602{
1604 int prettyFlags;
1605
1606 prettyFlags = GET_PRETTY_FLAGS(pretty);
1607
1609
1610 get_query_def(query, &buf, NIL, NULL, true,
1611 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1612
1613 return buf.data;
1614}
1615
1616/*
1617 * pg_get_propgraphdef - get the definition of a property graph
1618 */
1619Datum
1621{
1626 char *name;
1627 char *nsp;
1628
1630
1634
1636 name = NameStr(classform->relname);
1637
1638 if (classform->relkind != RELKIND_PROPGRAPH)
1639 ereport(ERROR,
1641 errmsg("\"%s\" is not a property graph", name)));
1642
1643 nsp = get_namespace_name(classform->relnamespace);
1644
1645 appendStringInfo(&buf, "CREATE PROPERTY GRAPH %s",
1647
1649
1652
1654}
1655
1656/*
1657 * Generates a VERTEX TABLES (...) or EDGE TABLES (...) clause. Pass in the
1658 * property graph relation OID and the element kind (vertex or edge). Result
1659 * is appended to buf.
1660 */
1661static void
1663{
1666 SysScanDesc scan;
1667 bool first;
1668 HeapTuple tup;
1669
1671
1672 ScanKeyInit(&scankey[0],
1676
1678
1679 first = true;
1680 while ((tup = systable_getnext(scan)))
1681 {
1683 char *relname;
1684 Datum datum;
1685 bool isnull;
1686
1687 if (pgeform->pgekind != pgekind)
1688 continue;
1689
1690 if (first)
1691 {
1692 appendStringInfo(buf, "\n %s TABLES (\n", pgekind == PGEKIND_VERTEX ? "VERTEX" : "EDGE");
1693 first = false;
1694 }
1695 else
1697
1698 relname = get_rel_name(pgeform->pgerelid);
1699 if (relname && strcmp(relname, NameStr(pgeform->pgealias)) == 0)
1700 appendStringInfo(buf, " %s",
1701 generate_relation_name(pgeform->pgerelid, NIL));
1702 else
1703 appendStringInfo(buf, " %s AS %s",
1705 quote_identifier(NameStr(pgeform->pgealias)));
1706
1708 if (!isnull)
1709 {
1710 appendStringInfoString(buf, " KEY (");
1711 decompile_column_index_array(datum, pgeform->pgerelid, false, buf);
1713 }
1714 else
1715 elog(ERROR, "null pgekey for element %u", pgeform->oid);
1716
1717 if (pgekind == PGEKIND_EDGE)
1718 {
1719 Datum srckey;
1720 Datum srcref;
1721 Datum destkey;
1722 Datum destref;
1725
1727 srckey = isnull ? 0 : datum;
1729 srcref = isnull ? 0 : datum;
1731 destkey = isnull ? 0 : datum;
1733 destref = isnull ? 0 : datum;
1734
1735 appendStringInfoString(buf, " SOURCE");
1737 if (!tup2)
1738 elog(ERROR, "cache lookup failed for property graph element %u", pgeform->pgesrcvertexid);
1740 if (srckey)
1741 {
1742 appendStringInfoString(buf, " KEY (");
1743 decompile_column_index_array(srckey, pgeform->pgerelid, false, buf);
1744 appendStringInfo(buf, ") REFERENCES %s (", quote_identifier(NameStr(pgeform2->pgealias)));
1745 decompile_column_index_array(srcref, pgeform2->pgerelid, false, buf);
1747 }
1748 else
1751
1752 appendStringInfoString(buf, " DESTINATION");
1754 if (!tup2)
1755 elog(ERROR, "cache lookup failed for property graph element %u", pgeform->pgedestvertexid);
1757 if (destkey)
1758 {
1759 appendStringInfoString(buf, " KEY (");
1760 decompile_column_index_array(destkey, pgeform->pgerelid, false, buf);
1761 appendStringInfo(buf, ") REFERENCES %s (", quote_identifier(NameStr(pgeform2->pgealias)));
1762 decompile_column_index_array(destref, pgeform2->pgerelid, false, buf);
1764 }
1765 else
1768 }
1769
1770 make_propgraphdef_labels(buf, pgeform->oid, NameStr(pgeform->pgealias), pgeform->pgerelid);
1771 }
1772 if (!first)
1773 appendStringInfoString(buf, "\n )");
1774
1775 systable_endscan(scan);
1777}
1778
1780{
1782 char *str;
1783};
1784
1785static int
1787{
1788 struct oid_str_pair *v1 = lfirst(p1);
1789 struct oid_str_pair *v2 = lfirst(p2);
1790
1791 return strcmp(v1->str, v2->str);
1792}
1793
1794/*
1795 * Generates label and properties list. Pass in the element OID, the element
1796 * alias, and the graph relation OID. Result is appended to buf.
1797 */
1798static void
1800{
1803 SysScanDesc scan;
1804 int count;
1805 HeapTuple tup;
1806 List *label_list = NIL;
1807
1809
1810 ScanKeyInit(&scankey[0],
1814
1815 /*
1816 * We want to output the labels in a deterministic order. So we first
1817 * read all the data, then sort, then print it.
1818 */
1820
1821 while ((tup = systable_getnext(scan)))
1822 {
1824 struct oid_str_pair *osp;
1825
1826 osp = palloc_object(struct oid_str_pair);
1827 osp->oid = pgelform->oid;
1828 osp->str = get_propgraph_label_name(pgelform->pgellabelid);
1829
1831 }
1832
1833 systable_endscan(scan);
1835
1836 count = list_length(label_list);
1837
1838 /* Each element has at least one label. */
1839 Assert(count > 0);
1840
1841 /*
1842 * It is enough for the comparison function to compare just labels, since
1843 * all the labels of an element table should have distinct names.
1844 */
1846
1848 {
1849 if (strcmp(osp->str, elalias) == 0)
1850 {
1851 /* If the default label is the only label, don't print anything. */
1852 if (count != 1)
1853 appendStringInfoString(buf, " DEFAULT LABEL");
1854 }
1855 else
1856 appendStringInfo(buf, " LABEL %s", quote_identifier(osp->str));
1857
1859 }
1860}
1861
1862/*
1863 * Helper function for make_propgraphdef_properties(): Sort (propname, expr)
1864 * pairs by name.
1865 */
1866static int
1868{
1869 List *la = lfirst_node(List, a);
1870 List *lb = lfirst_node(List, b);
1871 char *pna = strVal(linitial(la));
1872 char *pnb = strVal(linitial(lb));
1873
1874 return strcmp(pna, pnb);
1875}
1876
1877/*
1878 * Generates element table properties clause (PROPERTIES (...) or NO
1879 * PROPERTIES). Pass in label OID and element table OID. Result is appended
1880 * to buf.
1881 */
1882static void
1884{
1887 SysScanDesc scan;
1888 HeapTuple tup;
1889 List *outlist = NIL;
1890
1892
1893 ScanKeyInit(&scankey[0],
1897
1898 /*
1899 * We want to output the properties in a deterministic order. So we first
1900 * read all the data, then sort, then print it.
1901 */
1903
1904 while ((tup = systable_getnext(scan)))
1905 {
1908 bool isnull;
1909 char *tmp;
1910 Node *expr;
1911 char *propname;
1912
1914 Assert(!isnull);
1916 expr = stringToNode(tmp);
1917 pfree(tmp);
1918
1920
1921 outlist = lappend(outlist, list_make2(makeString(propname), expr));
1922 }
1923
1924 systable_endscan(scan);
1926
1928
1929 if (outlist)
1930 {
1931 List *context;
1932 ListCell *lc;
1933 bool first = true;
1934
1936
1937 appendStringInfoString(buf, " PROPERTIES (");
1938
1939 foreach(lc, outlist)
1940 {
1942 char *propname = strVal(linitial(data));
1943 Node *expr = lsecond(data);
1944
1945 if (first)
1946 first = false;
1947 else
1949
1950 if (IsA(expr, Var) && strcmp(propname, get_attname(elrelid, castNode(Var, expr)->varattno, false)) == 0)
1952 else
1953 appendStringInfo(buf, "%s AS %s",
1954 deparse_expression_pretty(expr, context, false, false, 0, 0),
1956 }
1957
1959 }
1960 else
1961 appendStringInfoString(buf, " NO PROPERTIES");
1962}
1963
1964/*
1965 * pg_get_statisticsobjdef
1966 * Get the definition of an extended statistics object
1967 */
1968Datum
1970{
1972 char *res;
1973
1974 res = pg_get_statisticsobj_worker(statextid, false, true);
1975
1976 if (res == NULL)
1978
1980}
1981
1982/*
1983 * Internal version for use by ALTER TABLE.
1984 * Returns a palloc'd C string; no pretty-printing.
1985 */
1986char *
1991
1992/*
1993 * pg_get_statisticsobjdef_columns
1994 * Get columns and expressions for an extended statistics object
1995 */
1996Datum
1998{
2000 char *res;
2001
2002 res = pg_get_statisticsobj_worker(statextid, true, true);
2003
2004 if (res == NULL)
2006
2008}
2009
2010/*
2011 * Internal workhorse to decompile an extended statistics object.
2012 */
2013static char *
2015{
2019 int colno;
2020 char *nsp;
2021 ArrayType *arr;
2022 char *enabled;
2023 Datum datum;
2024 bool ndistinct_enabled;
2026 bool mcv_enabled;
2027 int i;
2028 List *context;
2029 ListCell *lc;
2030 List *exprs = NIL;
2031 bool has_exprs;
2032 int ncolumns;
2033
2035
2037 {
2038 if (missing_ok)
2039 return NULL;
2040 elog(ERROR, "cache lookup failed for statistics object %u", statextid);
2041 }
2042
2043 /* has the statistics expressions? */
2045
2047
2048 /*
2049 * Get the statistics expressions, if any. (NOTE: we do not use the
2050 * relcache versions of the expressions, because we want to display
2051 * non-const-folded expressions.)
2052 */
2053 if (has_exprs)
2054 {
2056 char *exprsString;
2057
2061 exprs = (List *) stringToNode(exprsString);
2063 }
2064 else
2065 exprs = NIL;
2066
2067 /* count the number of columns (attributes and expressions) */
2068 ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
2069
2071
2072 if (!columns_only)
2073 {
2074 nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
2075 appendStringInfo(&buf, "CREATE STATISTICS %s",
2077 NameStr(statextrec->stxname)));
2078
2079 /*
2080 * Decode the stxkind column so that we know which stats types to
2081 * print.
2082 */
2085 arr = DatumGetArrayTypeP(datum);
2086 if (ARR_NDIM(arr) != 1 ||
2087 ARR_HASNULL(arr) ||
2088 ARR_ELEMTYPE(arr) != CHAROID)
2089 elog(ERROR, "stxkind is not a 1-D char array");
2090 enabled = (char *) ARR_DATA_PTR(arr);
2091
2092 ndistinct_enabled = false;
2093 dependencies_enabled = false;
2094 mcv_enabled = false;
2095
2096 for (i = 0; i < ARR_DIMS(arr)[0]; i++)
2097 {
2098 if (enabled[i] == STATS_EXT_NDISTINCT)
2099 ndistinct_enabled = true;
2100 else if (enabled[i] == STATS_EXT_DEPENDENCIES)
2101 dependencies_enabled = true;
2102 else if (enabled[i] == STATS_EXT_MCV)
2103 mcv_enabled = true;
2104
2105 /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
2106 }
2107
2108 /*
2109 * If any option is disabled, then we'll need to append the types
2110 * clause to show which options are enabled. We omit the types clause
2111 * on purpose when all options are enabled, so a pg_dump/pg_restore
2112 * will create all statistics types on a newer postgres version, if
2113 * the statistics had all options enabled on the original version.
2114 *
2115 * But if the statistics is defined on just a single column, it has to
2116 * be an expression statistics. In that case we don't need to specify
2117 * kinds.
2118 */
2120 (ncolumns > 1))
2121 {
2122 bool gotone = false;
2123
2125
2127 {
2128 appendStringInfoString(&buf, "ndistinct");
2129 gotone = true;
2130 }
2131
2133 {
2134 appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
2135 gotone = true;
2136 }
2137
2138 if (mcv_enabled)
2139 appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
2140
2142 }
2143
2144 appendStringInfoString(&buf, " ON ");
2145 }
2146
2147 /* decode simple column references */
2148 for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
2149 {
2150 AttrNumber attnum = statextrec->stxkeys.values[colno];
2151 char *attname;
2152
2153 if (colno > 0)
2155
2156 attname = get_attname(statextrec->stxrelid, attnum, false);
2157
2159 }
2160
2162 statextrec->stxrelid);
2163
2164 foreach(lc, exprs)
2165 {
2166 Node *expr = (Node *) lfirst(lc);
2167 char *str;
2168 int prettyFlags = PRETTYFLAG_PAREN;
2169
2170 str = deparse_expression_pretty(expr, context, false, false,
2171 prettyFlags, 0);
2172
2173 if (colno > 0)
2175
2176 /* Need parens if it's not a bare function call */
2177 if (looks_like_function(expr))
2179 else
2180 appendStringInfo(&buf, "(%s)", str);
2181
2182 colno++;
2183 }
2184
2185 if (!columns_only)
2186 appendStringInfo(&buf, " FROM %s",
2188
2190
2191 return buf.data;
2192}
2193
2194/*
2195 * Generate text array of expressions for statistics object.
2196 */
2197Datum
2199{
2203 Datum datum;
2204 List *context;
2205 ListCell *lc;
2206 List *exprs = NIL;
2207 bool has_exprs;
2208 char *tmp;
2209 ArrayBuildState *astate = NULL;
2210
2212
2215
2216 /* Does the stats object have expressions? */
2218
2219 /* no expressions? we're done */
2220 if (!has_exprs)
2221 {
2224 }
2225
2227
2228 /*
2229 * Get the statistics expressions, and deparse them into text values.
2230 */
2233 tmp = TextDatumGetCString(datum);
2234 exprs = (List *) stringToNode(tmp);
2235 pfree(tmp);
2236
2238 statextrec->stxrelid);
2239
2240 foreach(lc, exprs)
2241 {
2242 Node *expr = (Node *) lfirst(lc);
2243 char *str;
2244 int prettyFlags = PRETTYFLAG_INDENT;
2245
2246 str = deparse_expression_pretty(expr, context, false, false,
2247 prettyFlags, 0);
2248
2249 astate = accumArrayResult(astate,
2251 false,
2252 TEXTOID,
2254 }
2255
2257
2259}
2260
2261/*
2262 * pg_get_partkeydef
2263 *
2264 * Returns the partition key specification, ie, the following:
2265 *
2266 * { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
2267 */
2268Datum
2270{
2271 Oid relid = PG_GETARG_OID(0);
2272 char *res;
2273
2274 res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
2275
2276 if (res == NULL)
2278
2280}
2281
2282/* Internal version that just reports the column definitions */
2283char *
2285{
2286 int prettyFlags;
2287
2288 prettyFlags = GET_PRETTY_FLAGS(pretty);
2289
2290 return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
2291}
2292
2293/*
2294 * Internal workhorse to decompile a partition key definition.
2295 */
2296static char *
2297pg_get_partkeydef_worker(Oid relid, int prettyFlags,
2298 bool attrsOnly, bool missing_ok)
2299{
2301 HeapTuple tuple;
2303 oidvector *partcollation;
2304 List *partexprs;
2306 List *context;
2307 Datum datum;
2309 int keyno;
2310 char *str;
2311 char *sep;
2312
2314 if (!HeapTupleIsValid(tuple))
2315 {
2316 if (missing_ok)
2317 return NULL;
2318 elog(ERROR, "cache lookup failed for partition key of %u", relid);
2319 }
2320
2322
2323 Assert(form->partrelid == relid);
2324
2325 /* Must get partclass and partcollation the hard way */
2326 datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
2328 partclass = (oidvector *) DatumGetPointer(datum);
2329
2330 datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
2332 partcollation = (oidvector *) DatumGetPointer(datum);
2333
2334
2335 /*
2336 * Get the expressions, if any. (NOTE: we do not use the relcache
2337 * versions of the expressions, because we want to display
2338 * non-const-folded expressions.)
2339 */
2341 {
2343 char *exprsString;
2344
2348 partexprs = (List *) stringToNode(exprsString);
2349
2350 if (!IsA(partexprs, List))
2351 elog(ERROR, "unexpected node type found in partexprs: %d",
2352 (int) nodeTag(partexprs));
2353
2355 }
2356 else
2357 partexprs = NIL;
2358
2359 partexpr_item = list_head(partexprs);
2360 context = deparse_context_for(get_relation_name(relid), relid);
2361
2363
2364 switch (form->partstrat)
2365 {
2367 if (!attrsOnly)
2368 appendStringInfoString(&buf, "HASH");
2369 break;
2371 if (!attrsOnly)
2372 appendStringInfoString(&buf, "LIST");
2373 break;
2375 if (!attrsOnly)
2376 appendStringInfoString(&buf, "RANGE");
2377 break;
2378 default:
2379 elog(ERROR, "unexpected partition strategy: %d",
2380 (int) form->partstrat);
2381 }
2382
2383 if (!attrsOnly)
2385 sep = "";
2386 for (keyno = 0; keyno < form->partnatts; keyno++)
2387 {
2388 AttrNumber attnum = form->partattrs.values[keyno];
2391 Oid partcoll;
2392
2394 sep = ", ";
2395 if (attnum != 0)
2396 {
2397 /* Simple attribute reference */
2398 char *attname;
2400
2401 attname = get_attname(relid, attnum, false);
2406 }
2407 else
2408 {
2409 /* Expression */
2410 Node *partkey;
2411
2412 if (partexpr_item == NULL)
2413 elog(ERROR, "too few entries in partexprs list");
2415 partexpr_item = lnext(partexprs, partexpr_item);
2416
2417 /* Deparse */
2418 str = deparse_expression_pretty(partkey, context, false, false,
2419 prettyFlags, 0);
2420 /* Need parens if it's not a bare function call */
2423 else
2424 appendStringInfo(&buf, "(%s)", str);
2425
2428 }
2429
2430 /* Add collation, if not default for column */
2431 partcoll = partcollation->values[keyno];
2433 appendStringInfo(&buf, " COLLATE %s",
2435
2436 /* Add the operator class name, if not default */
2437 if (!attrsOnly)
2438 get_opclass_name(partclass->values[keyno], keycoltype, &buf);
2439 }
2440
2441 if (!attrsOnly)
2443
2444 /* Clean up */
2445 ReleaseSysCache(tuple);
2446
2447 return buf.data;
2448}
2449
2450/*
2451 * pg_get_partition_constraintdef
2452 *
2453 * Returns partition constraint expression as a string for the input relation
2454 */
2455Datum
2457{
2460 int prettyFlags;
2461 List *context;
2462 char *consrc;
2463
2465
2466 /* Quick exit if no partition constraint */
2467 if (constr_expr == NULL)
2469
2470 /*
2471 * Deparse and return the constraint expression.
2472 */
2473 prettyFlags = PRETTYFLAG_INDENT;
2475 consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2476 false, prettyFlags, 0);
2477
2479}
2480
2481/*
2482 * pg_get_partconstrdef_string
2483 *
2484 * Returns the partition constraint as a C-string for the input relation, with
2485 * the given alias. No pretty-printing.
2486 */
2487char *
2489{
2491 List *context;
2492
2494 context = deparse_context_for(aliasname, partitionId);
2495
2496 return deparse_expression((Node *) constr_expr, context, true, false);
2497}
2498
2499/*
2500 * pg_get_constraintdef
2501 *
2502 * Returns the definition for the constraint, ie, everything that needs to
2503 * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
2504 */
2505Datum
2507{
2509 int prettyFlags;
2510 char *res;
2511
2512 prettyFlags = PRETTYFLAG_INDENT;
2513
2514 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2515
2516 if (res == NULL)
2518
2520}
2521
2522Datum
2524{
2526 bool pretty = PG_GETARG_BOOL(1);
2527 int prettyFlags;
2528 char *res;
2529
2530 prettyFlags = GET_PRETTY_FLAGS(pretty);
2531
2532 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2533
2534 if (res == NULL)
2536
2538}
2539
2540/*
2541 * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
2542 */
2543char *
2548
2549/*
2550 * As of 9.4, we now use an MVCC snapshot for this.
2551 */
2552static char *
2554 int prettyFlags, bool missing_ok)
2555{
2556 HeapTuple tup;
2559 SysScanDesc scandesc;
2563
2564 ScanKeyInit(&scankey[0],
2568
2569 scandesc = systable_beginscan(relation,
2571 true,
2572 snapshot,
2573 1,
2574 scankey);
2575
2576 /*
2577 * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2578 * via SearchSysCache, which works fine.
2579 */
2580 tup = systable_getnext(scandesc);
2581
2582 UnregisterSnapshot(snapshot);
2583
2584 if (!HeapTupleIsValid(tup))
2585 {
2586 if (missing_ok)
2587 {
2588 systable_endscan(scandesc);
2589 table_close(relation, AccessShareLock);
2590 return NULL;
2591 }
2592 elog(ERROR, "could not find tuple for constraint %u", constraintId);
2593 }
2594
2596
2598
2599 if (fullCommand)
2600 {
2601 if (OidIsValid(conForm->conrelid))
2602 {
2603 /*
2604 * Currently, callers want ALTER TABLE (without ONLY) for CHECK
2605 * constraints, and other types of constraints don't inherit
2606 * anyway so it doesn't matter whether we say ONLY or not. Someday
2607 * we might need to let callers specify whether to put ONLY in the
2608 * command.
2609 */
2610 appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2612 quote_identifier(NameStr(conForm->conname)));
2613 }
2614 else
2615 {
2616 /* Must be a domain constraint */
2617 Assert(OidIsValid(conForm->contypid));
2618 appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
2620 quote_identifier(NameStr(conForm->conname)));
2621 }
2622 }
2623
2624 switch (conForm->contype)
2625 {
2626 case CONSTRAINT_FOREIGN:
2627 {
2628 Datum val;
2629 bool isnull;
2630 const char *string;
2631
2632 /* Start off the constraint definition */
2633 appendStringInfoString(&buf, "FOREIGN KEY (");
2634
2635 /* Fetch and build referencing-column list */
2638
2639 /* If it is a temporal foreign key then it uses PERIOD. */
2640 decompile_column_index_array(val, conForm->conrelid, conForm->conperiod, &buf);
2641
2642 /* add foreign relation name */
2643 appendStringInfo(&buf, ") REFERENCES %s(",
2645 NIL));
2646
2647 /* Fetch and build referenced-column list */
2650
2651 decompile_column_index_array(val, conForm->confrelid, conForm->conperiod, &buf);
2652
2654
2655 /* Add match type */
2656 switch (conForm->confmatchtype)
2657 {
2659 string = " MATCH FULL";
2660 break;
2662 string = " MATCH PARTIAL";
2663 break;
2665 string = "";
2666 break;
2667 default:
2668 elog(ERROR, "unrecognized confmatchtype: %d",
2669 conForm->confmatchtype);
2670 string = ""; /* keep compiler quiet */
2671 break;
2672 }
2673 appendStringInfoString(&buf, string);
2674
2675 /* Add ON UPDATE and ON DELETE clauses, if needed */
2676 switch (conForm->confupdtype)
2677 {
2679 string = NULL; /* suppress default */
2680 break;
2682 string = "RESTRICT";
2683 break;
2685 string = "CASCADE";
2686 break;
2688 string = "SET NULL";
2689 break;
2691 string = "SET DEFAULT";
2692 break;
2693 default:
2694 elog(ERROR, "unrecognized confupdtype: %d",
2695 conForm->confupdtype);
2696 string = NULL; /* keep compiler quiet */
2697 break;
2698 }
2699 if (string)
2700 appendStringInfo(&buf, " ON UPDATE %s", string);
2701
2702 switch (conForm->confdeltype)
2703 {
2705 string = NULL; /* suppress default */
2706 break;
2708 string = "RESTRICT";
2709 break;
2711 string = "CASCADE";
2712 break;
2714 string = "SET NULL";
2715 break;
2717 string = "SET DEFAULT";
2718 break;
2719 default:
2720 elog(ERROR, "unrecognized confdeltype: %d",
2721 conForm->confdeltype);
2722 string = NULL; /* keep compiler quiet */
2723 break;
2724 }
2725 if (string)
2726 appendStringInfo(&buf, " ON DELETE %s", string);
2727
2728 /*
2729 * Add columns specified to SET NULL or SET DEFAULT if
2730 * provided.
2731 */
2734 if (!isnull)
2735 {
2737 decompile_column_index_array(val, conForm->conrelid, false, &buf);
2739 }
2740
2741 break;
2742 }
2743 case CONSTRAINT_PRIMARY:
2744 case CONSTRAINT_UNIQUE:
2745 {
2746 Datum val;
2747 Oid indexId;
2748 int keyatts;
2750
2751 /* Start off the constraint definition */
2752 if (conForm->contype == CONSTRAINT_PRIMARY)
2753 appendStringInfoString(&buf, "PRIMARY KEY ");
2754 else
2755 appendStringInfoString(&buf, "UNIQUE ");
2756
2757 indexId = conForm->conindid;
2758
2761 elog(ERROR, "cache lookup failed for index %u", indexId);
2762 if (conForm->contype == CONSTRAINT_UNIQUE &&
2763 ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
2764 appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
2765
2767
2768 /* Fetch and build target column list */
2771
2772 keyatts = decompile_column_index_array(val, conForm->conrelid, false, &buf);
2773 if (conForm->conperiod)
2774 appendStringInfoString(&buf, " WITHOUT OVERLAPS");
2775
2777
2778 /* Build including column list (from pg_index.indkeys) */
2781 if (DatumGetInt32(val) > keyatts)
2782 {
2783 Datum cols;
2784 Datum *keys;
2785 int nKeys;
2786 int j;
2787
2788 appendStringInfoString(&buf, " INCLUDE (");
2789
2792
2794 &keys, NULL, &nKeys);
2795
2796 for (j = keyatts; j < nKeys; j++)
2797 {
2798 char *colName;
2799
2800 colName = get_attname(conForm->conrelid,
2801 DatumGetInt16(keys[j]), false);
2802 if (j > keyatts)
2805 }
2806
2808 }
2810
2811 /* XXX why do we only print these bits if fullCommand? */
2813 {
2815 Oid tblspc;
2816
2817 if (options)
2818 {
2819 appendStringInfo(&buf, " WITH (%s)", options);
2820 pfree(options);
2821 }
2822
2823 /*
2824 * Print the tablespace, unless it's the database default.
2825 * This is to help ALTER TABLE usage of this facility,
2826 * which needs this behavior to recreate exact catalog
2827 * state.
2828 */
2830 if (OidIsValid(tblspc))
2831 appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2833 }
2834
2835 break;
2836 }
2837 case CONSTRAINT_CHECK:
2838 {
2839 Datum val;
2840 char *conbin;
2841 char *consrc;
2842 Node *expr;
2843 List *context;
2844
2845 /* Fetch constraint expression in parsetree form */
2848
2850 expr = stringToNode(conbin);
2851
2852 /* Set up deparsing context for Var nodes in constraint */
2853 if (conForm->conrelid != InvalidOid)
2854 {
2855 /* relation constraint */
2856 context = deparse_context_for(get_relation_name(conForm->conrelid),
2857 conForm->conrelid);
2858 }
2859 else
2860 {
2861 /* domain constraint --- can't have Vars */
2862 context = NIL;
2863 }
2864
2865 consrc = deparse_expression_pretty(expr, context, false, false,
2866 prettyFlags, 0);
2867
2868 /*
2869 * Now emit the constraint definition, adding NO INHERIT if
2870 * necessary.
2871 *
2872 * There are cases where the constraint expression will be
2873 * fully parenthesized and we don't need the outer parens ...
2874 * but there are other cases where we do need 'em. Be
2875 * conservative for now.
2876 *
2877 * Note that simply checking for leading '(' and trailing ')'
2878 * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2879 */
2880 appendStringInfo(&buf, "CHECK (%s)%s",
2881 consrc,
2882 conForm->connoinherit ? " NO INHERIT" : "");
2883 break;
2884 }
2885 case CONSTRAINT_NOTNULL:
2886 {
2887 if (conForm->conrelid)
2888 {
2890
2892
2893 appendStringInfo(&buf, "NOT NULL %s",
2895 attnum, false)));
2897 appendStringInfoString(&buf, " NO INHERIT");
2898 }
2899 else if (conForm->contypid)
2900 {
2901 /* conkey is null for domain not-null constraints */
2902 appendStringInfoString(&buf, "NOT NULL");
2903 }
2904 break;
2905 }
2906
2907 case CONSTRAINT_TRIGGER:
2908
2909 /*
2910 * There isn't an ALTER TABLE syntax for creating a user-defined
2911 * constraint trigger, but it seems better to print something than
2912 * throw an error; if we throw error then this function couldn't
2913 * safely be applied to all rows of pg_constraint.
2914 */
2915 appendStringInfoString(&buf, "TRIGGER");
2916 break;
2918 {
2919 Oid indexOid = conForm->conindid;
2920 Datum val;
2921 Datum *elems;
2922 int nElems;
2923 int i;
2924 Oid *operators;
2925
2926 /* Extract operator OIDs from the pg_constraint tuple */
2929
2931 &elems, NULL, &nElems);
2932
2933 operators = (Oid *) palloc(nElems * sizeof(Oid));
2934 for (i = 0; i < nElems; i++)
2935 operators[i] = DatumGetObjectId(elems[i]);
2936
2937 /* pg_get_indexdef_worker does the rest */
2938 /* suppress tablespace because pg_dump wants it that way */
2940 pg_get_indexdef_worker(indexOid,
2941 0,
2942 operators,
2943 false,
2944 false,
2945 false,
2946 false,
2947 prettyFlags,
2948 false));
2949 break;
2950 }
2951 default:
2952 elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2953 break;
2954 }
2955
2956 if (conForm->condeferrable)
2957 appendStringInfoString(&buf, " DEFERRABLE");
2958 if (conForm->condeferred)
2959 appendStringInfoString(&buf, " INITIALLY DEFERRED");
2960
2961 /* Validated status is irrelevant when the constraint is NOT ENFORCED. */
2962 if (!conForm->conenforced)
2963 appendStringInfoString(&buf, " NOT ENFORCED");
2964 else if (!conForm->convalidated)
2965 appendStringInfoString(&buf, " NOT VALID");
2966
2967 /* Cleanup */
2968 systable_endscan(scandesc);
2969 table_close(relation, AccessShareLock);
2970
2971 return buf.data;
2972}
2973
2974
2975/*
2976 * Convert an int16[] Datum into a comma-separated list of column names
2977 * for the indicated relation; append the list to buf. Returns the number
2978 * of keys.
2979 */
2980static int
2983{
2984 Datum *keys;
2985 int nKeys;
2986 int j;
2987
2988 /* Extract data from array of int16 */
2990 &keys, NULL, &nKeys);
2991
2992 for (j = 0; j < nKeys; j++)
2993 {
2994 char *colName;
2995
2996 colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2997
2998 if (j == 0)
3000 else
3001 appendStringInfo(buf, ", %s%s",
3002 (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
3004 }
3005
3006 return nKeys;
3007}
3008
3009
3010/* ----------
3011 * pg_get_expr - Decompile an expression tree
3012 *
3013 * Input: an expression tree in nodeToString form, and a relation OID
3014 *
3015 * Output: reverse-listed expression
3016 *
3017 * Currently, the expression can only refer to a single relation, namely
3018 * the one specified by the second parameter. This is sufficient for
3019 * partial indexes, column default expressions, etc. We also support
3020 * Var-free expressions, for which the OID can be InvalidOid.
3021 *
3022 * If the OID is nonzero but not actually valid, don't throw an error,
3023 * just return NULL. This is a bit questionable, but it's what we've
3024 * done historically, and it can help avoid unwanted failures when
3025 * examining catalog entries for just-deleted relations.
3026 *
3027 * We expect this function to work, or throw a reasonably clean error,
3028 * for any node tree that can appear in a catalog pg_node_tree column.
3029 * Query trees, such as those appearing in pg_rewrite.ev_action, are
3030 * not supported. Nor are expressions in more than one relation, which
3031 * can appear in places like pg_rewrite.ev_qual.
3032 * ----------
3033 */
3034Datum
3036{
3037 text *expr = PG_GETARG_TEXT_PP(0);
3038 Oid relid = PG_GETARG_OID(1);
3039 text *result;
3040 int prettyFlags;
3041
3042 prettyFlags = PRETTYFLAG_INDENT;
3043
3044 result = pg_get_expr_worker(expr, relid, prettyFlags);
3045 if (result)
3047 else
3049}
3050
3051Datum
3053{
3054 text *expr = PG_GETARG_TEXT_PP(0);
3055 Oid relid = PG_GETARG_OID(1);
3056 bool pretty = PG_GETARG_BOOL(2);
3057 text *result;
3058 int prettyFlags;
3059
3060 prettyFlags = GET_PRETTY_FLAGS(pretty);
3061
3062 result = pg_get_expr_worker(expr, relid, prettyFlags);
3063 if (result)
3065 else
3067}
3068
3069static text *
3070pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
3071{
3072 Node *node;
3073 Node *tst;
3074 Relids relids;
3075 List *context;
3076 char *exprstr;
3077 Relation rel = NULL;
3078 char *str;
3079
3080 /* Convert input pg_node_tree (really TEXT) object to C string */
3081 exprstr = text_to_cstring(expr);
3082
3083 /* Convert expression to node tree */
3084 node = (Node *) stringToNode(exprstr);
3085
3086 pfree(exprstr);
3087
3088 /*
3089 * Throw error if the input is a querytree rather than an expression tree.
3090 * While we could support queries here, there seems no very good reason
3091 * to. In most such catalog columns, we'll see a List of Query nodes, or
3092 * even nested Lists, so drill down to a non-List node before checking.
3093 */
3094 tst = node;
3095 while (tst && IsA(tst, List))
3096 tst = linitial((List *) tst);
3097 if (tst && IsA(tst, Query))
3098 ereport(ERROR,
3100 errmsg("input is a query, not an expression")));
3101
3102 /*
3103 * Throw error if the expression contains Vars we won't be able to
3104 * deparse.
3105 */
3106 relids = pull_varnos(NULL, node);
3107 if (OidIsValid(relid))
3108 {
3109 if (!bms_is_subset(relids, bms_make_singleton(1)))
3110 ereport(ERROR,
3112 errmsg("expression contains variables of more than one relation")));
3113 }
3114 else
3115 {
3116 if (!bms_is_empty(relids))
3117 ereport(ERROR,
3119 errmsg("expression contains variables")));
3120 }
3121
3122 /*
3123 * Prepare deparse context if needed. If we are deparsing with a relid,
3124 * we need to transiently open and lock the rel, to make sure it won't go
3125 * away underneath us. (set_relation_column_names would lock it anyway,
3126 * so this isn't really introducing any new behavior.)
3127 */
3128 if (OidIsValid(relid))
3129 {
3130 rel = try_relation_open(relid, AccessShareLock);
3131 if (rel == NULL)
3132 return NULL;
3133 context = deparse_context_for(RelationGetRelationName(rel), relid);
3134 }
3135 else
3136 context = NIL;
3137
3138 /* Deparse */
3139 str = deparse_expression_pretty(node, context, false, false,
3140 prettyFlags, 0);
3141
3142 if (rel != NULL)
3144
3145 return string_to_text(str);
3146}
3147
3148
3149/* ----------
3150 * pg_get_userbyid - Get a user name by roleid and
3151 * fallback to 'unknown (OID=n)'
3152 * ----------
3153 */
3154Datum
3156{
3157 Oid roleid = PG_GETARG_OID(0);
3158 Name result;
3161
3162 /*
3163 * Allocate space for the result
3164 */
3167
3168 /*
3169 * Get the pg_authid entry and print the result
3170 */
3173 {
3175 *result = role_rec->rolname;
3177 }
3178 else
3179 sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
3180
3182}
3183
3184
3185/*
3186 * pg_get_serial_sequence
3187 * Get the name of the sequence used by an identity or serial column,
3188 * formatted suitably for passing to setval, nextval or currval.
3189 * First parameter is not treated as double-quoted, second parameter
3190 * is --- see documentation for reason.
3191 */
3192Datum
3194{
3195 text *tablename = PG_GETARG_TEXT_PP(0);
3198 Oid tableOid;
3199 char *column;
3203 ScanKeyData key[3];
3204 SysScanDesc scan;
3205 HeapTuple tup;
3206
3207 /* Look up table name. Can't lock it - we might not have privileges. */
3209 tableOid = RangeVarGetRelid(tablerv, NoLock, false);
3210
3211 /* Get the number of the column */
3213
3214 attnum = get_attnum(tableOid, column);
3216 ereport(ERROR,
3218 errmsg("column \"%s\" of relation \"%s\" does not exist",
3219 column, tablerv->relname)));
3220
3221 /* Search the dependency table for the dependent sequence */
3223
3224 ScanKeyInit(&key[0],
3228 ScanKeyInit(&key[1],
3231 ObjectIdGetDatum(tableOid));
3232 ScanKeyInit(&key[2],
3236
3238 NULL, 3, key);
3239
3240 while (HeapTupleIsValid(tup = systable_getnext(scan)))
3241 {
3243
3244 /*
3245 * Look for an auto dependency (serial column) or internal dependency
3246 * (identity column) of a sequence on a column. (We need the relkind
3247 * test because indexes can also have auto dependencies on columns.)
3248 */
3249 if (deprec->classid == RelationRelationId &&
3250 deprec->objsubid == 0 &&
3251 (deprec->deptype == DEPENDENCY_AUTO ||
3252 deprec->deptype == DEPENDENCY_INTERNAL) &&
3254 {
3255 sequenceId = deprec->objid;
3256 break;
3257 }
3258 }
3259
3260 systable_endscan(scan);
3262
3264 {
3265 char *result;
3266
3268
3270 }
3271
3273}
3274
3275
3276/*
3277 * pg_get_functiondef
3278 * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
3279 * the specified function.
3280 *
3281 * Note: if you change the output format of this function, be careful not
3282 * to break psql's rules (in \ef and \sf) for identifying the start of the
3283 * function body. To wit: the function body starts on a line that begins with
3284 * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
3285 */
3286Datum
3288{
3289 Oid funcid = PG_GETARG_OID(0);
3293 Form_pg_proc proc;
3294 bool isfunction;
3295 Datum tmp;
3296 bool isnull;
3297 const char *prosrc;
3298 const char *name;
3299 const char *nsp;
3301 int oldlen;
3302
3304
3305 /* Look up the function */
3309
3310 proc = (Form_pg_proc) GETSTRUCT(proctup);
3311 name = NameStr(proc->proname);
3312
3313 if (proc->prokind == PROKIND_AGGREGATE)
3314 ereport(ERROR,
3316 errmsg("\"%s\" is an aggregate function", name)));
3317
3318 isfunction = (proc->prokind != PROKIND_PROCEDURE);
3319
3320 /*
3321 * We always qualify the function name, to ensure the right function gets
3322 * replaced.
3323 */
3324 nsp = get_namespace_name_or_temp(proc->pronamespace);
3325 appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
3326 isfunction ? "FUNCTION" : "PROCEDURE",
3328 (void) print_function_arguments(&buf, proctup, false, true);
3329 appendStringInfoString(&buf, ")\n");
3330 if (isfunction)
3331 {
3332 appendStringInfoString(&buf, " RETURNS ");
3334 appendStringInfoChar(&buf, '\n');
3335 }
3336
3338
3339 appendStringInfo(&buf, " LANGUAGE %s\n",
3340 quote_identifier(get_language_name(proc->prolang, false)));
3341
3342 /* Emit some miscellaneous options on one line */
3343 oldlen = buf.len;
3344
3345 if (proc->prokind == PROKIND_WINDOW)
3346 appendStringInfoString(&buf, " WINDOW");
3347 switch (proc->provolatile)
3348 {
3350 appendStringInfoString(&buf, " IMMUTABLE");
3351 break;
3352 case PROVOLATILE_STABLE:
3353 appendStringInfoString(&buf, " STABLE");
3354 break;
3356 break;
3357 }
3358
3359 switch (proc->proparallel)
3360 {
3361 case PROPARALLEL_SAFE:
3362 appendStringInfoString(&buf, " PARALLEL SAFE");
3363 break;
3365 appendStringInfoString(&buf, " PARALLEL RESTRICTED");
3366 break;
3367 case PROPARALLEL_UNSAFE:
3368 break;
3369 }
3370
3371 if (proc->proisstrict)
3372 appendStringInfoString(&buf, " STRICT");
3373 if (proc->prosecdef)
3374 appendStringInfoString(&buf, " SECURITY DEFINER");
3375 if (proc->proleakproof)
3376 appendStringInfoString(&buf, " LEAKPROOF");
3377
3378 /* This code for the default cost and rows should match functioncmds.c */
3379 if (proc->prolang == INTERNALlanguageId ||
3380 proc->prolang == ClanguageId)
3381 procost = 1;
3382 else
3383 procost = 100;
3384 if (proc->procost != procost)
3385 appendStringInfo(&buf, " COST %g", proc->procost);
3386
3387 if (proc->prorows > 0 && proc->prorows != 1000)
3388 appendStringInfo(&buf, " ROWS %g", proc->prorows);
3389
3390 if (proc->prosupport)
3391 {
3392 Oid argtypes[1];
3393
3394 /*
3395 * We should qualify the support function's name if it wouldn't be
3396 * resolved by lookup in the current search path.
3397 */
3398 argtypes[0] = INTERNALOID;
3399 appendStringInfo(&buf, " SUPPORT %s",
3400 generate_function_name(proc->prosupport, 1,
3401 NIL, argtypes,
3402 false, NULL, false));
3403 }
3404
3405 if (oldlen != buf.len)
3406 appendStringInfoChar(&buf, '\n');
3407
3408 /* Emit any proconfig options, one per line */
3410 if (!isnull)
3411 {
3413 int i;
3414
3416 Assert(ARR_NDIM(a) == 1);
3417 Assert(ARR_LBOUND(a)[0] == 1);
3418
3419 for (i = 1; i <= ARR_DIMS(a)[0]; i++)
3420 {
3421 Datum d;
3422
3423 d = array_ref(a, 1, &i,
3424 -1 /* varlenarray */ ,
3425 -1 /* TEXT's typlen */ ,
3426 false /* TEXT's typbyval */ ,
3427 TYPALIGN_INT /* TEXT's typalign */ ,
3428 &isnull);
3429 if (!isnull)
3430 {
3432 char *pos;
3433
3434 pos = strchr(configitem, '=');
3435 if (pos == NULL)
3436 continue;
3437 *pos++ = '\0';
3438
3439 appendStringInfo(&buf, " SET %s TO ",
3441
3442 /*
3443 * Variables that are marked GUC_LIST_QUOTE were already fully
3444 * quoted by flatten_set_variable_args() before they were put
3445 * into the proconfig array. However, because the quoting
3446 * rules used there aren't exactly like SQL's, we have to
3447 * break the list value apart and then quote the elements as
3448 * string literals. (The elements may be double-quoted as-is,
3449 * but we can't just feed them to the SQL parser; it would do
3450 * the wrong thing with elements that are zero-length or
3451 * longer than NAMEDATALEN.) Also, we need a special case for
3452 * empty lists.
3453 *
3454 * Variables that are not so marked should just be emitted as
3455 * simple string literals. If the variable is not known to
3456 * guc.c, we'll do that; this makes it unsafe to use
3457 * GUC_LIST_QUOTE for extension variables.
3458 */
3460 {
3461 List *namelist;
3462 ListCell *lc;
3463
3464 /* Parse string into list of identifiers */
3465 if (!SplitGUCList(pos, ',', &namelist))
3466 {
3467 /* this shouldn't fail really */
3468 elog(ERROR, "invalid list syntax in proconfig item");
3469 }
3470 /* Special case: represent an empty list as NULL */
3471 if (namelist == NIL)
3472 appendStringInfoString(&buf, "NULL");
3473 foreach(lc, namelist)
3474 {
3475 char *curname = (char *) lfirst(lc);
3476
3478 if (lnext(namelist, lc))
3480 }
3481 }
3482 else
3484 appendStringInfoChar(&buf, '\n');
3485 }
3486 }
3487 }
3488
3489 /* And finally the function definition ... */
3491 if (proc->prolang == SQLlanguageId && !isnull)
3492 {
3494 }
3495 else
3496 {
3497 appendStringInfoString(&buf, "AS ");
3498
3500 if (!isnull)
3501 {
3503 appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
3504 }
3505
3507 prosrc = TextDatumGetCString(tmp);
3508
3509 /*
3510 * We always use dollar quoting. Figure out a suitable delimiter.
3511 *
3512 * Since the user is likely to be editing the function body string, we
3513 * shouldn't use a short delimiter that he might easily create a
3514 * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3515 * if needed.
3516 */
3518 appendStringInfoChar(&dq, '$');
3519 appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3520 while (strstr(prosrc, dq.data) != NULL)
3521 appendStringInfoChar(&dq, 'x');
3522 appendStringInfoChar(&dq, '$');
3523
3524 appendBinaryStringInfo(&buf, dq.data, dq.len);
3525 appendStringInfoString(&buf, prosrc);
3526 appendBinaryStringInfo(&buf, dq.data, dq.len);
3527 }
3528
3529 appendStringInfoChar(&buf, '\n');
3530
3532
3534}
3535
3536/*
3537 * pg_get_function_arguments
3538 * Get a nicely-formatted list of arguments for a function.
3539 * This is everything that would go between the parentheses in
3540 * CREATE FUNCTION.
3541 */
3542Datum
3561
3562/*
3563 * pg_get_function_identity_arguments
3564 * Get a formatted list of arguments for a function.
3565 * This is everything that would go between the parentheses in
3566 * ALTER FUNCTION, etc. In particular, don't print defaults.
3567 */
3568Datum
3587
3588/*
3589 * pg_get_function_result
3590 * Get a nicely-formatted version of the result type of a function.
3591 * This is what would appear after RETURNS in CREATE FUNCTION.
3592 */
3593Datum
3618
3619/*
3620 * Guts of pg_get_function_result: append the function's return type
3621 * to the specified buffer.
3622 */
3623static void
3625{
3627 int ntabargs = 0;
3629
3631
3632 if (proc->proretset)
3633 {
3634 /* It might be a table function; try to print the arguments */
3635 appendStringInfoString(&rbuf, "TABLE(");
3637 if (ntabargs > 0)
3639 else
3641 }
3642
3643 if (ntabargs == 0)
3644 {
3645 /* Not a table function, so do the normal thing */
3646 if (proc->proretset)
3647 appendStringInfoString(&rbuf, "SETOF ");
3648 appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3649 }
3650
3651 appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3652}
3653
3654/*
3655 * Common code for pg_get_function_arguments and pg_get_function_result:
3656 * append the desired subset of arguments to buf. We print only TABLE
3657 * arguments when print_table_args is true, and all the others when it's false.
3658 * We print argument defaults only if print_defaults is true.
3659 * Function return value is the number of arguments printed.
3660 */
3661static int
3664{
3666 int numargs;
3667 Oid *argtypes;
3668 char **argnames;
3669 char *argmodes;
3670 int insertorderbyat = -1;
3671 int argsprinted;
3672 int inputargno;
3673 int nlackdefaults;
3674 List *argdefaults = NIL;
3676 int i;
3677
3678 numargs = get_func_arg_info(proctup,
3679 &argtypes, &argnames, &argmodes);
3680
3681 nlackdefaults = numargs;
3682 if (print_defaults && proc->pronargdefaults > 0)
3683 {
3685 bool isnull;
3686
3689 &isnull);
3690 if (!isnull)
3691 {
3692 char *str;
3693
3696 pfree(str);
3698 /* nlackdefaults counts only *input* arguments lacking defaults */
3699 nlackdefaults = proc->pronargs - list_length(argdefaults);
3700 }
3701 }
3702
3703 /* Check for special treatment of ordered-set aggregates */
3704 if (proc->prokind == PROKIND_AGGREGATE)
3705 {
3708
3711 elog(ERROR, "cache lookup failed for aggregate %u",
3712 proc->oid);
3714 if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3715 insertorderbyat = agg->aggnumdirectargs;
3717 }
3718
3719 argsprinted = 0;
3720 inputargno = 0;
3721 for (i = 0; i < numargs; i++)
3722 {
3723 Oid argtype = argtypes[i];
3724 char *argname = argnames ? argnames[i] : NULL;
3726 const char *modename;
3727 bool isinput;
3728
3729 switch (argmode)
3730 {
3731 case PROARGMODE_IN:
3732
3733 /*
3734 * For procedures, explicitly mark all argument modes, so as
3735 * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3736 */
3737 if (proc->prokind == PROKIND_PROCEDURE)
3738 modename = "IN ";
3739 else
3740 modename = "";
3741 isinput = true;
3742 break;
3743 case PROARGMODE_INOUT:
3744 modename = "INOUT ";
3745 isinput = true;
3746 break;
3747 case PROARGMODE_OUT:
3748 modename = "OUT ";
3749 isinput = false;
3750 break;
3752 modename = "VARIADIC ";
3753 isinput = true;
3754 break;
3755 case PROARGMODE_TABLE:
3756 modename = "";
3757 isinput = false;
3758 break;
3759 default:
3760 elog(ERROR, "invalid parameter mode '%c'", argmode);
3761 modename = NULL; /* keep compiler quiet */
3762 isinput = false;
3763 break;
3764 }
3765 if (isinput)
3766 inputargno++; /* this is a 1-based counter */
3767
3769 continue;
3770
3772 {
3773 if (argsprinted)
3775 appendStringInfoString(buf, "ORDER BY ");
3776 }
3777 else if (argsprinted)
3779
3781 if (argname && argname[0])
3782 appendStringInfo(buf, "%s ", quote_identifier(argname));
3785 {
3786 Node *expr;
3787
3789 expr = (Node *) lfirst(nextargdefault);
3791
3792 appendStringInfo(buf, " DEFAULT %s",
3793 deparse_expression(expr, NIL, false, false));
3794 }
3795 argsprinted++;
3796
3797 /* nasty hack: print the last arg twice for variadic ordered-set agg */
3798 if (argsprinted == insertorderbyat && i == numargs - 1)
3799 {
3800 i--;
3801 /* aggs shouldn't have defaults anyway, but just to be sure ... */
3802 print_defaults = false;
3803 }
3804 }
3805
3806 return argsprinted;
3807}
3808
3809static bool
3811{
3812 return (!argmodes
3816}
3817
3818/*
3819 * Append used transformed types to specified buffer
3820 */
3821static void
3823{
3824 Oid *trftypes;
3825 int ntypes;
3826
3827 ntypes = get_func_trftypes(proctup, &trftypes);
3828 if (ntypes > 0)
3829 {
3830 int i;
3831
3832 appendStringInfoString(buf, " TRANSFORM ");
3833 for (i = 0; i < ntypes; i++)
3834 {
3835 if (i != 0)
3837 appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3838 }
3840 }
3841}
3842
3843/*
3844 * Get textual representation of a function argument's default value. The
3845 * second argument of this function is the argument number among all arguments
3846 * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3847 * how information_schema.sql uses it.
3848 */
3849Datum
3851{
3852 Oid funcid = PG_GETARG_OID(0);
3855 Form_pg_proc proc;
3856 int numargs;
3857 Oid *argtypes;
3858 char **argnames;
3859 char *argmodes;
3860 int i;
3862 Node *node;
3863 char *str;
3864 int nth_inputarg;
3866 bool isnull;
3867 int nth_default;
3868
3872
3873 numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3875 {
3878 }
3879
3880 nth_inputarg = 0;
3881 for (i = 0; i < nth_arg; i++)
3883 nth_inputarg++;
3884
3887 &isnull);
3888 if (isnull)
3889 {
3892 }
3893
3896 pfree(str);
3897
3898 proc = (Form_pg_proc) GETSTRUCT(proctup);
3899
3900 /*
3901 * Calculate index into proargdefaults: proargdefaults corresponds to the
3902 * last N input arguments, where N = pronargdefaults.
3903 */
3904 nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3905
3907 {
3910 }
3912 str = deparse_expression(node, NIL, false, false);
3913
3915
3917}
3918
3919static void
3921{
3922 int numargs;
3923 Oid *argtypes;
3924 char **argnames;
3925 char *argmodes;
3926 deparse_namespace dpns = {0};
3927 Datum tmp;
3928 Node *n;
3929
3931 numargs = get_func_arg_info(proctup,
3932 &argtypes, &argnames, &argmodes);
3933 dpns.numargs = numargs;
3934 dpns.argnames = argnames;
3935
3938
3939 if (IsA(n, List))
3940 {
3941 List *stmts;
3942 ListCell *lc;
3943
3944 stmts = linitial(castNode(List, n));
3945
3946 appendStringInfoString(buf, "BEGIN ATOMIC\n");
3947
3948 foreach(lc, stmts)
3949 {
3950 Query *query = lfirst_node(Query, lc);
3951
3952 /* It seems advisable to get at least AccessShareLock on rels */
3953 AcquireRewriteLocks(query, false, false);
3954 get_query_def(query, buf, list_make1(&dpns), NULL, false,
3958 }
3959
3961 }
3962 else
3963 {
3964 Query *query = castNode(Query, n);
3965
3966 /* It seems advisable to get at least AccessShareLock on rels */
3967 AcquireRewriteLocks(query, false, false);
3968 get_query_def(query, buf, list_make1(&dpns), NULL, false,
3969 0, WRAP_COLUMN_DEFAULT, 0);
3970 }
3971}
3972
3973Datum
3975{
3976 Oid funcid = PG_GETARG_OID(0);
3979 bool isnull;
3980
3982
3983 /* Look up the function */
3987
3989 if (isnull)
3990 {
3993 }
3994
3996
3998
4000}
4001
4002
4003/*
4004 * deparse_expression - General utility for deparsing expressions
4005 *
4006 * calls deparse_expression_pretty with all prettyPrinting disabled
4007 */
4008char *
4010 bool forceprefix, bool showimplicit)
4011{
4013 showimplicit, 0, 0);
4014}
4015
4016/* ----------
4017 * deparse_expression_pretty - General utility for deparsing expressions
4018 *
4019 * expr is the node tree to be deparsed. It must be a transformed expression
4020 * tree (ie, not the raw output of gram.y).
4021 *
4022 * dpcontext is a list of deparse_namespace nodes representing the context
4023 * for interpreting Vars in the node tree. It can be NIL if no Vars are
4024 * expected.
4025 *
4026 * forceprefix is true to force all Vars to be prefixed with their table names.
4027 *
4028 * showimplicit is true to force all implicit casts to be shown explicitly.
4029 *
4030 * Tries to pretty up the output according to prettyFlags and startIndent.
4031 *
4032 * The result is a palloc'd string.
4033 * ----------
4034 */
4035static char *
4037 bool forceprefix, bool showimplicit,
4038 int prettyFlags, int startIndent)
4039{
4041 deparse_context context;
4042
4044 context.buf = &buf;
4045 context.namespaces = dpcontext;
4046 context.resultDesc = NULL;
4047 context.targetList = NIL;
4048 context.windowClause = NIL;
4049 context.varprefix = forceprefix;
4050 context.prettyFlags = prettyFlags;
4052 context.indentLevel = startIndent;
4053 context.colNamesVisible = true;
4054 context.inGroupBy = false;
4055 context.varInOrderBy = false;
4056 context.appendparents = NULL;
4057
4058 get_rule_expr(expr, &context, showimplicit);
4059
4060 return buf.data;
4061}
4062
4063/* ----------
4064 * deparse_context_for - Build deparse context for a single relation
4065 *
4066 * Given the reference name (alias) and OID of a relation, build deparsing
4067 * context for an expression referencing only that relation (as varno 1,
4068 * varlevelsup 0). This is sufficient for many uses of deparse_expression.
4069 * ----------
4070 */
4071List *
4072deparse_context_for(const char *aliasname, Oid relid)
4073{
4076
4078
4079 /* Build a minimal RTE for the rel */
4081 rte->rtekind = RTE_RELATION;
4082 rte->relid = relid;
4083 rte->relkind = RELKIND_RELATION; /* no need for exactness here */
4084 rte->rellockmode = AccessShareLock;
4085 rte->alias = makeAlias(aliasname, NIL);
4086 rte->eref = rte->alias;
4087 rte->lateral = false;
4088 rte->inh = false;
4089 rte->inFromCl = true;
4090
4091 /* Build one-element rtable */
4092 dpns->rtable = list_make1(rte);
4093 dpns->subplans = NIL;
4094 dpns->ctes = NIL;
4095 dpns->appendrels = NULL;
4098
4099 /* Return a one-deep namespace stack */
4100 return list_make1(dpns);
4101}
4102
4103/*
4104 * deparse_context_for_plan_tree - Build deparse context for a Plan tree
4105 *
4106 * When deparsing an expression in a Plan tree, we use the plan's rangetable
4107 * to resolve names of simple Vars. The initialization of column names for
4108 * this is rather expensive if the rangetable is large, and it'll be the same
4109 * for every expression in the Plan tree; so we do it just once and re-use
4110 * the result of this function for each expression. (Note that the result
4111 * is not usable until set_deparse_context_plan() is applied to it.)
4112 *
4113 * In addition to the PlannedStmt, pass the per-RTE alias names
4114 * assigned by a previous call to select_rtable_names_for_explain.
4115 */
4116List *
4118{
4120
4122
4123 /* Initialize fields that stay the same across the whole plan tree */
4124 dpns->rtable = pstmt->rtable;
4125 dpns->rtable_names = rtable_names;
4126 dpns->subplans = pstmt->subplans;
4127 dpns->ctes = NIL;
4128 if (pstmt->appendRelations)
4129 {
4130 /* Set up the array, indexed by child relid */
4131 int ntables = list_length(dpns->rtable);
4132 ListCell *lc;
4133
4134 dpns->appendrels = (AppendRelInfo **)
4135 palloc0((ntables + 1) * sizeof(AppendRelInfo *));
4136 foreach(lc, pstmt->appendRelations)
4137 {
4139 Index crelid = appinfo->child_relid;
4140
4141 Assert(crelid > 0 && crelid <= ntables);
4142 Assert(dpns->appendrels[crelid] == NULL);
4143 dpns->appendrels[crelid] = appinfo;
4144 }
4145 }
4146 else
4147 dpns->appendrels = NULL; /* don't need it */
4148
4149 /*
4150 * Set up column name aliases, ignoring any join RTEs; they don't matter
4151 * because plan trees don't contain any join alias Vars.
4152 */
4154
4155 /* Return a one-deep namespace stack */
4156 return list_make1(dpns);
4157}
4158
4159/*
4160 * set_deparse_context_plan - Specify Plan node containing expression
4161 *
4162 * When deparsing an expression in a Plan tree, we might have to resolve
4163 * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
4164 * provide the parent Plan node. Then OUTER_VAR and INNER_VAR references
4165 * can be resolved by drilling down into the left and right child plans.
4166 * Similarly, INDEX_VAR references can be resolved by reference to the
4167 * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
4168 * ForeignScan and CustomScan nodes. (Note that we don't currently support
4169 * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
4170 * for those, we can only deparse the indexqualorig fields, which won't
4171 * contain INDEX_VAR Vars.)
4172 *
4173 * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
4174 * the most-closely-nested first. This is needed to resolve PARAM_EXEC
4175 * Params. Note we assume that all the Plan nodes share the same rtable.
4176 *
4177 * For a ModifyTable plan, we might also need to resolve references to OLD/NEW
4178 * variables in the RETURNING list, so we copy the alias names of the OLD and
4179 * NEW rows from the ModifyTable plan node.
4180 *
4181 * Once this function has been called, deparse_expression() can be called on
4182 * subsidiary expression(s) of the specified Plan node. To deparse
4183 * expressions of a different Plan node in the same Plan tree, re-call this
4184 * function to identify the new parent Plan node.
4185 *
4186 * The result is the same List passed in; this is a notational convenience.
4187 */
4188List *
4190{
4192
4193 /* Should always have one-entry namespace list for Plan deparsing */
4196
4197 /* Set our attention on the specific plan node passed in */
4198 dpns->ancestors = ancestors;
4200
4201 /* For ModifyTable, set aliases for OLD and NEW in RETURNING */
4202 if (IsA(plan, ModifyTable))
4203 {
4204 dpns->ret_old_alias = ((ModifyTable *) plan)->returningOldAlias;
4205 dpns->ret_new_alias = ((ModifyTable *) plan)->returningNewAlias;
4206 }
4207
4208 return dpcontext;
4209}
4210
4211/*
4212 * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
4213 *
4214 * Determine the relation aliases we'll use during an EXPLAIN operation.
4215 * This is just a frontend to set_rtable_names. We have to expose the aliases
4216 * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
4217 */
4218List *
4220{
4222
4223 memset(&dpns, 0, sizeof(dpns));
4224 dpns.rtable = rtable;
4225 dpns.subplans = NIL;
4226 dpns.ctes = NIL;
4227 dpns.appendrels = NULL;
4229 /* We needn't bother computing column aliases yet */
4230
4231 return dpns.rtable_names;
4232}
4233
4234/*
4235 * set_rtable_names: select RTE aliases to be used in printing a query
4236 *
4237 * We fill in dpns->rtable_names with a list of names that is one-for-one with
4238 * the already-filled dpns->rtable list. Each RTE name is unique among those
4239 * in the new namespace plus any ancestor namespaces listed in
4240 * parent_namespaces.
4241 *
4242 * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
4243 *
4244 * Note that this function is only concerned with relation names, not column
4245 * names.
4246 */
4247static void
4250{
4252 HTAB *names_hash;
4254 bool found;
4255 int rtindex;
4256 ListCell *lc;
4257
4258 dpns->rtable_names = NIL;
4259 /* nothing more to do if empty rtable */
4260 if (dpns->rtable == NIL)
4261 return;
4262
4263 /*
4264 * We use a hash table to hold known names, so that this process is O(N)
4265 * not O(N^2) for N names.
4266 */
4267 hash_ctl.keysize = NAMEDATALEN;
4268 hash_ctl.entrysize = sizeof(NameHashEntry);
4270 names_hash = hash_create("set_rtable_names names",
4271 list_length(dpns->rtable),
4272 &hash_ctl,
4274
4275 /* Preload the hash table with names appearing in parent_namespaces */
4276 foreach(lc, parent_namespaces)
4277 {
4279 ListCell *lc2;
4280
4281 foreach(lc2, olddpns->rtable_names)
4282 {
4283 char *oldname = (char *) lfirst(lc2);
4284
4285 if (oldname == NULL)
4286 continue;
4287 hentry = (NameHashEntry *) hash_search(names_hash,
4288 oldname,
4289 HASH_ENTER,
4290 &found);
4291 /* we do not complain about duplicate names in parent namespaces */
4292 hentry->counter = 0;
4293 }
4294 }
4295
4296 /* Now we can scan the rtable */
4297 rtindex = 1;
4298 foreach(lc, dpns->rtable)
4299 {
4301 char *refname;
4302
4303 /* Just in case this takes an unreasonable amount of time ... */
4305
4306 if (rels_used && !bms_is_member(rtindex, rels_used))
4307 {
4308 /* Ignore unreferenced RTE */
4309 refname = NULL;
4310 }
4311 else if (rte->alias)
4312 {
4313 /* If RTE has a user-defined alias, prefer that */
4314 refname = rte->alias->aliasname;
4315 }
4316 else if (rte->rtekind == RTE_RELATION)
4317 {
4318 /* Use the current actual name of the relation */
4319 refname = get_rel_name(rte->relid);
4320 }
4321 else if (rte->rtekind == RTE_JOIN)
4322 {
4323 /* Unnamed join has no refname */
4324 refname = NULL;
4325 }
4326 else
4327 {
4328 /* Otherwise use whatever the parser assigned */
4329 refname = rte->eref->aliasname;
4330 }
4331
4332 /*
4333 * If the selected name isn't unique, append digits to make it so, and
4334 * make a new hash entry for it once we've got a unique name. For a
4335 * very long input name, we might have to truncate to stay within
4336 * NAMEDATALEN.
4337 */
4338 if (refname)
4339 {
4340 hentry = (NameHashEntry *) hash_search(names_hash,
4341 refname,
4342 HASH_ENTER,
4343 &found);
4344 if (found)
4345 {
4346 /* Name already in use, must choose a new one */
4347 int refnamelen = strlen(refname);
4348 char *modname = (char *) palloc(refnamelen + 16);
4350
4351 do
4352 {
4353 hentry->counter++;
4354 for (;;)
4355 {
4356 memcpy(modname, refname, refnamelen);
4357 sprintf(modname + refnamelen, "_%d", hentry->counter);
4358 if (strlen(modname) < NAMEDATALEN)
4359 break;
4360 /* drop chars from refname to keep all the digits */
4362 refnamelen - 1);
4363 }
4364 hentry2 = (NameHashEntry *) hash_search(names_hash,
4365 modname,
4366 HASH_ENTER,
4367 &found);
4368 } while (found);
4369 hentry2->counter = 0; /* init new hash entry */
4370 refname = modname;
4371 }
4372 else
4373 {
4374 /* Name not previously used, need only initialize hentry */
4375 hentry->counter = 0;
4376 }
4377 }
4378
4379 dpns->rtable_names = lappend(dpns->rtable_names, refname);
4380 rtindex++;
4381 }
4382
4383 hash_destroy(names_hash);
4384}
4385
4386/*
4387 * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
4388 *
4389 * For convenience, this is defined to initialize the deparse_namespace struct
4390 * from scratch.
4391 */
4392static void
4395{
4396 ListCell *lc;
4397 ListCell *lc2;
4398
4399 /* Initialize *dpns and fill rtable/ctes links */
4400 memset(dpns, 0, sizeof(deparse_namespace));
4401 dpns->rtable = query->rtable;
4402 dpns->subplans = NIL;
4403 dpns->ctes = query->cteList;
4404 dpns->appendrels = NULL;
4405 dpns->ret_old_alias = query->returningOldAlias;
4406 dpns->ret_new_alias = query->returningNewAlias;
4407
4408 /* Assign a unique relation alias to each RTE */
4410
4411 /* Initialize dpns->rtable_columns to contain zeroed structs */
4412 dpns->rtable_columns = NIL;
4413 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4414 dpns->rtable_columns = lappend(dpns->rtable_columns,
4415 palloc0(sizeof(deparse_columns)));
4416
4417 /* If it's a utility query, it won't have a jointree */
4418 if (query->jointree)
4419 {
4420 /* Detect whether global uniqueness of USING names is needed */
4421 dpns->unique_using =
4423
4424 /*
4425 * Select names for columns merged by USING, via a recursive pass over
4426 * the query jointree.
4427 */
4428 set_using_names(dpns, (Node *) query->jointree, NIL);
4429 }
4430
4431 /*
4432 * Now assign remaining column aliases for each RTE. We do this in a
4433 * linear scan of the rtable, so as to process RTEs whether or not they
4434 * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
4435 * etc). JOIN RTEs must be processed after their children, but this is
4436 * okay because they appear later in the rtable list than their children
4437 * (cf Asserts in identify_join_columns()).
4438 */
4439 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4440 {
4443
4444 if (rte->rtekind == RTE_JOIN)
4446 else
4448 }
4449}
4450
4451/*
4452 * set_simple_column_names: fill in column aliases for non-query situations
4453 *
4454 * This handles EXPLAIN and cases where we only have relation RTEs. Without
4455 * a join tree, we can't do anything smart about join RTEs, but we don't
4456 * need to, because EXPLAIN should never see join alias Vars anyway.
4457 * If we find a join RTE we'll just skip it, leaving its deparse_columns
4458 * struct all-zero. If somehow we try to deparse a join alias Var, we'll
4459 * error out cleanly because the struct's num_cols will be zero.
4460 */
4461static void
4463{
4464 ListCell *lc;
4465 ListCell *lc2;
4466
4467 /* Initialize dpns->rtable_columns to contain zeroed structs */
4468 dpns->rtable_columns = NIL;
4469 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4470 dpns->rtable_columns = lappend(dpns->rtable_columns,
4471 palloc0(sizeof(deparse_columns)));
4472
4473 /* Assign unique column aliases within each non-join RTE */
4474 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4475 {
4478
4479 if (rte->rtekind != RTE_JOIN)
4481 }
4482}
4483
4484/*
4485 * has_dangerous_join_using: search jointree for unnamed JOIN USING
4486 *
4487 * Merged columns of a JOIN USING may act differently from either of the input
4488 * columns, either because they are merged with COALESCE (in a FULL JOIN) or
4489 * because an implicit coercion of the underlying input column is required.
4490 * In such a case the column must be referenced as a column of the JOIN not as
4491 * a column of either input. And this is problematic if the join is unnamed
4492 * (alias-less): we cannot qualify the column's name with an RTE name, since
4493 * there is none. (Forcibly assigning an alias to the join is not a solution,
4494 * since that will prevent legal references to tables below the join.)
4495 * To ensure that every column in the query is unambiguously referenceable,
4496 * we must assign such merged columns names that are globally unique across
4497 * the whole query, aliasing other columns out of the way as necessary.
4498 *
4499 * Because the ensuing re-aliasing is fairly damaging to the readability of
4500 * the query, we don't do this unless we have to. So, we must pre-scan
4501 * the join tree to see if we have to, before starting set_using_names().
4502 */
4503static bool
4505{
4506 if (IsA(jtnode, RangeTblRef))
4507 {
4508 /* nothing to do here */
4509 }
4510 else if (IsA(jtnode, FromExpr))
4511 {
4512 FromExpr *f = (FromExpr *) jtnode;
4513 ListCell *lc;
4514
4515 foreach(lc, f->fromlist)
4516 {
4518 return true;
4519 }
4520 }
4521 else if (IsA(jtnode, JoinExpr))
4522 {
4523 JoinExpr *j = (JoinExpr *) jtnode;
4524
4525 /* Is it an unnamed JOIN with USING? */
4526 if (j->alias == NULL && j->usingClause)
4527 {
4528 /*
4529 * Yes, so check each join alias var to see if any of them are not
4530 * simple references to underlying columns. If so, we have a
4531 * dangerous situation and must pick unique aliases.
4532 */
4533 RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4534
4535 /* We need only examine the merged columns */
4536 for (int i = 0; i < jrte->joinmergedcols; i++)
4537 {
4538 Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4539
4540 if (!IsA(aliasvar, Var))
4541 return true;
4542 }
4543 }
4544
4545 /* Nope, but inspect children */
4546 if (has_dangerous_join_using(dpns, j->larg))
4547 return true;
4548 if (has_dangerous_join_using(dpns, j->rarg))
4549 return true;
4550 }
4551 else
4552 elog(ERROR, "unrecognized node type: %d",
4553 (int) nodeTag(jtnode));
4554 return false;
4555}
4556
4557/*
4558 * set_using_names: select column aliases to be used for merged USING columns
4559 *
4560 * We do this during a recursive descent of the query jointree.
4561 * dpns->unique_using must already be set to determine the global strategy.
4562 *
4563 * Column alias info is saved in the dpns->rtable_columns list, which is
4564 * assumed to be filled with pre-zeroed deparse_columns structs.
4565 *
4566 * parentUsing is a list of all USING aliases assigned in parent joins of
4567 * the current jointree node. (The passed-in list must not be modified.)
4568 *
4569 * Note that we do not use per-deparse_columns hash tables in this function.
4570 * The number of names that need to be assigned should be small enough that
4571 * we don't need to trouble with that.
4572 */
4573static void
4575{
4576 if (IsA(jtnode, RangeTblRef))
4577 {
4578 /* nothing to do now */
4579 }
4580 else if (IsA(jtnode, FromExpr))
4581 {
4582 FromExpr *f = (FromExpr *) jtnode;
4583 ListCell *lc;
4584
4585 foreach(lc, f->fromlist)
4586 set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4587 }
4588 else if (IsA(jtnode, JoinExpr))
4589 {
4590 JoinExpr *j = (JoinExpr *) jtnode;
4591 RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4593 int *leftattnos;
4594 int *rightattnos;
4597 int i;
4598 ListCell *lc;
4599
4600 /* Get info about the shape of the join */
4602 leftattnos = colinfo->leftattnos;
4603 rightattnos = colinfo->rightattnos;
4604
4605 /* Look up the not-yet-filled-in child deparse_columns structs */
4608
4609 /*
4610 * If this join is unnamed, then we cannot substitute new aliases at
4611 * this level, so any name requirements pushed down to here must be
4612 * pushed down again to the children.
4613 */
4614 if (rte->alias == NULL)
4615 {
4616 for (i = 0; i < colinfo->num_cols; i++)
4617 {
4618 char *colname = colinfo->colnames[i];
4619
4620 if (colname == NULL)
4621 continue;
4622
4623 /* Push down to left column, unless it's a system column */
4624 if (leftattnos[i] > 0)
4625 {
4627 leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4628 }
4629
4630 /* Same on the righthand side */
4631 if (rightattnos[i] > 0)
4632 {
4634 rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4635 }
4636 }
4637 }
4638
4639 /*
4640 * If there's a USING clause, select the USING column names and push
4641 * those names down to the children. We have two strategies:
4642 *
4643 * If dpns->unique_using is true, we force all USING names to be
4644 * unique across the whole query level. In principle we'd only need
4645 * the names of dangerous USING columns to be globally unique, but to
4646 * safely assign all USING names in a single pass, we have to enforce
4647 * the same uniqueness rule for all of them. However, if a USING
4648 * column's name has been pushed down from the parent, we should use
4649 * it as-is rather than making a uniqueness adjustment. This is
4650 * necessary when we're at an unnamed join, and it creates no risk of
4651 * ambiguity. Also, if there's a user-written output alias for a
4652 * merged column, we prefer to use that rather than the input name;
4653 * this simplifies the logic and seems likely to lead to less aliasing
4654 * overall.
4655 *
4656 * If dpns->unique_using is false, we only need USING names to be
4657 * unique within their own join RTE. We still need to honor
4658 * pushed-down names, though.
4659 *
4660 * Though significantly different in results, these two strategies are
4661 * implemented by the same code, with only the difference of whether
4662 * to put assigned names into dpns->using_names.
4663 */
4664 if (j->usingClause)
4665 {
4666 /* Copy the input parentUsing list so we don't modify it */
4667 parentUsing = list_copy(parentUsing);
4668
4669 /* USING names must correspond to the first join output columns */
4671 i = 0;
4672 foreach(lc, j->usingClause)
4673 {
4674 char *colname = strVal(lfirst(lc));
4675
4676 /* Assert it's a merged column */
4677 Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4678
4679 /* Adopt passed-down name if any, else select unique name */
4680 if (colinfo->colnames[i] != NULL)
4681 colname = colinfo->colnames[i];
4682 else
4683 {
4684 /* Prefer user-written output alias if any */
4685 if (rte->alias && i < list_length(rte->alias->colnames))
4686 colname = strVal(list_nth(rte->alias->colnames, i));
4687 /* Make it appropriately unique */
4688 colname = make_colname_unique(colname, dpns, colinfo);
4689 if (dpns->unique_using)
4690 dpns->using_names = lappend(dpns->using_names,
4691 colname);
4692 /* Save it as output column name, too */
4693 colinfo->colnames[i] = colname;
4694 }
4695
4696 /* Remember selected names for use later */
4697 colinfo->usingNames = lappend(colinfo->usingNames, colname);
4698 parentUsing = lappend(parentUsing, colname);
4699
4700 /* Push down to left column, unless it's a system column */
4701 if (leftattnos[i] > 0)
4702 {
4704 leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4705 }
4706
4707 /* Same on the righthand side */
4708 if (rightattnos[i] > 0)
4709 {
4711 rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4712 }
4713
4714 i++;
4715 }
4716 }
4717
4718 /* Mark child deparse_columns structs with correct parentUsing info */
4719 leftcolinfo->parentUsing = parentUsing;
4720 rightcolinfo->parentUsing = parentUsing;
4721
4722 /* Now recursively assign USING column names in children */
4723 set_using_names(dpns, j->larg, parentUsing);
4724 set_using_names(dpns, j->rarg, parentUsing);
4725 }
4726 else
4727 elog(ERROR, "unrecognized node type: %d",
4728 (int) nodeTag(jtnode));
4729}
4730
4731/*
4732 * set_relation_column_names: select column aliases for a non-join RTE
4733 *
4734 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4735 * If any colnames entries are already filled in, those override local
4736 * choices.
4737 */
4738static void
4741{
4742 int ncolumns;
4743 char **real_colnames;
4744 bool changed_any;
4745 int noldcolumns;
4746 int i;
4747 int j;
4748
4749 /*
4750 * Construct an array of the current "real" column names of the RTE.
4751 * real_colnames[] will be indexed by physical column number, with NULL
4752 * entries for dropped columns.
4753 */
4754 if (rte->rtekind == RTE_RELATION)
4755 {
4756 /* Relation --- look to the system catalogs for up-to-date info */
4757 Relation rel;
4758 TupleDesc tupdesc;
4759
4760 rel = relation_open(rte->relid, AccessShareLock);
4761 tupdesc = RelationGetDescr(rel);
4762
4763 ncolumns = tupdesc->natts;
4764 real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4765
4766 for (i = 0; i < ncolumns; i++)
4767 {
4768 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4769
4770 if (attr->attisdropped)
4771 real_colnames[i] = NULL;
4772 else
4773 real_colnames[i] = pstrdup(NameStr(attr->attname));
4774 }
4776 }
4777 else
4778 {
4779 /* Otherwise get the column names from eref or expandRTE() */
4780 List *colnames;
4781 ListCell *lc;
4782
4783 /*
4784 * Functions returning composites have the annoying property that some
4785 * of the composite type's columns might have been dropped since the
4786 * query was parsed. If possible, use expandRTE() to handle that
4787 * case, since it has the tedious logic needed to find out about
4788 * dropped columns. However, if we're explaining a plan, then we
4789 * don't have rte->functions because the planner thinks that won't be
4790 * needed later, and that breaks expandRTE(). So in that case we have
4791 * to rely on rte->eref, which may lead us to report a dropped
4792 * column's old name; that seems close enough for EXPLAIN's purposes.
4793 *
4794 * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4795 * which should be sufficiently up-to-date: no other RTE types can
4796 * have columns get dropped from under them after parsing.
4797 */
4798 if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
4799 {
4800 /* Since we're not creating Vars, rtindex etc. don't matter */
4802 true /* include dropped */ , &colnames, NULL);
4803 }
4804 else
4805 colnames = rte->eref->colnames;
4806
4807 ncolumns = list_length(colnames);
4808 real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4809
4810 i = 0;
4811 foreach(lc, colnames)
4812 {
4813 /*
4814 * If the column name we find here is an empty string, then it's a
4815 * dropped column, so change to NULL.
4816 */
4817 char *cname = strVal(lfirst(lc));
4818
4819 if (cname[0] == '\0')
4820 cname = NULL;
4822 i++;
4823 }
4824 }
4825
4826 /*
4827 * Ensure colinfo->colnames has a slot for each column. (It could be long
4828 * enough already, if we pushed down a name for the last column.) Note:
4829 * it's possible that there are now more columns than there were when the
4830 * query was parsed, ie colnames could be longer than rte->eref->colnames.
4831 * We must assign unique aliases to the new columns too, else there could
4832 * be unresolved conflicts when the view/rule is reloaded.
4833 */
4835 Assert(colinfo->num_cols == ncolumns);
4836
4837 /*
4838 * Make sufficiently large new_colnames and is_new_col arrays, too.
4839 *
4840 * Note: because we leave colinfo->num_new_cols zero until after the loop,
4841 * colname_is_unique will not consult that array, which is fine because it
4842 * would only be duplicate effort.
4843 */
4844 colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4845 colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4846
4847 /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4849
4850 /*
4851 * Scan the columns, select a unique alias for each one, and store it in
4852 * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4853 * entries for dropped columns, the latter omits them. Also mark
4854 * new_colnames entries as to whether they are new since parse time; this
4855 * is the case for entries beyond the length of rte->eref->colnames.
4856 */
4857 noldcolumns = list_length(rte->eref->colnames);
4858 changed_any = false;
4859 j = 0;
4860 for (i = 0; i < ncolumns; i++)
4861 {
4862 char *real_colname = real_colnames[i];
4863 char *colname = colinfo->colnames[i];
4864
4865 /* Skip dropped columns */
4866 if (real_colname == NULL)
4867 {
4868 Assert(colname == NULL); /* colnames[i] is already NULL */
4869 continue;
4870 }
4871
4872 /* If alias already assigned, that's what to use */
4873 if (colname == NULL)
4874 {
4875 /* If user wrote an alias, prefer that over real column name */
4876 if (rte->alias && i < list_length(rte->alias->colnames))
4877 colname = strVal(list_nth(rte->alias->colnames, i));
4878 else
4879 colname = real_colname;
4880
4881 /* Unique-ify and insert into colinfo */
4882 colname = make_colname_unique(colname, dpns, colinfo);
4883
4884 colinfo->colnames[i] = colname;
4885 add_to_names_hash(colinfo, colname);
4886 }
4887
4888 /* Put names of non-dropped columns in new_colnames[] too */
4889 colinfo->new_colnames[j] = colname;
4890 /* And mark them as new or not */
4891 colinfo->is_new_col[j] = (i >= noldcolumns);
4892 j++;
4893
4894 /* Remember if any assigned aliases differ from "real" name */
4895 if (!changed_any && strcmp(colname, real_colname) != 0)
4896 changed_any = true;
4897 }
4898
4899 /* We're now done needing the colinfo's names_hash */
4901
4902 /*
4903 * Set correct length for new_colnames[] array. (Note: if columns have
4904 * been added, colinfo->num_cols includes them, which is not really quite
4905 * right but is harmless, since any new columns must be at the end where
4906 * they won't affect varattnos of pre-existing columns.)
4907 */
4908 colinfo->num_new_cols = j;
4909
4910 /*
4911 * For a relation RTE, we need only print the alias column names if any
4912 * are different from the underlying "real" names. For a function RTE,
4913 * always emit a complete column alias list; this is to protect against
4914 * possible instability of the default column names (eg, from altering
4915 * parameter names). For tablefunc RTEs, we never print aliases, because
4916 * the column names are part of the clause itself. For other RTE types,
4917 * print if we changed anything OR if there were user-written column
4918 * aliases (since the latter would be part of the underlying "reality").
4919 */
4920 if (rte->rtekind == RTE_RELATION)
4921 colinfo->printaliases = changed_any;
4922 else if (rte->rtekind == RTE_FUNCTION)
4923 colinfo->printaliases = true;
4924 else if (rte->rtekind == RTE_TABLEFUNC)
4925 colinfo->printaliases = false;
4926 else if (rte->alias && rte->alias->colnames != NIL)
4927 colinfo->printaliases = true;
4928 else
4929 colinfo->printaliases = changed_any;
4930}
4931
4932/*
4933 * set_join_column_names: select column aliases for a join RTE
4934 *
4935 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4936 * If any colnames entries are already filled in, those override local
4937 * choices. Also, names for USING columns were already chosen by
4938 * set_using_names(). We further expect that column alias selection has been
4939 * completed for both input RTEs.
4940 */
4941static void
4944{
4947 bool changed_any;
4948 int noldcolumns;
4949 int nnewcolumns;
4952 int i;
4953 int j;
4954 int ic;
4955 int jc;
4956
4957 /* Look up the previously-filled-in child deparse_columns structs */
4960
4961 /*
4962 * Ensure colinfo->colnames has a slot for each column. (It could be long
4963 * enough already, if we pushed down a name for the last column.) Note:
4964 * it's possible that one or both inputs now have more columns than there
4965 * were when the query was parsed, but we'll deal with that below. We
4966 * only need entries in colnames for pre-existing columns.
4967 */
4968 noldcolumns = list_length(rte->eref->colnames);
4970 Assert(colinfo->num_cols == noldcolumns);
4971
4972 /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4974
4975 /*
4976 * Scan the join output columns, select an alias for each one, and store
4977 * it in colinfo->colnames. If there are USING columns, set_using_names()
4978 * already selected their names, so we can start the loop at the first
4979 * non-merged column.
4980 */
4981 changed_any = false;
4982 for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4983 {
4984 char *colname = colinfo->colnames[i];
4985 char *real_colname;
4986
4987 /* Join column must refer to at least one input column */
4988 Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4989
4990 /* Get the child column name */
4991 if (colinfo->leftattnos[i] > 0)
4992 real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4993 else if (colinfo->rightattnos[i] > 0)
4994 real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4995 else
4996 {
4997 /* We're joining system columns --- use eref name */
4998 real_colname = strVal(list_nth(rte->eref->colnames, i));
4999 }
5000
5001 /* If child col has been dropped, no need to assign a join colname */
5002 if (real_colname == NULL)
5003 {
5004 colinfo->colnames[i] = NULL;
5005 continue;
5006 }
5007
5008 /* In an unnamed join, just report child column names as-is */
5009 if (rte->alias == NULL)
5010 {
5011 colinfo->colnames[i] = real_colname;
5013 continue;
5014 }
5015
5016 /* If alias already assigned, that's what to use */
5017 if (colname == NULL)
5018 {
5019 /* If user wrote an alias, prefer that over real column name */
5020 if (rte->alias && i < list_length(rte->alias->colnames))
5021 colname = strVal(list_nth(rte->alias->colnames, i));
5022 else
5023 colname = real_colname;
5024
5025 /* Unique-ify and insert into colinfo */
5026 colname = make_colname_unique(colname, dpns, colinfo);
5027
5028 colinfo->colnames[i] = colname;
5029 add_to_names_hash(colinfo, colname);
5030 }
5031
5032 /* Remember if any assigned aliases differ from "real" name */
5033 if (!changed_any && strcmp(colname, real_colname) != 0)
5034 changed_any = true;
5035 }
5036
5037 /*
5038 * Calculate number of columns the join would have if it were re-parsed
5039 * now, and create storage for the new_colnames and is_new_col arrays.
5040 *
5041 * Note: colname_is_unique will be consulting new_colnames[] during the
5042 * loops below, so its not-yet-filled entries must be zeroes.
5043 */
5044 nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
5045 list_length(colinfo->usingNames);
5046 colinfo->num_new_cols = nnewcolumns;
5047 colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
5048 colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
5049
5050 /*
5051 * Generating the new_colnames array is a bit tricky since any new columns
5052 * added since parse time must be inserted in the right places. This code
5053 * must match the parser, which will order a join's columns as merged
5054 * columns first (in USING-clause order), then non-merged columns from the
5055 * left input (in attnum order), then non-merged columns from the right
5056 * input (ditto). If one of the inputs is itself a join, its columns will
5057 * be ordered according to the same rule, which means newly-added columns
5058 * might not be at the end. We can figure out what's what by consulting
5059 * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
5060 *
5061 * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
5062 * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
5063 * meanings for the current child RTE.
5064 */
5065
5066 /* Handle merged columns; they are first and can't be new */
5067 i = j = 0;
5068 while (i < noldcolumns &&
5069 colinfo->leftattnos[i] != 0 &&
5070 colinfo->rightattnos[i] != 0)
5071 {
5072 /* column name is already determined and known unique */
5073 colinfo->new_colnames[j] = colinfo->colnames[i];
5074 colinfo->is_new_col[j] = false;
5075
5076 /* build bitmapsets of child attnums of merged columns */
5077 if (colinfo->leftattnos[i] > 0)
5078 leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
5079 if (colinfo->rightattnos[i] > 0)
5081
5082 i++, j++;
5083 }
5084
5085 /* Handle non-merged left-child columns */
5086 ic = 0;
5087 for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
5088 {
5089 char *child_colname = leftcolinfo->new_colnames[jc];
5090
5091 if (!leftcolinfo->is_new_col[jc])
5092 {
5093 /* Advance ic to next non-dropped old column of left child */
5094 while (ic < leftcolinfo->num_cols &&
5095 leftcolinfo->colnames[ic] == NULL)
5096 ic++;
5097 Assert(ic < leftcolinfo->num_cols);
5098 ic++;
5099 /* If it is a merged column, we already processed it */
5101 continue;
5102 /* Else, advance i to the corresponding existing join column */
5103 while (i < colinfo->num_cols &&
5104 colinfo->colnames[i] == NULL)
5105 i++;
5106 Assert(i < colinfo->num_cols);
5107 Assert(ic == colinfo->leftattnos[i]);
5108 /* Use the already-assigned name of this column */
5109 colinfo->new_colnames[j] = colinfo->colnames[i];
5110 i++;
5111 }
5112 else
5113 {
5114 /*
5115 * Unique-ify the new child column name and assign, unless we're
5116 * in an unnamed join, in which case just copy
5117 */
5118 if (rte->alias != NULL)
5119 {
5120 colinfo->new_colnames[j] =
5122 if (!changed_any &&
5123 strcmp(colinfo->new_colnames[j], child_colname) != 0)
5124 changed_any = true;
5125 }
5126 else
5127 colinfo->new_colnames[j] = child_colname;
5128 add_to_names_hash(colinfo, colinfo->new_colnames[j]);
5129 }
5130
5131 colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
5132 j++;
5133 }
5134
5135 /* Handle non-merged right-child columns in exactly the same way */
5136 ic = 0;
5137 for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
5138 {
5139 char *child_colname = rightcolinfo->new_colnames[jc];
5140
5141 if (!rightcolinfo->is_new_col[jc])
5142 {
5143 /* Advance ic to next non-dropped old column of right child */
5144 while (ic < rightcolinfo->num_cols &&
5145 rightcolinfo->colnames[ic] == NULL)
5146 ic++;
5147 Assert(ic < rightcolinfo->num_cols);
5148 ic++;
5149 /* If it is a merged column, we already processed it */
5151 continue;
5152 /* Else, advance i to the corresponding existing join column */
5153 while (i < colinfo->num_cols &&
5154 colinfo->colnames[i] == NULL)
5155 i++;
5156 Assert(i < colinfo->num_cols);
5157 Assert(ic == colinfo->rightattnos[i]);
5158 /* Use the already-assigned name of this column */
5159 colinfo->new_colnames[j] = colinfo->colnames[i];
5160 i++;
5161 }
5162 else
5163 {
5164 /*
5165 * Unique-ify the new child column name and assign, unless we're
5166 * in an unnamed join, in which case just copy
5167 */
5168 if (rte->alias != NULL)
5169 {
5170 colinfo->new_colnames[j] =
5172 if (!changed_any &&
5173 strcmp(colinfo->new_colnames[j], child_colname) != 0)
5174 changed_any = true;
5175 }
5176 else
5177 colinfo->new_colnames[j] = child_colname;
5178 add_to_names_hash(colinfo, colinfo->new_colnames[j]);
5179 }
5180
5181 colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
5182 j++;
5183 }
5184
5185 /* Assert we processed the right number of columns */
5186#ifdef USE_ASSERT_CHECKING
5187 while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
5188 i++;
5189 Assert(i == colinfo->num_cols);
5190 Assert(j == nnewcolumns);
5191#endif
5192
5193 /* We're now done needing the colinfo's names_hash */
5195
5196 /*
5197 * For a named join, print column aliases if we changed any from the child
5198 * names. Unnamed joins cannot print aliases.
5199 */
5200 if (rte->alias != NULL)
5201 colinfo->printaliases = changed_any;
5202 else
5203 colinfo->printaliases = false;
5204}
5205
5206/*
5207 * colname_is_unique: is colname distinct from already-chosen column names?
5208 *
5209 * dpns is query-wide info, colinfo is for the column's RTE
5210 */
5211static bool
5214{
5215 int i;
5216 ListCell *lc;
5217
5218 /*
5219 * If we have a hash table, consult that instead of linearly scanning the
5220 * colinfo's strings.
5221 */
5222 if (colinfo->names_hash)
5223 {
5224 if (hash_search(colinfo->names_hash,
5225 colname,
5226 HASH_FIND,
5227 NULL) != NULL)
5228 return false;
5229 }
5230 else
5231 {
5232 /* Check against already-assigned column aliases within RTE */
5233 for (i = 0; i < colinfo->num_cols; i++)
5234 {
5235 char *oldname = colinfo->colnames[i];
5236
5237 if (oldname && strcmp(oldname, colname) == 0)
5238 return false;
5239 }
5240
5241 /*
5242 * If we're building a new_colnames array, check that too (this will
5243 * be partially but not completely redundant with the previous checks)
5244 */
5245 for (i = 0; i < colinfo->num_new_cols; i++)
5246 {
5247 char *oldname = colinfo->new_colnames[i];
5248
5249 if (oldname && strcmp(oldname, colname) == 0)
5250 return false;
5251 }
5252
5253 /*
5254 * Also check against names already assigned for parent-join USING
5255 * cols
5256 */
5257 foreach(lc, colinfo->parentUsing)
5258 {
5259 char *oldname = (char *) lfirst(lc);
5260
5261 if (strcmp(oldname, colname) == 0)
5262 return false;
5263 }
5264 }
5265
5266 /*
5267 * Also check against USING-column names that must be globally unique.
5268 * These are not hashed, but there should be few of them.
5269 */
5270 foreach(lc, dpns->using_names)
5271 {
5272 char *oldname = (char *) lfirst(lc);
5273
5274 if (strcmp(oldname, colname) == 0)
5275 return false;
5276 }
5277
5278 return true;
5279}
5280
5281/*
5282 * make_colname_unique: modify colname if necessary to make it unique
5283 *
5284 * dpns is query-wide info, colinfo is for the column's RTE
5285 */
5286static char *
5289{
5290 /*
5291 * If the selected name isn't unique, append digits to make it so. For a
5292 * very long input name, we might have to truncate to stay within
5293 * NAMEDATALEN.
5294 */
5295 if (!colname_is_unique(colname, dpns, colinfo))
5296 {
5297 int colnamelen = strlen(colname);
5298 char *modname = (char *) palloc(colnamelen + 16);
5299 int i = 0;
5300
5301 do
5302 {
5303 i++;
5304 for (;;)
5305 {
5306 memcpy(modname, colname, colnamelen);
5307 sprintf(modname + colnamelen, "_%d", i);
5308 if (strlen(modname) < NAMEDATALEN)
5309 break;
5310 /* drop chars from colname to keep all the digits */
5312 colnamelen - 1);
5313 }
5314 } while (!colname_is_unique(modname, dpns, colinfo));
5315 colname = modname;
5316 }
5317 return colname;
5318}
5319
5320/*
5321 * expand_colnames_array_to: make colinfo->colnames at least n items long
5322 *
5323 * Any added array entries are initialized to zero.
5324 */
5325static void
5327{
5328 if (n > colinfo->num_cols)
5329 {
5330 if (colinfo->colnames == NULL)
5331 colinfo->colnames = palloc0_array(char *, n);
5332 else
5333 colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
5334 colinfo->num_cols = n;
5335 }
5336}
5337
5338/*
5339 * build_colinfo_names_hash: optionally construct a hash table for colinfo
5340 */
5341static void
5343{
5345 int i;
5346 ListCell *lc;
5347
5348 /*
5349 * Use a hash table only for RTEs with at least 32 columns. (The cutoff
5350 * is somewhat arbitrary, but let's choose it so that this code does get
5351 * exercised in the regression tests.)
5352 */
5353 if (colinfo->num_cols < 32)
5354 return;
5355
5356 /*
5357 * Set up the hash table. The entries are just strings with no other
5358 * payload.
5359 */
5360 hash_ctl.keysize = NAMEDATALEN;
5361 hash_ctl.entrysize = NAMEDATALEN;
5363 colinfo->names_hash = hash_create("deparse_columns names",
5364 colinfo->num_cols + colinfo->num_new_cols,
5365 &hash_ctl,
5367
5368 /*
5369 * Preload the hash table with any names already present (these would have
5370 * come from set_using_names).
5371 */
5372 for (i = 0; i < colinfo->num_cols; i++)
5373 {
5374 char *oldname = colinfo->colnames[i];
5375
5376 if (oldname)
5378 }
5379
5380 for (i = 0; i < colinfo->num_new_cols; i++)
5381 {
5382 char *oldname = colinfo->new_colnames[i];
5383
5384 if (oldname)
5386 }
5387
5388 foreach(lc, colinfo->parentUsing)
5389 {
5390 char *oldname = (char *) lfirst(lc);
5391
5393 }
5394}
5395
5396/*
5397 * add_to_names_hash: add a string to the names_hash, if we're using one
5398 */
5399static void
5401{
5402 if (colinfo->names_hash)
5403 (void) hash_search(colinfo->names_hash,
5404 name,
5405 HASH_ENTER,
5406 NULL);
5407}
5408
5409/*
5410 * destroy_colinfo_names_hash: destroy hash table when done with it
5411 */
5412static void
5414{
5415 if (colinfo->names_hash)
5416 {
5417 hash_destroy(colinfo->names_hash);
5418 colinfo->names_hash = NULL;
5419 }
5420}
5421
5422/*
5423 * identify_join_columns: figure out where columns of a join come from
5424 *
5425 * Fills the join-specific fields of the colinfo struct, except for
5426 * usingNames which is filled later.
5427 */
5428static void
5431{
5432 int numjoincols;
5433 int jcolno;
5434 int rcolno;
5435 ListCell *lc;
5436
5437 /* Extract left/right child RT indexes */
5438 if (IsA(j->larg, RangeTblRef))
5439 colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
5440 else if (IsA(j->larg, JoinExpr))
5441 colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
5442 else
5443 elog(ERROR, "unrecognized node type in jointree: %d",
5444 (int) nodeTag(j->larg));
5445 if (IsA(j->rarg, RangeTblRef))
5446 colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
5447 else if (IsA(j->rarg, JoinExpr))
5448 colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
5449 else
5450 elog(ERROR, "unrecognized node type in jointree: %d",
5451 (int) nodeTag(j->rarg));
5452
5453 /* Assert children will be processed earlier than join in second pass */
5454 Assert(colinfo->leftrti < j->rtindex);
5455 Assert(colinfo->rightrti < j->rtindex);
5456
5457 /* Initialize result arrays with zeroes */
5458 numjoincols = list_length(jrte->joinaliasvars);
5459 Assert(numjoincols == list_length(jrte->eref->colnames));
5460 colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
5461 colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
5462
5463 /*
5464 * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
5465 * Recall that the column(s) merged due to USING are the first column(s)
5466 * of the join output. We need not do anything special while scanning
5467 * joinleftcols, but while scanning joinrightcols we must distinguish
5468 * merged from unmerged columns.
5469 */
5470 jcolno = 0;
5471 foreach(lc, jrte->joinleftcols)
5472 {
5473 int leftattno = lfirst_int(lc);
5474
5475 colinfo->leftattnos[jcolno++] = leftattno;
5476 }
5477 rcolno = 0;
5478 foreach(lc, jrte->joinrightcols)
5479 {
5480 int rightattno = lfirst_int(lc);
5481
5482 if (rcolno < jrte->joinmergedcols) /* merged column? */
5483 colinfo->rightattnos[rcolno] = rightattno;
5484 else
5485 colinfo->rightattnos[jcolno++] = rightattno;
5486 rcolno++;
5487 }
5489}
5490
5491/*
5492 * get_rtable_name: convenience function to get a previously assigned RTE alias
5493 *
5494 * The RTE must belong to the topmost namespace level in "context".
5495 */
5496static char *
5497get_rtable_name(int rtindex, deparse_context *context)
5498{
5500
5501 Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
5502 return (char *) list_nth(dpns->rtable_names, rtindex - 1);
5503}
5504
5505/*
5506 * set_deparse_plan: set up deparse_namespace to parse subexpressions
5507 * of a given Plan node
5508 *
5509 * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
5510 * and index_tlist fields. Caller must already have adjusted the ancestors
5511 * list if necessary. Note that the rtable, subplans, and ctes fields do
5512 * not need to change when shifting attention to different plan nodes in a
5513 * single plan tree.
5514 */
5515static void
5517{
5518 dpns->plan = plan;
5519
5520 /*
5521 * We special-case Append and MergeAppend to pretend that the first child
5522 * plan is the OUTER referent; we have to interpret OUTER Vars in their
5523 * tlists according to one of the children, and the first one is the most
5524 * natural choice.
5525 */
5526 if (IsA(plan, Append))
5527 dpns->outer_plan = linitial(((Append *) plan)->appendplans);
5528 else if (IsA(plan, MergeAppend))
5529 dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
5530 else
5531 dpns->outer_plan = outerPlan(plan);
5532
5533 if (dpns->outer_plan)
5534 dpns->outer_tlist = dpns->outer_plan->targetlist;
5535 else
5536 dpns->outer_tlist = NIL;
5537
5538 /*
5539 * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
5540 * use OUTER because that could someday conflict with the normal meaning.)
5541 * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
5542 * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
5543 * that as INNER referent.
5544 *
5545 * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
5546 * INNER referent. This is the join from the target relation to the data
5547 * source, and all INNER_VAR Vars in other parts of the query refer to its
5548 * targetlist.
5549 *
5550 * For ON CONFLICT DO SELECT/UPDATE we just need the inner tlist to point
5551 * to the excluded expression's tlist. (Similar to the SubqueryScan we
5552 * don't want to reuse OUTER, it's used for RETURNING in some modify table
5553 * cases, although not INSERT .. CONFLICT).
5554 */
5555 if (IsA(plan, SubqueryScan))
5556 dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
5557 else if (IsA(plan, CteScan))
5558 dpns->inner_plan = list_nth(dpns->subplans,
5559 ((CteScan *) plan)->ctePlanId - 1);
5560 else if (IsA(plan, WorkTableScan))
5561 dpns->inner_plan = find_recursive_union(dpns,
5562 (WorkTableScan *) plan);
5563 else if (IsA(plan, ModifyTable))
5564 {
5565 if (((ModifyTable *) plan)->operation == CMD_MERGE)
5566 dpns->inner_plan = outerPlan(plan);
5567 else
5568 dpns->inner_plan = plan;
5569 }
5570 else
5571 dpns->inner_plan = innerPlan(plan);
5572
5574 dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5575 else if (dpns->inner_plan)
5576 dpns->inner_tlist = dpns->inner_plan->targetlist;
5577 else
5578 dpns->inner_tlist = NIL;
5579
5580 /* Set up referent for INDEX_VAR Vars, if needed */
5581 if (IsA(plan, IndexOnlyScan))
5582 dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5583 else if (IsA(plan, ForeignScan))
5584 dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5585 else if (IsA(plan, CustomScan))
5586 dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5587 else
5588 dpns->index_tlist = NIL;
5589}
5590
5591/*
5592 * Locate the ancestor plan node that is the RecursiveUnion generating
5593 * the WorkTableScan's work table. We can match on wtParam, since that
5594 * should be unique within the plan tree.
5595 */
5596static Plan *
5598{
5599 ListCell *lc;
5600
5601 foreach(lc, dpns->ancestors)
5602 {
5603 Plan *ancestor = (Plan *) lfirst(lc);
5604
5605 if (IsA(ancestor, RecursiveUnion) &&
5606 ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5607 return ancestor;
5608 }
5609 elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5610 wtscan->wtParam);
5611 return NULL;
5612}
5613
5614/*
5615 * push_child_plan: temporarily transfer deparsing attention to a child plan
5616 *
5617 * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
5618 * deparse context in case the referenced expression itself uses
5619 * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
5620 * affecting levelsup issues (although in a Plan tree there really shouldn't
5621 * be any).
5622 *
5623 * Caller must provide a local deparse_namespace variable to save the
5624 * previous state for pop_child_plan.
5625 */
5626static void
5629{
5630 /* Save state for restoration later */
5631 *save_dpns = *dpns;
5632
5633 /* Link current plan node into ancestors list */
5634 dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5635
5636 /* Set attention on selected child */
5638}
5639
5640/*
5641 * pop_child_plan: undo the effects of push_child_plan
5642 */
5643static void
5645{
5646 List *ancestors;
5647
5648 /* Get rid of ancestors list cell added by push_child_plan */
5649 ancestors = list_delete_first(dpns->ancestors);
5650
5651 /* Restore fields changed by push_child_plan */
5652 *dpns = *save_dpns;
5653
5654 /* Make sure dpns->ancestors is right (may be unnecessary) */
5655 dpns->ancestors = ancestors;
5656}
5657
5658/*
5659 * push_ancestor_plan: temporarily transfer deparsing attention to an
5660 * ancestor plan
5661 *
5662 * When expanding a Param reference, we must adjust the deparse context
5663 * to match the plan node that contains the expression being printed;
5664 * otherwise we'd fail if that expression itself contains a Param or
5665 * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
5666 *
5667 * The target ancestor is conveniently identified by the ListCell holding it
5668 * in dpns->ancestors.
5669 *
5670 * Caller must provide a local deparse_namespace variable to save the
5671 * previous state for pop_ancestor_plan.
5672 */
5673static void
5676{
5678
5679 /* Save state for restoration later */
5680 *save_dpns = *dpns;
5681
5682 /* Build a new ancestor list with just this node's ancestors */
5683 dpns->ancestors =
5684 list_copy_tail(dpns->ancestors,
5685 list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5686
5687 /* Set attention on selected ancestor */
5689}
5690
5691/*
5692 * pop_ancestor_plan: undo the effects of push_ancestor_plan
5693 */
5694static void
5696{
5697 /* Free the ancestor list made in push_ancestor_plan */
5698 list_free(dpns->ancestors);
5699
5700 /* Restore fields changed by push_ancestor_plan */
5701 *dpns = *save_dpns;
5702}
5703
5704
5705/* ----------
5706 * make_ruledef - reconstruct the CREATE RULE command
5707 * for a given pg_rewrite tuple
5708 * ----------
5709 */
5710static void
5712 int prettyFlags)
5713{
5714 char *rulename;
5715 char ev_type;
5716 Oid ev_class;
5717 bool is_instead;
5718 char *ev_qual;
5719 char *ev_action;
5720 List *actions;
5723 int fno;
5724 Datum dat;
5725 bool isnull;
5726
5727 /*
5728 * Get the attribute values from the rules tuple
5729 */
5730 fno = SPI_fnumber(rulettc, "rulename");
5731 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5732 Assert(!isnull);
5733 rulename = NameStr(*(DatumGetName(dat)));
5734
5735 fno = SPI_fnumber(rulettc, "ev_type");
5736 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5737 Assert(!isnull);
5738 ev_type = DatumGetChar(dat);
5739
5740 fno = SPI_fnumber(rulettc, "ev_class");
5741 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5742 Assert(!isnull);
5744
5745 fno = SPI_fnumber(rulettc, "is_instead");
5746 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5747 Assert(!isnull);
5748 is_instead = DatumGetBool(dat);
5749
5750 fno = SPI_fnumber(rulettc, "ev_qual");
5752 Assert(ev_qual != NULL);
5753
5754 fno = SPI_fnumber(rulettc, "ev_action");
5756 Assert(ev_action != NULL);
5757 actions = (List *) stringToNode(ev_action);
5758 if (actions == NIL)
5759 elog(ERROR, "invalid empty ev_action list");
5760
5762
5763 /*
5764 * Build the rules definition text
5765 */
5766 appendStringInfo(buf, "CREATE RULE %s AS",
5767 quote_identifier(rulename));
5768
5769 if (prettyFlags & PRETTYFLAG_INDENT)
5770 appendStringInfoString(buf, "\n ON ");
5771 else
5772 appendStringInfoString(buf, " ON ");
5773
5774 /* The event the rule is fired for */
5775 switch (ev_type)
5776 {
5777 case '1':
5778 appendStringInfoString(buf, "SELECT");
5780 break;
5781
5782 case '2':
5783 appendStringInfoString(buf, "UPDATE");
5784 break;
5785
5786 case '3':
5787 appendStringInfoString(buf, "INSERT");
5788 break;
5789
5790 case '4':
5791 appendStringInfoString(buf, "DELETE");
5792 break;
5793
5794 default:
5795 ereport(ERROR,
5797 errmsg("rule \"%s\" has unsupported event type %d",
5798 rulename, ev_type)));
5799 break;
5800 }
5801
5802 /* The relation the rule is fired on */
5803 appendStringInfo(buf, " TO %s",
5804 (prettyFlags & PRETTYFLAG_SCHEMA) ?
5807
5808 /* If the rule has an event qualification, add it */
5809 if (strcmp(ev_qual, "<>") != 0)
5810 {
5811 Node *qual;
5812 Query *query;
5813 deparse_context context;
5815
5816 if (prettyFlags & PRETTYFLAG_INDENT)
5818 appendStringInfoString(buf, " WHERE ");
5819
5820 qual = stringToNode(ev_qual);
5821
5822 /*
5823 * We need to make a context for recognizing any Vars in the qual
5824 * (which can only be references to OLD and NEW). Use the rtable of
5825 * the first query in the action list for this purpose.
5826 */
5827 query = (Query *) linitial(actions);
5828
5829 /*
5830 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5831 * into the SELECT, and that's what we need to look at. (Ugly kluge
5832 * ... try to fix this when we redesign querytrees.)
5833 */
5834 query = getInsertSelectQuery(query, NULL);
5835
5836 /* Must acquire locks right away; see notes in get_query_def() */
5837 AcquireRewriteLocks(query, false, false);
5838
5839 context.buf = buf;
5840 context.namespaces = list_make1(&dpns);
5841 context.resultDesc = NULL;
5842 context.targetList = NIL;
5843 context.windowClause = NIL;
5844 context.varprefix = (list_length(query->rtable) != 1);
5845 context.prettyFlags = prettyFlags;
5847 context.indentLevel = PRETTYINDENT_STD;
5848 context.colNamesVisible = true;
5849 context.inGroupBy = false;
5850 context.varInOrderBy = false;
5851 context.appendparents = NULL;
5852
5853 set_deparse_for_query(&dpns, query, NIL);
5854
5855 get_rule_expr(qual, &context, false);
5856 }
5857
5858 appendStringInfoString(buf, " DO ");
5859
5860 /* The INSTEAD keyword (if so) */
5861 if (is_instead)
5862 appendStringInfoString(buf, "INSTEAD ");
5863
5864 /* Finally the rules actions */
5865 if (list_length(actions) > 1)
5866 {
5867 ListCell *action;
5868 Query *query;
5869
5871 foreach(action, actions)
5872 {
5873 query = (Query *) lfirst(action);
5874 get_query_def(query, buf, NIL, viewResultDesc, true,
5875 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5876 if (prettyFlags)
5878 else
5880 }
5882 }
5883 else
5884 {
5885 Query *query;
5886
5887 query = (Query *) linitial(actions);
5888 get_query_def(query, buf, NIL, viewResultDesc, true,
5889 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5891 }
5892
5894}
5895
5896
5897/* ----------
5898 * make_viewdef - reconstruct the SELECT part of a
5899 * view rewrite rule
5900 * ----------
5901 */
5902static void
5904 int prettyFlags, int wrapColumn)
5905{
5906 Query *query;
5907 char ev_type;
5908 Oid ev_class;
5909 bool is_instead;
5910 char *ev_qual;
5911 char *ev_action;
5912 List *actions;
5914 int fno;
5915 Datum dat;
5916 bool isnull;
5917
5918 /*
5919 * Get the attribute values from the rules tuple
5920 */
5921 fno = SPI_fnumber(rulettc, "ev_type");
5922 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5923 Assert(!isnull);
5924 ev_type = DatumGetChar(dat);
5925
5926 fno = SPI_fnumber(rulettc, "ev_class");
5927 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5928 Assert(!isnull);
5930
5931 fno = SPI_fnumber(rulettc, "is_instead");
5932 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5933 Assert(!isnull);
5934 is_instead = DatumGetBool(dat);
5935
5936 fno = SPI_fnumber(rulettc, "ev_qual");
5938 Assert(ev_qual != NULL);
5939
5940 fno = SPI_fnumber(rulettc, "ev_action");
5942 Assert(ev_action != NULL);
5943 actions = (List *) stringToNode(ev_action);
5944
5945 if (list_length(actions) != 1)
5946 {
5947 /* keep output buffer empty and leave */
5948 return;
5949 }
5950
5951 query = (Query *) linitial(actions);
5952
5953 if (ev_type != '1' || !is_instead ||
5954 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5955 {
5956 /* keep output buffer empty and leave */
5957 return;
5958 }
5959
5961
5963 prettyFlags, wrapColumn, 0);
5965
5967}
5968
5969
5970/* ----------
5971 * get_query_def - Parse back one query parsetree
5972 *
5973 * query: parsetree to be displayed
5974 * buf: output text is appended to buf
5975 * parentnamespace: list (initially empty) of outer-level deparse_namespace's
5976 * resultDesc: if not NULL, the output tuple descriptor for the view
5977 * represented by a SELECT query. We use the column names from it
5978 * to label SELECT output columns, in preference to names in the query
5979 * colNamesVisible: true if the surrounding context cares about the output
5980 * column names at all (as, for example, an EXISTS() context does not);
5981 * when false, we can suppress dummy column labels such as "?column?"
5982 * prettyFlags: bitmask of PRETTYFLAG_XXX options
5983 * wrapColumn: maximum line length, or -1 to disable wrapping
5984 * startIndent: initial indentation amount
5985 * ----------
5986 */
5987static void
5989 TupleDesc resultDesc, bool colNamesVisible,
5990 int prettyFlags, int wrapColumn, int startIndent)
5991{
5992 deparse_context context;
5994 int rtable_size;
5995
5996 /* Guard against excessively long or deeply-nested queries */
5999
6000 rtable_size = query->hasGroupRTE ?
6001 list_length(query->rtable) - 1 :
6002 list_length(query->rtable);
6003
6004 /*
6005 * Replace any Vars in the query's targetlist and havingQual that
6006 * reference GROUP outputs with the underlying grouping expressions.
6007 *
6008 * We can safely pass NULL for the root here. Preserving varnullingrels
6009 * makes no difference to the deparsed source text.
6010 */
6011 if (query->hasGroupRTE)
6012 {
6013 query->targetList = (List *)
6014 flatten_group_exprs(NULL, query, (Node *) query->targetList);
6015 query->havingQual =
6016 flatten_group_exprs(NULL, query, query->havingQual);
6017 }
6018
6019 /*
6020 * Before we begin to examine the query, acquire locks on referenced
6021 * relations, and fix up deleted columns in JOIN RTEs. This ensures
6022 * consistent results. Note we assume it's OK to scribble on the passed
6023 * querytree!
6024 *
6025 * We are only deparsing the query (we are not about to execute it), so we
6026 * only need AccessShareLock on the relations it mentions.
6027 */
6028 AcquireRewriteLocks(query, false, false);
6029
6030 context.buf = buf;
6032 context.resultDesc = NULL;
6033 context.targetList = NIL;
6034 context.windowClause = NIL;
6035 context.varprefix = (parentnamespace != NIL ||
6036 rtable_size != 1);
6037 context.prettyFlags = prettyFlags;
6038 context.wrapColumn = wrapColumn;
6039 context.indentLevel = startIndent;
6040 context.colNamesVisible = colNamesVisible;
6041 context.inGroupBy = false;
6042 context.varInOrderBy = false;
6043 context.appendparents = NULL;
6044
6046
6047 switch (query->commandType)
6048 {
6049 case CMD_SELECT:
6050 /* We set context.resultDesc only if it's a SELECT */
6051 context.resultDesc = resultDesc;
6052 get_select_query_def(query, &context);
6053 break;
6054
6055 case CMD_UPDATE:
6056 get_update_query_def(query, &context);
6057 break;
6058
6059 case CMD_INSERT:
6060 get_insert_query_def(query, &context);
6061 break;
6062
6063 case CMD_DELETE:
6064 get_delete_query_def(query, &context);
6065 break;
6066
6067 case CMD_MERGE:
6068 get_merge_query_def(query, &context);
6069 break;
6070
6071 case CMD_NOTHING:
6072 appendStringInfoString(buf, "NOTHING");
6073 break;
6074
6075 case CMD_UTILITY:
6076 get_utility_query_def(query, &context);
6077 break;
6078
6079 default:
6080 elog(ERROR, "unrecognized query command type: %d",
6081 query->commandType);
6082 break;
6083 }
6084}
6085
6086/* ----------
6087 * get_values_def - Parse back a VALUES list
6088 * ----------
6089 */
6090static void
6091get_values_def(List *values_lists, deparse_context *context)
6092{
6093 StringInfo buf = context->buf;
6094 bool first_list = true;
6095 ListCell *vtl;
6096
6097 appendStringInfoString(buf, "VALUES ");
6098
6099 foreach(vtl, values_lists)
6100 {
6101 List *sublist = (List *) lfirst(vtl);
6102 bool first_col = true;
6103 ListCell *lc;
6104
6105 if (first_list)
6106 first_list = false;
6107 else
6109
6111 foreach(lc, sublist)
6112 {
6113 Node *col = (Node *) lfirst(lc);
6114
6115 if (first_col)
6116 first_col = false;
6117 else
6119
6120 /*
6121 * Print the value. Whole-row Vars need special treatment.
6122 */
6123 get_rule_expr_toplevel(col, context, false);
6124 }
6126 }
6127}
6128
6129/* ----------
6130 * get_with_clause - Parse back a WITH clause
6131 * ----------
6132 */
6133static void
6135{
6136 StringInfo buf = context->buf;
6137 const char *sep;
6138 ListCell *l;
6139
6140 if (query->cteList == NIL)
6141 return;
6142
6143 if (PRETTY_INDENT(context))
6144 {
6145 context->indentLevel += PRETTYINDENT_STD;
6147 }
6148
6149 if (query->hasRecursive)
6150 sep = "WITH RECURSIVE ";
6151 else
6152 sep = "WITH ";
6153 foreach(l, query->cteList)
6154 {
6156
6159 if (cte->aliascolnames)
6160 {
6161 bool first = true;
6162 ListCell *col;
6163
6165 foreach(col, cte->aliascolnames)
6166 {
6167 if (first)
6168 first = false;
6169 else
6173 }
6175 }
6176 appendStringInfoString(buf, " AS ");
6177 switch (cte->ctematerialized)
6178 {
6180 break;
6182 appendStringInfoString(buf, "MATERIALIZED ");
6183 break;
6185 appendStringInfoString(buf, "NOT MATERIALIZED ");
6186 break;
6187 }
6189 if (PRETTY_INDENT(context))
6190 appendContextKeyword(context, "", 0, 0, 0);
6191 get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
6192 true,
6193 context->prettyFlags, context->wrapColumn,
6194 context->indentLevel);
6195 if (PRETTY_INDENT(context))
6196 appendContextKeyword(context, "", 0, 0, 0);
6198
6199 if (cte->search_clause)
6200 {
6201 bool first = true;
6202 ListCell *lc;
6203
6204 appendStringInfo(buf, " SEARCH %s FIRST BY ",
6205 cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
6206
6207 foreach(lc, cte->search_clause->search_col_list)
6208 {
6209 if (first)
6210 first = false;
6211 else
6215 }
6216
6217 appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
6218 }
6219
6220 if (cte->cycle_clause)
6221 {
6222 bool first = true;
6223 ListCell *lc;
6224
6225 appendStringInfoString(buf, " CYCLE ");
6226
6227 foreach(lc, cte->cycle_clause->cycle_col_list)
6228 {
6229 if (first)
6230 first = false;
6231 else
6235 }
6236
6237 appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
6238
6239 {
6240 Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
6241 Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
6242
6243 if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
6244 cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
6245 {
6246 appendStringInfoString(buf, " TO ");
6247 get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
6248 appendStringInfoString(buf, " DEFAULT ");
6249 get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
6250 }
6251 }
6252
6253 appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
6254 }
6255
6256 sep = ", ";
6257 }
6258
6259 if (PRETTY_INDENT(context))
6260 {
6261 context->indentLevel -= PRETTYINDENT_STD;
6262 appendContextKeyword(context, "", 0, 0, 0);
6263 }
6264 else
6266}
6267
6268/* ----------
6269 * get_select_query_def - Parse back a SELECT parsetree
6270 * ----------
6271 */
6272static void
6274{
6275 StringInfo buf = context->buf;
6276 bool force_colno;
6277 ListCell *l;
6278
6279 /* Insert the WITH clause if given */
6280 get_with_clause(query, context);
6281
6282 /* Subroutines may need to consult the SELECT targetlist and windowClause */
6283 context->targetList = query->targetList;
6284 context->windowClause = query->windowClause;
6285
6286 /*
6287 * If the Query node has a setOperations tree, then it's the top level of
6288 * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
6289 * fields are interesting in the top query itself.
6290 */
6291 if (query->setOperations)
6292 {
6293 get_setop_query(query->setOperations, query, context);
6294 /* ORDER BY clauses must be simple in this case */
6295 force_colno = true;
6296 }
6297 else
6298 {
6299 get_basic_select_query(query, context);
6300 force_colno = false;
6301 }
6302
6303 /* Add the ORDER BY clause if given */
6304 if (query->sortClause != NIL)
6305 {
6306 appendContextKeyword(context, " ORDER BY ",
6308 get_rule_orderby(query->sortClause, query->targetList,
6309 force_colno, context);
6310 }
6311
6312 /*
6313 * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
6314 * standard spelling of LIMIT.
6315 */
6316 if (query->limitOffset != NULL)
6317 {
6318 appendContextKeyword(context, " OFFSET ",
6320 get_rule_expr(query->limitOffset, context, false);
6321 }
6322 if (query->limitCount != NULL)
6323 {
6324 if (query->limitOption == LIMIT_OPTION_WITH_TIES)
6325 {
6326 /*
6327 * The limitCount arg is a c_expr, so it needs parens. Simple
6328 * literals and function expressions would not need parens, but
6329 * unfortunately it's hard to tell if the expression will be
6330 * printed as a simple literal like 123 or as a typecast
6331 * expression, like '-123'::int4. The grammar accepts the former
6332 * without quoting, but not the latter.
6333 */
6334 appendContextKeyword(context, " FETCH FIRST ",
6337 get_rule_expr(query->limitCount, context, false);
6339 appendStringInfoString(buf, " ROWS WITH TIES");
6340 }
6341 else
6342 {
6343 appendContextKeyword(context, " LIMIT ",
6345 if (IsA(query->limitCount, Const) &&
6346 ((Const *) query->limitCount)->constisnull)
6348 else
6349 get_rule_expr(query->limitCount, context, false);
6350 }
6351 }
6352
6353 /* Add FOR [KEY] UPDATE/SHARE clauses if present */
6354 if (query->hasForUpdate)
6355 {
6356 foreach(l, query->rowMarks)
6357 {
6358 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
6359
6360 /* don't print implicit clauses */
6361 if (rc->pushedDown)
6362 continue;
6363
6364 appendContextKeyword(context,
6367
6368 appendStringInfo(buf, " OF %s",
6370 context)));
6371 if (rc->waitPolicy == LockWaitError)
6372 appendStringInfoString(buf, " NOWAIT");
6373 else if (rc->waitPolicy == LockWaitSkip)
6374 appendStringInfoString(buf, " SKIP LOCKED");
6375 }
6376 }
6377}
6378
6379static char *
6381{
6382 switch (strength)
6383 {
6384 case LCS_NONE:
6385 /* we intentionally throw an error for LCS_NONE */
6386 elog(ERROR, "unrecognized LockClauseStrength %d",
6387 (int) strength);
6388 break;
6389 case LCS_FORKEYSHARE:
6390 return " FOR KEY SHARE";
6391 case LCS_FORSHARE:
6392 return " FOR SHARE";
6393 case LCS_FORNOKEYUPDATE:
6394 return " FOR NO KEY UPDATE";
6395 case LCS_FORUPDATE:
6396 return " FOR UPDATE";
6397 }
6398 return NULL; /* keep compiler quiet */
6399}
6400
6401/*
6402 * Detect whether query looks like SELECT ... FROM VALUES(),
6403 * with no need to rename the output columns of the VALUES RTE.
6404 * If so, return the VALUES RTE. Otherwise return NULL.
6405 */
6406static RangeTblEntry *
6408{
6410 ListCell *lc;
6411
6412 /*
6413 * We want to detect a match even if the Query also contains OLD or NEW
6414 * rule RTEs. So the idea is to scan the rtable and see if there is only
6415 * one inFromCl RTE that is a VALUES RTE.
6416 */
6417 foreach(lc, query->rtable)
6418 {
6420
6421 if (rte->rtekind == RTE_VALUES && rte->inFromCl)
6422 {
6423 if (result)
6424 return NULL; /* multiple VALUES (probably not possible) */
6425 result = rte;
6426 }
6427 else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
6428 continue; /* ignore rule entries */
6429 else
6430 return NULL; /* something else -> not simple VALUES */
6431 }
6432
6433 /*
6434 * We don't need to check the targetlist in any great detail, because
6435 * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
6436 * appear inside auto-generated sub-queries with very restricted
6437 * structure. However, DefineView might have modified the tlist by
6438 * injecting new column aliases, or we might have some other column
6439 * aliases forced by a resultDesc. We can only simplify if the RTE's
6440 * column names match the names that get_target_list() would select.
6441 */
6442 if (result)
6443 {
6444 ListCell *lcn;
6445 int colno;
6446
6447 if (list_length(query->targetList) != list_length(result->eref->colnames))
6448 return NULL; /* this probably cannot happen */
6449 colno = 0;
6450 forboth(lc, query->targetList, lcn, result->eref->colnames)
6451 {
6453 char *cname = strVal(lfirst(lcn));
6454 char *colname;
6455
6456 if (tle->resjunk)
6457 return NULL; /* this probably cannot happen */
6458
6459 /* compute name that get_target_list would use for column */
6460 colno++;
6461 if (resultDesc && colno <= resultDesc->natts)
6462 colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6463 else
6464 colname = tle->resname;
6465
6466 /* does it match the VALUES RTE? */
6467 if (colname == NULL || strcmp(colname, cname) != 0)
6468 return NULL; /* column name has been changed */
6469 }
6470 }
6471
6472 return result;
6473}
6474
6475static void
6477{
6478 StringInfo buf = context->buf;
6480 char *sep;
6481 ListCell *l;
6482
6483 if (PRETTY_INDENT(context))
6484 {
6485 context->indentLevel += PRETTYINDENT_STD;
6487 }
6488
6489 /*
6490 * If the query looks like SELECT * FROM (VALUES ...), then print just the
6491 * VALUES part. This reverses what transformValuesClause() did at parse
6492 * time.
6493 */
6494 values_rte = get_simple_values_rte(query, context->resultDesc);
6495 if (values_rte)
6496 {
6497 get_values_def(values_rte->values_lists, context);
6498 return;
6499 }
6500
6501 /*
6502 * Build up the query string - first we say SELECT
6503 */
6504 if (query->isReturn)
6505 appendStringInfoString(buf, "RETURN");
6506 else
6507 appendStringInfoString(buf, "SELECT");
6508
6509 /* Add the DISTINCT clause if given */
6510 if (query->distinctClause != NIL)
6511 {
6512 if (query->hasDistinctOn)
6513 {
6514 appendStringInfoString(buf, " DISTINCT ON (");
6515 sep = "";
6516 foreach(l, query->distinctClause)
6517 {
6519
6521 get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList,
6522 false, context);
6523 sep = ", ";
6524 }
6526 }
6527 else
6528 appendStringInfoString(buf, " DISTINCT");
6529 }
6530
6531 /* Then we tell what to select (the targetlist) */
6532 get_target_list(query->targetList, context);
6533
6534 /* Add the FROM clause if needed */
6535 get_from_clause(query, " FROM ", context);
6536
6537 /* Add the WHERE clause if given */
6538 if (query->jointree->quals != NULL)
6539 {
6540 appendContextKeyword(context, " WHERE ",
6542 get_rule_expr(query->jointree->quals, context, false);
6543 }
6544
6545 /* Add the GROUP BY clause if given */
6546 if (query->groupClause != NULL || query->groupingSets != NULL)
6547 {
6548 bool save_ingroupby;
6549
6550 appendContextKeyword(context, " GROUP BY ",
6552 if (query->groupDistinct)
6553 appendStringInfoString(buf, "DISTINCT ");
6554
6555 save_ingroupby = context->inGroupBy;
6556 context->inGroupBy = true;
6557
6558 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 {
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 else if (ctor->type == JSCTOR_JSON_ARRAY_QUERY)
12285 {
12286 Query *query = castNode(Query, ctor->orig_query);
12287
12288 appendStringInfo(buf, "JSON_ARRAY(");
12289
12290 get_query_def(query, buf, context->namespaces, NULL, false,
12291 context->prettyFlags, context->wrapColumn,
12292 context->indentLevel);
12293
12296
12297 return;
12298 }
12299
12300 switch (ctor->type)
12301 {
12302 case JSCTOR_JSON_OBJECT:
12303 funcname = "JSON_OBJECT";
12304 break;
12305 case JSCTOR_JSON_ARRAY:
12306 funcname = "JSON_ARRAY";
12307 break;
12308 case JSCTOR_JSON_PARSE:
12309 funcname = "JSON";
12310 break;
12311 case JSCTOR_JSON_SCALAR:
12312 funcname = "JSON_SCALAR";
12313 break;
12315 funcname = "JSON_SERIALIZE";
12316 break;
12317 default:
12318 elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
12319 }
12320
12321 appendStringInfo(buf, "%s(", funcname);
12322
12324 foreach(lc, ctor->args)
12325 {
12327 if (curridx > 0)
12328 {
12329 const char *sep;
12330
12331 sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
12333 }
12334
12335 get_rule_expr((Node *) lfirst(lc), context, true);
12336 }
12337
12340}
12341
12342/*
12343 * Append options, if any, to the JSON constructor being deparsed
12344 */
12345static void
12347{
12348 if (ctor->absent_on_null)
12349 {
12350 if (ctor->type == JSCTOR_JSON_OBJECT ||
12351 ctor->type == JSCTOR_JSON_OBJECTAGG)
12352 appendStringInfoString(buf, " ABSENT ON NULL");
12353 }
12354 else
12355 {
12356 if (ctor->type == JSCTOR_JSON_ARRAY ||
12357 ctor->type == JSCTOR_JSON_ARRAYAGG)
12358 appendStringInfoString(buf, " NULL ON NULL");
12359 }
12360
12361 if (ctor->unique)
12362 appendStringInfoString(buf, " WITH UNIQUE KEYS");
12363
12364 /*
12365 * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
12366 * support one.
12367 */
12368 if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
12369 get_json_returning(ctor->returning, buf, true);
12370}
12371
12372/*
12373 * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
12374 */
12375static void
12377 const char *funcname, bool is_json_objectagg)
12378{
12380
12383
12384 if (IsA(ctor->func, Aggref))
12385 get_agg_expr_helper((Aggref *) ctor->func, context,
12386 (Aggref *) ctor->func,
12388 else if (IsA(ctor->func, WindowFunc))
12389 get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
12390 funcname, options.data,
12392 else if (IsA(ctor->func, Var))
12393 {
12394 /*
12395 * If the aggregate is computed by a lower plan node, setrefs.c will
12396 * have replaced the Aggref or WindowFunc with a Var referencing that
12397 * node's output. Chase the Var back to it so we can still print the
12398 * original JSON aggregate syntax. This only happens in EXPLAIN.
12399 */
12400 resolve_special_varno((Node *) ctor->func, context,
12402 }
12403 else
12404 elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
12405 nodeTag(ctor->func));
12406}
12407
12408/*
12409 * Deparse a JsonConstructorExpr whose aggregate is computed by a lower plan
12410 * node; resolve_special_varno has located the underlying Aggref/WindowFunc.
12411 */
12412static void
12414 void *callback_arg)
12415{
12417
12418 if (!IsA(node, Aggref) && !IsA(node, WindowFunc))
12419 elog(ERROR, "JSON aggregate constructor does not point to an Aggref or WindowFunc");
12420
12421 /* Flat copy suffices; we only replace func. */
12422 ctor = *(JsonConstructorExpr *) callback_arg;
12423 ctor.func = (Expr *) node;
12424 get_json_constructor(&ctor, context, false);
12425}
12426
12427/*
12428 * simple_quote_literal - Format a string as a SQL literal, append to buf
12429 */
12430static void
12432{
12433 const char *valptr;
12434
12435 /*
12436 * We always form the string literal according to standard SQL rules.
12437 */
12439 for (valptr = val; *valptr; valptr++)
12440 {
12441 char ch = *valptr;
12442
12443 if (SQL_STR_DOUBLE(ch, false))
12446 }
12448}
12449
12450
12451/* ----------
12452 * get_sublink_expr - Parse back a sublink
12453 * ----------
12454 */
12455static void
12457{
12458 StringInfo buf = context->buf;
12459 Query *query = (Query *) (sublink->subselect);
12460 char *opname = NULL;
12461 bool need_paren;
12462
12463 if (sublink->subLinkType == ARRAY_SUBLINK)
12464 appendStringInfoString(buf, "ARRAY(");
12465 else
12467
12468 /*
12469 * Note that we print the name of only the first operator, when there are
12470 * multiple combining operators. This is an approximation that could go
12471 * wrong in various scenarios (operators in different schemas, renamed
12472 * operators, etc) but there is not a whole lot we can do about it, since
12473 * the syntax allows only one operator to be shown.
12474 */
12475 if (sublink->testexpr)
12476 {
12477 if (IsA(sublink->testexpr, OpExpr))
12478 {
12479 /* single combining operator */
12480 OpExpr *opexpr = (OpExpr *) sublink->testexpr;
12481
12482 get_rule_expr(linitial(opexpr->args), context, true);
12484 exprType(linitial(opexpr->args)),
12485 exprType(lsecond(opexpr->args)));
12486 }
12487 else if (IsA(sublink->testexpr, BoolExpr))
12488 {
12489 /* multiple combining operators, = or <> cases */
12490 char *sep;
12491 ListCell *l;
12492
12494 sep = "";
12495 foreach(l, ((BoolExpr *) sublink->testexpr)->args)
12496 {
12497 OpExpr *opexpr = lfirst_node(OpExpr, l);
12498
12500 get_rule_expr(linitial(opexpr->args), context, true);
12501 if (!opname)
12503 exprType(linitial(opexpr->args)),
12504 exprType(lsecond(opexpr->args)));
12505 sep = ", ";
12506 }
12508 }
12509 else if (IsA(sublink->testexpr, RowCompareExpr))
12510 {
12511 /* multiple combining operators, < <= > >= cases */
12513
12515 get_rule_expr((Node *) rcexpr->largs, context, true);
12517 exprType(linitial(rcexpr->largs)),
12518 exprType(linitial(rcexpr->rargs)));
12520 }
12521 else
12522 elog(ERROR, "unrecognized testexpr type: %d",
12523 (int) nodeTag(sublink->testexpr));
12524 }
12525
12526 need_paren = true;
12527
12528 switch (sublink->subLinkType)
12529 {
12530 case EXISTS_SUBLINK:
12531 appendStringInfoString(buf, "EXISTS ");
12532 break;
12533
12534 case ANY_SUBLINK:
12535 if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
12536 appendStringInfoString(buf, " IN ");
12537 else
12538 appendStringInfo(buf, " %s ANY ", opname);
12539 break;
12540
12541 case ALL_SUBLINK:
12542 appendStringInfo(buf, " %s ALL ", opname);
12543 break;
12544
12545 case ROWCOMPARE_SUBLINK:
12546 appendStringInfo(buf, " %s ", opname);
12547 break;
12548
12549 case EXPR_SUBLINK:
12550 case MULTIEXPR_SUBLINK:
12551 case ARRAY_SUBLINK:
12552 need_paren = false;
12553 break;
12554
12555 case CTE_SUBLINK: /* shouldn't occur in a SubLink */
12556 default:
12557 elog(ERROR, "unrecognized sublink type: %d",
12558 (int) sublink->subLinkType);
12559 break;
12560 }
12561
12562 if (need_paren)
12564
12565 get_query_def(query, buf, context->namespaces, NULL, false,
12566 context->prettyFlags, context->wrapColumn,
12567 context->indentLevel);
12568
12569 if (need_paren)
12571 else
12573}
12574
12575
12576/* ----------
12577 * get_xmltable - Parse back a XMLTABLE function
12578 * ----------
12579 */
12580static void
12582{
12583 StringInfo buf = context->buf;
12584
12585 appendStringInfoString(buf, "XMLTABLE(");
12586
12587 if (tf->ns_uris != NIL)
12588 {
12589 ListCell *lc1,
12590 *lc2;
12591 bool first = true;
12592
12593 appendStringInfoString(buf, "XMLNAMESPACES (");
12594 forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
12595 {
12596 Node *expr = (Node *) lfirst(lc1);
12598
12599 if (!first)
12601 else
12602 first = false;
12603
12604 if (ns_node != NULL)
12605 {
12606 get_rule_expr(expr, context, showimplicit);
12607 appendStringInfo(buf, " AS %s",
12609 }
12610 else
12611 {
12612 appendStringInfoString(buf, "DEFAULT ");
12613 get_rule_expr(expr, context, showimplicit);
12614 }
12615 }
12617 }
12618
12620 get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
12621 appendStringInfoString(buf, ") PASSING (");
12622 get_rule_expr((Node *) tf->docexpr, context, showimplicit);
12624
12625 if (tf->colexprs != NIL)
12626 {
12627 ListCell *l1;
12628 ListCell *l2;
12629 ListCell *l3;
12630 ListCell *l4;
12631 ListCell *l5;
12632 int colnum = 0;
12633
12634 appendStringInfoString(buf, " COLUMNS ");
12635 forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
12636 l4, tf->colexprs, l5, tf->coldefexprs)
12637 {
12638 char *colname = strVal(lfirst(l1));
12639 Oid typid = lfirst_oid(l2);
12640 int32 typmod = lfirst_int(l3);
12641 Node *colexpr = (Node *) lfirst(l4);
12642 Node *coldefexpr = (Node *) lfirst(l5);
12643 bool ordinality = (tf->ordinalitycol == colnum);
12644 bool notnull = bms_is_member(colnum, tf->notnulls);
12645
12646 if (colnum > 0)
12648 colnum++;
12649
12650 appendStringInfo(buf, "%s %s", quote_identifier(colname),
12651 ordinality ? "FOR ORDINALITY" :
12652 format_type_with_typemod(typid, typmod));
12653 if (ordinality)
12654 continue;
12655
12656 if (coldefexpr != NULL)
12657 {
12658 appendStringInfoString(buf, " DEFAULT (");
12659 get_rule_expr((Node *) coldefexpr, context, showimplicit);
12661 }
12662 if (colexpr != NULL)
12663 {
12664 appendStringInfoString(buf, " PATH (");
12665 get_rule_expr((Node *) colexpr, context, showimplicit);
12667 }
12668 if (notnull)
12669 appendStringInfoString(buf, " NOT NULL");
12670 }
12671 }
12672
12674}
12675
12676/*
12677 * get_json_table_nested_columns - Parse back nested JSON_TABLE columns
12678 */
12679static void
12681 deparse_context *context, bool showimplicit,
12682 bool needcomma)
12683{
12685 {
12687
12688 if (needcomma)
12689 appendStringInfoChar(context->buf, ',');
12690
12691 appendStringInfoChar(context->buf, ' ');
12692 appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
12693 get_const_expr(scan->path->value, context, -1);
12694 appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
12695 get_json_table_columns(tf, scan, context, showimplicit);
12696 }
12697 else if (IsA(plan, JsonTableSiblingJoin))
12698 {
12700
12702 needcomma);
12704 true);
12705 }
12706}
12707
12708/*
12709 * json_table_plan_is_default - does this plan match the implicit default?
12710 *
12711 * When no PLAN clause is given, JSON_TABLE builds a default plan that joins
12712 * every nested path to its parent with OUTER and every set of sibling paths
12713 * with UNION (see transformJsonTableColumns()). Such a plan is fully implied
12714 * by the NESTED COLUMNS structure, so we need not (and, to match the input,
12715 * should not) print a PLAN clause for it; we only deparse a PLAN clause when
12716 * the plan deviates from the default, i.e. uses an INNER or CROSS join
12717 * somewhere. This follows the usual ruleutils convention of omitting a clause
12718 * that merely restates the default (cf. get_json_expr_options() for ON
12719 * EMPTY/ON ERROR, or the NULLS FIRST/LAST handling in get_rule_orderby()).
12720 */
12721static bool
12723{
12725 {
12727
12728 if (scan->child)
12729 {
12730 if (!scan->outerJoin)
12731 return false; /* INNER is not the default */
12732 return json_table_plan_is_default(scan->child);
12733 }
12734
12735 return true;
12736 }
12737 else
12738 {
12740
12741 if (join->cross)
12742 return false; /* CROSS is not the default */
12743 return json_table_plan_is_default(join->lplan) &&
12745 }
12746}
12747
12748/*
12749 * get_json_table_plan - Parse back a JSON_TABLE plan
12750 */
12751static void
12753 bool parenthesize)
12754{
12755 if (parenthesize)
12756 appendStringInfoChar(context->buf, '(');
12757
12759 {
12761
12763
12764 if (s->child)
12765 {
12766 appendStringInfoString(context->buf,
12767 s->outerJoin ? " OUTER " : " INNER ");
12768 get_json_table_plan(tf, s->child, context,
12770 castNode(JsonTablePathScan, s->child)->child);
12771 }
12772 }
12773 else if (IsA(plan, JsonTableSiblingJoin))
12774 {
12776
12777 get_json_table_plan(tf, j->lplan, context,
12778 IsA(j->lplan, JsonTableSiblingJoin) ||
12779 castNode(JsonTablePathScan, j->lplan)->child);
12780
12781 appendStringInfoString(context->buf, j->cross ? " CROSS " : " UNION ");
12782
12783 get_json_table_plan(tf, j->rplan, context,
12784 IsA(j->rplan, JsonTableSiblingJoin) ||
12785 castNode(JsonTablePathScan, j->rplan)->child);
12786 }
12787
12788 if (parenthesize)
12789 appendStringInfoChar(context->buf, ')');
12790}
12791
12792/*
12793 * get_json_table_columns - Parse back JSON_TABLE columns
12794 */
12795static void
12797 deparse_context *context,
12798 bool showimplicit)
12799{
12800 StringInfo buf = context->buf;
12805 int colnum = 0;
12806
12808 appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
12809
12810 if (PRETTY_INDENT(context))
12811 context->indentLevel += PRETTYINDENT_VAR;
12812
12813 forfour(lc_colname, tf->colnames,
12814 lc_coltype, tf->coltypes,
12815 lc_coltypmod, tf->coltypmods,
12816 lc_colvalexpr, tf->colvalexprs)
12817 {
12818 char *colname = strVal(lfirst(lc_colname));
12819 JsonExpr *colexpr;
12820 Oid typid;
12821 int32 typmod;
12822 bool ordinality;
12824
12825 typid = lfirst_oid(lc_coltype);
12826 typmod = lfirst_int(lc_coltypmod);
12828
12829 /* Skip columns that don't belong to this scan. */
12830 if (scan->colMin < 0 || colnum < scan->colMin)
12831 {
12832 colnum++;
12833 continue;
12834 }
12835 if (colnum > scan->colMax)
12836 break;
12837
12838 if (colnum > scan->colMin)
12840
12841 colnum++;
12842
12843 ordinality = !colexpr;
12844
12845 appendContextKeyword(context, "", 0, 0, 0);
12846
12847 appendStringInfo(buf, "%s %s", quote_identifier(colname),
12848 ordinality ? "FOR ORDINALITY" :
12849 format_type_with_typemod(typid, typmod));
12850 if (ordinality)
12851 continue;
12852
12853 /*
12854 * Set default_behavior to guide get_json_expr_options() on whether to
12855 * emit the ON ERROR / EMPTY clauses.
12856 */
12857 if (colexpr->op == JSON_EXISTS_OP)
12858 {
12859 appendStringInfoString(buf, " EXISTS");
12861 }
12862 else
12863 {
12864 if (colexpr->op == JSON_QUERY_OP)
12865 {
12866 char typcategory;
12867 bool typispreferred;
12868
12870
12873 colexpr->format->format_type == JS_FORMAT_JSONB ?
12874 " FORMAT JSONB" : " FORMAT JSON");
12875 }
12876
12878 }
12879
12880 appendStringInfoString(buf, " PATH ");
12881
12882 get_json_path_spec(colexpr->path_spec, context, showimplicit);
12883
12884 get_json_expr_options(colexpr, context, default_behavior);
12885 }
12886
12887 if (scan->child)
12889 scan->colMin >= 0);
12890
12891 if (PRETTY_INDENT(context))
12892 context->indentLevel -= PRETTYINDENT_VAR;
12893
12894 appendContextKeyword(context, ")", 0, 0, 0);
12895}
12896
12897/* ----------
12898 * get_json_table - Parse back a JSON_TABLE function
12899 * ----------
12900 */
12901static void
12903{
12904 StringInfo buf = context->buf;
12907
12908 appendStringInfoString(buf, "JSON_TABLE(");
12909
12910 if (PRETTY_INDENT(context))
12911 context->indentLevel += PRETTYINDENT_VAR;
12912
12913 appendContextKeyword(context, "", 0, 0, 0);
12914
12915 get_rule_expr(jexpr->formatted_expr, context, showimplicit);
12916
12918
12919 get_const_expr(root->path->value, context, -1);
12920
12921 appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
12922
12923 if (jexpr->passing_values)
12924 {
12925 ListCell *lc1,
12926 *lc2;
12927 bool needcomma = false;
12928
12930 appendContextKeyword(context, "PASSING ", 0, 0, 0);
12931
12932 if (PRETTY_INDENT(context))
12933 context->indentLevel += PRETTYINDENT_VAR;
12934
12935 forboth(lc1, jexpr->passing_names,
12936 lc2, jexpr->passing_values)
12937 {
12938 if (needcomma)
12940 needcomma = true;
12941
12942 appendContextKeyword(context, "", 0, 0, 0);
12943
12944 get_rule_expr((Node *) lfirst(lc2), context, false);
12945 appendStringInfo(buf, " AS %s",
12947 );
12948 }
12949
12950 if (PRETTY_INDENT(context))
12951 context->indentLevel -= PRETTYINDENT_VAR;
12952 }
12953
12954 get_json_table_columns(tf, castNode(JsonTablePathScan, tf->plan), context,
12955 showimplicit);
12956
12957 /*
12958 * Deparse a PLAN clause only for a non-default plan; the default plan is
12959 * implied by the NESTED COLUMNS structure (see
12960 * json_table_plan_is_default).
12961 */
12963 {
12965 appendContextKeyword(context, "PLAN ", 0, 0, 0);
12966 get_json_table_plan(tf, (JsonTablePlan *) root, context, true);
12967 }
12968
12969 if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY_ARRAY)
12970 get_json_behavior(jexpr->on_error, context, "ERROR");
12971
12972 if (PRETTY_INDENT(context))
12973 context->indentLevel -= PRETTYINDENT_VAR;
12974
12975 appendContextKeyword(context, ")", 0, 0, 0);
12976}
12977
12978/* ----------
12979 * get_tablefunc - Parse back a table function
12980 * ----------
12981 */
12982static void
12984{
12985 /* XMLTABLE and JSON_TABLE are the only existing implementations. */
12986
12987 if (tf->functype == TFT_XMLTABLE)
12988 get_xmltable(tf, context, showimplicit);
12989 else if (tf->functype == TFT_JSON_TABLE)
12990 get_json_table(tf, context, showimplicit);
12991}
12992
12993/* ----------
12994 * get_from_clause - Parse back a FROM clause
12995 *
12996 * "prefix" is the keyword that denotes the start of the list of FROM
12997 * elements. It is FROM when used to parse back SELECT and UPDATE, but
12998 * is USING when parsing back DELETE.
12999 * ----------
13000 */
13001static void
13002get_from_clause(Query *query, const char *prefix, deparse_context *context)
13003{
13004 StringInfo buf = context->buf;
13005 bool first = true;
13006 ListCell *l;
13007
13008 /*
13009 * We use the query's jointree as a guide to what to print. However, we
13010 * must ignore auto-added RTEs that are marked not inFromCl. (These can
13011 * only appear at the top level of the jointree, so it's sufficient to
13012 * check here.) This check also ensures we ignore the rule pseudo-RTEs
13013 * for NEW and OLD.
13014 */
13015 foreach(l, query->jointree->fromlist)
13016 {
13017 Node *jtnode = (Node *) lfirst(l);
13018
13019 if (IsA(jtnode, RangeTblRef))
13020 {
13021 int varno = ((RangeTblRef *) jtnode)->rtindex;
13022 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
13023
13024 if (!rte->inFromCl)
13025 continue;
13026 }
13027
13028 if (first)
13029 {
13030 appendContextKeyword(context, prefix,
13032 first = false;
13033
13034 get_from_clause_item(jtnode, query, context);
13035 }
13036 else
13037 {
13039
13041
13042 /*
13043 * Put the new FROM item's text into itembuf so we can decide
13044 * after we've got it whether or not it needs to go on a new line.
13045 */
13047 context->buf = &itembuf;
13048
13049 get_from_clause_item(jtnode, query, context);
13050
13051 /* Restore context's output buffer */
13052 context->buf = buf;
13053
13054 /* Consider line-wrapping if enabled */
13055 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
13056 {
13057 /* Does the new item start with a new line? */
13058 if (itembuf.len > 0 && itembuf.data[0] == '\n')
13059 {
13060 /* If so, we shouldn't add anything */
13061 /* instead, remove any trailing spaces currently in buf */
13063 }
13064 else
13065 {
13066 char *trailing_nl;
13067
13068 /* Locate the start of the current line in the buffer */
13069 trailing_nl = strrchr(buf->data, '\n');
13070 if (trailing_nl == NULL)
13071 trailing_nl = buf->data;
13072 else
13073 trailing_nl++;
13074
13075 /*
13076 * Add a newline, plus some indentation, if the new item
13077 * would cause an overflow.
13078 */
13079 if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
13083 }
13084 }
13085
13086 /* Add the new item */
13088
13089 /* clean up */
13090 pfree(itembuf.data);
13091 }
13092 }
13093}
13094
13095static void
13097{
13098 StringInfo buf = context->buf;
13100
13101 if (IsA(jtnode, RangeTblRef))
13102 {
13103 int varno = ((RangeTblRef *) jtnode)->rtindex;
13104 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
13107
13108 if (rte->lateral)
13109 appendStringInfoString(buf, "LATERAL ");
13110
13111 /* Print the FROM item proper */
13112 switch (rte->rtekind)
13113 {
13114 case RTE_RELATION:
13115 /* Normal relation RTE */
13116 appendStringInfo(buf, "%s%s",
13119 context->namespaces));
13120 break;
13121 case RTE_SUBQUERY:
13122 /* Subquery RTE */
13124 get_query_def(rte->subquery, buf, context->namespaces, NULL,
13125 true,
13126 context->prettyFlags, context->wrapColumn,
13127 context->indentLevel);
13129 break;
13130 case RTE_FUNCTION:
13131 /* Function RTE */
13132 rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
13133
13134 /*
13135 * Omit ROWS FROM() syntax for just one function, unless it
13136 * has both a coldeflist and WITH ORDINALITY. If it has both,
13137 * we must use ROWS FROM() syntax to avoid ambiguity about
13138 * whether the coldeflist includes the ordinality column.
13139 */
13140 if (list_length(rte->functions) == 1 &&
13141 (rtfunc1->funccolnames == NIL || !rte->funcordinality))
13142 {
13143 get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
13144 /* we'll print the coldeflist below, if it has one */
13145 }
13146 else
13147 {
13148 bool all_unnest;
13149 ListCell *lc;
13150
13151 /*
13152 * If all the function calls in the list are to unnest,
13153 * and none need a coldeflist, then collapse the list back
13154 * down to UNNEST(args). (If we had more than one
13155 * built-in unnest function, this would get more
13156 * difficult.)
13157 *
13158 * XXX This is pretty ugly, since it makes not-terribly-
13159 * future-proof assumptions about what the parser would do
13160 * with the output; but the alternative is to emit our
13161 * nonstandard ROWS FROM() notation for what might have
13162 * been a perfectly spec-compliant multi-argument
13163 * UNNEST().
13164 */
13165 all_unnest = true;
13166 foreach(lc, rte->functions)
13167 {
13169
13170 if (!IsA(rtfunc->funcexpr, FuncExpr) ||
13171 ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
13172 rtfunc->funccolnames != NIL)
13173 {
13174 all_unnest = false;
13175 break;
13176 }
13177 }
13178
13179 if (all_unnest)
13180 {
13181 List *allargs = NIL;
13182
13183 foreach(lc, rte->functions)
13184 {
13186 List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
13187
13188 allargs = list_concat(allargs, args);
13189 }
13190
13191 appendStringInfoString(buf, "UNNEST(");
13192 get_rule_expr((Node *) allargs, context, true);
13194 }
13195 else
13196 {
13197 int funcno = 0;
13198
13199 appendStringInfoString(buf, "ROWS FROM(");
13200 foreach(lc, rte->functions)
13201 {
13203
13204 if (funcno > 0)
13206 get_rule_expr_funccall(rtfunc->funcexpr, context, true);
13207 if (rtfunc->funccolnames != NIL)
13208 {
13209 /* Reconstruct the column definition list */
13210 appendStringInfoString(buf, " AS ");
13212 NULL,
13213 context);
13214 }
13215 funcno++;
13216 }
13218 }
13219 /* prevent printing duplicate coldeflist below */
13220 rtfunc1 = NULL;
13221 }
13222 if (rte->funcordinality)
13223 appendStringInfoString(buf, " WITH ORDINALITY");
13224 break;
13225 case RTE_TABLEFUNC:
13226 get_tablefunc(rte->tablefunc, context, true);
13227 break;
13228 case RTE_GRAPH_TABLE:
13229 appendStringInfoString(buf, "GRAPH_TABLE (");
13231 appendStringInfoString(buf, " MATCH ");
13232 get_graph_pattern_def(rte->graph_pattern, context);
13233 appendStringInfoString(buf, " COLUMNS (");
13234 {
13235 bool first = true;
13236
13237 foreach_node(TargetEntry, te, rte->graph_table_columns)
13238 {
13239 if (!first)
13241 else
13242 first = false;
13243
13244 get_rule_expr((Node *) te->expr, context, false);
13245 appendStringInfoString(buf, " AS ");
13247 }
13248 }
13250 break;
13251 case RTE_VALUES:
13252 /* Values list RTE */
13254 get_values_def(rte->values_lists, context);
13256 break;
13257 case RTE_CTE:
13259 break;
13260 default:
13261 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
13262 break;
13263 }
13264
13265 /* Print the relation alias, if needed */
13266 get_rte_alias(rte, varno, false, context);
13267
13268 /* Print the column definitions or aliases, if needed */
13269 if (rtfunc1 && rtfunc1->funccolnames != NIL)
13270 {
13271 /* Reconstruct the columndef list, which is also the aliases */
13273 }
13274 else
13275 {
13276 /* Else print column aliases as needed */
13278 }
13279
13280 /* Tablesample clause must go after any alias */
13281 if (rte->rtekind == RTE_RELATION && rte->tablesample)
13282 get_tablesample_def(rte->tablesample, context);
13283 }
13284 else if (IsA(jtnode, JoinExpr))
13285 {
13286 JoinExpr *j = (JoinExpr *) jtnode;
13289
13290 need_paren_on_right = PRETTY_PAREN(context) &&
13291 !IsA(j->rarg, RangeTblRef) &&
13292 !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
13293
13294 if (!PRETTY_PAREN(context) || j->alias != NULL)
13296
13297 get_from_clause_item(j->larg, query, context);
13298
13299 switch (j->jointype)
13300 {
13301 case JOIN_INNER:
13302 if (j->quals)
13303 appendContextKeyword(context, " JOIN ",
13307 else
13308 appendContextKeyword(context, " CROSS JOIN ",
13312 break;
13313 case JOIN_LEFT:
13314 appendContextKeyword(context, " LEFT JOIN ",
13318 break;
13319 case JOIN_FULL:
13320 appendContextKeyword(context, " FULL JOIN ",
13324 break;
13325 case JOIN_RIGHT:
13326 appendContextKeyword(context, " RIGHT JOIN ",
13330 break;
13331 default:
13332 elog(ERROR, "unrecognized join type: %d",
13333 (int) j->jointype);
13334 }
13335
13338 get_from_clause_item(j->rarg, query, context);
13341
13342 if (j->usingClause)
13343 {
13344 ListCell *lc;
13345 bool first = true;
13346
13347 appendStringInfoString(buf, " USING (");
13348 /* Use the assigned names, not what's in usingClause */
13349 foreach(lc, colinfo->usingNames)
13350 {
13351 char *colname = (char *) lfirst(lc);
13352
13353 if (first)
13354 first = false;
13355 else
13358 }
13360
13361 if (j->join_using_alias)
13362 appendStringInfo(buf, " AS %s",
13363 quote_identifier(j->join_using_alias->aliasname));
13364 }
13365 else if (j->quals)
13366 {
13367 appendStringInfoString(buf, " ON ");
13368 if (!PRETTY_PAREN(context))
13370 get_rule_expr(j->quals, context, false);
13371 if (!PRETTY_PAREN(context))
13373 }
13374 else if (j->jointype != JOIN_INNER)
13375 {
13376 /* If we didn't say CROSS JOIN above, we must provide an ON */
13377 appendStringInfoString(buf, " ON TRUE");
13378 }
13379
13380 if (!PRETTY_PAREN(context) || j->alias != NULL)
13382
13383 /* Yes, it's correct to put alias after the right paren ... */
13384 if (j->alias != NULL)
13385 {
13386 /*
13387 * Note that it's correct to emit an alias clause if and only if
13388 * there was one originally. Otherwise we'd be converting a named
13389 * join to unnamed or vice versa, which creates semantic
13390 * subtleties we don't want. However, we might print a different
13391 * alias name than was there originally.
13392 */
13393 appendStringInfo(buf, " %s",
13395 context)));
13397 }
13398 }
13399 else
13400 elog(ERROR, "unrecognized node type: %d",
13401 (int) nodeTag(jtnode));
13402}
13403
13404/*
13405 * get_rte_alias - print the relation's alias, if needed
13406 *
13407 * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
13408 */
13409static void
13411 deparse_context *context)
13412{
13414 char *refname = get_rtable_name(varno, context);
13416 bool printalias = false;
13417
13418 if (rte->alias != NULL)
13419 {
13420 /* Always print alias if user provided one */
13421 printalias = true;
13422 }
13423 else if (colinfo->printaliases)
13424 {
13425 /* Always print alias if we need to print column aliases */
13426 printalias = true;
13427 }
13428 else if (rte->rtekind == RTE_RELATION)
13429 {
13430 /*
13431 * No need to print alias if it's same as relation name (this would
13432 * normally be the case, but not if set_rtable_names had to resolve a
13433 * conflict).
13434 */
13435 if (strcmp(refname, get_relation_name(rte->relid)) != 0)
13436 printalias = true;
13437 }
13438 else if (rte->rtekind == RTE_FUNCTION)
13439 {
13440 /*
13441 * For a function RTE, always print alias. This covers possible
13442 * renaming of the function and/or instability of the FigureColname
13443 * rules for things that aren't simple functions. Note we'd need to
13444 * force it anyway for the columndef list case.
13445 */
13446 printalias = true;
13447 }
13448 else if (rte->rtekind == RTE_SUBQUERY ||
13449 rte->rtekind == RTE_VALUES)
13450 {
13451 /*
13452 * For a subquery, always print alias. This makes the output
13453 * SQL-spec-compliant, even though we allow such aliases to be omitted
13454 * on input.
13455 */
13456 printalias = true;
13457 }
13458 else if (rte->rtekind == RTE_CTE)
13459 {
13460 /*
13461 * No need to print alias if it's same as CTE name (this would
13462 * normally be the case, but not if set_rtable_names had to resolve a
13463 * conflict).
13464 */
13465 if (strcmp(refname, rte->ctename) != 0)
13466 printalias = true;
13467 }
13468
13469 if (printalias)
13470 appendStringInfo(context->buf, "%s%s",
13471 use_as ? " AS " : " ",
13472 quote_identifier(refname));
13473}
13474
13475/*
13476 * get_for_portion_of - print FOR PORTION OF if needed
13477 * XXX: Newlines would help here, at least when pretty-printing. But then the
13478 * alias and SET will be on their own line with a leading space.
13479 */
13480static void
13482{
13483 if (forPortionOf)
13484 {
13485 appendStringInfo(context->buf, " FOR PORTION OF %s",
13486 quote_identifier(forPortionOf->range_name));
13487
13488 /*
13489 * Try to write it as FROM ... TO ... if we received it that way,
13490 * otherwise (targetRange).
13491 */
13492 if (forPortionOf->targetFrom && forPortionOf->targetTo)
13493 {
13494 appendStringInfoString(context->buf, " FROM ");
13495 get_rule_expr(forPortionOf->targetFrom, context, false);
13496 appendStringInfoString(context->buf, " TO ");
13497 get_rule_expr(forPortionOf->targetTo, context, false);
13498 }
13499 else
13500 {
13501 appendStringInfoString(context->buf, " (");
13502 get_rule_expr(forPortionOf->targetRange, context, false);
13503 appendStringInfoChar(context->buf, ')');
13504 }
13505 }
13506}
13507
13508/*
13509 * get_column_alias_list - print column alias list for an RTE
13510 *
13511 * Caller must already have printed the relation's alias name.
13512 */
13513static void
13515{
13516 StringInfo buf = context->buf;
13517 int i;
13518 bool first = true;
13519
13520 /* Don't print aliases if not needed */
13521 if (!colinfo->printaliases)
13522 return;
13523
13524 for (i = 0; i < colinfo->num_new_cols; i++)
13525 {
13526 char *colname = colinfo->new_colnames[i];
13527
13528 if (first)
13529 {
13531 first = false;
13532 }
13533 else
13536 }
13537 if (!first)
13539}
13540
13541/*
13542 * get_from_clause_coldeflist - reproduce FROM clause coldeflist
13543 *
13544 * When printing a top-level coldeflist (which is syntactically also the
13545 * relation's column alias list), use column names from colinfo. But when
13546 * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
13547 * original coldeflist's names, which are available in rtfunc->funccolnames.
13548 * Pass NULL for colinfo to select the latter behavior.
13549 *
13550 * The coldeflist is appended immediately (no space) to buf. Caller is
13551 * responsible for ensuring that an alias or AS is present before it.
13552 */
13553static void
13556 deparse_context *context)
13557{
13558 StringInfo buf = context->buf;
13559 ListCell *l1;
13560 ListCell *l2;
13561 ListCell *l3;
13562 ListCell *l4;
13563 int i;
13564
13566
13567 i = 0;
13568 forfour(l1, rtfunc->funccoltypes,
13569 l2, rtfunc->funccoltypmods,
13570 l3, rtfunc->funccolcollations,
13571 l4, rtfunc->funccolnames)
13572 {
13573 Oid atttypid = lfirst_oid(l1);
13574 int32 atttypmod = lfirst_int(l2);
13575 Oid attcollation = lfirst_oid(l3);
13576 char *attname;
13577
13578 if (colinfo)
13579 attname = colinfo->colnames[i];
13580 else
13581 attname = strVal(lfirst(l4));
13582
13583 Assert(attname); /* shouldn't be any dropped columns here */
13584
13585 if (i > 0)
13587 appendStringInfo(buf, "%s %s",
13589 format_type_with_typemod(atttypid, atttypmod));
13590 if (OidIsValid(attcollation) &&
13591 attcollation != get_typcollation(atttypid))
13592 appendStringInfo(buf, " COLLATE %s",
13593 generate_collation_name(attcollation));
13594
13595 i++;
13596 }
13597
13599}
13600
13601/*
13602 * get_tablesample_def - print a TableSampleClause
13603 */
13604static void
13606{
13607 StringInfo buf = context->buf;
13608 Oid argtypes[1];
13609 int nargs;
13610 ListCell *l;
13611
13612 /*
13613 * We should qualify the handler's function name if it wouldn't be
13614 * resolved by lookup in the current search path.
13615 */
13616 argtypes[0] = INTERNALOID;
13617 appendStringInfo(buf, " TABLESAMPLE %s (",
13618 generate_function_name(tablesample->tsmhandler, 1,
13619 NIL, argtypes,
13620 false, NULL, false));
13621
13622 nargs = 0;
13623 foreach(l, tablesample->args)
13624 {
13625 if (nargs++ > 0)
13627 get_rule_expr((Node *) lfirst(l), context, false);
13628 }
13630
13631 if (tablesample->repeatable != NULL)
13632 {
13633 appendStringInfoString(buf, " REPEATABLE (");
13634 get_rule_expr((Node *) tablesample->repeatable, context, false);
13636 }
13637}
13638
13639/*
13640 * get_opclass_name - fetch name of an index operator class
13641 *
13642 * The opclass name is appended (after a space) to buf.
13643 *
13644 * Output is suppressed if the opclass is the default for the given
13645 * actual_datatype. (If you don't want this behavior, just pass
13646 * InvalidOid for actual_datatype.)
13647 */
13648static void
13651{
13654 char *opcname;
13655 char *nspname;
13656
13659 elog(ERROR, "cache lookup failed for opclass %u", opclass);
13661
13663 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
13664 {
13665 /* Okay, we need the opclass name. Do we need to qualify it? */
13666 opcname = NameStr(opcrec->opcname);
13667 if (OpclassIsVisible(opclass))
13669 else
13670 {
13671 nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
13672 appendStringInfo(buf, " %s.%s",
13673 quote_identifier(nspname),
13675 }
13676 }
13678}
13679
13680/*
13681 * generate_opclass_name
13682 * Compute the name to display for an opclass specified by OID
13683 *
13684 * The result includes all necessary quoting and schema-prefixing.
13685 */
13686char *
13688{
13690
13692 get_opclass_name(opclass, InvalidOid, &buf);
13693
13694 return &buf.data[1]; /* get_opclass_name() prepends space */
13695}
13696
13697/*
13698 * processIndirection - take care of array and subfield assignment
13699 *
13700 * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
13701 * appear in the input, printing them as decoration for the base column
13702 * name (which we assume the caller just printed). We might also need to
13703 * strip CoerceToDomain nodes, but only ones that appear above assignment
13704 * nodes.
13705 *
13706 * Returns the subexpression that's to be assigned.
13707 */
13708static Node *
13710{
13711 StringInfo buf = context->buf;
13713
13714 for (;;)
13715 {
13716 if (node == NULL)
13717 break;
13718 if (IsA(node, FieldStore))
13719 {
13720 FieldStore *fstore = (FieldStore *) node;
13721 Oid typrelid;
13722 char *fieldname;
13723
13724 /* lookup tuple type */
13725 typrelid = get_typ_typrelid(fstore->resulttype);
13726 if (!OidIsValid(typrelid))
13727 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
13728 format_type_be(fstore->resulttype));
13729
13730 /*
13731 * Print the field name. There should only be one target field in
13732 * stored rules. There could be more than that in executable
13733 * target lists, but this function cannot be used for that case.
13734 */
13735 Assert(list_length(fstore->fieldnums) == 1);
13736 fieldname = get_attname(typrelid,
13737 linitial_int(fstore->fieldnums), false);
13738 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
13739
13740 /*
13741 * We ignore arg since it should be an uninteresting reference to
13742 * the target column or subcolumn.
13743 */
13744 node = (Node *) linitial(fstore->newvals);
13745 }
13746 else if (IsA(node, SubscriptingRef))
13747 {
13748 SubscriptingRef *sbsref = (SubscriptingRef *) node;
13749
13750 if (sbsref->refassgnexpr == NULL)
13751 break;
13752
13753 printSubscripts(sbsref, context);
13754
13755 /*
13756 * We ignore refexpr since it should be an uninteresting reference
13757 * to the target column or subcolumn.
13758 */
13759 node = (Node *) sbsref->refassgnexpr;
13760 }
13761 else if (IsA(node, CoerceToDomain))
13762 {
13763 cdomain = (CoerceToDomain *) node;
13764 /* If it's an explicit domain coercion, we're done */
13765 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
13766 break;
13767 /* Tentatively descend past the CoerceToDomain */
13768 node = (Node *) cdomain->arg;
13769 }
13770 else
13771 break;
13772 }
13773
13774 /*
13775 * If we descended past a CoerceToDomain whose argument turned out not to
13776 * be a FieldStore or array assignment, back up to the CoerceToDomain.
13777 * (This is not enough to be fully correct if there are nested implicit
13778 * CoerceToDomains, but such cases shouldn't ever occur.)
13779 */
13780 if (cdomain && node == (Node *) cdomain->arg)
13781 node = (Node *) cdomain;
13782
13783 return node;
13784}
13785
13786static void
13788{
13789 StringInfo buf = context->buf;
13792
13793 lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
13794 foreach(uplist_item, sbsref->refupperindexpr)
13795 {
13797 if (lowlist_item)
13798 {
13799 /* If subexpression is NULL, get_rule_expr prints nothing */
13800 get_rule_expr((Node *) lfirst(lowlist_item), context, false);
13803 }
13804 /* If subexpression is NULL, get_rule_expr prints nothing */
13805 get_rule_expr((Node *) lfirst(uplist_item), context, false);
13807 }
13808}
13809
13810/*
13811 * quote_identifier - Quote an identifier only if needed
13812 *
13813 * When quotes are needed, we palloc the required space; slightly
13814 * space-wasteful but well worth it for notational simplicity.
13815 */
13816const char *
13818{
13819 /*
13820 * Can avoid quoting if ident starts with a lowercase letter or underscore
13821 * and contains only lowercase letters, digits, and underscores, *and* is
13822 * not any SQL keyword. Otherwise, supply quotes.
13823 */
13824 int nquotes = 0;
13825 bool safe;
13826 const char *ptr;
13827 char *result;
13828 char *optr;
13829
13830 /*
13831 * would like to use <ctype.h> macros here, but they might yield unwanted
13832 * locale-specific results...
13833 */
13834 safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
13835
13836 for (ptr = ident; *ptr; ptr++)
13837 {
13838 char ch = *ptr;
13839
13840 if ((ch >= 'a' && ch <= 'z') ||
13841 (ch >= '0' && ch <= '9') ||
13842 (ch == '_'))
13843 {
13844 /* okay */
13845 }
13846 else
13847 {
13848 safe = false;
13849 if (ch == '"')
13850 nquotes++;
13851 }
13852 }
13853
13855 safe = false;
13856
13857 if (safe)
13858 {
13859 /*
13860 * Check for keyword. We quote keywords except for unreserved ones.
13861 * (In some cases we could avoid quoting a col_name or type_func_name
13862 * keyword, but it seems much harder than it's worth to tell that.)
13863 *
13864 * Note: ScanKeywordLookup() does case-insensitive comparison, but
13865 * that's fine, since we already know we have all-lower-case.
13866 */
13868
13870 safe = false;
13871 }
13872
13873 if (safe)
13874 return ident; /* no change needed */
13875
13876 result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
13877
13878 optr = result;
13879 *optr++ = '"';
13880 for (ptr = ident; *ptr; ptr++)
13881 {
13882 char ch = *ptr;
13883
13884 if (ch == '"')
13885 *optr++ = '"';
13886 *optr++ = ch;
13887 }
13888 *optr++ = '"';
13889 *optr = '\0';
13890
13891 return result;
13892}
13893
13894/*
13895 * quote_qualified_identifier - Quote a possibly-qualified identifier
13896 *
13897 * Return a name of the form qualifier.ident, or just ident if qualifier
13898 * is NULL, quoting each component if necessary. The result is palloc'd.
13899 */
13900char *
13902 const char *ident)
13903{
13905
13907 if (qualifier)
13910 return buf.data;
13911}
13912
13913/*
13914 * get_relation_name
13915 * Get the unqualified name of a relation specified by OID
13916 *
13917 * This differs from the underlying get_rel_name() function in that it will
13918 * throw error instead of silently returning NULL if the OID is bad.
13919 */
13920static char *
13922{
13923 char *relname = get_rel_name(relid);
13924
13925 if (!relname)
13926 elog(ERROR, "cache lookup failed for relation %u", relid);
13927 return relname;
13928}
13929
13930/*
13931 * generate_relation_name
13932 * Compute the name to display for a relation specified by OID
13933 *
13934 * The result includes all necessary quoting and schema-prefixing.
13935 *
13936 * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
13937 * We will forcibly qualify the relation name if it equals any CTE name
13938 * visible in the namespace list.
13939 */
13940static char *
13942{
13943 HeapTuple tp;
13945 bool need_qual;
13947 char *relname;
13948 char *nspname;
13949 char *result;
13950
13952 if (!HeapTupleIsValid(tp))
13953 elog(ERROR, "cache lookup failed for relation %u", relid);
13955 relname = NameStr(reltup->relname);
13956
13957 /* Check for conflicting CTE name */
13958 need_qual = false;
13959 foreach(nslist, namespaces)
13960 {
13963
13964 foreach(ctlist, dpns->ctes)
13965 {
13967
13968 if (strcmp(cte->ctename, relname) == 0)
13969 {
13970 need_qual = true;
13971 break;
13972 }
13973 }
13974 if (need_qual)
13975 break;
13976 }
13977
13978 /* Otherwise, qualify the name if not visible in search path */
13979 if (!need_qual)
13980 need_qual = !RelationIsVisible(relid);
13981
13982 if (need_qual)
13983 nspname = get_namespace_name_or_temp(reltup->relnamespace);
13984 else
13985 nspname = NULL;
13986
13988
13989 ReleaseSysCache(tp);
13990
13991 return result;
13992}
13993
13994/*
13995 * generate_qualified_relation_name
13996 * Compute the name to display for a relation specified by OID
13997 *
13998 * As above, but unconditionally schema-qualify the name.
13999 */
14000static char *
14002{
14003 HeapTuple tp;
14005 char *result;
14006
14008 if (!HeapTupleIsValid(tp))
14009 elog(ERROR, "cache lookup failed for relation %u", relid);
14011
14012 result = get_qualified_objname(reltup->relnamespace,
14013 NameStr(reltup->relname));
14014 ReleaseSysCache(tp);
14015
14016 return result;
14017}
14018
14019/*
14020 * generate_function_name
14021 * Compute the name to display for a function specified by OID,
14022 * given that it is being called with the specified actual arg names and
14023 * types. (Those matter because of ambiguous-function resolution rules.)
14024 *
14025 * If we're dealing with a potentially variadic function (in practice, this
14026 * means a FuncExpr or Aggref, not some other way of calling a function), then
14027 * has_variadic must specify whether variadic arguments have been merged,
14028 * and *use_variadic_p will be set to indicate whether to print VARIADIC in
14029 * the output. For non-FuncExpr cases, has_variadic should be false and
14030 * use_variadic_p can be NULL.
14031 *
14032 * inGroupBy must be true if we're deparsing a GROUP BY clause.
14033 *
14034 * The result includes all necessary quoting and schema-prefixing.
14035 */
14036static char *
14037generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
14038 bool has_variadic, bool *use_variadic_p,
14039 bool inGroupBy)
14040{
14041 char *result;
14044 char *proname;
14045 bool use_variadic;
14046 char *nspname;
14048 int fgc_flags;
14049 Oid p_funcid;
14050 Oid p_rettype;
14051 bool p_retset;
14052 int p_nvargs;
14053 Oid p_vatype;
14055 bool force_qualify = false;
14056
14059 elog(ERROR, "cache lookup failed for function %u", funcid);
14061 proname = NameStr(procform->proname);
14062
14063 /*
14064 * Due to parser hacks to avoid needing to reserve CUBE, we need to force
14065 * qualification of some function names within GROUP BY.
14066 */
14067 if (inGroupBy)
14068 {
14069 if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
14070 force_qualify = true;
14071 }
14072
14073 /*
14074 * Determine whether VARIADIC should be printed. We must do this first
14075 * since it affects the lookup rules in func_get_detail().
14076 *
14077 * We always print VARIADIC if the function has a merged variadic-array
14078 * argument. Note that this is always the case for functions taking a
14079 * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
14080 * and printed the array elements as separate arguments, the call could
14081 * match a newer non-VARIADIC function.
14082 */
14083 if (use_variadic_p)
14084 {
14085 /* Parser should not have set funcvariadic unless fn is variadic */
14086 Assert(!has_variadic || OidIsValid(procform->provariadic));
14089 }
14090 else
14091 {
14093 use_variadic = false;
14094 }
14095
14096 /*
14097 * The idea here is to schema-qualify only if the parser would fail to
14098 * resolve the correct function given the unqualified func name with the
14099 * specified argtypes and VARIADIC flag. But if we already decided to
14100 * force qualification, then we can skip the lookup and pretend we didn't
14101 * find it.
14102 */
14103 if (!force_qualify)
14105 NIL, argnames, nargs, argtypes,
14106 !use_variadic, true, false,
14107 &fgc_flags,
14111 else
14112 {
14115 }
14116
14117 if ((p_result == FUNCDETAIL_NORMAL ||
14120 p_funcid == funcid)
14121 nspname = NULL;
14122 else
14123 nspname = get_namespace_name_or_temp(procform->pronamespace);
14124
14126
14128
14129 return result;
14130}
14131
14132/*
14133 * generate_operator_name
14134 * Compute the name to display for an operator specified by OID,
14135 * given that it is being called with the specified actual arg types.
14136 * (Arg types matter because of ambiguous-operator resolution rules.
14137 * Pass InvalidOid for unused arg of a unary operator.)
14138 *
14139 * The result includes all necessary quoting and schema-prefixing,
14140 * plus the OPERATOR() decoration needed to use a qualified operator name
14141 * in an expression.
14142 */
14143static char *
14145{
14149 char *oprname;
14150 char *nspname;
14152
14154
14157 elog(ERROR, "cache lookup failed for operator %u", operid);
14159 oprname = NameStr(operform->oprname);
14160
14161 /*
14162 * The idea here is to schema-qualify only if the parser would fail to
14163 * resolve the correct operator given the unqualified op name with the
14164 * specified argtypes.
14165 */
14166 switch (operform->oprkind)
14167 {
14168 case 'b':
14170 true, -1);
14171 break;
14172 case 'l':
14174 true, -1);
14175 break;
14176 default:
14177 elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
14178 p_result = NULL; /* keep compiler quiet */
14179 break;
14180 }
14181
14182 if (p_result != NULL && oprid(p_result) == operid)
14183 nspname = NULL;
14184 else
14185 {
14186 nspname = get_namespace_name_or_temp(operform->oprnamespace);
14187 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
14188 }
14189
14190 appendStringInfoString(&buf, oprname);
14191
14192 if (nspname)
14194
14195 if (p_result != NULL)
14197
14199
14200 return buf.data;
14201}
14202
14203/*
14204 * generate_operator_clause --- generate a binary-operator WHERE clause
14205 *
14206 * This is used for internally-generated-and-executed SQL queries, where
14207 * precision is essential and readability is secondary. The basic
14208 * requirement is to append "leftop op rightop" to buf, where leftop and
14209 * rightop are given as strings and are assumed to yield types leftoptype
14210 * and rightoptype; the operator is identified by OID. The complexity
14211 * comes from needing to be sure that the parser will select the desired
14212 * operator when the query is parsed. We always name the operator using
14213 * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
14214 * We have to emit casts too, if either input isn't already the input type
14215 * of the operator; else we are at the mercy of the parser's heuristics for
14216 * ambiguous-operator resolution. The caller must ensure that leftop and
14217 * rightop are suitable arguments for a cast operation; it's best to insert
14218 * parentheses if they aren't just variables or parameters.
14219 */
14220void
14222 const char *leftop, Oid leftoptype,
14223 Oid opoid,
14224 const char *rightop, Oid rightoptype)
14225{
14228 char *oprname;
14229 char *nspname;
14230
14233 elog(ERROR, "cache lookup failed for operator %u", opoid);
14235 Assert(operform->oprkind == 'b');
14236 oprname = NameStr(operform->oprname);
14237
14238 nspname = get_namespace_name(operform->oprnamespace);
14239
14241 if (leftoptype != operform->oprleft)
14242 add_cast_to(buf, operform->oprleft);
14243 appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
14244 appendStringInfoString(buf, oprname);
14245 appendStringInfo(buf, ") %s", rightop);
14246 if (rightoptype != operform->oprright)
14247 add_cast_to(buf, operform->oprright);
14248
14250}
14251
14252/*
14253 * Add a cast specification to buf. We spell out the type name the hard way,
14254 * intentionally not using format_type_be(). This is to avoid corner cases
14255 * for CHARACTER, BIT, and perhaps other types, where specifying the type
14256 * using SQL-standard syntax results in undesirable data truncation. By
14257 * doing it this way we can be certain that the cast will have default (-1)
14258 * target typmod.
14259 */
14260static void
14262{
14265 char *typname;
14266 char *nspname;
14267
14270 elog(ERROR, "cache lookup failed for type %u", typid);
14272
14273 typname = NameStr(typform->typname);
14274 nspname = get_namespace_name_or_temp(typform->typnamespace);
14275
14276 appendStringInfo(buf, "::%s.%s",
14278
14280}
14281
14282/*
14283 * generate_qualified_type_name
14284 * Compute the name to display for a type specified by OID
14285 *
14286 * This is different from format_type_be() in that we unconditionally
14287 * schema-qualify the name. That also means no special syntax for
14288 * SQL-standard type names ... although in current usage, this should
14289 * only get used for domains, so such cases wouldn't occur anyway.
14290 */
14291static char *
14293{
14294 HeapTuple tp;
14296 char *typname;
14297 char *nspname;
14298 char *result;
14299
14301 if (!HeapTupleIsValid(tp))
14302 elog(ERROR, "cache lookup failed for type %u", typid);
14304 typname = NameStr(typtup->typname);
14305
14306 nspname = get_namespace_name_or_temp(typtup->typnamespace);
14307 if (!nspname)
14308 elog(ERROR, "cache lookup failed for namespace %u",
14309 typtup->typnamespace);
14310
14312
14313 ReleaseSysCache(tp);
14314
14315 return result;
14316}
14317
14318/*
14319 * generate_collation_name
14320 * Compute the name to display for a collation specified by OID
14321 *
14322 * The result includes all necessary quoting and schema-prefixing.
14323 */
14324char *
14326{
14327 HeapTuple tp;
14329 char *collname;
14330 char *nspname;
14331 char *result;
14332
14334 if (!HeapTupleIsValid(tp))
14335 elog(ERROR, "cache lookup failed for collation %u", collid);
14337 collname = NameStr(colltup->collname);
14338
14340 nspname = get_namespace_name_or_temp(colltup->collnamespace);
14341 else
14342 nspname = NULL;
14343
14344 result = quote_qualified_identifier(nspname, collname);
14345
14346 ReleaseSysCache(tp);
14347
14348 return result;
14349}
14350
14351/*
14352 * Given a C string, produce a TEXT datum.
14353 *
14354 * We assume that the input was palloc'd and may be freed.
14355 */
14356static text *
14358{
14359 text *result;
14360
14362 pfree(str);
14363 return result;
14364}
14365
14366/*
14367 * Generate a C string representing a relation options from text[] datum.
14368 */
14369void
14371{
14372 Datum *options;
14373 int noptions;
14374 int i;
14375
14377 &options, NULL, &noptions);
14378
14379 for (i = 0; i < noptions; i++)
14380 {
14382 char *name;
14383 char *separator;
14384 char *value;
14385
14386 /*
14387 * Each array element should have the form name=value. If the "=" is
14388 * missing for some reason, treat it like an empty value.
14389 */
14390 name = option;
14391 separator = strchr(option, '=');
14392 if (separator)
14393 {
14394 *separator = '\0';
14395 value = separator + 1;
14396 }
14397 else
14398 value = "";
14399
14400 if (i > 0)
14403
14404 /*
14405 * In general we need to quote the value; but to avoid unnecessary
14406 * clutter, do not quote if it is an identifier that would not need
14407 * quoting. (We could also allow numbers, but that is a bit trickier
14408 * than it looks --- for example, are leading zeroes significant? We
14409 * don't want to assume very much here about what custom reloptions
14410 * might mean.)
14411 */
14414 else
14416
14417 pfree(option);
14418 }
14419}
14420
14421/*
14422 * Generate a C string representing a relation's reloptions, or NULL if none.
14423 */
14424static char *
14426{
14427 char *result = NULL;
14428 HeapTuple tuple;
14429 Datum reloptions;
14430 bool isnull;
14431
14432 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
14433 if (!HeapTupleIsValid(tuple))
14434 elog(ERROR, "cache lookup failed for relation %u", relid);
14435
14436 reloptions = SysCacheGetAttr(RELOID, tuple,
14437 Anum_pg_class_reloptions, &isnull);
14438 if (!isnull)
14439 {
14441
14443 get_reloptions(&buf, reloptions);
14444
14445 result = buf.data;
14446 }
14447
14448 ReleaseSysCache(tuple);
14449
14450 return result;
14451}
14452
14453/*
14454 * get_range_partbound_string
14455 * A C string representation of one range partition bound
14456 */
14457char *
14459{
14460 deparse_context context;
14462 ListCell *cell;
14463 char *sep;
14464
14466 memset(&context, 0, sizeof(deparse_context));
14467 context.buf = &buf;
14468
14470 sep = "";
14471 foreach(cell, bound_datums)
14472 {
14473 PartitionRangeDatum *datum =
14475
14478 appendStringInfoString(&buf, "MINVALUE");
14479 else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
14480 appendStringInfoString(&buf, "MAXVALUE");
14481 else
14482 {
14483 Const *val = castNode(Const, datum->value);
14484
14485 get_const_expr(val, &context, -1);
14486 }
14487 sep = ", ";
14488 }
14490
14491 return buf.data;
14492}
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:217
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:547
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:645
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:934
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:252
#define bms_is_empty(a)
Definition bitmapset.h:119
#define TextDatumGetCString(d)
Definition builtins.h:99
#define NameStr(name)
Definition c.h:894
NameData * Name
Definition c.h:892
#define Max(x, y)
Definition c.h:1125
#define Assert(condition)
Definition c.h:1002
int16_t int16
Definition c.h:678
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition c.h:1292
int32_t int32
Definition c.h:679
uint16_t uint16
Definition c.h:682
#define lengthof(array)
Definition c.h:932
unsigned int Index
Definition c.h:757
float float4
Definition c.h:772
#define pg_fallthrough
Definition c.h:220
#define OidIsValid(objectId)
Definition c.h:917
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:1323
int errcode(int sqlerrcode)
Definition elog.c:875
#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:89
#define palloc0_array(type, count)
Definition fe_memutils.h:92
#define palloc0_object(type)
Definition fe_memutils.h:90
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:688
#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:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
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:2381
long val
Definition informix.c:689
static struct @175 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:2242
char * get_propgraph_property_name(Oid propoid)
Definition lsyscache.c:4098
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:1084
Oid get_opclass_input_type(Oid opclass)
Definition lsyscache.c:1464
bool type_is_rowtype(Oid typid)
Definition lsyscache.c:2971
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3223
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1196
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2317
Oid get_typcollation(Oid typid)
Definition lsyscache.c:3372
char * get_language_name(Oid langoid, bool missing_ok)
Definition lsyscache.c:1413
char * get_namespace_name_or_temp(Oid nspid)
Definition lsyscache.c:3706
char * get_propgraph_label_name(Oid labeloid)
Definition lsyscache.c:4080
char * get_constraint_name(Oid conoid)
Definition lsyscache.c:1307
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:1053
Oid get_rel_tablespace(Oid relid)
Definition lsyscache.c:2368
Oid get_typ_typrelid(Oid typid)
Definition lsyscache.c:3047
Oid get_base_element_type(Oid typid)
Definition lsyscache.c:3148
char * get_qualified_objname(Oid nspid, char *objname)
Definition lsyscache.c:3720
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
Definition lsyscache.c:3026
void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod, Oid *collid)
Definition lsyscache.c:1169
Alias * makeAlias(const char *aliasname, List *colnames)
Definition makefuncs.c:438
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1212
char * pstrdup(const char *in)
Definition mcxt.c:1910
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
void * palloc(Size size)
Definition mcxt.c:1390
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
#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:394
#define IsA(nodeptr, _type_)
Definition nodes.h:162
#define nodeTag(nodeptr)
Definition nodes.h:137
#define DO_AGGSPLIT_COMBINE(as)
Definition nodes.h:393
@ ONCONFLICT_SELECT
Definition nodes.h:429
@ ONCONFLICT_UPDATE
Definition nodes.h:428
@ ONCONFLICT_NOTHING
Definition nodes.h:427
@ CMD_MERGE
Definition nodes.h:277
@ CMD_UTILITY
Definition nodes.h:278
@ CMD_INSERT
Definition nodes.h:275
@ CMD_DELETE
Definition nodes.h:276
@ CMD_UPDATE
Definition nodes.h:274
@ CMD_SELECT
Definition nodes.h:273
@ CMD_NOTHING
Definition nodes.h:280
@ LIMIT_OPTION_WITH_TIES
Definition nodes.h:441
#define makeNode(_type_)
Definition nodes.h:159
#define castNode(_type_, nodeptr)
Definition nodes.h:180
@ JOIN_FULL
Definition nodes.h:303
@ JOIN_INNER
Definition nodes.h:301
@ JOIN_RIGHT
Definition nodes.h:304
@ JOIN_LEFT
Definition nodes.h:302
static char * errmsg
Datum lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
#define repalloc0_array(pointer, type, oldcount, count)
Definition palloc.h:122
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:529
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:376
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:623
#define FRAMEOPTION_END_OFFSET
Definition parsenodes.h:634
#define FRAMEOPTION_EXCLUDE_CURRENT_ROW
Definition parsenodes.h:628
@ 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:625
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition parsenodes.h:618
#define GetCTETargetList(cte)
#define FKCONSTR_ACTION_SETDEFAULT
@ PARTITION_STRATEGY_HASH
Definition parsenodes.h:921
@ PARTITION_STRATEGY_LIST
Definition parsenodes.h:919
@ PARTITION_STRATEGY_RANGE
Definition parsenodes.h:920
#define FRAMEOPTION_START_CURRENT_ROW
Definition parsenodes.h:622
#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:632
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition parsenodes.h:973
@ PARTITION_RANGE_DATUM_MINVALUE
Definition parsenodes.h:971
@ 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:627
#define FRAMEOPTION_EXCLUDE_TIES
Definition parsenodes.h:630
#define FRAMEOPTION_RANGE
Definition parsenodes.h:614
#define FRAMEOPTION_EXCLUDE_GROUP
Definition parsenodes.h:629
#define FKCONSTR_ACTION_CASCADE
#define FRAMEOPTION_GROUPS
Definition parsenodes.h:616
#define FRAMEOPTION_BETWEEN
Definition parsenodes.h:617
#define FKCONSTR_ACTION_SETNULL
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING
Definition parsenodes.h:621
#define FRAMEOPTION_START_OFFSET_PRECEDING
Definition parsenodes.h:624
#define FRAMEOPTION_START_OFFSET_FOLLOWING
Definition parsenodes.h:626
#define FRAMEOPTION_NONDEFAULT
Definition parsenodes.h:613
#define FKCONSTR_MATCH_FULL
#define FKCONSTR_ACTION_NOACTION
#define FRAMEOPTION_ROWS
Definition parsenodes.h:615
@ 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:263
#define snprintf
Definition port.h:261
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static Name DatumGetName(Datum X)
Definition postgres.h:393
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:383
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 PointerGetDatum(X)
Definition postgres.h:354
#define InvalidOid
unsigned int Oid
e
static int fb(int x)
char string[11]
@ IS_NOT_TRUE
Definition primnodes.h:1999
@ IS_NOT_FALSE
Definition primnodes.h:1999
@ IS_NOT_UNKNOWN
Definition primnodes.h:1999
@ IS_TRUE
Definition primnodes.h:1999
@ IS_UNKNOWN
Definition primnodes.h:1999
@ IS_FALSE
Definition primnodes.h:1999
@ ARRAY_SUBLINK
Definition primnodes.h:1017
@ ANY_SUBLINK
Definition primnodes.h:1013
@ MULTIEXPR_SUBLINK
Definition primnodes.h:1016
@ CTE_SUBLINK
Definition primnodes.h:1018
@ EXPR_SUBLINK
Definition primnodes.h:1015
@ ROWCOMPARE_SUBLINK
Definition primnodes.h:1014
@ ALL_SUBLINK
Definition primnodes.h:1012
@ EXISTS_SUBLINK
Definition primnodes.h:1011
@ JS_FORMAT_JSONB
Definition primnodes.h:1648
@ JS_FORMAT_DEFAULT
Definition primnodes.h:1646
@ JS_FORMAT_JSON
Definition primnodes.h:1647
@ IS_LEAST
Definition primnodes.h:1511
@ IS_GREATEST
Definition primnodes.h:1510
@ TFT_XMLTABLE
Definition primnodes.h:101
@ TFT_JSON_TABLE
Definition primnodes.h:102
BoolExprType
Definition primnodes.h:944
@ AND_EXPR
Definition primnodes.h:945
@ OR_EXPR
Definition primnodes.h:945
@ NOT_EXPR
Definition primnodes.h:945
@ JS_ENC_DEFAULT
Definition primnodes.h:1634
@ JS_ENC_UTF32
Definition primnodes.h:1637
@ JS_ENC_UTF16
Definition primnodes.h:1636
@ XMLOPTION_DOCUMENT
Definition primnodes.h:1600
@ SVFOP_CURRENT_CATALOG
Definition primnodes.h:1557
@ SVFOP_LOCALTIME_N
Definition primnodes.h:1550
@ SVFOP_CURRENT_TIMESTAMP
Definition primnodes.h:1547
@ SVFOP_LOCALTIME
Definition primnodes.h:1549
@ SVFOP_CURRENT_TIMESTAMP_N
Definition primnodes.h:1548
@ SVFOP_CURRENT_ROLE
Definition primnodes.h:1553
@ SVFOP_USER
Definition primnodes.h:1555
@ SVFOP_CURRENT_SCHEMA
Definition primnodes.h:1558
@ SVFOP_LOCALTIMESTAMP_N
Definition primnodes.h:1552
@ SVFOP_CURRENT_DATE
Definition primnodes.h:1544
@ SVFOP_CURRENT_TIME_N
Definition primnodes.h:1546
@ SVFOP_CURRENT_TIME
Definition primnodes.h:1545
@ SVFOP_LOCALTIMESTAMP
Definition primnodes.h:1551
@ SVFOP_CURRENT_USER
Definition primnodes.h:1554
@ SVFOP_SESSION_USER
Definition primnodes.h:1556
@ PARAM_MULTIEXPR
Definition primnodes.h:388
@ PARAM_EXTERN
Definition primnodes.h:385
@ PARAM_EXEC
Definition primnodes.h:386
@ JSW_UNCONDITIONAL
Definition primnodes.h:1774
@ JSW_CONDITIONAL
Definition primnodes.h:1773
@ JSW_UNSPEC
Definition primnodes.h:1771
@ JSW_NONE
Definition primnodes.h:1772
#define PARSER_IGNORE_NULLS
Definition primnodes.h:577
@ IS_DOCUMENT
Definition primnodes.h:1595
@ IS_XMLFOREST
Definition primnodes.h:1590
@ IS_XMLCONCAT
Definition primnodes.h:1588
@ IS_XMLPI
Definition primnodes.h:1592
@ IS_XMLPARSE
Definition primnodes.h:1591
@ IS_XMLSERIALIZE
Definition primnodes.h:1594
@ IS_XMLROOT
Definition primnodes.h:1593
@ IS_XMLELEMENT
Definition primnodes.h:1589
@ 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:1785
@ JSON_BEHAVIOR_DEFAULT
Definition primnodes.h:1794
@ JSON_BEHAVIOR_FALSE
Definition primnodes.h:1790
@ JSON_BEHAVIOR_NULL
Definition primnodes.h:1786
@ JSON_BEHAVIOR_EMPTY_ARRAY
Definition primnodes.h:1792
@ JSON_QUERY_OP
Definition primnodes.h:1824
@ JSON_EXISTS_OP
Definition primnodes.h:1823
@ JSON_VALUE_OP
Definition primnodes.h:1825
CoercionForm
Definition primnodes.h:756
@ COERCE_SQL_SYNTAX
Definition primnodes.h:760
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:759
@ COERCE_EXPLICIT_CAST
Definition primnodes.h:758
@ COERCE_EXPLICIT_CALL
Definition primnodes.h:757
@ OVERRIDING_SYSTEM_VALUE
Definition primnodes.h:31
@ OVERRIDING_USER_VALUE
Definition primnodes.h:30
@ IS_NULL
Definition primnodes.h:1975
@ IS_NOT_NULL
Definition primnodes.h:1975
@ JS_TYPE_ARRAY
Definition primnodes.h:1744
@ JS_TYPE_OBJECT
Definition primnodes.h:1743
@ JS_TYPE_SCALAR
Definition primnodes.h:1745
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition primnodes.h:2021
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition primnodes.h:2020
@ MERGE_WHEN_MATCHED
Definition primnodes.h:2019
#define OUTER_VAR
Definition primnodes.h:244
@ JSCTOR_JSON_SERIALIZE
Definition primnodes.h:1705
@ JSCTOR_JSON_ARRAYAGG
Definition primnodes.h:1702
@ JSCTOR_JSON_PARSE
Definition primnodes.h:1703
@ JSCTOR_JSON_OBJECT
Definition primnodes.h:1698
@ JSCTOR_JSON_SCALAR
Definition primnodes.h:1704
@ JSCTOR_JSON_ARRAY_QUERY
Definition primnodes.h:1700
@ JSCTOR_JSON_ARRAY
Definition primnodes.h:1699
@ JSCTOR_JSON_OBJECTAGG
Definition primnodes.h:1701
#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:898
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags, int wrapColumn)
Definition ruleutils.c:5903
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:2456
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition ruleutils.c:5497
Datum pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
Definition ruleutils.c:729
static int decompile_column_index_array(Datum column_index_array, Oid relId, bool withPeriod, StringInfo buf)
Definition ruleutils.c:2981
static void make_propgraphdef_labels(StringInfo buf, Oid elid, const char *elalias, Oid elrelid)
Definition ruleutils.c:1799
static void set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition ruleutils.c:4739
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:4117
char * pg_get_statisticsobjdef_string(Oid statextid)
Definition ruleutils.c:1987
Datum pg_get_indexdef_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:1211
static void set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
Definition ruleutils.c:4574
static Plan * find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
Definition ruleutils.c:5597
static text * string_to_text(char *str)
static void get_values_def(List *values_lists, deparse_context *context)
Definition ruleutils.c:6091
#define PRETTYINDENT_LIMIT
Definition ruleutils.c:90
Datum pg_get_viewdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:691
static char * make_colname_unique(char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
Definition ruleutils.c:5287
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:2506
static void set_deparse_for_query(deparse_namespace *dpns, Query *query, List *parent_namespaces)
Definition ruleutils.c:4393
static void print_function_trftypes(StringInfo buf, HeapTuple proctup)
Definition ruleutils.c:3822
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:3810
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
Definition ruleutils.c:5988
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Datum pg_get_functiondef(PG_FUNCTION_ARGS)
Definition ruleutils.c:3287
Datum pg_get_function_result(PG_FUNCTION_ARGS)
Definition ruleutils.c:3594
Datum pg_get_indexdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:1191
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:6380
static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as, deparse_context *context)
#define only_marker(rte)
Definition ruleutils.c:563
Datum pg_get_function_arg_default(PG_FUNCTION_ARGS)
Definition ruleutils.c:3850
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:5342
Datum pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
Definition ruleutils.c:2198
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:573
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:1997
Datum pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:1969
static void add_to_names_hash(deparse_columns *colinfo, const char *name)
Definition ruleutils.c:5400
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:5212
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:1262
char * pg_get_partkeydef_columns(Oid relid, bool pretty)
Definition ruleutils.c:2284
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:4072
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Datum pg_get_partkeydef(PG_FUNCTION_ARGS)
Definition ruleutils.c:2269
static char * generate_qualified_relation_name(Oid relid)
static void set_simple_column_names(deparse_namespace *dpns)
Definition ruleutils.c:4462
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:1248
#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:1867
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:1283
static char * pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, int prettyFlags, bool missing_ok)
Definition ruleutils.c:2553
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:5326
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:4189
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:2014
#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:5695
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:4036
Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:591
char * pg_get_indexdef_string(Oid indexrelid)
Definition ruleutils.c:1238
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:1601
static void print_function_sqlbody(StringInfo buf, HeapTuple proctup)
Definition ruleutils.c:3920
static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
Definition ruleutils.c:4504
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:802
static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns)
Definition ruleutils.c:5674
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:3070
static Node * processIndirection(Node *node, deparse_context *context)
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
static bool json_table_plan_is_default(JsonTablePlan *plan)
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:884
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition ruleutils.c:4219
Datum pg_get_function_sqlbody(PG_FUNCTION_ARGS)
Definition ruleutils.c:3974
static void get_path_pattern_expr_def(List *path_pattern_expr, deparse_context *context)
Definition ruleutils.c:8031
static void get_json_agg_constructor_expr(Node *node, deparse_context *context, void *callback_arg)
Datum pg_get_expr(PG_FUNCTION_ARGS)
Definition ruleutils.c:3035
static char * generate_qualified_type_name(Oid typid)
static void get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
static void get_json_table_plan(TableFunc *tf, JsonTablePlan *plan, deparse_context *context, bool parenthesize)
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:3052
static int list_oid_str_pair_cmp_by_str(const ListCell *p1, const ListCell *p2)
Definition ruleutils.c:1786
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:774
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:5644
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:2544
char * pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
Definition ruleutils.c:2488
static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition ruleutils.c:4942
Datum pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
Definition ruleutils.c:2523
static void make_propgraphdef_properties(StringInfo buf, Oid ellabelid, Oid elrelid)
Definition ruleutils.c:1883
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
Definition ruleutils.c:4248
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:710
static char * pg_get_partkeydef_worker(Oid relid, int prettyFlags, bool attrsOnly, bool missing_ok)
Definition ruleutils.c:2297
static void get_oper_expr(OpExpr *expr, deparse_context *context)
Datum pg_get_propgraphdef(PG_FUNCTION_ARGS)
Definition ruleutils.c:1620
Datum pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
Definition ruleutils.c:3569
static char * pg_get_triggerdef_worker(Oid trigid, bool pretty)
Definition ruleutils.c:913
#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:4009
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:5711
static const char *const query_getviewrule
Definition ruleutils.c:341
static char * pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
Definition ruleutils.c:610
static int print_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults)
Definition ruleutils.c:3662
static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte, deparse_columns *colinfo)
Definition ruleutils.c:5429
static void print_function_rettype(StringInfo buf, HeapTuple proctup)
Definition ruleutils.c:3624
char * generate_opclass_name(Oid opclass)
static void set_deparse_plan(deparse_namespace *dpns, Plan *plan)
Definition ruleutils.c:5516
static void make_propgraphdef_elements(StringInfo buf, Oid pgrelid, char pgekind)
Definition ruleutils.c:1662
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:6407
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:5627
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:6476
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:6134
#define PRETTYINDENT_VAR
Definition ruleutils.c:88
static void destroy_colinfo_names_hash(deparse_columns *colinfo)
Definition ruleutils.c:5413
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:3193
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:3543
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:6273
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Datum pg_get_viewdef_name(PG_FUNCTION_ARGS)
Definition ruleutils.c:749
Datum pg_get_userbyid(PG_FUNCTION_ARGS)
Definition ruleutils.c:3155
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
int SPI_keepplan(SPIPlanPtr plan)
Definition spi.c:977
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition spi.c:1221
SPIPlanPtr SPI_prepare(const char *src, int nargs, const Oid *argtypes)
Definition spi.c:861
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:96
#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:461
List * aggdistinct
Definition primnodes.h:491
List * aggdirectargs
Definition primnodes.h:482
List * args
Definition primnodes.h:485
Expr * aggfilter
Definition primnodes.h:494
List * aggorder
Definition primnodes.h:488
Index parent_relid
Definition pathnodes.h:3301
BoolExprType boolop
Definition primnodes.h:953
List * args
Definition primnodes.h:954
CTEMaterialize ctematerialized
bool attisdropped
Definition tupdesc.h:78
Oid consttype
Definition primnodes.h:333
char * cursor_name
Definition primnodes.h:2121
List * newvals
Definition primnodes.h:1176
Node * quals
Definition primnodes.h:2380
List * fromlist
Definition primnodes.h:2379
Oid funcid
Definition primnodes.h:770
List * args
Definition primnodes.h:788
Node * whereClause
List * path_pattern_list
JsonBehaviorType btype
Definition primnodes.h:1811
JsonBehavior * on_empty
Definition primnodes.h:1860
JsonFormat * format
Definition primnodes.h:1847
Node * path_spec
Definition primnodes.h:1850
JsonWrapper wrapper
Definition primnodes.h:1871
JsonExprOp op
Definition primnodes.h:1838
JsonBehavior * on_error
Definition primnodes.h:1861
bool omit_quotes
Definition primnodes.h:1874
JsonFormatType format_type
Definition primnodes.h:1659
JsonValueType item_type
Definition primnodes.h:1757
JsonFormat * format
Definition primnodes.h:1671
JsonTablePath * path
Definition primnodes.h:1919
JsonTablePlan * child
Definition primnodes.h:1928
Const * value
Definition primnodes.h:1892
JsonTablePlan * rplan
Definition primnodes.h:1950
JsonTablePlan * lplan
Definition primnodes.h:1949
Definition pg_list.h:54
Definition nodes.h:133
Oid opno
Definition primnodes.h:835
List * args
Definition primnodes.h:853
int paramid
Definition primnodes.h:397
ParamKind paramkind
Definition primnodes.h:396
PartitionRangeDatumKind kind
Definition parsenodes.h:980
List * appendRelations
Definition plannodes.h:124
List * subplans
Definition plannodes.h:129
List * rtable
Definition plannodes.h:107
List * rowMarks
Definition parsenodes.h:238
bool groupDistinct
Definition parsenodes.h:222
Node * mergeJoinCondition
Definition parsenodes.h:201
Node * limitCount
Definition parsenodes.h:235
FromExpr * jointree
Definition parsenodes.h:187
List * returningList
Definition parsenodes.h:219
Node * setOperations
Definition parsenodes.h:240
List * cteList
Definition parsenodes.h:178
OnConflictExpr * onConflict
Definition parsenodes.h:208
ForPortionOfExpr * forPortionOf
Definition parsenodes.h:153
List * groupClause
Definition parsenodes.h:221
Node * havingQual
Definition parsenodes.h:226
List * rtable
Definition parsenodes.h:180
Node * limitOffset
Definition parsenodes.h:234
CmdType commandType
Definition parsenodes.h:124
LimitOption limitOption
Definition parsenodes.h:236
Node * utilityStmt
Definition parsenodes.h:144
List * mergeActionList
Definition parsenodes.h:190
List * windowClause
Definition parsenodes.h:228
List * targetList
Definition parsenodes.h:203
List * groupingSets
Definition parsenodes.h:224
List * distinctClause
Definition parsenodes.h:230
List * sortClause
Definition parsenodes.h:232
List * args
Definition primnodes.h:1431
LockClauseStrength strength
LockWaitPolicy waitPolicy
TupleDesc tupdesc
Definition spi.h:25
HeapTuple * vals
Definition spi.h:26
SQLValueFunctionOp op
Definition primnodes.h:1564
SetOperation op
Definition value.h:64
char * plan_name
Definition primnodes.h:1086
List * args
Definition primnodes.h:1106
List * paramIds
Definition primnodes.h:1082
bool isInitPlan
Definition primnodes.h:1093
bool useHashTable
Definition primnodes.h:1094
Node * testexpr
Definition primnodes.h:1081
List * parParam
Definition primnodes.h:1105
List * setParam
Definition primnodes.h:1103
SubLinkType subLinkType
Definition primnodes.h:1079
Expr * refassgnexpr
Definition primnodes.h:726
List * refupperindexpr
Definition primnodes.h:716
List * reflowerindexpr
Definition primnodes.h:722
Node * docexpr
Definition primnodes.h:121
Node * rowexpr
Definition primnodes.h:123
List * colexprs
Definition primnodes.h:133
TableFuncType functype
Definition primnodes.h:115
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:598
Index winref
Definition primnodes.h:604
Expr * aggfilter
Definition primnodes.h:600
int ignore_nulls
Definition primnodes.h:610
List * args
Definition primnodes.h:1616
bool indent
Definition primnodes.h:1620
List * named_args
Definition primnodes.h:1612
XmlExprOp op
Definition primnodes.h:1608
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:889
Definition c.h:874
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition c.h:881
Definition c.h:835
Definition type.h:90
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:1949
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:3063
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:2722
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(uint_fast32_t val, char *buf)
Definition zic.c:2854