PostgreSQL Source Code  git master
ruleutils.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include "access/amapi.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "access/table.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_am.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_language.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_partitioned_table.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/tablespace.h"
#include "common/keywords.h"
#include "executor/spi.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/pathnodes.h"
#include "optimizer/optimizer.h"
#include "parser/parse_agg.h"
#include "parser/parse_func.h"
#include "parser/parse_node.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "parser/parser.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rewriteSupport.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/hsearch.h"
#include "utils/lsyscache.h"
#include "utils/partcache.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
#include "utils/varlena.h"
#include "utils/xml.h"
Include dependency graph for ruleutils.c:

Go to the source code of this file.

Data Structures

struct  deparse_context
 
struct  deparse_namespace
 
struct  deparse_columns
 
struct  NameHashEntry
 

Macros

#define PRETTYINDENT_STD   8
 
#define PRETTYINDENT_JOIN   4
 
#define PRETTYINDENT_VAR   4
 
#define PRETTYINDENT_LIMIT   40 /* wrap limit */
 
#define PRETTYFLAG_PAREN   0x0001
 
#define PRETTYFLAG_INDENT   0x0002
 
#define PRETTYFLAG_SCHEMA   0x0004
 
#define GET_PRETTY_FLAGS(pretty)
 
#define WRAP_COLUMN_DEFAULT   0
 
#define PRETTY_PAREN(context)   ((context)->prettyFlags & PRETTYFLAG_PAREN)
 
#define PRETTY_INDENT(context)   ((context)->prettyFlags & PRETTYFLAG_INDENT)
 
#define PRETTY_SCHEMA(context)   ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
 
#define deparse_columns_fetch(rangetable_index, dpns)    ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
 
#define only_marker(rte)   ((rte)->inh ? "" : "ONLY ")
 

Typedefs

typedef void(* rsv_callback) (Node *node, deparse_context *context, void *callback_arg)
 

Functions

static char * deparse_expression_pretty (Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
 
static char * pg_get_viewdef_worker (Oid viewoid, int prettyFlags, int wrapColumn)
 
static char * pg_get_triggerdef_worker (Oid trigid, bool pretty)
 
static int decompile_column_index_array (Datum column_index_array, Oid relId, bool withPeriod, StringInfo buf)
 
static char * pg_get_ruledef_worker (Oid ruleoid, int prettyFlags)
 
static char * pg_get_indexdef_worker (Oid indexrelid, int colno, const Oid *excludeOps, bool attrsOnly, bool keysOnly, bool showTblSpc, bool inherits, int prettyFlags, bool missing_ok)
 
static char * pg_get_statisticsobj_worker (Oid statextid, bool columns_only, bool missing_ok)
 
static char * pg_get_partkeydef_worker (Oid relid, int prettyFlags, bool attrsOnly, bool missing_ok)
 
static char * pg_get_constraintdef_worker (Oid constraintId, bool fullCommand, int prettyFlags, bool missing_ok)
 
static textpg_get_expr_worker (text *expr, Oid relid, int prettyFlags)
 
static int print_function_arguments (StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults)
 
static void print_function_rettype (StringInfo buf, HeapTuple proctup)
 
static void print_function_trftypes (StringInfo buf, HeapTuple proctup)
 
static void print_function_sqlbody (StringInfo buf, HeapTuple proctup)
 
static void set_rtable_names (deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
 
static void set_deparse_for_query (deparse_namespace *dpns, Query *query, List *parent_namespaces)
 
static void set_simple_column_names (deparse_namespace *dpns)
 
static bool has_dangerous_join_using (deparse_namespace *dpns, Node *jtnode)
 
static void set_using_names (deparse_namespace *dpns, Node *jtnode, List *parentUsing)
 
static void set_relation_column_names (deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
 
static void set_join_column_names (deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
 
static bool colname_is_unique (const char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
 
static char * make_colname_unique (char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
 
static void expand_colnames_array_to (deparse_columns *colinfo, int n)
 
static void identify_join_columns (JoinExpr *j, RangeTblEntry *jrte, deparse_columns *colinfo)
 
static char * get_rtable_name (int rtindex, deparse_context *context)
 
static void set_deparse_plan (deparse_namespace *dpns, Plan *plan)
 
static Planfind_recursive_union (deparse_namespace *dpns, WorkTableScan *wtscan)
 
static void push_child_plan (deparse_namespace *dpns, Plan *plan, deparse_namespace *save_dpns)
 
static void pop_child_plan (deparse_namespace *dpns, deparse_namespace *save_dpns)
 
static void push_ancestor_plan (deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns)
 
static void pop_ancestor_plan (deparse_namespace *dpns, deparse_namespace *save_dpns)
 
static void make_ruledef (StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
 
static void make_viewdef (StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags, int wrapColumn)
 
static void get_query_def (Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
 
static void get_values_def (List *values_lists, deparse_context *context)
 
static void get_with_clause (Query *query, deparse_context *context)
 
static void get_select_query_def (Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
 
static void get_insert_query_def (Query *query, deparse_context *context, bool colNamesVisible)
 
static void get_update_query_def (Query *query, deparse_context *context, bool colNamesVisible)
 
static void get_update_query_targetlist_def (Query *query, List *targetList, deparse_context *context, RangeTblEntry *rte)
 
static void get_delete_query_def (Query *query, deparse_context *context, bool colNamesVisible)
 
static void get_merge_query_def (Query *query, deparse_context *context, bool colNamesVisible)
 
static void get_utility_query_def (Query *query, deparse_context *context)
 
static void get_basic_select_query (Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
 
static void get_target_list (List *targetList, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
 
static void get_setop_query (Node *setOp, Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
 
static Nodeget_rule_sortgroupclause (Index ref, List *tlist, bool force_colno, deparse_context *context)
 
static void get_rule_groupingset (GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context)
 
static void get_rule_orderby (List *orderList, List *targetList, bool force_colno, deparse_context *context)
 
static void get_rule_windowclause (Query *query, deparse_context *context)
 
static void get_rule_windowspec (WindowClause *wc, List *targetList, deparse_context *context)
 
static char * get_variable (Var *var, int levelsup, bool istoplevel, deparse_context *context)
 
static void get_special_variable (Node *node, deparse_context *context, void *callback_arg)
 
static void resolve_special_varno (Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
 
static Nodefind_param_referent (Param *param, deparse_context *context, deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
 
static SubPlanfind_param_generator (Param *param, deparse_context *context, int *column_p)
 
static SubPlanfind_param_generator_initplan (Param *param, Plan *plan, int *column_p)
 
static void get_parameter (Param *param, deparse_context *context)
 
static const char * get_simple_binary_op_name (OpExpr *expr)
 
static bool isSimpleNode (Node *node, Node *parentNode, int prettyFlags)
 
static void appendContextKeyword (deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
 
static void removeStringInfoSpaces (StringInfo str)
 
static void get_rule_expr (Node *node, deparse_context *context, bool showimplicit)
 
static void get_rule_expr_toplevel (Node *node, deparse_context *context, bool showimplicit)
 
static void get_rule_list_toplevel (List *lst, deparse_context *context, bool showimplicit)
 
static void get_rule_expr_funccall (Node *node, deparse_context *context, bool showimplicit)
 
static bool looks_like_function (Node *node)
 
static void get_oper_expr (OpExpr *expr, deparse_context *context)
 
static void get_func_expr (FuncExpr *expr, deparse_context *context, bool showimplicit)
 
static void get_agg_expr (Aggref *aggref, deparse_context *context, Aggref *original_aggref)
 
static void get_agg_expr_helper (Aggref *aggref, deparse_context *context, Aggref *original_aggref, const char *funcname, const char *options, bool is_json_objectagg)
 
static void get_agg_combine_expr (Node *node, deparse_context *context, void *callback_arg)
 
static void get_windowfunc_expr (WindowFunc *wfunc, deparse_context *context)
 
static void get_windowfunc_expr_helper (WindowFunc *wfunc, deparse_context *context, const char *funcname, const char *options, bool is_json_objectagg)
 
static bool get_func_sql_syntax (FuncExpr *expr, deparse_context *context)
 
static void get_coercion_expr (Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
 
static void get_const_expr (Const *constval, deparse_context *context, int showtype)
 
static void get_const_collation (Const *constval, deparse_context *context)
 
static void get_json_format (JsonFormat *format, StringInfo buf)
 
static void get_json_returning (JsonReturning *returning, StringInfo buf, bool json_format_by_default)
 
static void get_json_constructor (JsonConstructorExpr *ctor, deparse_context *context, bool showimplicit)
 
static void get_json_constructor_options (JsonConstructorExpr *ctor, StringInfo buf)
 
static void get_json_agg_constructor (JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
 
static void simple_quote_literal (StringInfo buf, const char *val)
 
static void get_sublink_expr (SubLink *sublink, deparse_context *context)
 
static void get_tablefunc (TableFunc *tf, deparse_context *context, bool showimplicit)
 
static void get_from_clause (Query *query, const char *prefix, deparse_context *context)
 
static void get_from_clause_item (Node *jtnode, Query *query, deparse_context *context)
 
static void get_rte_alias (RangeTblEntry *rte, int varno, bool use_as, deparse_context *context)
 
static void get_column_alias_list (deparse_columns *colinfo, deparse_context *context)
 
static void get_from_clause_coldeflist (RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
 
static void get_tablesample_def (TableSampleClause *tablesample, deparse_context *context)
 
static void get_opclass_name (Oid opclass, Oid actual_datatype, StringInfo buf)
 
static NodeprocessIndirection (Node *node, deparse_context *context)
 
static void printSubscripts (SubscriptingRef *sbsref, deparse_context *context)
 
static char * get_relation_name (Oid relid)
 
static char * generate_relation_name (Oid relid, List *namespaces)
 
static char * generate_qualified_relation_name (Oid relid)
 
static char * generate_function_name (Oid funcid, int nargs, List *argnames, Oid *argtypes, bool has_variadic, bool *use_variadic_p, ParseExprKind special_exprkind)
 
static char * generate_operator_name (Oid operid, Oid arg1, Oid arg2)
 
static void add_cast_to (StringInfo buf, Oid typid)
 
static char * generate_qualified_type_name (Oid typid)
 
static textstring_to_text (char *str)
 
static char * flatten_reloptions (Oid relid)
 
static void get_reloptions (StringInfo buf, Datum reloptions)
 
static void get_json_path_spec (Node *path_spec, deparse_context *context, bool showimplicit)
 
static void get_json_table_columns (TableFunc *tf, JsonTablePathScan *scan, deparse_context *context, bool showimplicit)
 
static void get_json_table_nested_columns (TableFunc *tf, JsonTablePlan *plan, deparse_context *context, bool showimplicit, bool needcomma)
 
Datum pg_get_ruledef (PG_FUNCTION_ARGS)
 
Datum pg_get_ruledef_ext (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef_ext (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef_wrap (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef_name (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef_name_ext (PG_FUNCTION_ARGS)
 
Datum pg_get_triggerdef (PG_FUNCTION_ARGS)
 
Datum pg_get_triggerdef_ext (PG_FUNCTION_ARGS)
 
Datum pg_get_indexdef (PG_FUNCTION_ARGS)
 
Datum pg_get_indexdef_ext (PG_FUNCTION_ARGS)
 
char * pg_get_indexdef_string (Oid indexrelid)
 
char * pg_get_indexdef_columns (Oid indexrelid, bool pretty)
 
char * pg_get_indexdef_columns_extended (Oid indexrelid, bits16 flags)
 
char * pg_get_querydef (Query *query, bool pretty)
 
Datum pg_get_statisticsobjdef (PG_FUNCTION_ARGS)
 
char * pg_get_statisticsobjdef_string (Oid statextid)
 
Datum pg_get_statisticsobjdef_columns (PG_FUNCTION_ARGS)
 
Datum pg_get_statisticsobjdef_expressions (PG_FUNCTION_ARGS)
 
Datum pg_get_partkeydef (PG_FUNCTION_ARGS)
 
char * pg_get_partkeydef_columns (Oid relid, bool pretty)
 
Datum pg_get_partition_constraintdef (PG_FUNCTION_ARGS)
 
char * pg_get_partconstrdef_string (Oid partitionId, char *aliasname)
 
Datum pg_get_constraintdef (PG_FUNCTION_ARGS)
 
Datum pg_get_constraintdef_ext (PG_FUNCTION_ARGS)
 
char * pg_get_constraintdef_command (Oid constraintId)
 
Datum pg_get_expr (PG_FUNCTION_ARGS)
 
Datum pg_get_expr_ext (PG_FUNCTION_ARGS)
 
Datum pg_get_userbyid (PG_FUNCTION_ARGS)
 
Datum pg_get_serial_sequence (PG_FUNCTION_ARGS)
 
Datum pg_get_functiondef (PG_FUNCTION_ARGS)
 
Datum pg_get_function_arguments (PG_FUNCTION_ARGS)
 
Datum pg_get_function_identity_arguments (PG_FUNCTION_ARGS)
 
Datum pg_get_function_result (PG_FUNCTION_ARGS)
 
static bool is_input_argument (int nth, const char *argmodes)
 
Datum pg_get_function_arg_default (PG_FUNCTION_ARGS)
 
Datum pg_get_function_sqlbody (PG_FUNCTION_ARGS)
 
char * deparse_expression (Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
 
Listdeparse_context_for (const char *aliasname, Oid relid)
 
Listdeparse_context_for_plan_tree (PlannedStmt *pstmt, List *rtable_names)
 
Listset_deparse_context_plan (List *dpcontext, Plan *plan, List *ancestors)
 
Listselect_rtable_names_for_explain (List *rtable, Bitmapset *rels_used)
 
static RangeTblEntryget_simple_values_rte (Query *query, TupleDesc resultDesc)
 
static const char * get_name_for_var_field (Var *var, int fieldno, int levelsup, deparse_context *context)
 
static void get_rule_expr_paren (Node *node, deparse_context *context, bool showimplicit, Node *parentNode)
 
static void get_json_behavior (JsonBehavior *behavior, deparse_context *context, const char *on)
 
static void get_json_expr_options (JsonExpr *jsexpr, deparse_context *context, JsonBehaviorType default_behavior)
 
static void get_xmltable (TableFunc *tf, deparse_context *context, bool showimplicit)
 
static void get_json_table (TableFunc *tf, deparse_context *context, bool showimplicit)
 
char * generate_opclass_name (Oid opclass)
 
const char * quote_identifier (const char *ident)
 
char * quote_qualified_identifier (const char *qualifier, const char *ident)
 
void generate_operator_clause (StringInfo buf, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype)
 
char * generate_collation_name (Oid collid)
 
char * get_range_partbound_string (List *bound_datums)
 
char * get_list_partvalue_string (Const *val)
 

Variables

static SPIPlanPtr plan_getrulebyoid = NULL
 
static const char *const query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1"
 
static SPIPlanPtr plan_getviewrule = NULL
 
static const char *const query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2"
 
bool quote_all_identifiers = false
 

Macro Definition Documentation

◆ deparse_columns_fetch

#define deparse_columns_fetch (   rangetable_index,
  dpns 
)     ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))

Definition at line 296 of file ruleutils.c.

◆ GET_PRETTY_FLAGS

#define GET_PRETTY_FLAGS (   pretty)
Value:
#define PRETTYFLAG_INDENT
Definition: ruleutils.c:90
#define PRETTYFLAG_PAREN
Definition: ruleutils.c:89
#define PRETTYFLAG_SCHEMA
Definition: ruleutils.c:91

Definition at line 94 of file ruleutils.c.

◆ only_marker

#define only_marker (   rte)    ((rte)->inh ? "" : "ONLY ")

Definition at line 535 of file ruleutils.c.

◆ PRETTY_INDENT

#define PRETTY_INDENT (   context)    ((context)->prettyFlags & PRETTYFLAG_INDENT)

Definition at line 103 of file ruleutils.c.

◆ PRETTY_PAREN

#define PRETTY_PAREN (   context)    ((context)->prettyFlags & PRETTYFLAG_PAREN)

Definition at line 102 of file ruleutils.c.

◆ PRETTY_SCHEMA

#define PRETTY_SCHEMA (   context)    ((context)->prettyFlags & PRETTYFLAG_SCHEMA)

Definition at line 104 of file ruleutils.c.

◆ PRETTYFLAG_INDENT

#define PRETTYFLAG_INDENT   0x0002

Definition at line 90 of file ruleutils.c.

◆ PRETTYFLAG_PAREN

#define PRETTYFLAG_PAREN   0x0001

Definition at line 89 of file ruleutils.c.

◆ PRETTYFLAG_SCHEMA

#define PRETTYFLAG_SCHEMA   0x0004

Definition at line 91 of file ruleutils.c.

◆ PRETTYINDENT_JOIN

#define PRETTYINDENT_JOIN   4

Definition at line 83 of file ruleutils.c.

◆ PRETTYINDENT_LIMIT

#define PRETTYINDENT_LIMIT   40 /* wrap limit */

Definition at line 86 of file ruleutils.c.

◆ PRETTYINDENT_STD

#define PRETTYINDENT_STD   8

Definition at line 82 of file ruleutils.c.

◆ PRETTYINDENT_VAR

#define PRETTYINDENT_VAR   4

Definition at line 84 of file ruleutils.c.

◆ WRAP_COLUMN_DEFAULT

#define WRAP_COLUMN_DEFAULT   0

Definition at line 99 of file ruleutils.c.

Typedef Documentation

◆ rsv_callback

typedef void(* rsv_callback) (Node *node, deparse_context *context, void *callback_arg)

Definition at line 309 of file ruleutils.c.

Function Documentation

◆ add_cast_to()

static void add_cast_to ( StringInfo  buf,
Oid  typid 
)
static

Definition at line 13071 of file ruleutils.c.

13072 {
13073  HeapTuple typetup;
13074  Form_pg_type typform;
13075  char *typname;
13076  char *nspname;
13077 
13078  typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13079  if (!HeapTupleIsValid(typetup))
13080  elog(ERROR, "cache lookup failed for type %u", typid);
13081  typform = (Form_pg_type) GETSTRUCT(typetup);
13082 
13083  typname = NameStr(typform->typname);
13084  nspname = get_namespace_name_or_temp(typform->typnamespace);
13085 
13086  appendStringInfo(buf, "::%s.%s",
13088 
13089  ReleaseSysCache(typetup);
13090 }
#define NameStr(name)
Definition: c.h:746
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3390
static char * buf
Definition: pg_test_fsync.c:73
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
NameData typname
Definition: pg_type.h:41
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12623
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References appendStringInfo(), buf, elog, ERROR, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), quote_identifier(), ReleaseSysCache(), SearchSysCache1(), and typname.

Referenced by generate_operator_clause().

◆ appendContextKeyword()

static void appendContextKeyword ( deparse_context context,
const char *  str,
int  indentBefore,
int  indentAfter,
int  indentPlus 
)
static

Definition at line 8718 of file ruleutils.c.

8720 {
8721  StringInfo buf = context->buf;
8722 
8723  if (PRETTY_INDENT(context))
8724  {
8725  int indentAmount;
8726 
8727  context->indentLevel += indentBefore;
8728 
8729  /* remove any trailing spaces currently in the buffer ... */
8731  /* ... then add a newline and some spaces */
8732  appendStringInfoChar(buf, '\n');
8733 
8734  if (context->indentLevel < PRETTYINDENT_LIMIT)
8735  indentAmount = Max(context->indentLevel, 0) + indentPlus;
8736  else
8737  {
8738  /*
8739  * If we're indented more than PRETTYINDENT_LIMIT characters, try
8740  * to conserve horizontal space by reducing the per-level
8741  * indentation. For best results the scale factor here should
8742  * divide all the indent amounts that get added to indentLevel
8743  * (PRETTYINDENT_STD, etc). It's important that the indentation
8744  * not grow unboundedly, else deeply-nested trees use O(N^2)
8745  * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8746  */
8747  indentAmount = PRETTYINDENT_LIMIT +
8748  (context->indentLevel - PRETTYINDENT_LIMIT) /
8749  (PRETTYINDENT_STD / 2);
8750  indentAmount %= PRETTYINDENT_LIMIT;
8751  /* scale/wrap logic affects indentLevel, but not indentPlus */
8752  indentAmount += indentPlus;
8753  }
8754  appendStringInfoSpaces(buf, indentAmount);
8755 
8757 
8758  context->indentLevel += indentAfter;
8759  if (context->indentLevel < 0)
8760  context->indentLevel = 0;
8761  }
8762  else
8764 }
#define Max(x, y)
Definition: c.h:998
const char * str
tree context
Definition: radixtree.h:1829
static void removeStringInfoSpaces(StringInfo str)
Definition: ruleutils.c:8772
#define PRETTYINDENT_LIMIT
Definition: ruleutils.c:86
#define PRETTYINDENT_STD
Definition: ruleutils.c:82
#define PRETTY_INDENT(context)
Definition: ruleutils.c:103
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:212
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194

References appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), buf, context, Max, PRETTY_INDENT, PRETTYINDENT_LIMIT, PRETTYINDENT_STD, removeStringInfoSpaces(), and str.

Referenced by get_basic_select_query(), get_delete_query_def(), get_from_clause(), get_from_clause_item(), get_insert_query_def(), get_json_table(), get_json_table_columns(), get_json_table_nested_columns(), get_merge_query_def(), get_rule_expr(), get_rule_windowclause(), get_select_query_def(), get_setop_query(), get_target_list(), get_update_query_def(), get_utility_query_def(), and get_with_clause().

◆ colname_is_unique()

static bool colname_is_unique ( const char *  colname,
deparse_namespace dpns,
deparse_columns colinfo 
)
static

Definition at line 4789 of file ruleutils.c.

4791 {
4792  int i;
4793  ListCell *lc;
4794 
4795  /* Check against already-assigned column aliases within RTE */
4796  for (i = 0; i < colinfo->num_cols; i++)
4797  {
4798  char *oldname = colinfo->colnames[i];
4799 
4800  if (oldname && strcmp(oldname, colname) == 0)
4801  return false;
4802  }
4803 
4804  /*
4805  * If we're building a new_colnames array, check that too (this will be
4806  * partially but not completely redundant with the previous checks)
4807  */
4808  for (i = 0; i < colinfo->num_new_cols; i++)
4809  {
4810  char *oldname = colinfo->new_colnames[i];
4811 
4812  if (oldname && strcmp(oldname, colname) == 0)
4813  return false;
4814  }
4815 
4816  /* Also check against USING-column names that must be globally unique */
4817  foreach(lc, dpns->using_names)
4818  {
4819  char *oldname = (char *) lfirst(lc);
4820 
4821  if (strcmp(oldname, colname) == 0)
4822  return false;
4823  }
4824 
4825  /* Also check against names already assigned for parent-join USING cols */
4826  foreach(lc, colinfo->parentUsing)
4827  {
4828  char *oldname = (char *) lfirst(lc);
4829 
4830  if (strcmp(oldname, colname) == 0)
4831  return false;
4832  }
4833 
4834  return true;
4835 }
int i
Definition: isn.c:73
#define lfirst(lc)
Definition: pg_list.h:172
List * parentUsing
Definition: ruleutils.c:269
char ** new_colnames
Definition: ruleutils.c:262
char ** colnames
Definition: ruleutils.c:245
List * using_names
Definition: ruleutils.c:171

References deparse_columns::colnames, i, lfirst, deparse_columns::new_colnames, deparse_columns::num_cols, deparse_columns::num_new_cols, deparse_columns::parentUsing, and deparse_namespace::using_names.

Referenced by make_colname_unique().

◆ decompile_column_index_array()

static int decompile_column_index_array ( Datum  column_index_array,
Oid  relId,
bool  withPeriod,
StringInfo  buf 
)
static

Definition at line 2601 of file ruleutils.c.

2603 {
2604  Datum *keys;
2605  int nKeys;
2606  int j;
2607 
2608  /* Extract data from array of int16 */
2609  deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2610  &keys, NULL, &nKeys);
2611 
2612  for (j = 0; j < nKeys; j++)
2613  {
2614  char *colName;
2615 
2616  colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2617 
2618  if (j == 0)
2620  else
2621  appendStringInfo(buf, ", %s%s",
2622  (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
2623  quote_identifier(colName));
2624  }
2625 
2626  return nKeys;
2627 }
#define DatumGetArrayTypeP(X)
Definition: array.h:261
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3678
int j
Definition: isn.c:74
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
uintptr_t Datum
Definition: postgres.h:64
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:162

References appendStringInfo(), appendStringInfoString(), buf, DatumGetArrayTypeP, DatumGetInt16(), deconstruct_array_builtin(), get_attname(), j, and quote_identifier().

Referenced by pg_get_constraintdef_worker().

◆ deparse_context_for()

List* deparse_context_for ( const char *  aliasname,
Oid  relid 
)

Definition at line 3685 of file ruleutils.c.

3686 {
3687  deparse_namespace *dpns;
3688  RangeTblEntry *rte;
3689 
3690  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3691 
3692  /* Build a minimal RTE for the rel */
3693  rte = makeNode(RangeTblEntry);
3694  rte->rtekind = RTE_RELATION;
3695  rte->relid = relid;
3696  rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3697  rte->rellockmode = AccessShareLock;
3698  rte->alias = makeAlias(aliasname, NIL);
3699  rte->eref = rte->alias;
3700  rte->lateral = false;
3701  rte->inh = false;
3702  rte->inFromCl = true;
3703 
3704  /* Build one-element rtable */
3705  dpns->rtable = list_make1(rte);
3706  dpns->subplans = NIL;
3707  dpns->ctes = NIL;
3708  dpns->appendrels = NULL;
3709  set_rtable_names(dpns, NIL, NULL);
3711 
3712  /* Return a one-deep namespace stack */
3713  return list_make1(dpns);
3714 }
#define AccessShareLock
Definition: lockdefs.h:36
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:389
void * palloc0(Size size)
Definition: mcxt.c:1346
#define makeNode(_type_)
Definition: nodes.h:155
@ RTE_RELATION
Definition: parsenodes.h:1028
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
static void set_simple_column_names(deparse_namespace *dpns)
Definition: ruleutils.c:4061
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
Definition: ruleutils.c:3851
RTEKind rtekind
Definition: parsenodes.h:1057
AppendRelInfo ** appendrels
Definition: ruleutils.c:168

References AccessShareLock, deparse_namespace::appendrels, deparse_namespace::ctes, RangeTblEntry::inh, list_make1, makeAlias(), makeNode, NIL, palloc0(), RangeTblEntry::relid, deparse_namespace::rtable, RTE_RELATION, RangeTblEntry::rtekind, set_rtable_names(), set_simple_column_names(), and deparse_namespace::subplans.

Referenced by pg_get_constraintdef_worker(), pg_get_expr_worker(), pg_get_indexdef_worker(), pg_get_partconstrdef_string(), pg_get_partition_constraintdef(), pg_get_partkeydef_worker(), pg_get_statisticsobj_worker(), pg_get_statisticsobjdef_expressions(), transformPartitionBound(), and transformPartitionRangeBounds().

◆ deparse_context_for_plan_tree()

List* deparse_context_for_plan_tree ( PlannedStmt pstmt,
List rtable_names 
)

Definition at line 3730 of file ruleutils.c.

3731 {
3732  deparse_namespace *dpns;
3733 
3734  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3735 
3736  /* Initialize fields that stay the same across the whole plan tree */
3737  dpns->rtable = pstmt->rtable;
3738  dpns->rtable_names = rtable_names;
3739  dpns->subplans = pstmt->subplans;
3740  dpns->ctes = NIL;
3741  if (pstmt->appendRelations)
3742  {
3743  /* Set up the array, indexed by child relid */
3744  int ntables = list_length(dpns->rtable);
3745  ListCell *lc;
3746 
3747  dpns->appendrels = (AppendRelInfo **)
3748  palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3749  foreach(lc, pstmt->appendRelations)
3750  {
3751  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3752  Index crelid = appinfo->child_relid;
3753 
3754  Assert(crelid > 0 && crelid <= ntables);
3755  Assert(dpns->appendrels[crelid] == NULL);
3756  dpns->appendrels[crelid] = appinfo;
3757  }
3758  }
3759  else
3760  dpns->appendrels = NULL; /* don't need it */
3761 
3762  /*
3763  * Set up column name aliases. We will get rather bogus results for join
3764  * RTEs, but that doesn't matter because plan trees don't contain any join
3765  * alias Vars.
3766  */
3768 
3769  /* Return a one-deep namespace stack */
3770  return list_make1(dpns);
3771 }
#define Assert(condition)
Definition: c.h:858
unsigned int Index
Definition: c.h:614
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
Index child_relid
Definition: pathnodes.h:2958
List * appendRelations
Definition: plannodes.h:80
List * subplans
Definition: plannodes.h:82
List * rtable
Definition: plannodes.h:72
List * rtable_names
Definition: ruleutils.c:164

References PlannedStmt::appendRelations, deparse_namespace::appendrels, Assert, AppendRelInfo::child_relid, deparse_namespace::ctes, lfirst_node, list_length(), list_make1, NIL, palloc0(), deparse_namespace::rtable, PlannedStmt::rtable, deparse_namespace::rtable_names, set_simple_column_names(), deparse_namespace::subplans, and PlannedStmt::subplans.

Referenced by ExplainPrintPlan().

◆ deparse_expression()

char* deparse_expression ( Node expr,
List dpcontext,
bool  forceprefix,
bool  showimplicit 
)

Definition at line 3625 of file ruleutils.c.

3627 {
3628  return deparse_expression_pretty(expr, dpcontext, forceprefix,
3629  showimplicit, 0, 0);
3630 }
static char * deparse_expression_pretty(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
Definition: ruleutils.c:3652

References deparse_expression_pretty().

Referenced by AlterDomainDefault(), DefineDomain(), pg_get_function_arg_default(), pg_get_partconstrdef_string(), print_function_arguments(), show_expression(), show_grouping_set_keys(), show_memoize_info(), show_plan_tlist(), show_sort_group_keys(), show_tablesample(), transformPartitionBound(), and transformPartitionRangeBounds().

◆ deparse_expression_pretty()

static char * deparse_expression_pretty ( Node expr,
List dpcontext,
bool  forceprefix,
bool  showimplicit,
int  prettyFlags,
int  startIndent 
)
static

Definition at line 3652 of file ruleutils.c.

3655 {
3658 
3659  initStringInfo(&buf);
3660  context.buf = &buf;
3661  context.namespaces = dpcontext;
3662  context.windowClause = NIL;
3663  context.windowTList = NIL;
3664  context.varprefix = forceprefix;
3665  context.prettyFlags = prettyFlags;
3666  context.wrapColumn = WRAP_COLUMN_DEFAULT;
3667  context.indentLevel = startIndent;
3668  context.special_exprkind = EXPR_KIND_NONE;
3669  context.appendparents = NULL;
3670 
3671  get_rule_expr(expr, &context, showimplicit);
3672 
3673  return buf.data;
3674 }
@ EXPR_KIND_NONE
Definition: parse_node.h:40
#define WRAP_COLUMN_DEFAULT
Definition: ruleutils.c:99
static void get_rule_expr(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:8888
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

References buf, context, EXPR_KIND_NONE, get_rule_expr(), initStringInfo(), NIL, and WRAP_COLUMN_DEFAULT.

Referenced by deparse_expression(), pg_get_constraintdef_worker(), pg_get_expr_worker(), pg_get_indexdef_worker(), pg_get_partition_constraintdef(), pg_get_partkeydef_worker(), pg_get_statisticsobj_worker(), and pg_get_statisticsobjdef_expressions().

◆ expand_colnames_array_to()

static void expand_colnames_array_to ( deparse_columns colinfo,
int  n 
)
static

Definition at line 4882 of file ruleutils.c.

4883 {
4884  if (n > colinfo->num_cols)
4885  {
4886  if (colinfo->colnames == NULL)
4887  colinfo->colnames = palloc0_array(char *, n);
4888  else
4889  colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4890  colinfo->num_cols = n;
4891  }
4892 }
#define palloc0_array(type, count)
Definition: fe_memutils.h:65
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:109

References deparse_columns::colnames, deparse_columns::num_cols, palloc0_array, and repalloc0_array.

Referenced by set_join_column_names(), set_relation_column_names(), and set_using_names().

◆ find_param_generator()

static SubPlan * find_param_generator ( Param param,
deparse_context context,
int *  column_p 
)
static

Definition at line 8208 of file ruleutils.c.

8209 {
8210  /* Initialize output parameter to prevent compiler warnings */
8211  *column_p = 0;
8212 
8213  /*
8214  * If it's a PARAM_EXEC parameter, search the current plan node as well as
8215  * ancestor nodes looking for a subplan or initplan that emits the value
8216  * for the Param. It could appear in the setParams of an initplan or
8217  * MULTIEXPR_SUBLINK subplan, or in the paramIds of an ancestral SubPlan.
8218  */
8219  if (param->paramkind == PARAM_EXEC)
8220  {
8221  SubPlan *result;
8222  deparse_namespace *dpns;
8223  ListCell *lc;
8224 
8225  dpns = (deparse_namespace *) linitial(context->namespaces);
8226 
8227  /* First check the innermost plan node's initplans */
8228  result = find_param_generator_initplan(param, dpns->plan, column_p);
8229  if (result)
8230  return result;
8231 
8232  /*
8233  * The plan's targetlist might contain MULTIEXPR_SUBLINK SubPlans,
8234  * which can be referenced by Params elsewhere in the targetlist.
8235  * (Such Params should always be in the same targetlist, so there's no
8236  * need to do this work at upper plan nodes.)
8237  */
8238  foreach_node(TargetEntry, tle, dpns->plan->targetlist)
8239  {
8240  if (tle->expr && IsA(tle->expr, SubPlan))
8241  {
8242  SubPlan *subplan = (SubPlan *) tle->expr;
8243 
8244  if (subplan->subLinkType == MULTIEXPR_SUBLINK)
8245  {
8246  foreach_int(paramid, subplan->setParam)
8247  {
8248  if (paramid == param->paramid)
8249  {
8250  /* Found a match, so return it. */
8251  *column_p = foreach_current_index(paramid);
8252  return subplan;
8253  }
8254  }
8255  }
8256  }
8257  }
8258 
8259  /* No luck, so check the ancestor nodes */
8260  foreach(lc, dpns->ancestors)
8261  {
8262  Node *ancestor = (Node *) lfirst(lc);
8263 
8264  /*
8265  * If ancestor is a SubPlan, check the paramIds it provides.
8266  */
8267  if (IsA(ancestor, SubPlan))
8268  {
8269  SubPlan *subplan = (SubPlan *) ancestor;
8270 
8271  foreach_int(paramid, subplan->paramIds)
8272  {
8273  if (paramid == param->paramid)
8274  {
8275  /* Found a match, so return it. */
8276  *column_p = foreach_current_index(paramid);
8277  return subplan;
8278  }
8279  }
8280 
8281  /* SubPlan isn't a kind of Plan, so skip the rest */
8282  continue;
8283  }
8284 
8285  /*
8286  * Otherwise, it's some kind of Plan node, so check its initplans.
8287  */
8288  result = find_param_generator_initplan(param, (Plan *) ancestor,
8289  column_p);
8290  if (result)
8291  return result;
8292 
8293  /* No luck, crawl up to next ancestor */
8294  }
8295  }
8296 
8297  /* No generator found */
8298  return NULL;
8299 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
#define linitial(l)
Definition: pg_list.h:178
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
#define foreach_int(var, lst)
Definition: pg_list.h:470
@ MULTIEXPR_SUBLINK
Definition: primnodes.h:972
@ PARAM_EXEC
Definition: primnodes.h:368
static SubPlan * find_param_generator_initplan(Param *param, Plan *plan, int *column_p)
Definition: ruleutils.c:8305
Definition: nodes.h:129
int paramid
Definition: primnodes.h:377
ParamKind paramkind
Definition: primnodes.h:376
List * targetlist
Definition: plannodes.h:152
List * paramIds
Definition: primnodes.h:1038
List * setParam
Definition: primnodes.h:1058
SubLinkType subLinkType
Definition: primnodes.h:1035

References deparse_namespace::ancestors, context, find_param_generator_initplan(), foreach_current_index, foreach_int, foreach_node, if(), IsA, lfirst, linitial, MULTIEXPR_SUBLINK, PARAM_EXEC, Param::paramid, SubPlan::paramIds, Param::paramkind, deparse_namespace::plan, SubPlan::setParam, SubPlan::subLinkType, and Plan::targetlist.

Referenced by get_parameter().

◆ find_param_generator_initplan()

static SubPlan * find_param_generator_initplan ( Param param,
Plan plan,
int *  column_p 
)
static

Definition at line 8305 of file ruleutils.c.

8306 {
8307  foreach_node(SubPlan, subplan, plan->initPlan)
8308  {
8309  foreach_int(paramid, subplan->setParam)
8310  {
8311  if (paramid == param->paramid)
8312  {
8313  /* Found a match, so return it. */
8314  *column_p = foreach_current_index(paramid);
8315  return subplan;
8316  }
8317  }
8318  }
8319  return NULL;
8320 }
#define plan(x)
Definition: pg_regress.c:162

References foreach_current_index, foreach_int, foreach_node, Param::paramid, and plan.

Referenced by find_param_generator().

◆ find_param_referent()

static Node * find_param_referent ( Param param,
deparse_context context,
deparse_namespace **  dpns_p,
ListCell **  ancestor_cell_p 
)
static

Definition at line 8094 of file ruleutils.c.

8096 {
8097  /* Initialize output parameters to prevent compiler warnings */
8098  *dpns_p = NULL;
8099  *ancestor_cell_p = NULL;
8100 
8101  /*
8102  * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
8103  * SubPlan argument. This will necessarily be in some ancestor of the
8104  * current expression's Plan node.
8105  */
8106  if (param->paramkind == PARAM_EXEC)
8107  {
8108  deparse_namespace *dpns;
8109  Plan *child_plan;
8110  ListCell *lc;
8111 
8112  dpns = (deparse_namespace *) linitial(context->namespaces);
8113  child_plan = dpns->plan;
8114 
8115  foreach(lc, dpns->ancestors)
8116  {
8117  Node *ancestor = (Node *) lfirst(lc);
8118  ListCell *lc2;
8119 
8120  /*
8121  * NestLoops transmit params to their inner child only.
8122  */
8123  if (IsA(ancestor, NestLoop) &&
8124  child_plan == innerPlan(ancestor))
8125  {
8126  NestLoop *nl = (NestLoop *) ancestor;
8127 
8128  foreach(lc2, nl->nestParams)
8129  {
8130  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
8131 
8132  if (nlp->paramno == param->paramid)
8133  {
8134  /* Found a match, so return it */
8135  *dpns_p = dpns;
8136  *ancestor_cell_p = lc;
8137  return (Node *) nlp->paramval;
8138  }
8139  }
8140  }
8141 
8142  /*
8143  * If ancestor is a SubPlan, check the arguments it provides.
8144  */
8145  if (IsA(ancestor, SubPlan))
8146  {
8147  SubPlan *subplan = (SubPlan *) ancestor;
8148  ListCell *lc3;
8149  ListCell *lc4;
8150 
8151  forboth(lc3, subplan->parParam, lc4, subplan->args)
8152  {
8153  int paramid = lfirst_int(lc3);
8154  Node *arg = (Node *) lfirst(lc4);
8155 
8156  if (paramid == param->paramid)
8157  {
8158  /*
8159  * Found a match, so return it. But, since Vars in
8160  * the arg are to be evaluated in the surrounding
8161  * context, we have to point to the next ancestor item
8162  * that is *not* a SubPlan.
8163  */
8164  ListCell *rest;
8165 
8166  for_each_cell(rest, dpns->ancestors,
8167  lnext(dpns->ancestors, lc))
8168  {
8169  Node *ancestor2 = (Node *) lfirst(rest);
8170 
8171  if (!IsA(ancestor2, SubPlan))
8172  {
8173  *dpns_p = dpns;
8174  *ancestor_cell_p = rest;
8175  return arg;
8176  }
8177  }
8178  elog(ERROR, "SubPlan cannot be outermost ancestor");
8179  }
8180  }
8181 
8182  /* SubPlan isn't a kind of Plan, so skip the rest */
8183  continue;
8184  }
8185 
8186  /*
8187  * We need not consider the ancestor's initPlan list, since
8188  * initplans never have any parParams.
8189  */
8190 
8191  /* No luck, crawl up to next ancestor */
8192  child_plan = (Plan *) ancestor;
8193  }
8194  }
8195 
8196  /* No referent found */
8197  return NULL;
8198 }
void * arg
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define lfirst_int(lc)
Definition: pg_list.h:173
#define for_each_cell(cell, lst, initcell)
Definition: pg_list.h:438
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define innerPlan(node)
Definition: plannodes.h:181
Var * paramval
Definition: plannodes.h:819
List * nestParams
Definition: plannodes.h:810
List * args
Definition: primnodes.h:1061
List * parParam
Definition: primnodes.h:1060

References deparse_namespace::ancestors, arg, SubPlan::args, context, elog, ERROR, for_each_cell, forboth, innerPlan, IsA, lfirst, lfirst_int, linitial, lnext(), NestLoop::nestParams, PARAM_EXEC, Param::paramid, Param::paramkind, NestLoopParam::paramno, NestLoopParam::paramval, SubPlan::parParam, and deparse_namespace::plan.

Referenced by get_name_for_var_field(), and get_parameter().

◆ find_recursive_union()

static Plan * find_recursive_union ( deparse_namespace dpns,
WorkTableScan wtscan 
)
static

Definition at line 5069 of file ruleutils.c.

5070 {
5071  ListCell *lc;
5072 
5073  foreach(lc, dpns->ancestors)
5074  {
5075  Plan *ancestor = (Plan *) lfirst(lc);
5076 
5077  if (IsA(ancestor, RecursiveUnion) &&
5078  ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5079  return ancestor;
5080  }
5081  elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5082  wtscan->wtParam);
5083  return NULL;
5084 }

References deparse_namespace::ancestors, elog, ERROR, IsA, lfirst, and WorkTableScan::wtParam.

Referenced by set_deparse_plan().

◆ flatten_reloptions()

static char * flatten_reloptions ( Oid  relid)
static

Definition at line 13235 of file ruleutils.c.

13236 {
13237  char *result = NULL;
13238  HeapTuple tuple;
13239  Datum reloptions;
13240  bool isnull;
13241 
13242  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13243  if (!HeapTupleIsValid(tuple))
13244  elog(ERROR, "cache lookup failed for relation %u", relid);
13245 
13246  reloptions = SysCacheGetAttr(RELOID, tuple,
13247  Anum_pg_class_reloptions, &isnull);
13248  if (!isnull)
13249  {
13251 
13252  initStringInfo(&buf);
13253  get_reloptions(&buf, reloptions);
13254 
13255  result = buf.data;
13256  }
13257 
13258  ReleaseSysCache(tuple);
13259 
13260  return result;
13261 }
static void get_reloptions(StringInfo buf, Datum reloptions)
Definition: ruleutils.c:13180
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479

References buf, elog, ERROR, get_reloptions(), HeapTupleIsValid, initStringInfo(), ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache1(), and SysCacheGetAttr().

Referenced by pg_get_constraintdef_worker(), and pg_get_indexdef_worker().

◆ generate_collation_name()

char* generate_collation_name ( Oid  collid)

Definition at line 13135 of file ruleutils.c.

13136 {
13137  HeapTuple tp;
13138  Form_pg_collation colltup;
13139  char *collname;
13140  char *nspname;
13141  char *result;
13142 
13143  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
13144  if (!HeapTupleIsValid(tp))
13145  elog(ERROR, "cache lookup failed for collation %u", collid);
13146  colltup = (Form_pg_collation) GETSTRUCT(tp);
13147  collname = NameStr(colltup->collname);
13148 
13149  if (!CollationIsVisible(collid))
13150  nspname = get_namespace_name_or_temp(colltup->collnamespace);
13151  else
13152  nspname = NULL;
13153 
13154  result = quote_qualified_identifier(nspname, collname);
13155 
13156  ReleaseSysCache(tp);
13157 
13158  return result;
13159 }
Oid collid
bool CollationIsVisible(Oid collid)
Definition: namespace.c:2392
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:58
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:12707

References CollationIsVisible(), collid, elog, ERROR, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), quote_qualified_identifier(), ReleaseSysCache(), and SearchSysCache1().

Referenced by get_const_collation(), get_from_clause_coldeflist(), get_rule_expr(), pg_collation_for(), pg_get_indexdef_worker(), and pg_get_partkeydef_worker().

◆ generate_function_name()

static char * generate_function_name ( Oid  funcid,
int  nargs,
List argnames,
Oid argtypes,
bool  has_variadic,
bool use_variadic_p,
ParseExprKind  special_exprkind 
)
static

Definition at line 12849 of file ruleutils.c.

12852 {
12853  char *result;
12854  HeapTuple proctup;
12855  Form_pg_proc procform;
12856  char *proname;
12857  bool use_variadic;
12858  char *nspname;
12859  FuncDetailCode p_result;
12860  Oid p_funcid;
12861  Oid p_rettype;
12862  bool p_retset;
12863  int p_nvargs;
12864  Oid p_vatype;
12865  Oid *p_true_typeids;
12866  bool force_qualify = false;
12867 
12868  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
12869  if (!HeapTupleIsValid(proctup))
12870  elog(ERROR, "cache lookup failed for function %u", funcid);
12871  procform = (Form_pg_proc) GETSTRUCT(proctup);
12872  proname = NameStr(procform->proname);
12873 
12874  /*
12875  * Due to parser hacks to avoid needing to reserve CUBE, we need to force
12876  * qualification in some special cases.
12877  */
12878  if (special_exprkind == EXPR_KIND_GROUP_BY)
12879  {
12880  if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
12881  force_qualify = true;
12882  }
12883 
12884  /*
12885  * Determine whether VARIADIC should be printed. We must do this first
12886  * since it affects the lookup rules in func_get_detail().
12887  *
12888  * We always print VARIADIC if the function has a merged variadic-array
12889  * argument. Note that this is always the case for functions taking a
12890  * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
12891  * and printed the array elements as separate arguments, the call could
12892  * match a newer non-VARIADIC function.
12893  */
12894  if (use_variadic_p)
12895  {
12896  /* Parser should not have set funcvariadic unless fn is variadic */
12897  Assert(!has_variadic || OidIsValid(procform->provariadic));
12898  use_variadic = has_variadic;
12899  *use_variadic_p = use_variadic;
12900  }
12901  else
12902  {
12903  Assert(!has_variadic);
12904  use_variadic = false;
12905  }
12906 
12907  /*
12908  * The idea here is to schema-qualify only if the parser would fail to
12909  * resolve the correct function given the unqualified func name with the
12910  * specified argtypes and VARIADIC flag. But if we already decided to
12911  * force qualification, then we can skip the lookup and pretend we didn't
12912  * find it.
12913  */
12914  if (!force_qualify)
12916  NIL, argnames, nargs, argtypes,
12917  !use_variadic, true, false,
12918  &p_funcid, &p_rettype,
12919  &p_retset, &p_nvargs, &p_vatype,
12920  &p_true_typeids, NULL);
12921  else
12922  {
12923  p_result = FUNCDETAIL_NOTFOUND;
12924  p_funcid = InvalidOid;
12925  }
12926 
12927  if ((p_result == FUNCDETAIL_NORMAL ||
12928  p_result == FUNCDETAIL_AGGREGATE ||
12929  p_result == FUNCDETAIL_WINDOWFUNC) &&
12930  p_funcid == funcid)
12931  nspname = NULL;
12932  else
12933  nspname = get_namespace_name_or_temp(procform->pronamespace);
12934 
12935  result = quote_qualified_identifier(nspname, proname);
12936 
12937  ReleaseSysCache(proctup);
12938 
12939  return result;
12940 }
#define OidIsValid(objectId)
Definition: c.h:775
FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, bool include_out_arguments, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, Oid **true_typeids, List **argdefaults)
Definition: parse_func.c:1394
FuncDetailCode
Definition: parse_func.h:23
@ FUNCDETAIL_NORMAL
Definition: parse_func.h:26
@ FUNCDETAIL_WINDOWFUNC
Definition: parse_func.h:29
@ FUNCDETAIL_NOTFOUND
Definition: parse_func.h:24
@ FUNCDETAIL_AGGREGATE
Definition: parse_func.h:28
@ EXPR_KIND_GROUP_BY
Definition: parse_node.h:59
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
NameData proname
Definition: pg_proc.h:35
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
String * makeString(char *str)
Definition: value.c:63

References Assert, elog, ERROR, EXPR_KIND_GROUP_BY, func_get_detail(), FUNCDETAIL_AGGREGATE, FUNCDETAIL_NORMAL, FUNCDETAIL_NOTFOUND, FUNCDETAIL_WINDOWFUNC, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, InvalidOid, list_make1, makeString(), NameStr, NIL, ObjectIdGetDatum(), OidIsValid, proname, quote_qualified_identifier(), ReleaseSysCache(), and SearchSysCache1().

Referenced by get_agg_expr_helper(), get_func_expr(), get_tablesample_def(), get_windowfunc_expr_helper(), pg_get_functiondef(), and pg_get_triggerdef_worker().

◆ generate_opclass_name()

char* generate_opclass_name ( Oid  opclass)

Definition at line 12493 of file ruleutils.c.

12494 {
12496 
12497  initStringInfo(&buf);
12498  get_opclass_name(opclass, InvalidOid, &buf);
12499 
12500  return &buf.data[1]; /* get_opclass_name() prepends space */
12501 }
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Definition: ruleutils.c:12455

References buf, get_opclass_name(), initStringInfo(), and InvalidOid.

Referenced by index_opclass_options().

◆ generate_operator_clause()

void generate_operator_clause ( StringInfo  buf,
const char *  leftop,
Oid  leftoptype,
Oid  opoid,
const char *  rightop,
Oid  rightoptype 
)

Definition at line 13031 of file ruleutils.c.

13035 {
13036  HeapTuple opertup;
13037  Form_pg_operator operform;
13038  char *oprname;
13039  char *nspname;
13040 
13041  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
13042  if (!HeapTupleIsValid(opertup))
13043  elog(ERROR, "cache lookup failed for operator %u", opoid);
13044  operform = (Form_pg_operator) GETSTRUCT(opertup);
13045  Assert(operform->oprkind == 'b');
13046  oprname = NameStr(operform->oprname);
13047 
13048  nspname = get_namespace_name(operform->oprnamespace);
13049 
13050  appendStringInfoString(buf, leftop);
13051  if (leftoptype != operform->oprleft)
13052  add_cast_to(buf, operform->oprleft);
13053  appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
13054  appendStringInfoString(buf, oprname);
13055  appendStringInfo(buf, ") %s", rightop);
13056  if (rightoptype != operform->oprright)
13057  add_cast_to(buf, operform->oprright);
13058 
13059  ReleaseSysCache(opertup);
13060 }
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static void add_cast_to(StringInfo buf, Oid typid)
Definition: ruleutils.c:13071

References add_cast_to(), appendStringInfo(), appendStringInfoString(), Assert, buf, elog, ERROR, get_namespace_name(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), quote_identifier(), ReleaseSysCache(), and SearchSysCache1().

Referenced by refresh_by_match_merge(), and ri_GenerateQual().

◆ generate_operator_name()

static char * generate_operator_name ( Oid  operid,
Oid  arg1,
Oid  arg2 
)
static

Definition at line 12954 of file ruleutils.c.

12955 {
12957  HeapTuple opertup;
12958  Form_pg_operator operform;
12959  char *oprname;
12960  char *nspname;
12961  Operator p_result;
12962 
12963  initStringInfo(&buf);
12964 
12965  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
12966  if (!HeapTupleIsValid(opertup))
12967  elog(ERROR, "cache lookup failed for operator %u", operid);
12968  operform = (Form_pg_operator) GETSTRUCT(opertup);
12969  oprname = NameStr(operform->oprname);
12970 
12971  /*
12972  * The idea here is to schema-qualify only if the parser would fail to
12973  * resolve the correct operator given the unqualified op name with the
12974  * specified argtypes.
12975  */
12976  switch (operform->oprkind)
12977  {
12978  case 'b':
12979  p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
12980  true, -1);
12981  break;
12982  case 'l':
12983  p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
12984  true, -1);
12985  break;
12986  default:
12987  elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
12988  p_result = NULL; /* keep compiler quiet */
12989  break;
12990  }
12991 
12992  if (p_result != NULL && oprid(p_result) == operid)
12993  nspname = NULL;
12994  else
12995  {
12996  nspname = get_namespace_name_or_temp(operform->oprnamespace);
12997  appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
12998  }
12999 
13000  appendStringInfoString(&buf, oprname);
13001 
13002  if (nspname)
13003  appendStringInfoChar(&buf, ')');
13004 
13005  if (p_result != NULL)
13006  ReleaseSysCache(p_result);
13007 
13008  ReleaseSysCache(opertup);
13009 
13010  return buf.data;
13011 }
Operator left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
Definition: parse_oper.c:518
Oid oprid(Operator op)
Definition: parse_oper.c:238
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:370

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), buf, elog, ERROR, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, initStringInfo(), left_oper(), list_make1, makeString(), NameStr, ObjectIdGetDatum(), oper(), oprid(), quote_identifier(), ReleaseSysCache(), and SearchSysCache1().

Referenced by get_oper_expr(), get_rule_expr(), get_rule_orderby(), get_simple_binary_op_name(), get_sublink_expr(), and pg_get_indexdef_worker().

◆ generate_qualified_relation_name()

static char * generate_qualified_relation_name ( Oid  relid)
static

Definition at line 12807 of file ruleutils.c.

12808 {
12809  HeapTuple tp;
12810  Form_pg_class reltup;
12811  char *relname;
12812  char *nspname;
12813  char *result;
12814 
12815  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12816  if (!HeapTupleIsValid(tp))
12817  elog(ERROR, "cache lookup failed for relation %u", relid);
12818  reltup = (Form_pg_class) GETSTRUCT(tp);
12819  relname = NameStr(reltup->relname);
12820 
12821  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12822  if (!nspname)
12823  elog(ERROR, "cache lookup failed for namespace %u",
12824  reltup->relnamespace);
12825 
12826  result = quote_qualified_identifier(nspname, relname);
12827 
12828  ReleaseSysCache(tp);
12829 
12830  return result;
12831 }
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153

References elog, ERROR, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), quote_qualified_identifier(), ReleaseSysCache(), relname, and SearchSysCache1().

Referenced by make_ruledef(), pg_get_constraintdef_worker(), pg_get_indexdef_worker(), pg_get_serial_sequence(), and pg_get_triggerdef_worker().

◆ generate_qualified_type_name()

static char * generate_qualified_type_name ( Oid  typid)
static

Definition at line 13102 of file ruleutils.c.

13103 {
13104  HeapTuple tp;
13105  Form_pg_type typtup;
13106  char *typname;
13107  char *nspname;
13108  char *result;
13109 
13110  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13111  if (!HeapTupleIsValid(tp))
13112  elog(ERROR, "cache lookup failed for type %u", typid);
13113  typtup = (Form_pg_type) GETSTRUCT(tp);
13114  typname = NameStr(typtup->typname);
13115 
13116  nspname = get_namespace_name_or_temp(typtup->typnamespace);
13117  if (!nspname)
13118  elog(ERROR, "cache lookup failed for namespace %u",
13119  typtup->typnamespace);
13120 
13121  result = quote_qualified_identifier(nspname, typname);
13122 
13123  ReleaseSysCache(tp);
13124 
13125  return result;
13126 }

References elog, ERROR, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), quote_qualified_identifier(), ReleaseSysCache(), SearchSysCache1(), and typname.

Referenced by pg_get_constraintdef_worker().

◆ generate_relation_name()

static char * generate_relation_name ( Oid  relid,
List namespaces 
)
static

Definition at line 12747 of file ruleutils.c.

12748 {
12749  HeapTuple tp;
12750  Form_pg_class reltup;
12751  bool need_qual;
12752  ListCell *nslist;
12753  char *relname;
12754  char *nspname;
12755  char *result;
12756 
12757  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12758  if (!HeapTupleIsValid(tp))
12759  elog(ERROR, "cache lookup failed for relation %u", relid);
12760  reltup = (Form_pg_class) GETSTRUCT(tp);
12761  relname = NameStr(reltup->relname);
12762 
12763  /* Check for conflicting CTE name */
12764  need_qual = false;
12765  foreach(nslist, namespaces)
12766  {
12767  deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
12768  ListCell *ctlist;
12769 
12770  foreach(ctlist, dpns->ctes)
12771  {
12772  CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
12773 
12774  if (strcmp(cte->ctename, relname) == 0)
12775  {
12776  need_qual = true;
12777  break;
12778  }
12779  }
12780  if (need_qual)
12781  break;
12782  }
12783 
12784  /* Otherwise, qualify the name if not visible in search path */
12785  if (!need_qual)
12786  need_qual = !RelationIsVisible(relid);
12787 
12788  if (need_qual)
12789  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12790  else
12791  nspname = NULL;
12792 
12793  result = quote_qualified_identifier(nspname, relname);
12794 
12795  ReleaseSysCache(tp);
12796 
12797  return result;
12798 }
bool RelationIsVisible(Oid relid)
Definition: namespace.c:898

References CommonTableExpr::ctename, deparse_namespace::ctes, elog, ERROR, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, lfirst, NameStr, ObjectIdGetDatum(), quote_qualified_identifier(), RelationIsVisible(), ReleaseSysCache(), relname, and SearchSysCache1().

Referenced by get_delete_query_def(), get_from_clause_item(), get_insert_query_def(), get_merge_query_def(), get_rule_expr(), get_update_query_def(), make_ruledef(), pg_get_constraintdef_worker(), pg_get_indexdef_worker(), pg_get_statisticsobj_worker(), and pg_get_triggerdef_worker().

◆ get_agg_combine_expr()

static void get_agg_combine_expr ( Node node,
deparse_context context,
void *  callback_arg 
)
static

Definition at line 10624 of file ruleutils.c.

10625 {
10626  Aggref *aggref;
10627  Aggref *original_aggref = callback_arg;
10628 
10629  if (!IsA(node, Aggref))
10630  elog(ERROR, "combining Aggref does not point to an Aggref");
10631 
10632  aggref = (Aggref *) node;
10633  get_agg_expr(aggref, context, original_aggref);
10634 }
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
Definition: ruleutils.c:10486

References context, elog, ERROR, get_agg_expr(), and IsA.

Referenced by get_agg_expr_helper().

◆ get_agg_expr()

static void get_agg_expr ( Aggref aggref,
deparse_context context,
Aggref original_aggref 
)
static

Definition at line 10486 of file ruleutils.c.

10488 {
10489  get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10490  false);
10491 }
static void get_agg_expr_helper(Aggref *aggref, deparse_context *context, Aggref *original_aggref, const char *funcname, const char *options, bool is_json_objectagg)
Definition: ruleutils.c:10498

References context, and get_agg_expr_helper().

Referenced by get_agg_combine_expr(), and get_rule_expr().

◆ get_agg_expr_helper()

static void get_agg_expr_helper ( Aggref aggref,
deparse_context context,
Aggref original_aggref,
const char *  funcname,
const char *  options,
bool  is_json_objectagg 
)
static

Definition at line 10498 of file ruleutils.c.

10501 {
10502  StringInfo buf = context->buf;
10503  Oid argtypes[FUNC_MAX_ARGS];
10504  int nargs;
10505  bool use_variadic = false;
10506 
10507  /*
10508  * For a combining aggregate, we look up and deparse the corresponding
10509  * partial aggregate instead. This is necessary because our input
10510  * argument list has been replaced; the new argument list always has just
10511  * one element, which will point to a partial Aggref that supplies us with
10512  * transition states to combine.
10513  */
10514  if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10515  {
10516  TargetEntry *tle;
10517 
10518  Assert(list_length(aggref->args) == 1);
10519  tle = linitial_node(TargetEntry, aggref->args);
10521  get_agg_combine_expr, original_aggref);
10522  return;
10523  }
10524 
10525  /*
10526  * Mark as PARTIAL, if appropriate. We look to the original aggref so as
10527  * to avoid printing this when recursing from the code just above.
10528  */
10529  if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10530  appendStringInfoString(buf, "PARTIAL ");
10531 
10532  /* Extract the argument types as seen by the parser */
10533  nargs = get_aggregate_argtypes(aggref, argtypes);
10534 
10535  if (!funcname)
10536  funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10537  argtypes, aggref->aggvariadic,
10538  &use_variadic,
10539  context->special_exprkind);
10540 
10541  /* Print the aggregate name, schema-qualified if needed */
10542  appendStringInfo(buf, "%s(%s", funcname,
10543  (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10544 
10545  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10546  {
10547  /*
10548  * Ordered-set aggregates do not use "*" syntax. Also, we needn't
10549  * worry about inserting VARIADIC. So we can just dump the direct
10550  * args as-is.
10551  */
10552  Assert(!aggref->aggvariadic);
10553  get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10554  Assert(aggref->aggorder != NIL);
10555  appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10556  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10557  }
10558  else
10559  {
10560  /* aggstar can be set only in zero-argument aggregates */
10561  if (aggref->aggstar)
10562  appendStringInfoChar(buf, '*');
10563  else
10564  {
10565  ListCell *l;
10566  int i;
10567 
10568  i = 0;
10569  foreach(l, aggref->args)
10570  {
10571  TargetEntry *tle = (TargetEntry *) lfirst(l);
10572  Node *arg = (Node *) tle->expr;
10573 
10574  Assert(!IsA(arg, NamedArgExpr));
10575  if (tle->resjunk)
10576  continue;
10577  if (i++ > 0)
10578  {
10579  if (is_json_objectagg)
10580  {
10581  /*
10582  * the ABSENT ON NULL and WITH UNIQUE args are printed
10583  * separately, so ignore them here
10584  */
10585  if (i > 2)
10586  break;
10587 
10588  appendStringInfoString(buf, " : ");
10589  }
10590  else
10591  appendStringInfoString(buf, ", ");
10592  }
10593  if (use_variadic && i == nargs)
10594  appendStringInfoString(buf, "VARIADIC ");
10595  get_rule_expr(arg, context, true);
10596  }
10597  }
10598 
10599  if (aggref->aggorder != NIL)
10600  {
10601  appendStringInfoString(buf, " ORDER BY ");
10602  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10603  }
10604  }
10605 
10606  if (options)
10608 
10609  if (aggref->aggfilter != NULL)
10610  {
10611  appendStringInfoString(buf, ") FILTER (WHERE ");
10612  get_rule_expr((Node *) aggref->aggfilter, context, false);
10613  }
10614 
10615  appendStringInfoChar(buf, ')');
10616 }
#define funcname
Definition: indent_codes.h:69
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:385
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:384
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1908
#define FUNC_MAX_ARGS
#define linitial_node(type, l)
Definition: pg_list.h:181
static char * generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, bool has_variadic, bool *use_variadic_p, ParseExprKind special_exprkind)
Definition: ruleutils.c:12849
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:10624
static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6439
static void resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
Definition: ruleutils.c:7580
Oid aggfnoid
Definition: primnodes.h:444
List * aggdistinct
Definition: primnodes.h:474
List * aggdirectargs
Definition: primnodes.h:465
List * args
Definition: primnodes.h:468
Expr * aggfilter
Definition: primnodes.h:477
List * aggorder
Definition: primnodes.h:471
Expr * expr
Definition: primnodes.h:2162

References Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggorder, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, Aggref::args, Assert, buf, context, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_SKIPFINAL, TargetEntry::expr, FUNC_MAX_ARGS, funcname, generate_function_name(), get_agg_combine_expr(), get_aggregate_argtypes(), get_rule_expr(), get_rule_orderby(), i, IsA, lfirst, linitial_node, list_length(), NIL, and resolve_special_varno().

Referenced by get_agg_expr(), and get_json_agg_constructor().

◆ get_basic_select_query()

static void get_basic_select_query ( Query query,
deparse_context context,
TupleDesc  resultDesc,
bool  colNamesVisible 
)
static

Definition at line 5918 of file ruleutils.c.

5920 {
5921  StringInfo buf = context->buf;
5922  RangeTblEntry *values_rte;
5923  char *sep;
5924  ListCell *l;
5925 
5926  if (PRETTY_INDENT(context))
5927  {
5928  context->indentLevel += PRETTYINDENT_STD;
5929  appendStringInfoChar(buf, ' ');
5930  }
5931 
5932  /*
5933  * If the query looks like SELECT * FROM (VALUES ...), then print just the
5934  * VALUES part. This reverses what transformValuesClause() did at parse
5935  * time.
5936  */
5937  values_rte = get_simple_values_rte(query, resultDesc);
5938  if (values_rte)
5939  {
5940  get_values_def(values_rte->values_lists, context);
5941  return;
5942  }
5943 
5944  /*
5945  * Build up the query string - first we say SELECT
5946  */
5947  if (query->isReturn)
5948  appendStringInfoString(buf, "RETURN");
5949  else
5950  appendStringInfoString(buf, "SELECT");
5951 
5952  /* Add the DISTINCT clause if given */
5953  if (query->distinctClause != NIL)
5954  {
5955  if (query->hasDistinctOn)
5956  {
5957  appendStringInfoString(buf, " DISTINCT ON (");
5958  sep = "";
5959  foreach(l, query->distinctClause)
5960  {
5961  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5962 
5965  false, context);
5966  sep = ", ";
5967  }
5968  appendStringInfoChar(buf, ')');
5969  }
5970  else
5971  appendStringInfoString(buf, " DISTINCT");
5972  }
5973 
5974  /* Then we tell what to select (the targetlist) */
5975  get_target_list(query->targetList, context, resultDesc, colNamesVisible);
5976 
5977  /* Add the FROM clause if needed */
5978  get_from_clause(query, " FROM ", context);
5979 
5980  /* Add the WHERE clause if given */
5981  if (query->jointree->quals != NULL)
5982  {
5983  appendContextKeyword(context, " WHERE ",
5985  get_rule_expr(query->jointree->quals, context, false);
5986  }
5987 
5988  /* Add the GROUP BY clause if given */
5989  if (query->groupClause != NULL || query->groupingSets != NULL)
5990  {
5991  ParseExprKind save_exprkind;
5992 
5993  appendContextKeyword(context, " GROUP BY ",
5995  if (query->groupDistinct)
5996  appendStringInfoString(buf, "DISTINCT ");
5997 
5998  save_exprkind = context->special_exprkind;
5999  context->special_exprkind = EXPR_KIND_GROUP_BY;
6000 
6001  if (query->groupingSets == NIL)
6002  {
6003  sep = "";
6004  foreach(l, query->groupClause)
6005  {
6006  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6007 
6010  false, context);
6011  sep = ", ";
6012  }
6013  }
6014  else
6015  {
6016  sep = "";
6017  foreach(l, query->groupingSets)
6018  {
6019  GroupingSet *grp = lfirst(l);
6020 
6022  get_rule_groupingset(grp, query->targetList, true, context);
6023  sep = ", ";
6024  }
6025  }
6026 
6027  context->special_exprkind = save_exprkind;
6028  }
6029 
6030  /* Add the HAVING clause if given */
6031  if (query->havingQual != NULL)
6032  {
6033  appendContextKeyword(context, " HAVING ",
6035  get_rule_expr(query->havingQual, context, false);
6036  }
6037 
6038  /* Add the WINDOW clause if needed */
6039  if (query->windowClause != NIL)
6041 }
ParseExprKind
Definition: parse_node.h:39
static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
Definition: ruleutils.c:8718
static void get_values_def(List *values_lists, deparse_context *context)
Definition: ruleutils.c:5535
static void get_from_clause(Query *query, const char *prefix, deparse_context *context)
Definition: ruleutils.c:11864
static void get_target_list(List *targetList, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6052
static void get_rule_groupingset(GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context)
Definition: ruleutils.c:6379
static Node * get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6322
static void get_rule_windowclause(Query *query, deparse_context *context)
Definition: ruleutils.c:6497
static RangeTblEntry * get_simple_values_rte(Query *query, TupleDesc resultDesc)
Definition: ruleutils.c:5849
Node * quals
Definition: primnodes.h:2281
bool groupDistinct
Definition: parsenodes.h:201
FromExpr * jointree
Definition: parsenodes.h:175
List * groupClause
Definition: parsenodes.h:200
Node * havingQual
Definition: parsenodes.h:205
List * windowClause
Definition: parsenodes.h:207
List * targetList
Definition: parsenodes.h:191
List * groupingSets
Definition: parsenodes.h:203
List * distinctClause
Definition: parsenodes.h:209
List * values_lists
Definition: parsenodes.h:1200
Index tleSortGroupRef
Definition: parsenodes.h:1442

References appendContextKeyword(), appendStringInfoChar(), appendStringInfoString(), buf, context, Query::distinctClause, EXPR_KIND_GROUP_BY, get_from_clause(), get_rule_expr(), get_rule_groupingset(), get_rule_sortgroupclause(), get_rule_windowclause(), get_simple_values_rte(), get_target_list(), get_values_def(), Query::groupClause, Query::groupDistinct, Query::groupingSets, Query::havingQual, Query::jointree, lfirst, NIL, PRETTY_INDENT, PRETTYINDENT_STD, FromExpr::quals, Query::targetList, SortGroupClause::tleSortGroupRef, RangeTblEntry::values_lists, and Query::windowClause.

Referenced by get_select_query_def().

◆ get_coercion_expr()

static void get_coercion_expr ( Node arg,
deparse_context context,
Oid  resulttype,
int32  resulttypmod,
Node parentNode 
)
static

Definition at line 10996 of file ruleutils.c.

10999 {
11000  StringInfo buf = context->buf;
11001 
11002  /*
11003  * Since parse_coerce.c doesn't immediately collapse application of
11004  * length-coercion functions to constants, what we'll typically see in
11005  * such cases is a Const with typmod -1 and a length-coercion function
11006  * right above it. Avoid generating redundant output. However, beware of
11007  * suppressing casts when the user actually wrote something like
11008  * 'foo'::text::char(3).
11009  *
11010  * Note: it might seem that we are missing the possibility of needing to
11011  * print a COLLATE clause for such a Const. However, a Const could only
11012  * have nondefault collation in a post-constant-folding tree, in which the
11013  * length coercion would have been folded too. See also the special
11014  * handling of CollateExpr in coerce_to_target_type(): any collation
11015  * marking will be above the coercion node, not below it.
11016  */
11017  if (arg && IsA(arg, Const) &&
11018  ((Const *) arg)->consttype == resulttype &&
11019  ((Const *) arg)->consttypmod == -1)
11020  {
11021  /* Show the constant without normal ::typename decoration */
11022  get_const_expr((Const *) arg, context, -1);
11023  }
11024  else
11025  {
11026  if (!PRETTY_PAREN(context))
11027  appendStringInfoChar(buf, '(');
11028  get_rule_expr_paren(arg, context, false, parentNode);
11029  if (!PRETTY_PAREN(context))
11030  appendStringInfoChar(buf, ')');
11031  }
11032 
11033  /*
11034  * Never emit resulttype(arg) functional notation. A pg_proc entry could
11035  * take precedence, and a resulttype in pg_temp would require schema
11036  * qualification that format_type_with_typemod() would usually omit. We've
11037  * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
11038  * would work fine.
11039  */
11040  appendStringInfo(buf, "::%s",
11041  format_type_with_typemod(resulttype, resulttypmod));
11042 }
char * format_type_with_typemod(Oid type_oid, int32 typemod)
Definition: format_type.c:362
static void get_rule_expr_paren(Node *node, deparse_context *context, bool showimplicit, Node *parentNode)
Definition: ruleutils.c:8791
#define PRETTY_PAREN(context)
Definition: ruleutils.c:102
static void get_const_expr(Const *constval, deparse_context *context, int showtype)
Definition: ruleutils.c:11060

References appendStringInfo(), appendStringInfoChar(), arg, buf, context, format_type_with_typemod(), get_const_expr(), get_rule_expr_paren(), IsA, and PRETTY_PAREN.

Referenced by get_func_expr(), and get_rule_expr().

◆ get_column_alias_list()

static void get_column_alias_list ( deparse_columns colinfo,
deparse_context context 
)
static

Definition at line 12320 of file ruleutils.c.

12321 {
12322  StringInfo buf = context->buf;
12323  int i;
12324  bool first = true;
12325 
12326  /* Don't print aliases if not needed */
12327  if (!colinfo->printaliases)
12328  return;
12329 
12330  for (i = 0; i < colinfo->num_new_cols; i++)
12331  {
12332  char *colname = colinfo->new_colnames[i];
12333 
12334  if (first)
12335  {
12336  appendStringInfoChar(buf, '(');
12337  first = false;
12338  }
12339  else
12340  appendStringInfoString(buf, ", ");
12342  }
12343  if (!first)
12344  appendStringInfoChar(buf, ')');
12345 }

References appendStringInfoChar(), appendStringInfoString(), buf, context, i, deparse_columns::new_colnames, deparse_columns::num_new_cols, deparse_columns::printaliases, and quote_identifier().

Referenced by get_from_clause_item().

◆ get_const_collation()

static void get_const_collation ( Const constval,
deparse_context context 
)
static

Definition at line 11190 of file ruleutils.c.

11191 {
11192  StringInfo buf = context->buf;
11193 
11194  if (OidIsValid(constval->constcollid))
11195  {
11196  Oid typcollation = get_typcollation(constval->consttype);
11197 
11198  if (constval->constcollid != typcollation)
11199  {
11200  appendStringInfo(buf, " COLLATE %s",
11201  generate_collation_name(constval->constcollid));
11202  }
11203  }
11204 }
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3056
char * generate_collation_name(Oid collid)
Definition: ruleutils.c:13135
Oid consttype
Definition: primnodes.h:312

References appendStringInfo(), buf, Const::consttype, context, generate_collation_name(), get_typcollation(), and OidIsValid.

Referenced by get_const_expr().

◆ get_const_expr()

static void get_const_expr ( Const constval,
deparse_context context,
int  showtype 
)
static

Definition at line 11060 of file ruleutils.c.

11061 {
11062  StringInfo buf = context->buf;
11063  Oid typoutput;
11064  bool typIsVarlena;
11065  char *extval;
11066  bool needlabel = false;
11067 
11068  if (constval->constisnull)
11069  {
11070  /*
11071  * Always label the type of a NULL constant to prevent misdecisions
11072  * about type when reparsing.
11073  */
11074  appendStringInfoString(buf, "NULL");
11075  if (showtype >= 0)
11076  {
11077  appendStringInfo(buf, "::%s",
11079  constval->consttypmod));
11080  get_const_collation(constval, context);
11081  }
11082  return;
11083  }
11084 
11085  getTypeOutputInfo(constval->consttype,
11086  &typoutput, &typIsVarlena);
11087 
11088  extval = OidOutputFunctionCall(typoutput, constval->constvalue);
11089 
11090  switch (constval->consttype)
11091  {
11092  case INT4OID:
11093 
11094  /*
11095  * INT4 can be printed without any decoration, unless it is
11096  * negative; in that case print it as '-nnn'::integer to ensure
11097  * that the output will re-parse as a constant, not as a constant
11098  * plus operator. In most cases we could get away with printing
11099  * (-nnn) instead, because of the way that gram.y handles negative
11100  * literals; but that doesn't work for INT_MIN, and it doesn't
11101  * seem that much prettier anyway.
11102  */
11103  if (extval[0] != '-')
11104  appendStringInfoString(buf, extval);
11105  else
11106  {
11107  appendStringInfo(buf, "'%s'", extval);
11108  needlabel = true; /* we must attach a cast */
11109  }
11110  break;
11111 
11112  case NUMERICOID:
11113 
11114  /*
11115  * NUMERIC can be printed without quotes if it looks like a float
11116  * constant (not an integer, and not Infinity or NaN) and doesn't
11117  * have a leading sign (for the same reason as for INT4).
11118  */
11119  if (isdigit((unsigned char) extval[0]) &&
11120  strcspn(extval, "eE.") != strlen(extval))
11121  {
11122  appendStringInfoString(buf, extval);
11123  }
11124  else
11125  {
11126  appendStringInfo(buf, "'%s'", extval);
11127  needlabel = true; /* we must attach a cast */
11128  }
11129  break;
11130 
11131  case BOOLOID:
11132  if (strcmp(extval, "t") == 0)
11133  appendStringInfoString(buf, "true");
11134  else
11135  appendStringInfoString(buf, "false");
11136  break;
11137 
11138  default:
11139  simple_quote_literal(buf, extval);
11140  break;
11141  }
11142 
11143  pfree(extval);
11144 
11145  if (showtype < 0)
11146  return;
11147 
11148  /*
11149  * For showtype == 0, append ::typename unless the constant will be
11150  * implicitly typed as the right type when it is read in.
11151  *
11152  * XXX this code has to be kept in sync with the behavior of the parser,
11153  * especially make_const.
11154  */
11155  switch (constval->consttype)
11156  {
11157  case BOOLOID:
11158  case UNKNOWNOID:
11159  /* These types can be left unlabeled */
11160  needlabel = false;
11161  break;
11162  case INT4OID:
11163  /* We determined above whether a label is needed */
11164  break;
11165  case NUMERICOID:
11166 
11167  /*
11168  * Float-looking constants will be typed as numeric, which we
11169  * checked above; but if there's a nondefault typmod we need to
11170  * show it.
11171  */
11172  needlabel |= (constval->consttypmod >= 0);
11173  break;
11174  default:
11175  needlabel = true;
11176  break;
11177  }
11178  if (needlabel || showtype > 0)
11179  appendStringInfo(buf, "::%s",
11181  constval->consttypmod));
11182 
11183  get_const_collation(constval, context);
11184 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2907
void pfree(void *pointer)
Definition: mcxt.c:1520
static void simple_quote_literal(StringInfo buf, const char *val)
Definition: ruleutils.c:11388
static void get_const_collation(Const *constval, deparse_context *context)
Definition: ruleutils.c:11190

References appendStringInfo(), appendStringInfoString(), buf, Const::consttype, context, format_type_with_typemod(), get_const_collation(), getTypeOutputInfo(), OidOutputFunctionCall(), pfree(), and simple_quote_literal().

Referenced by get_coercion_expr(), get_json_path_spec(), get_json_table(), get_json_table_nested_columns(), get_list_partvalue_string(), get_range_partbound_string(), get_rule_expr(), and get_rule_sortgroupclause().

◆ get_delete_query_def()

static void get_delete_query_def ( Query query,
deparse_context context,
bool  colNamesVisible 
)
static

Definition at line 7064 of file ruleutils.c.

7066 {
7067  StringInfo buf = context->buf;
7068  RangeTblEntry *rte;
7069 
7070  /* Insert the WITH clause if given */
7071  get_with_clause(query, context);
7072 
7073  /*
7074  * Start the query with DELETE FROM relname
7075  */
7076  rte = rt_fetch(query->resultRelation, query->rtable);
7077  Assert(rte->rtekind == RTE_RELATION);
7078  if (PRETTY_INDENT(context))
7079  {
7080  appendStringInfoChar(buf, ' ');
7081  context->indentLevel += PRETTYINDENT_STD;
7082  }
7083  appendStringInfo(buf, "DELETE FROM %s%s",
7084  only_marker(rte),
7086 
7087  /* Print the relation alias, if needed */
7088  get_rte_alias(rte, query->resultRelation, false, context);
7089 
7090  /* Add the USING clause if given */
7091  get_from_clause(query, " USING ", context);
7092 
7093  /* Add a WHERE clause if given */
7094  if (query->jointree->quals != NULL)
7095  {
7096  appendContextKeyword(context, " WHERE ",
7098  get_rule_expr(query->jointree->quals, context, false);
7099  }
7100 
7101  /* Add RETURNING if present */
7102  if (query->returningList)
7103  {
7104  appendContextKeyword(context, " RETURNING",
7106  get_target_list(query->returningList, context, NULL, colNamesVisible);
7107  }
7108 }
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as, deparse_context *context)
Definition: ruleutils.c:12249
#define only_marker(rte)
Definition: ruleutils.c:535
static void get_with_clause(Query *query, deparse_context *context)
Definition: ruleutils.c:5578
static char * generate_relation_name(Oid relid, List *namespaces)
Definition: ruleutils.c:12747
List * returningList
Definition: parsenodes.h:198
List * rtable
Definition: parsenodes.h:168

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), Assert, buf, context, generate_relation_name(), get_from_clause(), get_rte_alias(), get_rule_expr(), get_target_list(), get_with_clause(), Query::jointree, NIL, only_marker, PRETTY_INDENT, PRETTYINDENT_STD, FromExpr::quals, RangeTblEntry::relid, Query::returningList, rt_fetch, Query::rtable, RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by get_query_def().

◆ get_from_clause()

static void get_from_clause ( Query query,
const char *  prefix,
deparse_context context 
)
static

Definition at line 11864 of file ruleutils.c.

11865 {
11866  StringInfo buf = context->buf;
11867  bool first = true;
11868  ListCell *l;
11869 
11870  /*
11871  * We use the query's jointree as a guide to what to print. However, we
11872  * must ignore auto-added RTEs that are marked not inFromCl. (These can
11873  * only appear at the top level of the jointree, so it's sufficient to
11874  * check here.) This check also ensures we ignore the rule pseudo-RTEs
11875  * for NEW and OLD.
11876  */
11877  foreach(l, query->jointree->fromlist)
11878  {
11879  Node *jtnode = (Node *) lfirst(l);
11880 
11881  if (IsA(jtnode, RangeTblRef))
11882  {
11883  int varno = ((RangeTblRef *) jtnode)->rtindex;
11884  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11885 
11886  if (!rte->inFromCl)
11887  continue;
11888  }
11889 
11890  if (first)
11891  {
11892  appendContextKeyword(context, prefix,
11894  first = false;
11895 
11896  get_from_clause_item(jtnode, query, context);
11897  }
11898  else
11899  {
11900  StringInfoData itembuf;
11901 
11902  appendStringInfoString(buf, ", ");
11903 
11904  /*
11905  * Put the new FROM item's text into itembuf so we can decide
11906  * after we've got it whether or not it needs to go on a new line.
11907  */
11908  initStringInfo(&itembuf);
11909  context->buf = &itembuf;
11910 
11911  get_from_clause_item(jtnode, query, context);
11912 
11913  /* Restore context's output buffer */
11914  context->buf = buf;
11915 
11916  /* Consider line-wrapping if enabled */
11917  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
11918  {
11919  /* Does the new item start with a new line? */
11920  if (itembuf.len > 0 && itembuf.data[0] == '\n')
11921  {
11922  /* If so, we shouldn't add anything */
11923  /* instead, remove any trailing spaces currently in buf */
11925  }
11926  else
11927  {
11928  char *trailing_nl;
11929 
11930  /* Locate the start of the current line in the buffer */
11931  trailing_nl = strrchr(buf->data, '\n');
11932  if (trailing_nl == NULL)
11933  trailing_nl = buf->data;
11934  else
11935  trailing_nl++;
11936 
11937  /*
11938  * Add a newline, plus some indentation, if the new item
11939  * would cause an overflow.
11940  */
11941  if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
11945  }
11946  }
11947 
11948  /* Add the new item */
11949  appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
11950 
11951  /* clean up */
11952  pfree(itembuf.data);
11953  }
11954  }
11955 }
#define PRETTYINDENT_VAR
Definition: ruleutils.c:84
static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
Definition: ruleutils.c:11958
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:233
List * fromlist
Definition: primnodes.h:2280

References appendBinaryStringInfo(), appendContextKeyword(), appendStringInfoString(), buf, context, StringInfoData::data, FromExpr::fromlist, get_from_clause_item(), initStringInfo(), IsA, Query::jointree, StringInfoData::len, lfirst, pfree(), PRETTY_INDENT, PRETTYINDENT_STD, PRETTYINDENT_VAR, removeStringInfoSpaces(), rt_fetch, and Query::rtable.

Referenced by get_basic_select_query(), get_delete_query_def(), get_merge_query_def(), and get_update_query_def().

◆ get_from_clause_coldeflist()

static void get_from_clause_coldeflist ( RangeTblFunction rtfunc,
deparse_columns colinfo,
deparse_context context 
)
static

Definition at line 12360 of file ruleutils.c.

12363 {
12364  StringInfo buf = context->buf;
12365  ListCell *l1;
12366  ListCell *l2;
12367  ListCell *l3;
12368  ListCell *l4;
12369  int i;
12370 
12371  appendStringInfoChar(buf, '(');
12372 
12373  i = 0;
12374  forfour(l1, rtfunc->funccoltypes,
12375  l2, rtfunc->funccoltypmods,
12376  l3, rtfunc->funccolcollations,
12377  l4, rtfunc->funccolnames)
12378  {
12379  Oid atttypid = lfirst_oid(l1);
12380  int32 atttypmod = lfirst_int(l2);
12381  Oid attcollation = lfirst_oid(l3);
12382  char *attname;
12383 
12384  if (colinfo)
12385  attname = colinfo->colnames[i];
12386  else
12387  attname = strVal(lfirst(l4));
12388 
12389  Assert(attname); /* shouldn't be any dropped columns here */
12390 
12391  if (i > 0)
12392  appendStringInfoString(buf, ", ");
12393  appendStringInfo(buf, "%s %s",
12395  format_type_with_typemod(atttypid, atttypmod));
12396  if (OidIsValid(attcollation) &&
12397  attcollation != get_typcollation(atttypid))
12398  appendStringInfo(buf, " COLLATE %s",
12399  generate_collation_name(attcollation));
12400 
12401  i++;
12402  }
12403 
12404  appendStringInfoChar(buf, ')');
12405 }
signed int int32
Definition: c.h:494
NameData attname
Definition: pg_attribute.h:41
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:575
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define strVal(v)
Definition: value.h:82

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, attname, buf, deparse_columns::colnames, context, forfour, format_type_with_typemod(), generate_collation_name(), get_typcollation(), i, lfirst, lfirst_int, lfirst_oid, OidIsValid, quote_identifier(), and strVal.

Referenced by get_from_clause_item().

◆ get_from_clause_item()

static void get_from_clause_item ( Node jtnode,
Query query,
deparse_context context 
)
static

Definition at line 11958 of file ruleutils.c.

11959 {
11960  StringInfo buf = context->buf;
11961  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
11962 
11963  if (IsA(jtnode, RangeTblRef))
11964  {
11965  int varno = ((RangeTblRef *) jtnode)->rtindex;
11966  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11967  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
11968  RangeTblFunction *rtfunc1 = NULL;
11969 
11970  if (rte->lateral)
11971  appendStringInfoString(buf, "LATERAL ");
11972 
11973  /* Print the FROM item proper */
11974  switch (rte->rtekind)
11975  {
11976  case RTE_RELATION:
11977  /* Normal relation RTE */
11978  appendStringInfo(buf, "%s%s",
11979  only_marker(rte),
11981  context->namespaces));
11982  break;
11983  case RTE_SUBQUERY:
11984  /* Subquery RTE */
11985  appendStringInfoChar(buf, '(');
11986  get_query_def(rte->subquery, buf, context->namespaces, NULL,
11987  true,
11988  context->prettyFlags, context->wrapColumn,
11989  context->indentLevel);
11990  appendStringInfoChar(buf, ')');
11991  break;
11992  case RTE_FUNCTION:
11993  /* Function RTE */
11994  rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
11995 
11996  /*
11997  * Omit ROWS FROM() syntax for just one function, unless it
11998  * has both a coldeflist and WITH ORDINALITY. If it has both,
11999  * we must use ROWS FROM() syntax to avoid ambiguity about
12000  * whether the coldeflist includes the ordinality column.
12001  */
12002  if (list_length(rte->functions) == 1 &&
12003  (rtfunc1->funccolnames == NIL || !rte->funcordinality))
12004  {
12005  get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
12006  /* we'll print the coldeflist below, if it has one */
12007  }
12008  else
12009  {
12010  bool all_unnest;
12011  ListCell *lc;
12012 
12013  /*
12014  * If all the function calls in the list are to unnest,
12015  * and none need a coldeflist, then collapse the list back
12016  * down to UNNEST(args). (If we had more than one
12017  * built-in unnest function, this would get more
12018  * difficult.)
12019  *
12020  * XXX This is pretty ugly, since it makes not-terribly-
12021  * future-proof assumptions about what the parser would do
12022  * with the output; but the alternative is to emit our
12023  * nonstandard ROWS FROM() notation for what might have
12024  * been a perfectly spec-compliant multi-argument
12025  * UNNEST().
12026  */
12027  all_unnest = true;
12028  foreach(lc, rte->functions)
12029  {
12030  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12031 
12032  if (!IsA(rtfunc->funcexpr, FuncExpr) ||
12033  ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
12034  rtfunc->funccolnames != NIL)
12035  {
12036  all_unnest = false;
12037  break;
12038  }
12039  }
12040 
12041  if (all_unnest)
12042  {
12043  List *allargs = NIL;
12044 
12045  foreach(lc, rte->functions)
12046  {
12047  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12048  List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
12049 
12050  allargs = list_concat(allargs, args);
12051  }
12052 
12053  appendStringInfoString(buf, "UNNEST(");
12054  get_rule_expr((Node *) allargs, context, true);
12055  appendStringInfoChar(buf, ')');
12056  }
12057  else
12058  {
12059  int funcno = 0;
12060 
12061  appendStringInfoString(buf, "ROWS FROM(");
12062  foreach(lc, rte->functions)
12063  {
12064  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12065 
12066  if (funcno > 0)
12067  appendStringInfoString(buf, ", ");
12068  get_rule_expr_funccall(rtfunc->funcexpr, context, true);
12069  if (rtfunc->funccolnames != NIL)
12070  {
12071  /* Reconstruct the column definition list */
12072  appendStringInfoString(buf, " AS ");
12074  NULL,
12075  context);
12076  }
12077  funcno++;
12078  }
12079  appendStringInfoChar(buf, ')');
12080  }
12081  /* prevent printing duplicate coldeflist below */
12082  rtfunc1 = NULL;
12083  }
12084  if (rte->funcordinality)
12085  appendStringInfoString(buf, " WITH ORDINALITY");
12086  break;
12087  case RTE_TABLEFUNC:
12088  get_tablefunc(rte->tablefunc, context, true);
12089  break;
12090  case RTE_VALUES:
12091  /* Values list RTE */
12092  appendStringInfoChar(buf, '(');
12094  appendStringInfoChar(buf, ')');
12095  break;
12096  case RTE_CTE:
12098  break;
12099  default:
12100  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
12101  break;
12102  }
12103 
12104  /* Print the relation alias, if needed */
12105  get_rte_alias(rte, varno, false, context);
12106 
12107  /* Print the column definitions or aliases, if needed */
12108  if (rtfunc1 && rtfunc1->funccolnames != NIL)
12109  {
12110  /* Reconstruct the columndef list, which is also the aliases */
12111  get_from_clause_coldeflist(rtfunc1, colinfo, context);
12112  }
12113  else
12114  {
12115  /* Else print column aliases as needed */
12116  get_column_alias_list(colinfo, context);
12117  }
12118 
12119  /* Tablesample clause must go after any alias */
12120  if (rte->rtekind == RTE_RELATION && rte->tablesample)
12122  }
12123  else if (IsA(jtnode, JoinExpr))
12124  {
12125  JoinExpr *j = (JoinExpr *) jtnode;
12126  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
12127  bool need_paren_on_right;
12128 
12129  need_paren_on_right = PRETTY_PAREN(context) &&
12130  !IsA(j->rarg, RangeTblRef) &&
12131  !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
12132 
12133  if (!PRETTY_PAREN(context) || j->alias != NULL)
12134  appendStringInfoChar(buf, '(');
12135 
12136  get_from_clause_item(j->larg, query, context);
12137 
12138  switch (j->jointype)
12139  {
12140  case JOIN_INNER:
12141  if (j->quals)
12142  appendContextKeyword(context, " JOIN ",
12146  else
12147  appendContextKeyword(context, " CROSS JOIN ",
12151  break;
12152  case JOIN_LEFT:
12153  appendContextKeyword(context, " LEFT JOIN ",
12157  break;
12158  case JOIN_FULL:
12159  appendContextKeyword(context, " FULL JOIN ",
12163  break;
12164  case JOIN_RIGHT:
12165  appendContextKeyword(context, " RIGHT JOIN ",
12169  break;
12170  default:
12171  elog(ERROR, "unrecognized join type: %d",
12172  (int) j->jointype);
12173  }
12174 
12175  if (need_paren_on_right)
12176  appendStringInfoChar(buf, '(');
12177  get_from_clause_item(j->rarg, query, context);
12178  if (need_paren_on_right)
12179  appendStringInfoChar(buf, ')');
12180 
12181  if (j->usingClause)
12182  {
12183  ListCell *lc;
12184  bool first = true;
12185 
12186  appendStringInfoString(buf, " USING (");
12187  /* Use the assigned names, not what's in usingClause */
12188  foreach(lc, colinfo->usingNames)
12189  {
12190  char *colname = (char *) lfirst(lc);
12191 
12192  if (first)
12193  first = false;
12194  else
12195  appendStringInfoString(buf, ", ");
12197  }
12198  appendStringInfoChar(buf, ')');
12199 
12200  if (j->join_using_alias)
12201  appendStringInfo(buf, " AS %s",
12202  quote_identifier(j->join_using_alias->aliasname));
12203  }
12204  else if (j->quals)
12205  {
12206  appendStringInfoString(buf, " ON ");
12207  if (!PRETTY_PAREN(context))
12208  appendStringInfoChar(buf, '(');
12209  get_rule_expr(j->quals, context, false);
12210  if (!PRETTY_PAREN(context))
12211  appendStringInfoChar(buf, ')');
12212  }
12213  else if (j->jointype != JOIN_INNER)
12214  {
12215  /* If we didn't say CROSS JOIN above, we must provide an ON */
12216  appendStringInfoString(buf, " ON TRUE");
12217  }
12218 
12219  if (!PRETTY_PAREN(context) || j->alias != NULL)
12220  appendStringInfoChar(buf, ')');
12221 
12222  /* Yes, it's correct to put alias after the right paren ... */
12223  if (j->alias != NULL)
12224  {
12225  /*
12226  * Note that it's correct to emit an alias clause if and only if
12227  * there was one originally. Otherwise we'd be converting a named
12228  * join to unnamed or vice versa, which creates semantic
12229  * subtleties we don't want. However, we might print a different
12230  * alias name than was there originally.
12231  */
12232  appendStringInfo(buf, " %s",
12234  context)));
12235  get_column_alias_list(colinfo, context);
12236  }
12237  }
12238  else
12239  elog(ERROR, "unrecognized node type: %d",
12240  (int) nodeTag(jtnode));
12241 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ JOIN_FULL
Definition: nodes.h:295
@ JOIN_INNER
Definition: nodes.h:293
@ JOIN_RIGHT
Definition: nodes.h:296
@ JOIN_LEFT
Definition: nodes.h:294
@ RTE_CTE
Definition: parsenodes.h:1034
@ RTE_VALUES
Definition: parsenodes.h:1033
@ RTE_SUBQUERY
Definition: parsenodes.h:1029
@ RTE_FUNCTION
Definition: parsenodes.h:1031
@ RTE_TABLEFUNC
Definition: parsenodes.h:1032
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition: ruleutils.c:4969
#define PRETTYINDENT_JOIN
Definition: ruleutils.c:83
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
Definition: ruleutils.c:5457
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Definition: ruleutils.c:12411
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12320
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12360
static void get_rule_expr_funccall(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10298
#define deparse_columns_fetch(rangetable_index, dpns)
Definition: ruleutils.c:296
static void get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11845
Definition: pg_list.h:54
char * ctename
Definition: parsenodes.h:1206
TableFunc * tablefunc
Definition: parsenodes.h:1194
bool funcordinality
Definition: parsenodes.h:1189
struct TableSampleClause * tablesample
Definition: parsenodes.h:1108
Query * subquery
Definition: parsenodes.h:1114
List * functions
Definition: parsenodes.h:1187
List * usingNames
Definition: ruleutils.c:292

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), generate_unaccent_rules::args, buf, context, RangeTblEntry::ctename, deparse_columns_fetch, elog, ERROR, RangeTblFunction::funcexpr, RangeTblEntry::funcordinality, RangeTblEntry::functions, generate_relation_name(), get_column_alias_list(), get_from_clause_coldeflist(), get_query_def(), get_rtable_name(), get_rte_alias(), get_rule_expr(), get_rule_expr_funccall(), get_tablefunc(), get_tablesample_def(), get_values_def(), IsA, j, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, lfirst, linitial, list_concat(), list_length(), NIL, nodeTag, only_marker, PRETTY_PAREN, PRETTYINDENT_JOIN, PRETTYINDENT_STD, quote_identifier(), RangeTblEntry::relid, rt_fetch, Query::rtable, RTE_CTE, RTE_FUNCTION, RTE_RELATION, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, RangeTblEntry::subquery, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, deparse_columns::usingNames, and RangeTblEntry::values_lists.

Referenced by get_from_clause().

◆ get_func_expr()

static void get_func_expr ( FuncExpr expr,
deparse_context context,
bool  showimplicit 
)
static

Definition at line 10390 of file ruleutils.c.

10392 {
10393  StringInfo buf = context->buf;
10394  Oid funcoid = expr->funcid;
10395  Oid argtypes[FUNC_MAX_ARGS];
10396  int nargs;
10397  List *argnames;
10398  bool use_variadic;
10399  ListCell *l;
10400 
10401  /*
10402  * If the function call came from an implicit coercion, then just show the
10403  * first argument --- unless caller wants to see implicit coercions.
10404  */
10405  if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
10406  {
10408  false, (Node *) expr);
10409  return;
10410  }
10411 
10412  /*
10413  * If the function call came from a cast, then show the first argument
10414  * plus an explicit cast operation.
10415  */
10416  if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10417  expr->funcformat == COERCE_IMPLICIT_CAST)
10418  {
10419  Node *arg = linitial(expr->args);
10420  Oid rettype = expr->funcresulttype;
10421  int32 coercedTypmod;
10422 
10423  /* Get the typmod if this is a length-coercion function */
10424  (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10425 
10427  rettype, coercedTypmod,
10428  (Node *) expr);
10429 
10430  return;
10431  }
10432 
10433  /*
10434  * If the function was called using one of the SQL spec's random special
10435  * syntaxes, try to reproduce that. If we don't recognize the function,
10436  * fall through.
10437  */
10438  if (expr->funcformat == COERCE_SQL_SYNTAX)
10439  {
10440  if (get_func_sql_syntax(expr, context))
10441  return;
10442  }
10443 
10444  /*
10445  * Normal function: display as proname(args). First we need to extract
10446  * the argument datatypes.
10447  */
10448  if (list_length(expr->args) > FUNC_MAX_ARGS)
10449  ereport(ERROR,
10450  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10451  errmsg("too many arguments")));
10452  nargs = 0;
10453  argnames = NIL;
10454  foreach(l, expr->args)
10455  {
10456  Node *arg = (Node *) lfirst(l);
10457 
10458  if (IsA(arg, NamedArgExpr))
10459  argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10460  argtypes[nargs] = exprType(arg);
10461  nargs++;
10462  }
10463 
10464  appendStringInfo(buf, "%s(",
10465  generate_function_name(funcoid, nargs,
10466  argnames, argtypes,
10467  expr->funcvariadic,
10468  &use_variadic,
10469  context->special_exprkind));
10470  nargs = 0;
10471  foreach(l, expr->args)
10472  {
10473  if (nargs++ > 0)
10474  appendStringInfoString(buf, ", ");
10475  if (use_variadic && lnext(expr->args, l) == NULL)
10476  appendStringInfoString(buf, "VARIADIC ");
10477  get_rule_expr((Node *) lfirst(l), context, true);
10478  }
10479  appendStringInfoChar(buf, ')');
10480 }
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereport(elevel,...)
Definition: elog.h:149
List * lappend(List *list, void *datum)
Definition: list.c:339
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:552
@ COERCE_SQL_SYNTAX
Definition: primnodes.h:707
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:706
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:705
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Definition: ruleutils.c:10744
static void get_coercion_expr(Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
Definition: ruleutils.c:10996
Oid funcid
Definition: primnodes.h:720
List * args
Definition: primnodes.h:738

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, FuncExpr::args, buf, COERCE_EXPLICIT_CAST, COERCE_IMPLICIT_CAST, COERCE_SQL_SYNTAX, context, ereport, errcode(), errmsg(), ERROR, exprIsLengthCoercion(), exprType(), FUNC_MAX_ARGS, FuncExpr::funcid, generate_function_name(), get_coercion_expr(), get_func_sql_syntax(), get_rule_expr(), get_rule_expr_paren(), IsA, lappend(), lfirst, linitial, list_length(), lnext(), and NIL.

Referenced by get_rule_expr().

◆ get_func_sql_syntax()

static bool get_func_sql_syntax ( FuncExpr expr,
deparse_context context 
)
static

Definition at line 10744 of file ruleutils.c.

10745 {
10746  StringInfo buf = context->buf;
10747  Oid funcoid = expr->funcid;
10748 
10749  switch (funcoid)
10750  {
10751  case F_TIMEZONE_INTERVAL_TIMESTAMP:
10752  case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
10753  case F_TIMEZONE_INTERVAL_TIMETZ:
10754  case F_TIMEZONE_TEXT_TIMESTAMP:
10755  case F_TIMEZONE_TEXT_TIMESTAMPTZ:
10756  case F_TIMEZONE_TEXT_TIMETZ:
10757  /* AT TIME ZONE ... note reversed argument order */
10758  appendStringInfoChar(buf, '(');
10759  get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
10760  (Node *) expr);
10761  appendStringInfoString(buf, " AT TIME ZONE ");
10762  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10763  (Node *) expr);
10764  appendStringInfoChar(buf, ')');
10765  return true;
10766 
10767  case F_TIMEZONE_TIMESTAMP:
10768  case F_TIMEZONE_TIMESTAMPTZ:
10769  case F_TIMEZONE_TIMETZ:
10770  /* AT LOCAL */
10771  appendStringInfoChar(buf, '(');
10772  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10773  (Node *) expr);
10774  appendStringInfoString(buf, " AT LOCAL)");
10775  return true;
10776 
10777  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
10778  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
10779  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
10780  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
10781  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
10782  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
10783  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
10784  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
10785  case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
10786  case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
10787  case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
10788  case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
10789  case F_OVERLAPS_TIME_TIME_TIME_TIME:
10790  /* (x1, x2) OVERLAPS (y1, y2) */
10791  appendStringInfoString(buf, "((");
10792  get_rule_expr((Node *) linitial(expr->args), context, false);
10793  appendStringInfoString(buf, ", ");
10794  get_rule_expr((Node *) lsecond(expr->args), context, false);
10795  appendStringInfoString(buf, ") OVERLAPS (");
10796  get_rule_expr((Node *) lthird(expr->args), context, false);
10797  appendStringInfoString(buf, ", ");
10798  get_rule_expr((Node *) lfourth(expr->args), context, false);
10799  appendStringInfoString(buf, "))");
10800  return true;
10801 
10802  case F_EXTRACT_TEXT_DATE:
10803  case F_EXTRACT_TEXT_TIME:
10804  case F_EXTRACT_TEXT_TIMETZ:
10805  case F_EXTRACT_TEXT_TIMESTAMP:
10806  case F_EXTRACT_TEXT_TIMESTAMPTZ:
10807  case F_EXTRACT_TEXT_INTERVAL:
10808  /* EXTRACT (x FROM y) */
10809  appendStringInfoString(buf, "EXTRACT(");
10810  {
10811  Const *con = (Const *) linitial(expr->args);
10812 
10813  Assert(IsA(con, Const) &&
10814  con->consttype == TEXTOID &&
10815  !con->constisnull);
10816  appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
10817  }
10818  appendStringInfoString(buf, " FROM ");
10819  get_rule_expr((Node *) lsecond(expr->args), context, false);
10820  appendStringInfoChar(buf, ')');
10821  return true;
10822 
10823  case F_IS_NORMALIZED:
10824  /* IS xxx NORMALIZED */
10825  appendStringInfoChar(buf, '(');
10826  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10827  (Node *) expr);
10828  appendStringInfoString(buf, " IS");
10829  if (list_length(expr->args) == 2)
10830  {
10831  Const *con = (Const *) lsecond(expr->args);
10832 
10833  Assert(IsA(con, Const) &&
10834  con->consttype == TEXTOID &&
10835  !con->constisnull);
10836  appendStringInfo(buf, " %s",
10837  TextDatumGetCString(con->constvalue));
10838  }
10839  appendStringInfoString(buf, " NORMALIZED)");
10840  return true;
10841 
10842  case F_PG_COLLATION_FOR:
10843  /* COLLATION FOR */
10844  appendStringInfoString(buf, "COLLATION FOR (");
10845  get_rule_expr((Node *) linitial(expr->args), context, false);
10846  appendStringInfoChar(buf, ')');
10847  return true;
10848 
10849  case F_NORMALIZE:
10850  /* NORMALIZE() */
10851  appendStringInfoString(buf, "NORMALIZE(");
10852  get_rule_expr((Node *) linitial(expr->args), context, false);
10853  if (list_length(expr->args) == 2)
10854  {
10855  Const *con = (Const *) lsecond(expr->args);
10856 
10857  Assert(IsA(con, Const) &&
10858  con->consttype == TEXTOID &&
10859  !con->constisnull);
10860  appendStringInfo(buf, ", %s",
10861  TextDatumGetCString(con->constvalue));
10862  }
10863  appendStringInfoChar(buf, ')');
10864  return true;
10865 
10866  case F_OVERLAY_BIT_BIT_INT4:
10867  case F_OVERLAY_BIT_BIT_INT4_INT4:
10868  case F_OVERLAY_BYTEA_BYTEA_INT4:
10869  case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
10870  case F_OVERLAY_TEXT_TEXT_INT4:
10871  case F_OVERLAY_TEXT_TEXT_INT4_INT4:
10872  /* OVERLAY() */
10873  appendStringInfoString(buf, "OVERLAY(");
10874  get_rule_expr((Node *) linitial(expr->args), context, false);
10875  appendStringInfoString(buf, " PLACING ");
10876  get_rule_expr((Node *) lsecond(expr->args), context, false);
10877  appendStringInfoString(buf, " FROM ");
10878  get_rule_expr((Node *) lthird(expr->args), context, false);
10879  if (list_length(expr->args) == 4)
10880  {
10881  appendStringInfoString(buf, " FOR ");
10882  get_rule_expr((Node *) lfourth(expr->args), context, false);
10883  }
10884  appendStringInfoChar(buf, ')');
10885  return true;
10886 
10887  case F_POSITION_BIT_BIT:
10888  case F_POSITION_BYTEA_BYTEA:
10889  case F_POSITION_TEXT_TEXT:
10890  /* POSITION() ... extra parens since args are b_expr not a_expr */
10891  appendStringInfoString(buf, "POSITION((");
10892  get_rule_expr((Node *) lsecond(expr->args), context, false);
10893  appendStringInfoString(buf, ") IN (");
10894  get_rule_expr((Node *) linitial(expr->args), context, false);
10895  appendStringInfoString(buf, "))");
10896  return true;
10897 
10898  case F_SUBSTRING_BIT_INT4:
10899  case F_SUBSTRING_BIT_INT4_INT4:
10900  case F_SUBSTRING_BYTEA_INT4:
10901  case F_SUBSTRING_BYTEA_INT4_INT4:
10902  case F_SUBSTRING_TEXT_INT4:
10903  case F_SUBSTRING_TEXT_INT4_INT4:
10904  /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
10905  appendStringInfoString(buf, "SUBSTRING(");
10906  get_rule_expr((Node *) linitial(expr->args), context, false);
10907  appendStringInfoString(buf, " FROM ");
10908  get_rule_expr((Node *) lsecond(expr->args), context, false);
10909  if (list_length(expr->args) == 3)
10910  {
10911  appendStringInfoString(buf, " FOR ");
10912  get_rule_expr((Node *) lthird(expr->args), context, false);
10913  }
10914  appendStringInfoChar(buf, ')');
10915  return true;
10916 
10917  case F_SUBSTRING_TEXT_TEXT_TEXT:
10918  /* SUBSTRING SIMILAR/ESCAPE */
10919  appendStringInfoString(buf, "SUBSTRING(");
10920  get_rule_expr((Node *) linitial(expr->args), context, false);
10921  appendStringInfoString(buf, " SIMILAR ");
10922  get_rule_expr((Node *) lsecond(expr->args), context, false);
10923  appendStringInfoString(buf, " ESCAPE ");
10924  get_rule_expr((Node *) lthird(expr->args), context, false);
10925  appendStringInfoChar(buf, ')');
10926  return true;
10927 
10928  case F_BTRIM_BYTEA_BYTEA:
10929  case F_BTRIM_TEXT:
10930  case F_BTRIM_TEXT_TEXT:
10931  /* TRIM() */
10932  appendStringInfoString(buf, "TRIM(BOTH");
10933  if (list_length(expr->args) == 2)
10934  {
10935  appendStringInfoChar(buf, ' ');
10936  get_rule_expr((Node *) lsecond(expr->args), context, false);
10937  }
10938  appendStringInfoString(buf, " FROM ");
10939  get_rule_expr((Node *) linitial(expr->args), context, false);
10940  appendStringInfoChar(buf, ')');
10941  return true;
10942 
10943  case F_LTRIM_BYTEA_BYTEA:
10944  case F_LTRIM_TEXT:
10945  case F_LTRIM_TEXT_TEXT:
10946  /* TRIM() */
10947  appendStringInfoString(buf, "TRIM(LEADING");
10948  if (list_length(expr->args) == 2)
10949  {
10950  appendStringInfoChar(buf, ' ');
10951  get_rule_expr((Node *) lsecond(expr->args), context, false);
10952  }
10953  appendStringInfoString(buf, " FROM ");
10954  get_rule_expr((Node *) linitial(expr->args), context, false);
10955  appendStringInfoChar(buf, ')');
10956  return true;
10957 
10958  case F_RTRIM_BYTEA_BYTEA:
10959  case F_RTRIM_TEXT:
10960  case F_RTRIM_TEXT_TEXT:
10961  /* TRIM() */
10962  appendStringInfoString(buf, "TRIM(TRAILING");
10963  if (list_length(expr->args) == 2)
10964  {
10965  appendStringInfoChar(buf, ' ');
10966  get_rule_expr((Node *) lsecond(expr->args), context, false);
10967  }
10968  appendStringInfoString(buf, " FROM ");
10969  get_rule_expr((Node *) linitial(expr->args), context, false);
10970  appendStringInfoChar(buf, ')');
10971  return true;
10972 
10973  case F_SYSTEM_USER:
10974  appendStringInfoString(buf, "SYSTEM_USER");
10975  return true;
10976 
10977  case F_XMLEXISTS:
10978  /* XMLEXISTS ... extra parens because args are c_expr */
10979  appendStringInfoString(buf, "XMLEXISTS((");
10980  get_rule_expr((Node *) linitial(expr->args), context, false);
10981  appendStringInfoString(buf, ") PASSING (");
10982  get_rule_expr((Node *) lsecond(expr->args), context, false);
10983  appendStringInfoString(buf, "))");
10984  return true;
10985  }
10986  return false;
10987 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define lthird(l)
Definition: pg_list.h:188
#define lsecond(l)
Definition: pg_list.h:183
#define lfourth(l)
Definition: pg_list.h:193

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), FuncExpr::args, Assert, buf, Const::consttype, context, FuncExpr::funcid, get_rule_expr(), get_rule_expr_paren(), IsA, lfourth, linitial, list_length(), lsecond, lthird, and TextDatumGetCString.

Referenced by get_func_expr().

◆ get_insert_query_def()

static void get_insert_query_def ( Query query,
deparse_context context,
bool  colNamesVisible 
)
static

Definition at line 6638 of file ruleutils.c.

6640 {
6641  StringInfo buf = context->buf;
6642  RangeTblEntry *select_rte = NULL;
6643  RangeTblEntry *values_rte = NULL;
6644  RangeTblEntry *rte;
6645  char *sep;
6646  ListCell *l;
6647  List *strippedexprs;
6648 
6649  /* Insert the WITH clause if given */
6650  get_with_clause(query, context);
6651 
6652  /*
6653  * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6654  * single RTE for the SELECT or VALUES. Plain VALUES has neither.
6655  */
6656  foreach(l, query->rtable)
6657  {
6658  rte = (RangeTblEntry *) lfirst(l);
6659 
6660  if (rte->rtekind == RTE_SUBQUERY)
6661  {
6662  if (select_rte)
6663  elog(ERROR, "too many subquery RTEs in INSERT");
6664  select_rte = rte;
6665  }
6666 
6667  if (rte->rtekind == RTE_VALUES)
6668  {
6669  if (values_rte)
6670  elog(ERROR, "too many values RTEs in INSERT");
6671  values_rte = rte;
6672  }
6673  }
6674  if (select_rte && values_rte)
6675  elog(ERROR, "both subquery and values RTEs in INSERT");
6676 
6677  /*
6678  * Start the query with INSERT INTO relname
6679  */
6680  rte = rt_fetch(query->resultRelation, query->rtable);
6681  Assert(rte->rtekind == RTE_RELATION);
6682 
6683  if (PRETTY_INDENT(context))
6684  {
6685  context->indentLevel += PRETTYINDENT_STD;
6686  appendStringInfoChar(buf, ' ');
6687  }
6688  appendStringInfo(buf, "INSERT INTO %s",
6690 
6691  /* Print the relation alias, if needed; INSERT requires explicit AS */
6692  get_rte_alias(rte, query->resultRelation, true, context);
6693 
6694  /* always want a space here */
6695  appendStringInfoChar(buf, ' ');
6696 
6697  /*
6698  * Add the insert-column-names list. Any indirection decoration needed on
6699  * the column names can be inferred from the top targetlist.
6700  */
6701  strippedexprs = NIL;
6702  sep = "";
6703  if (query->targetList)
6704  appendStringInfoChar(buf, '(');
6705  foreach(l, query->targetList)
6706  {
6707  TargetEntry *tle = (TargetEntry *) lfirst(l);
6708 
6709  if (tle->resjunk)
6710  continue; /* ignore junk entries */
6711 
6713  sep = ", ";
6714 
6715  /*
6716  * Put out name of target column; look in the catalogs, not at
6717  * tle->resname, since resname will fail to track RENAME.
6718  */
6721  tle->resno,
6722  false)));
6723 
6724  /*
6725  * Print any indirection needed (subfields or subscripts), and strip
6726  * off the top-level nodes representing the indirection assignments.
6727  * Add the stripped expressions to strippedexprs. (If it's a
6728  * single-VALUES statement, the stripped expressions are the VALUES to
6729  * print below. Otherwise they're just Vars and not really
6730  * interesting.)
6731  */
6732  strippedexprs = lappend(strippedexprs,
6733  processIndirection((Node *) tle->expr,
6734  context));
6735  }
6736  if (query->targetList)
6737  appendStringInfoString(buf, ") ");
6738 
6739  if (query->override)
6740  {
6741  if (query->override == OVERRIDING_SYSTEM_VALUE)
6742  appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
6743  else if (query->override == OVERRIDING_USER_VALUE)
6744  appendStringInfoString(buf, "OVERRIDING USER VALUE ");
6745  }
6746 
6747  if (select_rte)
6748  {
6749  /* Add the SELECT */
6750  get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
6751  false,
6752  context->prettyFlags, context->wrapColumn,
6753  context->indentLevel);
6754  }
6755  else if (values_rte)
6756  {
6757  /* Add the multi-VALUES expression lists */
6758  get_values_def(values_rte->values_lists, context);
6759  }
6760  else if (strippedexprs)
6761  {
6762  /* Add the single-VALUES expression list */
6763  appendContextKeyword(context, "VALUES (",
6765  get_rule_list_toplevel(strippedexprs, context, false);
6766  appendStringInfoChar(buf, ')');
6767  }
6768  else
6769  {
6770  /* No expressions, so it must be DEFAULT VALUES */
6771  appendStringInfoString(buf, "DEFAULT VALUES");
6772  }
6773 
6774  /* Add ON CONFLICT if present */
6775  if (query->onConflict)
6776  {
6777  OnConflictExpr *confl = query->onConflict;
6778 
6779  appendStringInfoString(buf, " ON CONFLICT");
6780 
6781  if (confl->arbiterElems)
6782  {
6783  /* Add the single-VALUES expression list */
6784  appendStringInfoChar(buf, '(');
6785  get_rule_expr((Node *) confl->arbiterElems, context, false);
6786  appendStringInfoChar(buf, ')');
6787 
6788  /* Add a WHERE clause (for partial indexes) if given */
6789  if (confl->arbiterWhere != NULL)
6790  {
6791  bool save_varprefix;
6792 
6793  /*
6794  * Force non-prefixing of Vars, since parser assumes that they
6795  * belong to target relation. WHERE clause does not use
6796  * InferenceElem, so this is separately required.
6797  */
6798  save_varprefix = context->varprefix;
6799  context->varprefix = false;
6800 
6801  appendContextKeyword(context, " WHERE ",
6803  get_rule_expr(confl->arbiterWhere, context, false);
6804 
6805  context->varprefix = save_varprefix;
6806  }
6807  }
6808  else if (OidIsValid(confl->constraint))
6809  {
6810  char *constraint = get_constraint_name(confl->constraint);
6811 
6812  if (!constraint)
6813  elog(ERROR, "cache lookup failed for constraint %u",
6814  confl->constraint);
6815  appendStringInfo(buf, " ON CONSTRAINT %s",
6816  quote_identifier(constraint));
6817  }
6818 
6819  if (confl->action == ONCONFLICT_NOTHING)
6820  {
6821  appendStringInfoString(buf, " DO NOTHING");
6822  }
6823  else
6824  {
6825  appendStringInfoString(buf, " DO UPDATE SET ");
6826  /* Deparse targetlist */
6828  context, rte);
6829 
6830  /* Add a WHERE clause if given */
6831  if (confl->onConflictWhere != NULL)
6832  {
6833  appendContextKeyword(context, " WHERE ",
6835  get_rule_expr(confl->onConflictWhere, context, false);
6836  }
6837  }
6838  }
6839 
6840  /* Add RETURNING if present */
6841  if (query->returningList)
6842  {
6843  appendContextKeyword(context, " RETURNING",
6845  get_target_list(query->returningList, context, NULL, colNamesVisible);
6846  }
6847 }
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1081
@ ONCONFLICT_NOTHING
Definition: nodes.h:418
@ OVERRIDING_SYSTEM_VALUE
Definition: primnodes.h:29
@ OVERRIDING_USER_VALUE
Definition: primnodes.h:28
static void get_rule_list_toplevel(List *lst, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10268
static Node * processIndirection(Node *node, deparse_context *context)
Definition: ruleutils.c:12515
static void get_update_query_targetlist_def(Query *query, List *targetList, deparse_context *context, RangeTblEntry *rte)
Definition: ruleutils.c:6912
List * arbiterElems
Definition: primnodes.h:2299
OnConflictAction action
Definition: primnodes.h:2296
List * onConflictSet
Definition: primnodes.h:2305
Node * onConflictWhere
Definition: primnodes.h:2306
Node * arbiterWhere
Definition: primnodes.h:2301
OnConflictExpr * onConflict
Definition: parsenodes.h:196
AttrNumber resno
Definition: primnodes.h:2164

References OnConflictExpr::action, appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), OnConflictExpr::arbiterElems, OnConflictExpr::arbiterWhere, Assert, buf, OnConflictExpr::constraint, context, elog, ERROR, TargetEntry::expr, generate_relation_name(), get_attname(), get_constraint_name(), get_query_def(), get_rte_alias(), get_rule_expr(), get_rule_list_toplevel(), get_target_list(), get_update_query_targetlist_def(), get_values_def(), get_with_clause(), lappend(), lfirst, NIL, OidIsValid, Query::onConflict, ONCONFLICT_NOTHING, OnConflictExpr::onConflictSet, OnConflictExpr::onConflictWhere, OVERRIDING_SYSTEM_VALUE, OVERRIDING_USER_VALUE, PRETTY_INDENT, PRETTYINDENT_STD, processIndirection(), quote_identifier(), RangeTblEntry::relid, TargetEntry::resno, Query::returningList, rt_fetch, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RTE_VALUES, RangeTblEntry::rtekind, RangeTblEntry::subquery, Query::targetList, and RangeTblEntry::values_lists.

Referenced by get_query_def().

◆ get_json_agg_constructor()

static void get_json_agg_constructor ( JsonConstructorExpr ctor,
deparse_context context,
const char *  funcname,
bool  is_json_objectagg 
)
static

Definition at line 11363 of file ruleutils.c.

11365 {
11367 
11370 
11371  if (IsA(ctor->func, Aggref))
11373  (Aggref *) ctor->func,
11374  funcname, options.data, is_json_objectagg);
11375  else if (IsA(ctor->func, WindowFunc))
11377  funcname, options.data,
11378  is_json_objectagg);
11379  else
11380  elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
11381  nodeTag(ctor->func));
11382 }
static char ** options
static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context, const char *funcname, const char *options, bool is_json_objectagg)
Definition: ruleutils.c:10651
static void get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
Definition: ruleutils.c:11333

References context, elog, ERROR, JsonConstructorExpr::func, funcname, get_agg_expr_helper(), get_json_constructor_options(), get_windowfunc_expr_helper(), initStringInfo(), IsA, nodeTag, and options.

Referenced by get_json_constructor().

◆ get_json_behavior()

static void get_json_behavior ( JsonBehavior behavior,
deparse_context context,
const char *  on 
)
static

Definition at line 8809 of file ruleutils.c.

8811 {
8812  /*
8813  * The order of array elements must correspond to the order of
8814  * JsonBehaviorType members.
8815  */
8816  const char *behavior_names[] =
8817  {
8818  " NULL",
8819  " ERROR",
8820  " EMPTY",
8821  " TRUE",
8822  " FALSE",
8823  " UNKNOWN",
8824  " EMPTY ARRAY",
8825  " EMPTY OBJECT",
8826  " DEFAULT "
8827  };
8828 
8829  if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
8830  elog(ERROR, "invalid json behavior type: %d", behavior->btype);
8831 
8832  appendStringInfoString(context->buf, behavior_names[behavior->btype]);
8833 
8834  if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
8835  get_rule_expr(behavior->expr, context, false);
8836 
8837  appendStringInfo(context->buf, " ON %s", on);
8838 }
#define lengthof(array)
Definition: c.h:788
@ JSON_BEHAVIOR_DEFAULT
Definition: primnodes.h:1739
Node * expr
Definition: primnodes.h:1757
JsonBehaviorType btype
Definition: primnodes.h:1756

References appendStringInfo(), appendStringInfoString(), JsonBehavior::btype, context, elog, ERROR, JsonBehavior::expr, get_rule_expr(), JSON_BEHAVIOR_DEFAULT, and lengthof.

Referenced by get_json_expr_options(), and get_json_table().

◆ get_json_constructor()

static void get_json_constructor ( JsonConstructorExpr ctor,
deparse_context context,
bool  showimplicit 
)
static

Definition at line 11267 of file ruleutils.c.

11269 {
11270  StringInfo buf = context->buf;
11271  const char *funcname;
11272  bool is_json_object;
11273  int curridx;
11274  ListCell *lc;
11275 
11276  if (ctor->type == JSCTOR_JSON_OBJECTAGG)
11277  {
11278  get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
11279  return;
11280  }
11281  else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
11282  {
11283  get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
11284  return;
11285  }
11286 
11287  switch (ctor->type)
11288  {
11289  case JSCTOR_JSON_OBJECT:
11290  funcname = "JSON_OBJECT";
11291  break;
11292  case JSCTOR_JSON_ARRAY:
11293  funcname = "JSON_ARRAY";
11294  break;
11295  case JSCTOR_JSON_PARSE:
11296  funcname = "JSON";
11297  break;
11298  case JSCTOR_JSON_SCALAR:
11299  funcname = "JSON_SCALAR";
11300  break;
11301  case JSCTOR_JSON_SERIALIZE:
11302  funcname = "JSON_SERIALIZE";
11303  break;
11304  default:
11305  elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
11306  }
11307 
11308  appendStringInfo(buf, "%s(", funcname);
11309 
11310  is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
11311  foreach(lc, ctor->args)
11312  {
11313  curridx = foreach_current_index(lc);
11314  if (curridx > 0)
11315  {
11316  const char *sep;
11317 
11318  sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
11320  }
11321 
11322  get_rule_expr((Node *) lfirst(lc), context, true);
11323  }
11324 
11326  appendStringInfoChar(buf, ')');
11327 }
@ JSCTOR_JSON_SERIALIZE
Definition: primnodes.h:1662
@ JSCTOR_JSON_ARRAYAGG
Definition: primnodes.h:1659
@ JSCTOR_JSON_PARSE
Definition: primnodes.h:1660
@ JSCTOR_JSON_OBJECT
Definition: primnodes.h:1656
@ JSCTOR_JSON_SCALAR
Definition: primnodes.h:1661
@ JSCTOR_JSON_ARRAY
Definition: primnodes.h:1657
@ JSCTOR_JSON_OBJECTAGG
Definition: primnodes.h:1658
static void get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
Definition: ruleutils.c:11363
JsonConstructorType type
Definition: primnodes.h:1672

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), JsonConstructorExpr::args, buf, context, elog, ERROR, foreach_current_index, funcname, get_json_agg_constructor(), get_json_constructor_options(), get_rule_expr(), JSCTOR_JSON_ARRAY, JSCTOR_JSON_ARRAYAGG, JSCTOR_JSON_OBJECT, JSCTOR_JSON_OBJECTAGG, JSCTOR_JSON_PARSE, JSCTOR_JSON_SCALAR, JSCTOR_JSON_SERIALIZE, lfirst, and JsonConstructorExpr::type.

Referenced by get_rule_expr().

◆ get_json_constructor_options()

static void get_json_constructor_options ( JsonConstructorExpr ctor,
StringInfo  buf 
)
static

Definition at line 11333 of file ruleutils.c.

11334 {
11335  if (ctor->absent_on_null)
11336  {
11337  if (ctor->type == JSCTOR_JSON_OBJECT ||
11338  ctor->type == JSCTOR_JSON_OBJECTAGG)
11339  appendStringInfoString(buf, " ABSENT ON NULL");
11340  }
11341  else
11342  {
11343  if (ctor->type == JSCTOR_JSON_ARRAY ||
11344  ctor->type == JSCTOR_JSON_ARRAYAGG)
11345  appendStringInfoString(buf, " NULL ON NULL");
11346  }
11347 
11348  if (ctor->unique)
11349  appendStringInfoString(buf, " WITH UNIQUE KEYS");
11350 
11351  /*
11352  * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
11353  * support one.
11354  */
11355  if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
11356  get_json_returning(ctor->returning, buf, true);
11357 }
static void get_json_returning(JsonReturning *returning, StringInfo buf, bool json_format_by_default)
Definition: ruleutils.c:11247
JsonReturning * returning
Definition: primnodes.h:1676

References JsonConstructorExpr::absent_on_null, appendStringInfoString(), buf, get_json_returning(), JSCTOR_JSON_ARRAY, JSCTOR_JSON_ARRAYAGG, JSCTOR_JSON_OBJECT, JSCTOR_JSON_OBJECTAGG, JSCTOR_JSON_PARSE, JSCTOR_JSON_SCALAR, JsonConstructorExpr::returning, JsonConstructorExpr::type, and JsonConstructorExpr::unique.

Referenced by get_json_agg_constructor(), and get_json_constructor().

◆ get_json_expr_options()

static void get_json_expr_options ( JsonExpr jsexpr,
deparse_context context,
JsonBehaviorType  default_behavior 
)
static

Definition at line 8847 of file ruleutils.c.

8849 {
8850  if (jsexpr->op == JSON_QUERY_OP)
8851  {
8852  if (jsexpr->wrapper == JSW_CONDITIONAL)
8853  appendStringInfoString(context->buf, " WITH CONDITIONAL WRAPPER");
8854  else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
8855  appendStringInfoString(context->buf, " WITH UNCONDITIONAL WRAPPER");
8856  /* The default */
8857  else if (jsexpr->wrapper == JSW_NONE || jsexpr->wrapper == JSW_UNSPEC)
8858  appendStringInfoString(context->buf, " WITHOUT WRAPPER");
8859 
8860  if (jsexpr->omit_quotes)
8861  appendStringInfoString(context->buf, " OMIT QUOTES");
8862  /* The default */
8863  else
8864  appendStringInfoString(context->buf, " KEEP QUOTES");
8865  }
8866 
8867  if (jsexpr->on_empty && jsexpr->on_empty->btype != default_behavior)
8868  get_json_behavior(jsexpr->on_empty, context, "EMPTY");
8869 
8870  if (jsexpr->on_error && jsexpr->on_error->btype != default_behavior)
8871  get_json_behavior(jsexpr->on_error, context, "ERROR");
8872 }
@ JSW_UNCONDITIONAL
Definition: primnodes.h:1719
@ JSW_CONDITIONAL
Definition: primnodes.h:1718
@ JSW_UNSPEC
Definition: primnodes.h:1716
@ JSW_NONE
Definition: primnodes.h:1717
@ JSON_QUERY_OP
Definition: primnodes.h:1769
static void get_json_behavior(JsonBehavior *behavior, deparse_context *context, const char *on)
Definition: ruleutils.c:8809
JsonBehavior * on_empty
Definition: primnodes.h:1805
JsonWrapper wrapper
Definition: primnodes.h:1822
JsonExprOp op
Definition: primnodes.h:1783
JsonBehavior * on_error
Definition: primnodes.h:1806
bool omit_quotes
Definition: primnodes.h:1825

References appendStringInfoString(), JsonBehavior::btype, context, get_json_behavior(), JSON_QUERY_OP, JSW_CONDITIONAL, JSW_NONE, JSW_UNCONDITIONAL, JSW_UNSPEC, JsonExpr::omit_quotes, JsonExpr::on_empty, JsonExpr::on_error, JsonExpr::op, and JsonExpr::wrapper.

Referenced by get_json_table_columns(), and get_rule_expr().

◆ get_json_format()

static void get_json_format ( JsonFormat format,
StringInfo  buf 
)
static

Definition at line 11222 of file ruleutils.c.

11223 {
11224  if (format->format_type == JS_FORMAT_DEFAULT)
11225  return;
11226 
11228  format->format_type == JS_FORMAT_JSONB ?
11229  " FORMAT JSONB" : " FORMAT JSON");
11230 
11231  if (format->encoding != JS_ENC_DEFAULT)
11232  {
11233  const char *encoding;
11234 
11235  encoding =
11236  format->encoding == JS_ENC_UTF16 ? "UTF16" :
11237  format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
11238 
11239  appendStringInfo(buf, " ENCODING %s", encoding);
11240  }
11241 }
static char format
int32 encoding
Definition: pg_database.h:41
@ JS_FORMAT_JSONB
Definition: primnodes.h:1610
@ JS_FORMAT_DEFAULT
Definition: primnodes.h:1608
@ JS_ENC_DEFAULT
Definition: primnodes.h:1596
@ JS_ENC_UTF32
Definition: primnodes.h:1599
@ JS_ENC_UTF16
Definition: primnodes.h:1598

References appendStringInfo(), appendStringInfoString(), buf, encoding, format, JS_ENC_DEFAULT, JS_ENC_UTF16, JS_ENC_UTF32, JS_FORMAT_DEFAULT, and JS_FORMAT_JSONB.

Referenced by get_json_returning(), and get_rule_expr().

◆ get_json_path_spec()

static void get_json_path_spec ( Node path_spec,
deparse_context context,
bool  showimplicit 
)
static

Definition at line 11210 of file ruleutils.c.

11211 {
11212  if (IsA(path_spec, Const))
11213  get_const_expr((Const *) path_spec, context, -1);
11214  else
11215  get_rule_expr(path_spec, context, showimplicit);
11216 }

References context, get_const_expr(), get_rule_expr(), and IsA.

Referenced by get_json_table_columns(), and get_rule_expr().

◆ get_json_returning()

static void get_json_returning ( JsonReturning returning,
StringInfo  buf,
bool  json_format_by_default 
)
static

Definition at line 11247 of file ruleutils.c.

11249 {
11250  if (!OidIsValid(returning->typid))
11251  return;
11252 
11253  appendStringInfo(buf, " RETURNING %s",
11254  format_type_with_typemod(returning->typid,
11255  returning->typmod));
11256 
11257  if (!json_format_by_default ||
11258  returning->format->format_type !=
11259  (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
11260  get_json_format(returning->format, buf);
11261 }
@ JS_FORMAT_JSON
Definition: primnodes.h:1609
static void get_json_format(JsonFormat *format, StringInfo buf)
Definition: ruleutils.c:11222
JsonFormatType format_type
Definition: primnodes.h:1621
JsonFormat * format
Definition: primnodes.h:1633

References appendStringInfo(), buf, JsonReturning::format, JsonFormat::format_type, format_type_with_typemod(), get_json_format(), JS_FORMAT_JSON, JS_FORMAT_JSONB, OidIsValid, JsonReturning::typid, and JsonReturning::typmod.

Referenced by get_json_constructor_options(), and get_rule_expr().

◆ get_json_table()

static void get_json_table ( TableFunc tf,
deparse_context context,
bool  showimplicit 
)
static

Definition at line 11776 of file ruleutils.c.

11777 {
11778  StringInfo buf = context->buf;
11779  JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
11781 
11782  appendStringInfoString(buf, "JSON_TABLE(");
11783 
11784  if (PRETTY_INDENT(context))
11785  context->indentLevel += PRETTYINDENT_VAR;
11786 
11787  appendContextKeyword(context, "", 0, 0, 0);
11788 
11789  get_rule_expr(jexpr->formatted_expr, context, showimplicit);
11790 
11791  appendStringInfoString(buf, ", ");
11792 
11793  get_const_expr(root->path->value, context, -1);
11794 
11795  appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
11796 
11797  if (jexpr->passing_values)
11798  {
11799  ListCell *lc1,
11800  *lc2;
11801  bool needcomma = false;
11802 
11803  appendStringInfoChar(buf, ' ');
11804  appendContextKeyword(context, "PASSING ", 0, 0, 0);
11805 
11806  if (PRETTY_INDENT(context))
11807  context->indentLevel += PRETTYINDENT_VAR;
11808 
11809  forboth(lc1, jexpr->passing_names,
11810  lc2, jexpr->passing_values)
11811  {
11812  if (needcomma)
11813  appendStringInfoString(buf, ", ");
11814  needcomma = true;
11815 
11816  appendContextKeyword(context, "", 0, 0, 0);
11817 
11818  get_rule_expr((Node *) lfirst(lc2), context, false);
11819  appendStringInfo(buf, " AS %s",
11820  quote_identifier((lfirst_node(String, lc1))->sval)
11821  );
11822  }
11823 
11824  if (PRETTY_INDENT(context))
11825  context->indentLevel -= PRETTYINDENT_VAR;
11826  }
11827 
11829  showimplicit);
11830 
11831  if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY)
11832  get_json_behavior(jexpr->on_error, context, "ERROR");
11833 
11834  if (PRETTY_INDENT(context))
11835  context->indentLevel -= PRETTYINDENT_VAR;
11836 
11837  appendContextKeyword(context, ")", 0, 0, 0);
11838 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
@ JSON_BEHAVIOR_EMPTY
Definition: primnodes.h:1733
tree ctl root
Definition: radixtree.h:1880
static void get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11670
Node * formatted_expr
Definition: primnodes.h:1789
List * passing_values
Definition: primnodes.h:1802
List * passing_names
Definition: primnodes.h:1801
Definition: value.h:64
Node * docexpr
Definition: primnodes.h:119

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), JsonBehavior::btype, buf, castNode, context, TableFunc::docexpr, forboth, JsonExpr::formatted_expr, get_const_expr(), get_json_behavior(), get_json_table_columns(), get_rule_expr(), JSON_BEHAVIOR_EMPTY, lfirst, lfirst_node, JsonExpr::on_error, JsonExpr::passing_names, JsonExpr::passing_values, PRETTY_INDENT, PRETTYINDENT_VAR, quote_identifier(), and root.

Referenced by get_tablefunc().

◆ get_json_table_columns()

static void get_json_table_columns ( TableFunc tf,
JsonTablePathScan scan,
deparse_context context,
bool  showimplicit 
)
static

Definition at line 11670 of file ruleutils.c.

11673 {
11674  StringInfo buf = context->buf;
11675  JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
11676  ListCell *lc_colname;
11677  ListCell *lc_coltype;
11678  ListCell *lc_coltypmod;
11679  ListCell *lc_colvalexpr;
11680  int colnum = 0;
11681 
11682  appendStringInfoChar(buf, ' ');
11683  appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
11684 
11685  if (PRETTY_INDENT(context))
11686  context->indentLevel += PRETTYINDENT_VAR;
11687 
11688  forfour(lc_colname, tf->colnames,
11689  lc_coltype, tf->coltypes,
11690  lc_coltypmod, tf->coltypmods,
11691  lc_colvalexpr, tf->colvalexprs)
11692  {
11693  char *colname = strVal(lfirst(lc_colname));
11694  JsonExpr *colexpr;
11695  Oid typid;
11696  int32 typmod;
11697  bool ordinality;
11698  JsonBehaviorType default_behavior;
11699 
11700  typid = lfirst_oid(lc_coltype);
11701  typmod = lfirst_int(lc_coltypmod);
11702  colexpr = castNode(JsonExpr, lfirst(lc_colvalexpr));
11703 
11704  /* Skip columns that don't belong to this scan. */
11705  if (scan->colMin < 0 || colnum < scan->colMin)
11706  {
11707  colnum++;
11708  continue;
11709  }
11710  if (colnum > scan->colMax)
11711  break;
11712 
11713  if (colnum > scan->colMin)
11714  appendStringInfoString(buf, ", ");
11715 
11716  colnum++;
11717 
11718  ordinality = !colexpr;
11719 
11720  appendContextKeyword(context, "", 0, 0, 0);
11721 
11722  appendStringInfo(buf, "%s %s", quote_identifier(colname),
11723  ordinality ? "FOR ORDINALITY" :
11724  format_type_with_typemod(typid, typmod));
11725  if (ordinality)
11726  continue;
11727 
11728  if (colexpr->op == JSON_EXISTS_OP)
11729  {
11730  appendStringInfoString(buf, " EXISTS");
11731  default_behavior = JSON_BEHAVIOR_FALSE;
11732  }
11733  else
11734  {
11735  if (colexpr->op == JSON_QUERY_OP)
11736  {
11737  char typcategory;
11738  bool typispreferred;
11739 
11740  get_type_category_preferred(typid, &typcategory, &typispreferred);
11741 
11742  if (typcategory == TYPCATEGORY_STRING)
11744  colexpr->format->format_type == JS_FORMAT_JSONB ?
11745  " FORMAT JSONB" : " FORMAT JSON");
11746  }
11747 
11748  default_behavior = JSON_BEHAVIOR_NULL;
11749  }
11750 
11751  if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
11752  default_behavior = JSON_BEHAVIOR_ERROR;
11753 
11754  appendStringInfoString(buf, " PATH ");
11755 
11756  get_json_path_spec(colexpr->path_spec, context, showimplicit);
11757 
11758  get_json_expr_options(colexpr, context, default_behavior);
11759  }
11760 
11761  if (scan->child)
11762  get_json_table_nested_columns(tf, scan->child, context, showimplicit,
11763  scan->colMin >= 0);
11764 
11765  if (PRETTY_INDENT(context))
11766  context->indentLevel -= PRETTYINDENT_VAR;
11767 
11768  appendContextKeyword(context, ")", 0, 0, 0);
11769 }
void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
Definition: lsyscache.c:2710
JsonBehaviorType
Definition: primnodes.h:1730
@ JSON_BEHAVIOR_ERROR
Definition: primnodes.h:1732
@ JSON_BEHAVIOR_FALSE
Definition: primnodes.h:1735
@ JSON_BEHAVIOR_NULL
Definition: primnodes.h:1731
@ JSON_EXISTS_OP
Definition: primnodes.h:1768
static void get_json_expr_options(JsonExpr *jsexpr, deparse_context *context, JsonBehaviorType default_behavior)
Definition: ruleutils.c:8847
static void get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11210
static void get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan, deparse_context *context, bool showimplicit, bool needcomma)
Definition: ruleutils.c:11638
JsonFormat * format
Definition: primnodes.h:1792
Node * path_spec
Definition: primnodes.h:1795
JsonTablePlan * child
Definition: primnodes.h:1879

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), JsonBehavior::btype, buf, castNode, JsonTablePathScan::child, JsonTablePathScan::colMax, JsonTablePathScan::colMin, context, TableFunc::docexpr, forfour, JsonExpr::format, JsonFormat::format_type, format_type_with_typemod(), get_json_expr_options(), get_json_path_spec(), get_json_table_nested_columns(), get_type_category_preferred(), JS_FORMAT_JSONB, JSON_BEHAVIOR_ERROR, JSON_BEHAVIOR_FALSE, JSON_BEHAVIOR_NULL, JSON_EXISTS_OP, JSON_QUERY_OP, lfirst, lfirst_int, lfirst_oid, JsonExpr::on_error, JsonExpr::op, JsonExpr::path_spec, PRETTY_INDENT, PRETTYINDENT_VAR, quote_identifier(), and strVal.

Referenced by get_json_table(), and get_json_table_nested_columns().

◆ get_json_table_nested_columns()

static void get_json_table_nested_columns ( TableFunc tf,
JsonTablePlan plan,
deparse_context context,
bool  showimplicit,
bool  needcomma 
)
static

Definition at line 11638 of file ruleutils.c.

11641 {
11642  if (IsA(plan, JsonTablePathScan))
11643  {
11645 
11646  if (needcomma)
11647  appendStringInfoChar(context->buf, ',');
11648 
11649  appendStringInfoChar(context->buf, ' ');
11650  appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
11651  get_const_expr(scan->path->value, context, -1);
11652  appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
11653  get_json_table_columns(tf, scan, context, showimplicit);
11654  }
11655  else if (IsA(plan, JsonTableSiblingJoin))
11656  {
11658 
11659  get_json_table_nested_columns(tf, join->lplan, context, showimplicit,
11660  needcomma);
11661  get_json_table_nested_columns(tf, join->rplan, context, showimplicit,
11662  true);
11663  }
11664 }
JsonTablePath * path
Definition: primnodes.h:1870
Const * value
Definition: primnodes.h:1843
JsonTablePlan * rplan
Definition: primnodes.h:1900
JsonTablePlan * lplan
Definition: primnodes.h:1899

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), castNode, context, get_const_expr(), get_json_table_columns(), IsA, JsonTableSiblingJoin::lplan, JsonTablePath::name, JsonTablePathScan::path, plan, quote_identifier(), JsonTableSiblingJoin::rplan, and JsonTablePath::value.

Referenced by get_json_table_columns().

◆ get_list_partvalue_string()

char* get_list_partvalue_string ( Const val)

Definition at line 13308 of file ruleutils.c.

13309 {
13312 
13313  memset(&context, 0, sizeof(deparse_context));
13314  context.buf = buf;
13315 
13316  get_const_expr(val, &context, -1);
13317 
13318  return buf->data;
13319 }
long val
Definition: informix.c:670
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41

References buf, context, get_const_expr(), makeStringInfo(), and val.

Referenced by check_parent_values_in_new_partitions().

◆ get_merge_query_def()

static void get_merge_query_def ( Query query,
deparse_context context,
bool  colNamesVisible 
)
static

Definition at line 7116 of file ruleutils.c.

7118 {
7119  StringInfo buf = context->buf;
7120  RangeTblEntry *rte;
7121  ListCell *lc;
7122  bool haveNotMatchedBySource;
7123 
7124  /* Insert the WITH clause if given */
7125  get_with_clause(query, context);
7126 
7127  /*
7128  * Start the query with MERGE INTO relname
7129  */
7130  rte = rt_fetch(query->resultRelation, query->rtable);
7131  Assert(rte->rtekind == RTE_RELATION);
7132  if (PRETTY_INDENT(context))
7133  {
7134  appendStringInfoChar(buf, ' ');
7135  context->indentLevel += PRETTYINDENT_STD;
7136  }
7137  appendStringInfo(buf, "MERGE INTO %s%s",
7138  only_marker(rte),
7140 
7141  /* Print the relation alias, if needed */
7142  get_rte_alias(rte, query->resultRelation, false, context);
7143 
7144  /* Print the source relation and join clause */
7145  get_from_clause(query, " USING ", context);
7146  appendContextKeyword(context, " ON ",
7148  get_rule_expr(query->mergeJoinCondition, context, false);
7149 
7150  /*
7151  * Test for any NOT MATCHED BY SOURCE actions. If there are none, then
7152  * any NOT MATCHED BY TARGET actions are output as "WHEN NOT MATCHED", per
7153  * SQL standard. Otherwise, we have a non-SQL-standard query, so output
7154  * "BY SOURCE" / "BY TARGET" qualifiers for all NOT MATCHED actions, to be
7155  * more explicit.
7156  */
7157  haveNotMatchedBySource = false;
7158  foreach(lc, query->mergeActionList)
7159  {
7161 
7162  if (action->matchKind == MERGE_WHEN_NOT_MATCHED_BY_SOURCE)
7163  {
7164  haveNotMatchedBySource = true;
7165  break;
7166  }
7167  }
7168 
7169  /* Print each merge action */
7170  foreach(lc, query->mergeActionList)
7171  {
7173 
7174  appendContextKeyword(context, " WHEN ",
7176  switch (action->matchKind)
7177  {
7178  case MERGE_WHEN_MATCHED:
7179  appendStringInfoString(buf, "MATCHED");
7180  break;
7182  appendStringInfoString(buf, "NOT MATCHED BY SOURCE");
7183  break;
7185  if (haveNotMatchedBySource)
7186  appendStringInfoString(buf, "NOT MATCHED BY TARGET");
7187  else
7188  appendStringInfoString(buf, "NOT MATCHED");
7189  break;
7190  default:
7191  elog(ERROR, "unrecognized matchKind: %d",
7192  (int) action->matchKind);
7193  }
7194 
7195  if (action->qual)
7196  {
7197  appendContextKeyword(context, " AND ",
7199  get_rule_expr(action->qual, context, false);
7200  }
7201  appendContextKeyword(context, " THEN ",
7203 
7204  if (action->commandType == CMD_INSERT)
7205  {
7206  /* This generally matches get_insert_query_def() */
7207  List *strippedexprs = NIL;
7208  const char *sep = "";
7209  ListCell *lc2;
7210 
7211  appendStringInfoString(buf, "INSERT");
7212 
7213  if (action->targetList)
7214  appendStringInfoString(buf, " (");
7215  foreach(lc2, action->targetList)
7216  {
7217  TargetEntry *tle = (TargetEntry *) lfirst(lc2);
7218 
7219  Assert(!tle->resjunk);
7220 
7222  sep = ", ";
7223 
7226  tle->resno,
7227  false)));
7228  strippedexprs = lappend(strippedexprs,
7229  processIndirection((Node *) tle->expr,
7230  context));
7231  }
7232  if (action->targetList)
7233  appendStringInfoChar(buf, ')');
7234 
7235  if (action->override)
7236  {
7237  if (action->override == OVERRIDING_SYSTEM_VALUE)
7238  appendStringInfoString(buf, " OVERRIDING SYSTEM VALUE");
7239  else if (action->override == OVERRIDING_USER_VALUE)
7240  appendStringInfoString(buf, " OVERRIDING USER VALUE");
7241  }
7242 
7243  if (strippedexprs)
7244  {
7245  appendContextKeyword(context, " VALUES (",
7247  get_rule_list_toplevel(strippedexprs, context, false);
7248  appendStringInfoChar(buf, ')');
7249  }
7250  else
7251  appendStringInfoString(buf, " DEFAULT VALUES");
7252  }
7253  else if (action->commandType == CMD_UPDATE)
7254  {
7255  appendStringInfoString(buf, "UPDATE SET ");
7256  get_update_query_targetlist_def(query, action->targetList,
7257  context, rte);
7258  }
7259  else if (action->commandType == CMD_DELETE)
7260  appendStringInfoString(buf, "DELETE");
7261  else if (action->commandType == CMD_NOTHING)
7262  appendStringInfoString(buf, "DO NOTHING");
7263  }
7264 
7265  /* Add RETURNING if present */
7266  if (query->returningList)
7267  {
7268  appendContextKeyword(context, " RETURNING",
7270  get_target_list(query->returningList, context, NULL, colNamesVisible);
7271  }
7272 }
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
@ CMD_NOTHING
Definition: nodes.h:272
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition: primnodes.h:1970
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition: primnodes.h:1969
@ MERGE_WHEN_MATCHED
Definition: primnodes.h:1968
Node * mergeJoinCondition
Definition: parsenodes.h:189
List * mergeActionList
Definition: parsenodes.h:178

References generate_unaccent_rules::action, appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, buf, CMD_DELETE, CMD_INSERT, CMD_NOTHING, CMD_UPDATE, context, elog, ERROR, TargetEntry::expr, generate_relation_name(), get_attname(), get_from_clause(), get_rte_alias(), get_rule_expr(), get_rule_list_toplevel(), get_target_list(), get_update_query_targetlist_def(), get_with_clause(), lappend(), lfirst, lfirst_node, MERGE_WHEN_MATCHED, MERGE_WHEN_NOT_MATCHED_BY_SOURCE, MERGE_WHEN_NOT_MATCHED_BY_TARGET, Query::mergeActionList, Query::mergeJoinCondition, NIL, only_marker, OVERRIDING_SYSTEM_VALUE, OVERRIDING_USER_VALUE, PRETTY_INDENT, PRETTYINDENT_STD, processIndirection(), quote_identifier(), RangeTblEntry::relid, TargetEntry::resno, Query::returningList, rt_fetch, Query::rtable, RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by get_query_def().

◆ get_name_for_var_field()

static const char* get_name_for_var_field ( Var var,
int  fieldno,
int  levelsup,
deparse_context context 
)
static

Definition at line 7688 of file ruleutils.c.

7690 {
7691  RangeTblEntry *rte;
7693  int netlevelsup;
7694  deparse_namespace *dpns;
7695  int varno;
7696  AttrNumber varattno;
7697  TupleDesc tupleDesc;
7698  Node *expr;
7699 
7700  /*
7701  * If it's a RowExpr that was expanded from a whole-row Var, use the
7702  * column names attached to it. (We could let get_expr_result_tupdesc()
7703  * handle this, but it's much cheaper to just pull out the name we need.)
7704  */
7705  if (IsA(var, RowExpr))
7706  {
7707  RowExpr *r = (RowExpr *) var;
7708 
7709  if (fieldno > 0 && fieldno <= list_length(r->colnames))
7710  return strVal(list_nth(r->colnames, fieldno - 1));
7711  }
7712 
7713  /*
7714  * If it's a Param of type RECORD, try to find what the Param refers to.
7715  */
7716  if (IsA(var, Param))
7717  {
7718  Param *param = (Param *) var;
7719  ListCell *ancestor_cell;
7720 
7721  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7722  if (expr)
7723  {
7724  /* Found a match, so recurse to decipher the field name */
7725  deparse_namespace save_dpns;
7726  const char *result;
7727 
7728  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7729  result = get_name_for_var_field((Var *) expr, fieldno,
7730  0, context);
7731  pop_ancestor_plan(dpns, &save_dpns);
7732  return result;
7733  }
7734  }
7735 
7736  /*
7737  * If it's a Var of type RECORD, we have to find what the Var refers to;
7738  * if not, we can use get_expr_result_tupdesc().
7739  */
7740  if (!IsA(var, Var) ||
7741  var->vartype != RECORDOID)
7742  {
7743  tupleDesc = get_expr_result_tupdesc((Node *) var, false);
7744  /* Got the tupdesc, so we can extract the field name */
7745  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7746  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7747  }
7748 
7749  /* Find appropriate nesting depth */
7750  netlevelsup = var->varlevelsup + levelsup;
7751  if (netlevelsup >= list_length(context->namespaces))
7752  elog(ERROR, "bogus varlevelsup: %d offset %d",
7753  var->varlevelsup, levelsup);
7754  dpns = (deparse_namespace *) list_nth(context->namespaces,
7755  netlevelsup);
7756 
7757  /*
7758  * If we have a syntactic referent for the Var, and we're working from a
7759  * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7760  * on the semantic referent. (See comments in get_variable().)
7761  */
7762  if (var->varnosyn > 0 && dpns->plan == NULL)
7763  {
7764  varno = var->varnosyn;
7765  varattno = var->varattnosyn;
7766  }
7767  else
7768  {
7769  varno = var->varno;
7770  varattno = var->varattno;
7771  }
7772 
7773  /*
7774  * Try to find the relevant RTE in this rtable. In a plan tree, it's
7775  * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7776  * down into the subplans, or INDEX_VAR, which is resolved similarly.
7777  *
7778  * Note: unlike get_variable and resolve_special_varno, we need not worry
7779  * about inheritance mapping: a child Var should have the same datatype as
7780  * its parent, and here we're really only interested in the Var's type.
7781  */
7782  if (varno >= 1 && varno <= list_length(dpns->rtable))
7783  {
7784  rte = rt_fetch(varno, dpns->rtable);
7785  attnum = varattno;
7786  }
7787  else if (varno == OUTER_VAR && dpns->outer_tlist)
7788  {
7789  TargetEntry *tle;
7790  deparse_namespace save_dpns;
7791  const char *result;
7792 
7793  tle = get_tle_by_resno(dpns->outer_tlist, varattno);
7794  if (!tle)
7795  elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
7796 
7797  Assert(netlevelsup == 0);
7798  push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7799 
7800  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7801  levelsup, context);
7802 
7803  pop_child_plan(dpns, &save_dpns);
7804  return result;
7805  }
7806  else if (varno == INNER_VAR && dpns->inner_tlist)
7807  {
7808  TargetEntry *tle;
7809  deparse_namespace save_dpns;
7810  const char *result;
7811 
7812  tle = get_tle_by_resno(dpns->inner_tlist, varattno);
7813  if (!tle)
7814  elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
7815 
7816  Assert(netlevelsup == 0);
7817  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7818 
7819  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7820  levelsup, context);
7821 
7822  pop_child_plan(dpns, &save_dpns);
7823  return result;
7824  }
7825  else if (varno == INDEX_VAR && dpns->index_tlist)
7826  {
7827  TargetEntry *tle;
7828  const char *result;
7829 
7830  tle = get_tle_by_resno(dpns->index_tlist, varattno);
7831  if (!tle)
7832  elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
7833 
7834  Assert(netlevelsup == 0);
7835 
7836  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7837  levelsup, context);
7838 
7839  return result;
7840  }
7841  else
7842  {
7843  elog(ERROR, "bogus varno: %d", varno);
7844  return NULL; /* keep compiler quiet */
7845  }
7846 
7847  if (attnum == InvalidAttrNumber)
7848  {
7849  /* Var is whole-row reference to RTE, so select the right field */
7850  return get_rte_attribute_name(rte, fieldno);
7851  }
7852 
7853  /*
7854  * This part has essentially the same logic as the parser's
7855  * expandRecordVariable() function, but we are dealing with a different
7856  * representation of the input context, and we only need one field name
7857  * not a TupleDesc. Also, we need special cases for finding subquery and
7858  * CTE subplans when deparsing Plan trees.
7859  */
7860  expr = (Node *) var; /* default if we can't drill down */
7861 
7862  switch (rte->rtekind)
7863  {
7864  case RTE_RELATION:
7865  case RTE_VALUES:
7866  case RTE_NAMEDTUPLESTORE:
7867  case RTE_RESULT:
7868 
7869  /*
7870  * This case should not occur: a column of a table, values list,
7871  * or ENR shouldn't have type RECORD. Fall through and fail (most
7872  * likely) at the bottom.
7873  */
7874  break;
7875  case RTE_SUBQUERY:
7876  /* Subselect-in-FROM: examine sub-select's output expr */
7877  {
7878  if (rte->subquery)
7879  {
7881  attnum);
7882 
7883  if (ste == NULL || ste->resjunk)
7884  elog(ERROR, "subquery %s does not have attribute %d",
7885  rte->eref->aliasname, attnum);
7886  expr = (Node *) ste->expr;
7887  if (IsA(expr, Var))
7888  {
7889  /*
7890  * Recurse into the sub-select to see what its Var
7891  * refers to. We have to build an additional level of
7892  * namespace to keep in step with varlevelsup in the
7893  * subselect; furthermore, the subquery RTE might be
7894  * from an outer query level, in which case the
7895  * namespace for the subselect must have that outer
7896  * level as parent namespace.
7897  */
7898  List *save_nslist = context->namespaces;
7899  List *parent_namespaces;
7900  deparse_namespace mydpns;
7901  const char *result;
7902 
7903  parent_namespaces = list_copy_tail(context->namespaces,
7904  netlevelsup);
7905 
7906  set_deparse_for_query(&mydpns, rte->subquery,
7907  parent_namespaces);
7908 
7909  context->namespaces = lcons(&mydpns, parent_namespaces);
7910 
7911  result = get_name_for_var_field((Var *) expr, fieldno,
7912  0, context);
7913 
7914  context->namespaces = save_nslist;
7915 
7916  return result;
7917  }
7918  /* else fall through to inspect the expression */
7919  }
7920  else
7921  {
7922  /*
7923  * We're deparsing a Plan tree so we don't have complete
7924  * RTE entries (in particular, rte->subquery is NULL). But
7925  * the only place we'd see a Var directly referencing a
7926  * SUBQUERY RTE is in a SubqueryScan plan node, and we can
7927  * look into the child plan's tlist instead.
7928  */
7929  TargetEntry *tle;
7930  deparse_namespace save_dpns;
7931  const char *result;
7932 
7933  if (!dpns->inner_plan)
7934  elog(ERROR, "failed to find plan for subquery %s",
7935  rte->eref->aliasname);
7936  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7937  if (!tle)
7938  elog(ERROR, "bogus varattno for subquery var: %d",
7939  attnum);
7940  Assert(netlevelsup == 0);
7941  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7942 
7943  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7944  levelsup, context);
7945 
7946  pop_child_plan(dpns, &save_dpns);
7947  return result;
7948  }
7949  }
7950  break;
7951  case RTE_JOIN:
7952  /* Join RTE --- recursively inspect the alias variable */
7953  if (rte->joinaliasvars == NIL)
7954  elog(ERROR, "cannot decompile join alias var in plan tree");
7955  Assert(attnum > 0 && attnum <=