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