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/sysattr.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, 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, const char *relname, 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 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_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)
 
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_returning (JsonReturning *returning, StringInfo buf, bool json_format_by_default)
 
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)
 

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 297 of file ruleutils.c.

◆ GET_PRETTY_FLAGS

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

Definition at line 95 of file ruleutils.c.

◆ only_marker

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

Definition at line 522 of file ruleutils.c.

◆ PRETTY_INDENT

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

Definition at line 104 of file ruleutils.c.

◆ PRETTY_PAREN

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

Definition at line 103 of file ruleutils.c.

◆ PRETTY_SCHEMA

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

Definition at line 105 of file ruleutils.c.

◆ PRETTYFLAG_INDENT

#define PRETTYFLAG_INDENT   0x0002

Definition at line 91 of file ruleutils.c.

◆ PRETTYFLAG_PAREN

#define PRETTYFLAG_PAREN   0x0001

Definition at line 90 of file ruleutils.c.

◆ PRETTYFLAG_SCHEMA

#define PRETTYFLAG_SCHEMA   0x0004

Definition at line 92 of file ruleutils.c.

◆ PRETTYINDENT_JOIN

#define PRETTYINDENT_JOIN   4

Definition at line 84 of file ruleutils.c.

◆ PRETTYINDENT_LIMIT

#define PRETTYINDENT_LIMIT   40 /* wrap limit */

Definition at line 87 of file ruleutils.c.

◆ PRETTYINDENT_STD

#define PRETTYINDENT_STD   8

Definition at line 83 of file ruleutils.c.

◆ PRETTYINDENT_VAR

#define PRETTYINDENT_VAR   4

Definition at line 85 of file ruleutils.c.

◆ WRAP_COLUMN_DEFAULT

#define WRAP_COLUMN_DEFAULT   0

Definition at line 100 of file ruleutils.c.

Typedef Documentation

◆ rsv_callback

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

Definition at line 310 of file ruleutils.c.

Function Documentation

◆ add_cast_to()

static void add_cast_to ( StringInfo  buf,
Oid  typid 
)
static

Definition at line 12413 of file ruleutils.c.

12414 {
12415  HeapTuple typetup;
12416  Form_pg_type typform;
12417  char *typname;
12418  char *nspname;
12419 
12420  typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
12421  if (!HeapTupleIsValid(typetup))
12422  elog(ERROR, "cache lookup failed for type %u", typid);
12423  typform = (Form_pg_type) GETSTRUCT(typetup);
12424 
12425  typname = NameStr(typform->typname);
12426  nspname = get_namespace_name_or_temp(typform->typnamespace);
12427 
12428  appendStringInfo(buf, "::%s.%s",
12430 
12431  ReleaseSysCache(typetup);
12432 }
#define NameStr(name)
Definition: c.h:735
#define ERROR
Definition: elog.h:39
#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:3372
static char * buf
Definition: pg_test_fsync.c:67
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:11965
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
@ TYPEOID
Definition: syscache.h:114

References appendStringInfo(), buf, elog(), ERROR, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), quote_identifier(), ReleaseSysCache(), SearchSysCache1(), TYPEOID, 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 8499 of file ruleutils.c.

8501 {
8502  StringInfo buf = context->buf;
8503 
8504  if (PRETTY_INDENT(context))
8505  {
8506  int indentAmount;
8507 
8508  context->indentLevel += indentBefore;
8509 
8510  /* remove any trailing spaces currently in the buffer ... */
8512  /* ... then add a newline and some spaces */
8513  appendStringInfoChar(buf, '\n');
8514 
8515  if (context->indentLevel < PRETTYINDENT_LIMIT)
8516  indentAmount = Max(context->indentLevel, 0) + indentPlus;
8517  else
8518  {
8519  /*
8520  * If we're indented more than PRETTYINDENT_LIMIT characters, try
8521  * to conserve horizontal space by reducing the per-level
8522  * indentation. For best results the scale factor here should
8523  * divide all the indent amounts that get added to indentLevel
8524  * (PRETTYINDENT_STD, etc). It's important that the indentation
8525  * not grow unboundedly, else deeply-nested trees use O(N^2)
8526  * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8527  */
8528  indentAmount = PRETTYINDENT_LIMIT +
8529  (context->indentLevel - PRETTYINDENT_LIMIT) /
8530  (PRETTYINDENT_STD / 2);
8531  indentAmount %= PRETTYINDENT_LIMIT;
8532  /* scale/wrap logic affects indentLevel, but not indentPlus */
8533  indentAmount += indentPlus;
8534  }
8535  appendStringInfoSpaces(buf, indentAmount);
8536 
8538 
8539  context->indentLevel += indentAfter;
8540  if (context->indentLevel < 0)
8541  context->indentLevel = 0;
8542  }
8543  else
8545 }
#define Max(x, y)
Definition: c.h:987
static void removeStringInfoSpaces(StringInfo str)
Definition: ruleutils.c:8553
#define PRETTYINDENT_LIMIT
Definition: ruleutils.c:87
#define PRETTYINDENT_STD
Definition: ruleutils.c:83
#define PRETTY_INDENT(context)
Definition: ruleutils.c:104
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
StringInfo buf
Definition: ruleutils.c:116

References appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), deparse_context::buf, buf, deparse_context::indentLevel, Max, PRETTY_INDENT, PRETTYINDENT_LIMIT, PRETTYINDENT_STD, removeStringInfoSpaces(), and generate_unaccent_rules::str.

Referenced by get_basic_select_query(), get_delete_query_def(), get_from_clause(), get_from_clause_item(), get_insert_query_def(), 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 4764 of file ruleutils.c.

4766 {
4767  int i;
4768  ListCell *lc;
4769 
4770  /* Check against already-assigned column aliases within RTE */
4771  for (i = 0; i < colinfo->num_cols; i++)
4772  {
4773  char *oldname = colinfo->colnames[i];
4774 
4775  if (oldname && strcmp(oldname, colname) == 0)
4776  return false;
4777  }
4778 
4779  /*
4780  * If we're building a new_colnames array, check that too (this will be
4781  * partially but not completely redundant with the previous checks)
4782  */
4783  for (i = 0; i < colinfo->num_new_cols; i++)
4784  {
4785  char *oldname = colinfo->new_colnames[i];
4786 
4787  if (oldname && strcmp(oldname, colname) == 0)
4788  return false;
4789  }
4790 
4791  /* Also check against USING-column names that must be globally unique */
4792  foreach(lc, dpns->using_names)
4793  {
4794  char *oldname = (char *) lfirst(lc);
4795 
4796  if (strcmp(oldname, colname) == 0)
4797  return false;
4798  }
4799 
4800  /* Also check against names already assigned for parent-join USING cols */
4801  foreach(lc, colinfo->parentUsing)
4802  {
4803  char *oldname = (char *) lfirst(lc);
4804 
4805  if (strcmp(oldname, colname) == 0)
4806  return false;
4807  }
4808 
4809  return true;
4810 }
int i
Definition: isn.c:73
#define lfirst(lc)
Definition: pg_list.h:172
List * parentUsing
Definition: ruleutils.c:270
char ** new_colnames
Definition: ruleutils.c:263
char ** colnames
Definition: ruleutils.c:246
List * using_names
Definition: ruleutils.c:172

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,
StringInfo  buf 
)
static

Definition at line 2577 of file ruleutils.c.

2579 {
2580  Datum *keys;
2581  int nKeys;
2582  int j;
2583 
2584  /* Extract data from array of int16 */
2585  deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2586  &keys, NULL, &nKeys);
2587 
2588  for (j = 0; j < nKeys; j++)
2589  {
2590  char *colName;
2591 
2592  colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2593 
2594  if (j == 0)
2596  else
2597  appendStringInfo(buf, ", %s", quote_identifier(colName));
2598  }
2599 
2600  return nKeys;
2601 }
#define DatumGetArrayTypeP(X)
Definition: array.h:254
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3644
int j
Definition: isn.c:74
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:826
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 3660 of file ruleutils.c.

3661 {
3662  deparse_namespace *dpns;
3663  RangeTblEntry *rte;
3664 
3665  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3666 
3667  /* Build a minimal RTE for the rel */
3668  rte = makeNode(RangeTblEntry);
3669  rte->rtekind = RTE_RELATION;
3670  rte->relid = relid;
3671  rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3673  rte->alias = makeAlias(aliasname, NIL);
3674  rte->eref = rte->alias;
3675  rte->lateral = false;
3676  rte->inh = false;
3677  rte->inFromCl = true;
3678 
3679  /* Build one-element rtable */
3680  dpns->rtable = list_make1(rte);
3681  dpns->subplans = NIL;
3682  dpns->ctes = NIL;
3683  dpns->appendrels = NULL;
3684  set_rtable_names(dpns, NIL, NULL);
3686 
3687  /* Return a one-deep namespace stack */
3688  return list_make1(dpns);
3689 }
#define AccessShareLock
Definition: lockdefs.h:36
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:390
void * palloc0(Size size)
Definition: mcxt.c:1257
#define makeNode(_type_)
Definition: nodes.h:176
@ RTE_RELATION
Definition: parsenodes.h:1013
#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:4036
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
Definition: ruleutils.c:3826
Alias * eref
Definition: parsenodes.h:1199
Alias * alias
Definition: parsenodes.h:1198
RTEKind rtekind
Definition: parsenodes.h:1032
AppendRelInfo ** appendrels
Definition: ruleutils.c:169

References AccessShareLock, RangeTblEntry::alias, deparse_namespace::appendrels, deparse_namespace::ctes, RangeTblEntry::eref, RangeTblEntry::inFromCl, RangeTblEntry::inh, RangeTblEntry::lateral, list_make1, makeAlias(), makeNode, NIL, palloc0(), RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::rellockmode, 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 3705 of file ruleutils.c.

3706 {
3707  deparse_namespace *dpns;
3708 
3709  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3710 
3711  /* Initialize fields that stay the same across the whole plan tree */
3712  dpns->rtable = pstmt->rtable;
3713  dpns->rtable_names = rtable_names;
3714  dpns->subplans = pstmt->subplans;
3715  dpns->ctes = NIL;
3716  if (pstmt->appendRelations)
3717  {
3718  /* Set up the array, indexed by child relid */
3719  int ntables = list_length(dpns->rtable);
3720  ListCell *lc;
3721 
3722  dpns->appendrels = (AppendRelInfo **)
3723  palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3724  foreach(lc, pstmt->appendRelations)
3725  {
3726  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3727  Index crelid = appinfo->child_relid;
3728 
3729  Assert(crelid > 0 && crelid <= ntables);
3730  Assert(dpns->appendrels[crelid] == NULL);
3731  dpns->appendrels[crelid] = appinfo;
3732  }
3733  }
3734  else
3735  dpns->appendrels = NULL; /* don't need it */
3736 
3737  /*
3738  * Set up column name aliases. We will get rather bogus results for join
3739  * RTEs, but that doesn't matter because plan trees don't contain any join
3740  * alias Vars.
3741  */
3743 
3744  /* Return a one-deep namespace stack */
3745  return list_make1(dpns);
3746 }
unsigned int Index
Definition: c.h:603
Assert(fmt[strlen(fmt) - 1] !='\n')
#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:2929
List * appendRelations
Definition: plannodes.h:81
List * subplans
Definition: plannodes.h:83
List * rtable
Definition: plannodes.h:73
List * rtable_names
Definition: ruleutils.c:165

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 3600 of file ruleutils.c.

3602 {
3603  return deparse_expression_pretty(expr, dpcontext, forceprefix,
3604  showimplicit, 0, 0);
3605 }
static char * deparse_expression_pretty(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
Definition: ruleutils.c:3627

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 3627 of file ruleutils.c.

3630 {
3632  deparse_context context;
3633 
3634  initStringInfo(&buf);
3635  context.buf = &buf;
3636  context.namespaces = dpcontext;
3637  context.windowClause = NIL;
3638  context.windowTList = NIL;
3639  context.varprefix = forceprefix;
3640  context.prettyFlags = prettyFlags;
3641  context.wrapColumn = WRAP_COLUMN_DEFAULT;
3642  context.indentLevel = startIndent;
3643  context.special_exprkind = EXPR_KIND_NONE;
3644  context.appendparents = NULL;
3645 
3646  get_rule_expr(expr, &context, showimplicit);
3647 
3648  return buf.data;
3649 }
@ EXPR_KIND_NONE
Definition: parse_node.h:40
#define WRAP_COLUMN_DEFAULT
Definition: ruleutils.c:100
static void get_rule_expr(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:8604
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
List * namespaces
Definition: ruleutils.c:117
List * windowClause
Definition: ruleutils.c:118
List * windowTList
Definition: ruleutils.c:119
Bitmapset * appendparents
Definition: ruleutils.c:126
ParseExprKind special_exprkind
Definition: ruleutils.c:124

References deparse_context::appendparents, deparse_context::buf, buf, EXPR_KIND_NONE, get_rule_expr(), deparse_context::indentLevel, initStringInfo(), deparse_context::namespaces, NIL, deparse_context::prettyFlags, deparse_context::special_exprkind, deparse_context::varprefix, deparse_context::windowClause, deparse_context::windowTList, WRAP_COLUMN_DEFAULT, and deparse_context::wrapColumn.

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 4857 of file ruleutils.c.

4858 {
4859  if (n > colinfo->num_cols)
4860  {
4861  if (colinfo->colnames == NULL)
4862  colinfo->colnames = palloc0_array(char *, n);
4863  else
4864  colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4865  colinfo->num_cols = n;
4866  }
4867 }
#define palloc0_array(type, count)
Definition: fe_memutils.h:65
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:110

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_referent()

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

Definition at line 8024 of file ruleutils.c.

8026 {
8027  /* Initialize output parameters to prevent compiler warnings */
8028  *dpns_p = NULL;
8029  *ancestor_cell_p = NULL;
8030 
8031  /*
8032  * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
8033  * SubPlan argument. This will necessarily be in some ancestor of the
8034  * current expression's Plan node.
8035  */
8036  if (param->paramkind == PARAM_EXEC)
8037  {
8038  deparse_namespace *dpns;
8039  Plan *child_plan;
8040  ListCell *lc;
8041 
8042  dpns = (deparse_namespace *) linitial(context->namespaces);
8043  child_plan = dpns->plan;
8044 
8045  foreach(lc, dpns->ancestors)
8046  {
8047  Node *ancestor = (Node *) lfirst(lc);
8048  ListCell *lc2;
8049 
8050  /*
8051  * NestLoops transmit params to their inner child only.
8052  */
8053  if (IsA(ancestor, NestLoop) &&
8054  child_plan == innerPlan(ancestor))
8055  {
8056  NestLoop *nl = (NestLoop *) ancestor;
8057 
8058  foreach(lc2, nl->nestParams)
8059  {
8060  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
8061 
8062  if (nlp->paramno == param->paramid)
8063  {
8064  /* Found a match, so return it */
8065  *dpns_p = dpns;
8066  *ancestor_cell_p = lc;
8067  return (Node *) nlp->paramval;
8068  }
8069  }
8070  }
8071 
8072  /*
8073  * If ancestor is a SubPlan, check the arguments it provides.
8074  */
8075  if (IsA(ancestor, SubPlan))
8076  {
8077  SubPlan *subplan = (SubPlan *) ancestor;
8078  ListCell *lc3;
8079  ListCell *lc4;
8080 
8081  forboth(lc3, subplan->parParam, lc4, subplan->args)
8082  {
8083  int paramid = lfirst_int(lc3);
8084  Node *arg = (Node *) lfirst(lc4);
8085 
8086  if (paramid == param->paramid)
8087  {
8088  /*
8089  * Found a match, so return it. But, since Vars in
8090  * the arg are to be evaluated in the surrounding
8091  * context, we have to point to the next ancestor item
8092  * that is *not* a SubPlan.
8093  */
8094  ListCell *rest;
8095 
8096  for_each_cell(rest, dpns->ancestors,
8097  lnext(dpns->ancestors, lc))
8098  {
8099  Node *ancestor2 = (Node *) lfirst(rest);
8100 
8101  if (!IsA(ancestor2, SubPlan))
8102  {
8103  *dpns_p = dpns;
8104  *ancestor_cell_p = rest;
8105  return arg;
8106  }
8107  }
8108  elog(ERROR, "SubPlan cannot be outermost ancestor");
8109  }
8110  }
8111 
8112  /* SubPlan isn't a kind of Plan, so skip the rest */
8113  continue;
8114  }
8115 
8116  /*
8117  * We need not consider the ancestor's initPlan list, since
8118  * initplans never have any parParams.
8119  */
8120 
8121  /* No luck, crawl up to next ancestor */
8122  child_plan = (Plan *) ancestor;
8123  }
8124  }
8125 
8126  /* No referent found */
8127  return NULL;
8128 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
void * arg
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
#define lfirst_int(lc)
Definition: pg_list.h:173
#define for_each_cell(cell, lst, initcell)
Definition: pg_list.h:438
#define linitial(l)
Definition: pg_list.h:178
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define innerPlan(node)
Definition: plannodes.h:182
@ PARAM_EXEC
Definition: primnodes.h:346
Var * paramval
Definition: plannodes.h:817
List * nestParams
Definition: plannodes.h:808
Definition: nodes.h:129
int paramid
Definition: primnodes.h:355
ParamKind paramkind
Definition: primnodes.h:354
List * args
Definition: primnodes.h:1018
List * parParam
Definition: primnodes.h:1017

References deparse_namespace::ancestors, arg, SubPlan::args, elog(), ERROR, for_each_cell, forboth, innerPlan, IsA, lfirst, lfirst_int, linitial, lnext(), deparse_context::namespaces, 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 5041 of file ruleutils.c.

5042 {
5043  ListCell *lc;
5044 
5045  foreach(lc, dpns->ancestors)
5046  {
5047  Plan *ancestor = (Plan *) lfirst(lc);
5048 
5049  if (IsA(ancestor, RecursiveUnion) &&
5050  ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5051  return ancestor;
5052  }
5053  elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5054  wtscan->wtParam);
5055  return NULL;
5056 }

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 12577 of file ruleutils.c.

12578 {
12579  char *result = NULL;
12580  HeapTuple tuple;
12581  Datum reloptions;
12582  bool isnull;
12583 
12584  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12585  if (!HeapTupleIsValid(tuple))
12586  elog(ERROR, "cache lookup failed for relation %u", relid);
12587 
12588  reloptions = SysCacheGetAttr(RELOID, tuple,
12589  Anum_pg_class_reloptions, &isnull);
12590  if (!isnull)
12591  {
12593 
12594  initStringInfo(&buf);
12595  get_reloptions(&buf, reloptions);
12596 
12597  result = buf.data;
12598  }
12599 
12600  ReleaseSysCache(tuple);
12601 
12602  return result;
12603 }
static void get_reloptions(StringInfo buf, Datum reloptions)
Definition: ruleutils.c:12522
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1081
@ RELOID
Definition: syscache.h:89

References buf, elog(), ERROR, get_reloptions(), HeapTupleIsValid, initStringInfo(), ObjectIdGetDatum(), ReleaseSysCache(), RELOID, 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 12477 of file ruleutils.c.

12478 {
12479  HeapTuple tp;
12480  Form_pg_collation colltup;
12481  char *collname;
12482  char *nspname;
12483  char *result;
12484 
12486  if (!HeapTupleIsValid(tp))
12487  elog(ERROR, "cache lookup failed for collation %u", collid);
12488  colltup = (Form_pg_collation) GETSTRUCT(tp);
12489  collname = NameStr(colltup->collname);
12490 
12491  if (!CollationIsVisible(collid))
12492  nspname = get_namespace_name_or_temp(colltup->collnamespace);
12493  else
12494  nspname = NULL;
12495 
12496  result = quote_qualified_identifier(nspname, collname);
12497 
12498  ReleaseSysCache(tp);
12499 
12500  return result;
12501 }
Oid collid
bool CollationIsVisible(Oid collid)
Definition: namespace.c:2073
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:58
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:12049
@ COLLOID
Definition: syscache.h:50

References CollationIsVisible(), collid, COLLOID, 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 12191 of file ruleutils.c.

12194 {
12195  char *result;
12196  HeapTuple proctup;
12197  Form_pg_proc procform;
12198  char *proname;
12199  bool use_variadic;
12200  char *nspname;
12201  FuncDetailCode p_result;
12202  Oid p_funcid;
12203  Oid p_rettype;
12204  bool p_retset;
12205  int p_nvargs;
12206  Oid p_vatype;
12207  Oid *p_true_typeids;
12208  bool force_qualify = false;
12209 
12210  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
12211  if (!HeapTupleIsValid(proctup))
12212  elog(ERROR, "cache lookup failed for function %u", funcid);
12213  procform = (Form_pg_proc) GETSTRUCT(proctup);
12214  proname = NameStr(procform->proname);
12215 
12216  /*
12217  * Due to parser hacks to avoid needing to reserve CUBE, we need to force
12218  * qualification in some special cases.
12219  */
12220  if (special_exprkind == EXPR_KIND_GROUP_BY)
12221  {
12222  if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
12223  force_qualify = true;
12224  }
12225 
12226  /*
12227  * Determine whether VARIADIC should be printed. We must do this first
12228  * since it affects the lookup rules in func_get_detail().
12229  *
12230  * We always print VARIADIC if the function has a merged variadic-array
12231  * argument. Note that this is always the case for functions taking a
12232  * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
12233  * and printed the array elements as separate arguments, the call could
12234  * match a newer non-VARIADIC function.
12235  */
12236  if (use_variadic_p)
12237  {
12238  /* Parser should not have set funcvariadic unless fn is variadic */
12239  Assert(!has_variadic || OidIsValid(procform->provariadic));
12240  use_variadic = has_variadic;
12241  *use_variadic_p = use_variadic;
12242  }
12243  else
12244  {
12245  Assert(!has_variadic);
12246  use_variadic = false;
12247  }
12248 
12249  /*
12250  * The idea here is to schema-qualify only if the parser would fail to
12251  * resolve the correct function given the unqualified func name with the
12252  * specified argtypes and VARIADIC flag. But if we already decided to
12253  * force qualification, then we can skip the lookup and pretend we didn't
12254  * find it.
12255  */
12256  if (!force_qualify)
12258  NIL, argnames, nargs, argtypes,
12259  !use_variadic, true, false,
12260  &p_funcid, &p_rettype,
12261  &p_retset, &p_nvargs, &p_vatype,
12262  &p_true_typeids, NULL);
12263  else
12264  {
12265  p_result = FUNCDETAIL_NOTFOUND;
12266  p_funcid = InvalidOid;
12267  }
12268 
12269  if ((p_result == FUNCDETAIL_NORMAL ||
12270  p_result == FUNCDETAIL_AGGREGATE ||
12271  p_result == FUNCDETAIL_WINDOWFUNC) &&
12272  p_funcid == funcid)
12273  nspname = NULL;
12274  else
12275  nspname = get_namespace_name_or_temp(procform->pronamespace);
12276 
12277  result = quote_qualified_identifier(nspname, proname);
12278 
12279  ReleaseSysCache(proctup);
12280 
12281  return result;
12282 }
#define OidIsValid(objectId)
Definition: c.h:764
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
@ PROCOID
Definition: syscache.h:79
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, PROCOID, 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 11835 of file ruleutils.c.

11836 {
11838 
11839  initStringInfo(&buf);
11840  get_opclass_name(opclass, InvalidOid, &buf);
11841 
11842  return &buf.data[1]; /* get_opclass_name() prepends space */
11843 }
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Definition: ruleutils.c:11797

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 12373 of file ruleutils.c.

12377 {
12378  HeapTuple opertup;
12379  Form_pg_operator operform;
12380  char *oprname;
12381  char *nspname;
12382 
12383  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
12384  if (!HeapTupleIsValid(opertup))
12385  elog(ERROR, "cache lookup failed for operator %u", opoid);
12386  operform = (Form_pg_operator) GETSTRUCT(opertup);
12387  Assert(operform->oprkind == 'b');
12388  oprname = NameStr(operform->oprname);
12389 
12390  nspname = get_namespace_name(operform->oprnamespace);
12391 
12392  appendStringInfoString(buf, leftop);
12393  if (leftoptype != operform->oprleft)
12394  add_cast_to(buf, operform->oprleft);
12395  appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
12396  appendStringInfoString(buf, oprname);
12397  appendStringInfo(buf, ") %s", rightop);
12398  if (rightoptype != operform->oprright)
12399  add_cast_to(buf, operform->oprright);
12400 
12401  ReleaseSysCache(opertup);
12402 }
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3348
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static void add_cast_to(StringInfo buf, Oid typid)
Definition: ruleutils.c:12413
@ OPEROID
Definition: syscache.h:72

References add_cast_to(), appendStringInfo(), appendStringInfoString(), Assert(), buf, elog(), ERROR, get_namespace_name(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), OPEROID, 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 12296 of file ruleutils.c.

12297 {
12299  HeapTuple opertup;
12300  Form_pg_operator operform;
12301  char *oprname;
12302  char *nspname;
12303  Operator p_result;
12304 
12305  initStringInfo(&buf);
12306 
12307  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
12308  if (!HeapTupleIsValid(opertup))
12309  elog(ERROR, "cache lookup failed for operator %u", operid);
12310  operform = (Form_pg_operator) GETSTRUCT(opertup);
12311  oprname = NameStr(operform->oprname);
12312 
12313  /*
12314  * The idea here is to schema-qualify only if the parser would fail to
12315  * resolve the correct operator given the unqualified op name with the
12316  * specified argtypes.
12317  */
12318  switch (operform->oprkind)
12319  {
12320  case 'b':
12321  p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
12322  true, -1);
12323  break;
12324  case 'l':
12325  p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
12326  true, -1);
12327  break;
12328  default:
12329  elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
12330  p_result = NULL; /* keep compiler quiet */
12331  break;
12332  }
12333 
12334  if (p_result != NULL && oprid(p_result) == operid)
12335  nspname = NULL;
12336  else
12337  {
12338  nspname = get_namespace_name_or_temp(operform->oprnamespace);
12339  appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
12340  }
12341 
12342  appendStringInfoString(&buf, oprname);
12343 
12344  if (nspname)
12345  appendStringInfoChar(&buf, ')');
12346 
12347  if (p_result != NULL)
12348  ReleaseSysCache(p_result);
12349 
12350  ReleaseSysCache(opertup);
12351 
12352  return buf.data;
12353 }
Operator left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
Definition: parse_oper.c:530
Oid oprid(Operator op)
Definition: parse_oper.c:250
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:382

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), buf, elog(), ERROR, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, initStringInfo(), left_oper(), list_make1, makeString(), NameStr, ObjectIdGetDatum(), oper(), OPEROID, 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 12149 of file ruleutils.c.

12150 {
12151  HeapTuple tp;
12152  Form_pg_class reltup;
12153  char *relname;
12154  char *nspname;
12155  char *result;
12156 
12157  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12158  if (!HeapTupleIsValid(tp))
12159  elog(ERROR, "cache lookup failed for relation %u", relid);
12160  reltup = (Form_pg_class) GETSTRUCT(tp);
12161  relname = NameStr(reltup->relname);
12162 
12163  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12164  if (!nspname)
12165  elog(ERROR, "cache lookup failed for namespace %u",
12166  reltup->relnamespace);
12167 
12168  result = quote_qualified_identifier(nspname, relname);
12169 
12170  ReleaseSysCache(tp);
12171 
12172  return result;
12173 }
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, RELOID, 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 12444 of file ruleutils.c.

12445 {
12446  HeapTuple tp;
12447  Form_pg_type typtup;
12448  char *typname;
12449  char *nspname;
12450  char *result;
12451 
12453  if (!HeapTupleIsValid(tp))
12454  elog(ERROR, "cache lookup failed for type %u", typid);
12455  typtup = (Form_pg_type) GETSTRUCT(tp);
12456  typname = NameStr(typtup->typname);
12457 
12458  nspname = get_namespace_name_or_temp(typtup->typnamespace);
12459  if (!nspname)
12460  elog(ERROR, "cache lookup failed for namespace %u",
12461  typtup->typnamespace);
12462 
12463  result = quote_qualified_identifier(nspname, typname);
12464 
12465  ReleaseSysCache(tp);
12466 
12467  return result;
12468 }

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

Referenced by pg_get_constraintdef_worker().

◆ generate_relation_name()

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

Definition at line 12089 of file ruleutils.c.

12090 {
12091  HeapTuple tp;
12092  Form_pg_class reltup;
12093  bool need_qual;
12094  ListCell *nslist;
12095  char *relname;
12096  char *nspname;
12097  char *result;
12098 
12099  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12100  if (!HeapTupleIsValid(tp))
12101  elog(ERROR, "cache lookup failed for relation %u", relid);
12102  reltup = (Form_pg_class) GETSTRUCT(tp);
12103  relname = NameStr(reltup->relname);
12104 
12105  /* Check for conflicting CTE name */
12106  need_qual = false;
12107  foreach(nslist, namespaces)
12108  {
12109  deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
12110  ListCell *ctlist;
12111 
12112  foreach(ctlist, dpns->ctes)
12113  {
12114  CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
12115 
12116  if (strcmp(cte->ctename, relname) == 0)
12117  {
12118  need_qual = true;
12119  break;
12120  }
12121  }
12122  if (need_qual)
12123  break;
12124  }
12125 
12126  /* Otherwise, qualify the name if not visible in search path */
12127  if (!need_qual)
12128  need_qual = !RelationIsVisible(relid);
12129 
12130  if (need_qual)
12131  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12132  else
12133  nspname = NULL;
12134 
12135  result = quote_qualified_identifier(nspname, relname);
12136 
12137  ReleaseSysCache(tp);
12138 
12139  return result;
12140 }
bool RelationIsVisible(Oid relid)
Definition: namespace.c:693

References CommonTableExpr::ctename, deparse_namespace::ctes, elog(), ERROR, get_namespace_name_or_temp(), GETSTRUCT, HeapTupleIsValid, lfirst, NameStr, ObjectIdGetDatum(), quote_qualified_identifier(), RelationIsVisible(), ReleaseSysCache(), relname, RELOID, 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 10207 of file ruleutils.c.

10208 {
10209  Aggref *aggref;
10210  Aggref *original_aggref = callback_arg;
10211 
10212  if (!IsA(node, Aggref))
10213  elog(ERROR, "combining Aggref does not point to an Aggref");
10214 
10215  aggref = (Aggref *) node;
10216  get_agg_expr(aggref, context, original_aggref);
10217 }
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
Definition: ruleutils.c:10069

References 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 10069 of file ruleutils.c.

10071 {
10072  get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10073  false);
10074 }
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:10081

References 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 10081 of file ruleutils.c.

10084 {
10085  StringInfo buf = context->buf;
10086  Oid argtypes[FUNC_MAX_ARGS];
10087  int nargs;
10088  bool use_variadic = false;
10089 
10090  /*
10091  * For a combining aggregate, we look up and deparse the corresponding
10092  * partial aggregate instead. This is necessary because our input
10093  * argument list has been replaced; the new argument list always has just
10094  * one element, which will point to a partial Aggref that supplies us with
10095  * transition states to combine.
10096  */
10097  if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10098  {
10099  TargetEntry *tle;
10100 
10101  Assert(list_length(aggref->args) == 1);
10102  tle = linitial_node(TargetEntry, aggref->args);
10103  resolve_special_varno((Node *) tle->expr, context,
10104  get_agg_combine_expr, original_aggref);
10105  return;
10106  }
10107 
10108  /*
10109  * Mark as PARTIAL, if appropriate. We look to the original aggref so as
10110  * to avoid printing this when recursing from the code just above.
10111  */
10112  if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10113  appendStringInfoString(buf, "PARTIAL ");
10114 
10115  /* Extract the argument types as seen by the parser */
10116  nargs = get_aggregate_argtypes(aggref, argtypes);
10117 
10118  if (!funcname)
10119  funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10120  argtypes, aggref->aggvariadic,
10121  &use_variadic,
10122  context->special_exprkind);
10123 
10124  /* Print the aggregate name, schema-qualified if needed */
10125  appendStringInfo(buf, "%s(%s", funcname,
10126  (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10127 
10128  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10129  {
10130  /*
10131  * Ordered-set aggregates do not use "*" syntax. Also, we needn't
10132  * worry about inserting VARIADIC. So we can just dump the direct
10133  * args as-is.
10134  */
10135  Assert(!aggref->aggvariadic);
10136  get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10137  Assert(aggref->aggorder != NIL);
10138  appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10139  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10140  }
10141  else
10142  {
10143  /* aggstar can be set only in zero-argument aggregates */
10144  if (aggref->aggstar)
10145  appendStringInfoChar(buf, '*');
10146  else
10147  {
10148  ListCell *l;
10149  int i;
10150 
10151  i = 0;
10152  foreach(l, aggref->args)
10153  {
10154  TargetEntry *tle = (TargetEntry *) lfirst(l);
10155  Node *arg = (Node *) tle->expr;
10156 
10157  Assert(!IsA(arg, NamedArgExpr));
10158  if (tle->resjunk)
10159  continue;
10160  if (i++ > 0)
10161  {
10162  if (is_json_objectagg)
10163  {
10164  /*
10165  * the ABSENT ON NULL and WITH UNIQUE args are printed
10166  * separately, so ignore them here
10167  */
10168  if (i > 2)
10169  break;
10170 
10171  appendStringInfoString(buf, " : ");
10172  }
10173  else
10174  appendStringInfoString(buf, ", ");
10175  }
10176  if (use_variadic && i == nargs)
10177  appendStringInfoString(buf, "VARIADIC ");
10178  get_rule_expr(arg, context, true);
10179  }
10180  }
10181 
10182  if (aggref->aggorder != NIL)
10183  {
10184  appendStringInfoString(buf, " ORDER BY ");
10185  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10186  }
10187  }
10188 
10189  if (options)
10191 
10192  if (aggref->aggfilter != NULL)
10193  {
10194  appendStringInfoString(buf, ") FILTER (WHERE ");
10195  get_rule_expr((Node *) aggref->aggfilter, context, false);
10196  }
10197 
10198  appendStringInfoChar(buf, ')');
10199 }
#define funcname
Definition: indent_codes.h:69
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:396
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:395
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1894
#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:12191
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:10207
static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6411
static void resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
Definition: ruleutils.c:7510
Oid aggfnoid
Definition: primnodes.h:422
List * aggdistinct
Definition: primnodes.h:452
List * aggdirectargs
Definition: primnodes.h:443
List * args
Definition: primnodes.h:446
Expr * aggfilter
Definition: primnodes.h:455
List * aggorder
Definition: primnodes.h:449
Expr * expr
Definition: primnodes.h:1895

References Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggorder, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, Aggref::args, Assert(), deparse_context::buf, buf, 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, resolve_special_varno(), and deparse_context::special_exprkind.

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 5890 of file ruleutils.c.

5892 {
5893  StringInfo buf = context->buf;
5894  RangeTblEntry *values_rte;
5895  char *sep;
5896  ListCell *l;
5897 
5898  if (PRETTY_INDENT(context))
5899  {
5900  context->indentLevel += PRETTYINDENT_STD;
5901  appendStringInfoChar(buf, ' ');
5902  }
5903 
5904  /*
5905  * If the query looks like SELECT * FROM (VALUES ...), then print just the
5906  * VALUES part. This reverses what transformValuesClause() did at parse
5907  * time.
5908  */
5909  values_rte = get_simple_values_rte(query, resultDesc);
5910  if (values_rte)
5911  {
5912  get_values_def(values_rte->values_lists, context);
5913  return;
5914  }
5915 
5916  /*
5917  * Build up the query string - first we say SELECT
5918  */
5919  if (query->isReturn)
5920  appendStringInfoString(buf, "RETURN");
5921  else
5922  appendStringInfoString(buf, "SELECT");
5923 
5924  /* Add the DISTINCT clause if given */
5925  if (query->distinctClause != NIL)
5926  {
5927  if (query->hasDistinctOn)
5928  {
5929  appendStringInfoString(buf, " DISTINCT ON (");
5930  sep = "";
5931  foreach(l, query->distinctClause)
5932  {
5933  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5934 
5937  false, context);
5938  sep = ", ";
5939  }
5940  appendStringInfoChar(buf, ')');
5941  }
5942  else
5943  appendStringInfoString(buf, " DISTINCT");
5944  }
5945 
5946  /* Then we tell what to select (the targetlist) */
5947  get_target_list(query->targetList, context, resultDesc, colNamesVisible);
5948 
5949  /* Add the FROM clause if needed */
5950  get_from_clause(query, " FROM ", context);
5951 
5952  /* Add the WHERE clause if given */
5953  if (query->jointree->quals != NULL)
5954  {
5955  appendContextKeyword(context, " WHERE ",
5957  get_rule_expr(query->jointree->quals, context, false);
5958  }
5959 
5960  /* Add the GROUP BY clause if given */
5961  if (query->groupClause != NULL || query->groupingSets != NULL)
5962  {
5963  ParseExprKind save_exprkind;
5964 
5965  appendContextKeyword(context, " GROUP BY ",
5967  if (query->groupDistinct)
5968  appendStringInfoString(buf, "DISTINCT ");
5969 
5970  save_exprkind = context->special_exprkind;
5972 
5973  if (query->groupingSets == NIL)
5974  {
5975  sep = "";
5976  foreach(l, query->groupClause)
5977  {
5978  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
5979 
5982  false, context);
5983  sep = ", ";
5984  }
5985  }
5986  else
5987  {
5988  sep = "";
5989  foreach(l, query->groupingSets)
5990  {
5991  GroupingSet *grp = lfirst(l);
5992 
5994  get_rule_groupingset(grp, query->targetList, true, context);
5995  sep = ", ";
5996  }
5997  }
5998 
5999  context->special_exprkind = save_exprkind;
6000  }
6001 
6002  /* Add the HAVING clause if given */
6003  if (query->havingQual != NULL)
6004  {
6005  appendContextKeyword(context, " HAVING ",
6007  get_rule_expr(query->havingQual, context, false);
6008  }
6009 
6010  /* Add the WINDOW clause if needed */
6011  if (query->windowClause != NIL)
6012  get_rule_windowclause(query, context);
6013 }
ParseExprKind
Definition: parse_node.h:39
static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
Definition: ruleutils.c:8499
static void get_values_def(List *values_lists, deparse_context *context)
Definition: ruleutils.c:5507
static void get_from_clause(Query *query, const char *prefix, deparse_context *context)
Definition: ruleutils.c:11206
static void get_target_list(List *targetList, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6024
static void get_rule_groupingset(GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context)
Definition: ruleutils.c:6351
static Node * get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6294
static void get_rule_windowclause(Query *query, deparse_context *context)
Definition: ruleutils.c:6469
static RangeTblEntry * get_simple_values_rte(Query *query, TupleDesc resultDesc)
Definition: ruleutils.c:5821
Node * quals
Definition: primnodes.h:2014
bool groupDistinct
Definition: parsenodes.h:198
FromExpr * jointree
Definition: parsenodes.h:181
List * groupClause
Definition: parsenodes.h:197
Node * havingQual
Definition: parsenodes.h:202
List * windowClause
Definition: parsenodes.h:204
List * targetList
Definition: parsenodes.h:188
List * groupingSets
Definition: parsenodes.h:200
List * distinctClause
Definition: parsenodes.h:206
List * values_lists
Definition: parsenodes.h:1158
Index tleSortGroupRef
Definition: parsenodes.h:1392

References appendContextKeyword(), appendStringInfoChar(), appendStringInfoString(), deparse_context::buf, buf, 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, deparse_context::indentLevel, Query::jointree, lfirst, NIL, PRETTY_INDENT, PRETTYINDENT_STD, FromExpr::quals, deparse_context::special_exprkind, 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 10569 of file ruleutils.c.

10572 {
10573  StringInfo buf = context->buf;
10574 
10575  /*
10576  * Since parse_coerce.c doesn't immediately collapse application of
10577  * length-coercion functions to constants, what we'll typically see in
10578  * such cases is a Const with typmod -1 and a length-coercion function
10579  * right above it. Avoid generating redundant output. However, beware of
10580  * suppressing casts when the user actually wrote something like
10581  * 'foo'::text::char(3).
10582  *
10583  * Note: it might seem that we are missing the possibility of needing to
10584  * print a COLLATE clause for such a Const. However, a Const could only
10585  * have nondefault collation in a post-constant-folding tree, in which the
10586  * length coercion would have been folded too. See also the special
10587  * handling of CollateExpr in coerce_to_target_type(): any collation
10588  * marking will be above the coercion node, not below it.
10589  */
10590  if (arg && IsA(arg, Const) &&
10591  ((Const *) arg)->consttype == resulttype &&
10592  ((Const *) arg)->consttypmod == -1)
10593  {
10594  /* Show the constant without normal ::typename decoration */
10595  get_const_expr((Const *) arg, context, -1);
10596  }
10597  else
10598  {
10599  if (!PRETTY_PAREN(context))
10600  appendStringInfoChar(buf, '(');
10601  get_rule_expr_paren(arg, context, false, parentNode);
10602  if (!PRETTY_PAREN(context))
10603  appendStringInfoChar(buf, ')');
10604  }
10605 
10606  /*
10607  * Never emit resulttype(arg) functional notation. A pg_proc entry could
10608  * take precedence, and a resulttype in pg_temp would require schema
10609  * qualification that format_type_with_typemod() would usually omit. We've
10610  * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
10611  * would work fine.
10612  */
10613  appendStringInfo(buf, "::%s",
10614  format_type_with_typemod(resulttype, resulttypmod));
10615 }
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:8572
#define PRETTY_PAREN(context)
Definition: ruleutils.c:103
static void get_const_expr(Const *constval, deparse_context *context, int showtype)
Definition: ruleutils.c:10633

References appendStringInfo(), appendStringInfoChar(), arg, deparse_context::buf, buf, 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 11662 of file ruleutils.c.

11663 {
11664  StringInfo buf = context->buf;
11665  int i;
11666  bool first = true;
11667 
11668  /* Don't print aliases if not needed */
11669  if (!colinfo->printaliases)
11670  return;
11671 
11672  for (i = 0; i < colinfo->num_new_cols; i++)
11673  {
11674  char *colname = colinfo->new_colnames[i];
11675 
11676  if (first)
11677  {
11678  appendStringInfoChar(buf, '(');
11679  first = false;
11680  }
11681  else
11682  appendStringInfoString(buf, ", ");
11684  }
11685  if (!first)
11686  appendStringInfoChar(buf, ')');
11687 }

References appendStringInfoChar(), appendStringInfoString(), deparse_context::buf, buf, 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 10763 of file ruleutils.c.

10764 {
10765  StringInfo buf = context->buf;
10766 
10767  if (OidIsValid(constval->constcollid))
10768  {
10769  Oid typcollation = get_typcollation(constval->consttype);
10770 
10771  if (constval->constcollid != typcollation)
10772  {
10773  appendStringInfo(buf, " COLLATE %s",
10774  generate_collation_name(constval->constcollid));
10775  }
10776  }
10777 }
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3038
char * generate_collation_name(Oid collid)
Definition: ruleutils.c:12477
Oid consttype
Definition: primnodes.h:290

References appendStringInfo(), deparse_context::buf, buf, Const::consttype, 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 10633 of file ruleutils.c.

10634 {
10635  StringInfo buf = context->buf;
10636  Oid typoutput;
10637  bool typIsVarlena;
10638  char *extval;
10639  bool needlabel = false;
10640 
10641  if (constval->constisnull)
10642  {
10643  /*
10644  * Always label the type of a NULL constant to prevent misdecisions
10645  * about type when reparsing.
10646  */
10647  appendStringInfoString(buf, "NULL");
10648  if (showtype >= 0)
10649  {
10650  appendStringInfo(buf, "::%s",
10652  constval->consttypmod));
10653  get_const_collation(constval, context);
10654  }
10655  return;
10656  }
10657 
10658  getTypeOutputInfo(constval->consttype,
10659  &typoutput, &typIsVarlena);
10660 
10661  extval = OidOutputFunctionCall(typoutput, constval->constvalue);
10662 
10663  switch (constval->consttype)
10664  {
10665  case INT4OID:
10666 
10667  /*
10668  * INT4 can be printed without any decoration, unless it is
10669  * negative; in that case print it as '-nnn'::integer to ensure
10670  * that the output will re-parse as a constant, not as a constant
10671  * plus operator. In most cases we could get away with printing
10672  * (-nnn) instead, because of the way that gram.y handles negative
10673  * literals; but that doesn't work for INT_MIN, and it doesn't
10674  * seem that much prettier anyway.
10675  */
10676  if (extval[0] != '-')
10677  appendStringInfoString(buf, extval);
10678  else
10679  {
10680  appendStringInfo(buf, "'%s'", extval);
10681  needlabel = true; /* we must attach a cast */
10682  }
10683  break;
10684 
10685  case NUMERICOID:
10686 
10687  /*
10688  * NUMERIC can be printed without quotes if it looks like a float
10689  * constant (not an integer, and not Infinity or NaN) and doesn't
10690  * have a leading sign (for the same reason as for INT4).
10691  */
10692  if (isdigit((unsigned char) extval[0]) &&
10693  strcspn(extval, "eE.") != strlen(extval))
10694  {
10695  appendStringInfoString(buf, extval);
10696  }
10697  else
10698  {
10699  appendStringInfo(buf, "'%s'", extval);
10700  needlabel = true; /* we must attach a cast */
10701  }
10702  break;
10703 
10704  case BOOLOID:
10705  if (strcmp(extval, "t") == 0)
10706  appendStringInfoString(buf, "true");
10707  else
10708  appendStringInfoString(buf, "false");
10709  break;
10710 
10711  default:
10712  simple_quote_literal(buf, extval);
10713  break;
10714  }
10715 
10716  pfree(extval);
10717 
10718  if (showtype < 0)
10719  return;
10720 
10721  /*
10722  * For showtype == 0, append ::typename unless the constant will be
10723  * implicitly typed as the right type when it is read in.
10724  *
10725  * XXX this code has to be kept in sync with the behavior of the parser,
10726  * especially make_const.
10727  */
10728  switch (constval->consttype)
10729  {
10730  case BOOLOID:
10731  case UNKNOWNOID:
10732  /* These types can be left unlabeled */
10733  needlabel = false;
10734  break;
10735  case INT4OID:
10736  /* We determined above whether a label is needed */
10737  break;
10738  case NUMERICOID:
10739 
10740  /*
10741  * Float-looking constants will be typed as numeric, which we
10742  * checked above; but if there's a nondefault typmod we need to
10743  * show it.
10744  */
10745  needlabel |= (constval->consttypmod >= 0);
10746  break;
10747  default:
10748  needlabel = true;
10749  break;
10750  }
10751  if (needlabel || showtype > 0)
10752  appendStringInfo(buf, "::%s",
10754  constval->consttypmod));
10755 
10756  get_const_collation(constval, context);
10757 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1746
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2889
void pfree(void *pointer)
Definition: mcxt.c:1456
static void simple_quote_literal(StringInfo buf, const char *val)
Definition: ruleutils.c:10949
static void get_const_collation(Const *constval, deparse_context *context)
Definition: ruleutils.c:10763

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

Referenced by get_coercion_expr(), 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 7036 of file ruleutils.c.

7038 {
7039  StringInfo buf = context->buf;
7040  RangeTblEntry *rte;
7041 
7042  /* Insert the WITH clause if given */
7043  get_with_clause(query, context);
7044 
7045  /*
7046  * Start the query with DELETE FROM relname
7047  */
7048  rte = rt_fetch(query->resultRelation, query->rtable);
7049  Assert(rte->rtekind == RTE_RELATION);
7050  if (PRETTY_INDENT(context))
7051  {
7052  appendStringInfoChar(buf, ' ');
7053  context->indentLevel += PRETTYINDENT_STD;
7054  }
7055  appendStringInfo(buf, "DELETE FROM %s%s",
7056  only_marker(rte),
7058 
7059  /* Print the relation alias, if needed */
7060  get_rte_alias(rte, query->resultRelation, false, context);
7061 
7062  /* Add the USING clause if given */
7063  get_from_clause(query, " USING ", context);
7064 
7065  /* Add a WHERE clause if given */
7066  if (query->jointree->quals != NULL)
7067  {
7068  appendContextKeyword(context, " WHERE ",
7070  get_rule_expr(query->jointree->quals, context, false);
7071  }
7072 
7073  /* Add RETURNING if present */
7074  if (query->returningList)
7075  {
7076  appendContextKeyword(context, " RETURNING",
7078  get_target_list(query->returningList, context, NULL, colNamesVisible);
7079  }
7080 }
#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:11591
#define only_marker(rte)
Definition: ruleutils.c:522
static void get_with_clause(Query *query, deparse_context *context)
Definition: ruleutils.c:5550
static char * generate_relation_name(Oid relid, List *namespaces)
Definition: ruleutils.c:12089
List * returningList
Definition: parsenodes.h:195
List * rtable
Definition: parsenodes.h:174

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), Assert(), deparse_context::buf, buf, generate_relation_name(), get_from_clause(), get_rte_alias(), get_rule_expr(), get_target_list(), get_with_clause(), deparse_context::indentLevel, 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 11206 of file ruleutils.c.

11207 {
11208  StringInfo buf = context->buf;
11209  bool first = true;
11210  ListCell *l;
11211 
11212  /*
11213  * We use the query's jointree as a guide to what to print. However, we
11214  * must ignore auto-added RTEs that are marked not inFromCl. (These can
11215  * only appear at the top level of the jointree, so it's sufficient to
11216  * check here.) This check also ensures we ignore the rule pseudo-RTEs
11217  * for NEW and OLD.
11218  */
11219  foreach(l, query->jointree->fromlist)
11220  {
11221  Node *jtnode = (Node *) lfirst(l);
11222 
11223  if (IsA(jtnode, RangeTblRef))
11224  {
11225  int varno = ((RangeTblRef *) jtnode)->rtindex;
11226  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11227 
11228  if (!rte->inFromCl)
11229  continue;
11230  }
11231 
11232  if (first)
11233  {
11234  appendContextKeyword(context, prefix,
11236  first = false;
11237 
11238  get_from_clause_item(jtnode, query, context);
11239  }
11240  else
11241  {
11242  StringInfoData itembuf;
11243 
11244  appendStringInfoString(buf, ", ");
11245 
11246  /*
11247  * Put the new FROM item's text into itembuf so we can decide
11248  * after we've got it whether or not it needs to go on a new line.
11249  */
11250  initStringInfo(&itembuf);
11251  context->buf = &itembuf;
11252 
11253  get_from_clause_item(jtnode, query, context);
11254 
11255  /* Restore context's output buffer */
11256  context->buf = buf;
11257 
11258  /* Consider line-wrapping if enabled */
11259  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
11260  {
11261  /* Does the new item start with a new line? */
11262  if (itembuf.len > 0 && itembuf.data[0] == '\n')
11263  {
11264  /* If so, we shouldn't add anything */
11265  /* instead, remove any trailing spaces currently in buf */
11267  }
11268  else
11269  {
11270  char *trailing_nl;
11271 
11272  /* Locate the start of the current line in the buffer */
11273  trailing_nl = strrchr(buf->data, '\n');
11274  if (trailing_nl == NULL)
11275  trailing_nl = buf->data;
11276  else
11277  trailing_nl++;
11278 
11279  /*
11280  * Add a newline, plus some indentation, if the new item
11281  * would cause an overflow.
11282  */
11283  if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
11284  appendContextKeyword(context, "", -PRETTYINDENT_STD,
11287  }
11288  }
11289 
11290  /* Add the new item */
11291  appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
11292 
11293  /* clean up */
11294  pfree(itembuf.data);
11295  }
11296  }
11297 }
#define PRETTYINDENT_VAR
Definition: ruleutils.c:85
static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
Definition: ruleutils.c:11300
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:227
List * fromlist
Definition: primnodes.h:2013

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

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 11702 of file ruleutils.c.

11705 {
11706  StringInfo buf = context->buf;
11707  ListCell *l1;
11708  ListCell *l2;
11709  ListCell *l3;
11710  ListCell *l4;
11711  int i;
11712 
11713  appendStringInfoChar(buf, '(');
11714 
11715  i = 0;
11716  forfour(l1, rtfunc->funccoltypes,
11717  l2, rtfunc->funccoltypmods,
11718  l3, rtfunc->funccolcollations,
11719  l4, rtfunc->funccolnames)
11720  {
11721  Oid atttypid = lfirst_oid(l1);
11722  int32 atttypmod = lfirst_int(l2);
11723  Oid attcollation = lfirst_oid(l3);
11724  char *attname;
11725 
11726  if (colinfo)
11727  attname = colinfo->colnames[i];
11728  else
11729  attname = strVal(lfirst(l4));
11730 
11731  Assert(attname); /* shouldn't be any dropped columns here */
11732 
11733  if (i > 0)
11734  appendStringInfoString(buf, ", ");
11735  appendStringInfo(buf, "%s %s",
11737  format_type_with_typemod(atttypid, atttypmod));
11738  if (OidIsValid(attcollation) &&
11739  attcollation != get_typcollation(atttypid))
11740  appendStringInfo(buf, " COLLATE %s",
11741  generate_collation_name(attcollation));
11742 
11743  i++;
11744  }
11745 
11746  appendStringInfoChar(buf, ')');
11747 }
signed int int32
Definition: c.h:483
NameData attname
Definition: pg_attribute.h:41
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:524
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define strVal(v)
Definition: value.h:82

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), attname, deparse_context::buf, buf, deparse_columns::colnames, 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 11300 of file ruleutils.c.

11301 {
11302  StringInfo buf = context->buf;
11304 
11305  if (IsA(jtnode, RangeTblRef))
11306  {
11307  int varno = ((RangeTblRef *) jtnode)->rtindex;
11308  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11309  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
11310  RangeTblFunction *rtfunc1 = NULL;
11311 
11312  if (rte->lateral)
11313  appendStringInfoString(buf, "LATERAL ");
11314 
11315  /* Print the FROM item proper */
11316  switch (rte->rtekind)
11317  {
11318  case RTE_RELATION:
11319  /* Normal relation RTE */
11320  appendStringInfo(buf, "%s%s",
11321  only_marker(rte),
11323  context->namespaces));
11324  break;
11325  case RTE_SUBQUERY:
11326  /* Subquery RTE */
11327  appendStringInfoChar(buf, '(');
11328  get_query_def(rte->subquery, buf, context->namespaces, NULL,
11329  true,
11330  context->prettyFlags, context->wrapColumn,
11331  context->indentLevel);
11332  appendStringInfoChar(buf, ')');
11333  break;
11334  case RTE_FUNCTION:
11335  /* Function RTE */
11336  rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
11337 
11338  /*
11339  * Omit ROWS FROM() syntax for just one function, unless it
11340  * has both a coldeflist and WITH ORDINALITY. If it has both,
11341  * we must use ROWS FROM() syntax to avoid ambiguity about
11342  * whether the coldeflist includes the ordinality column.
11343  */
11344  if (list_length(rte->functions) == 1 &&
11345  (rtfunc1->funccolnames == NIL || !rte->funcordinality))
11346  {
11347  get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
11348  /* we'll print the coldeflist below, if it has one */
11349  }
11350  else
11351  {
11352  bool all_unnest;
11353  ListCell *lc;
11354 
11355  /*
11356  * If all the function calls in the list are to unnest,
11357  * and none need a coldeflist, then collapse the list back
11358  * down to UNNEST(args). (If we had more than one
11359  * built-in unnest function, this would get more
11360  * difficult.)
11361  *
11362  * XXX This is pretty ugly, since it makes not-terribly-
11363  * future-proof assumptions about what the parser would do
11364  * with the output; but the alternative is to emit our
11365  * nonstandard ROWS FROM() notation for what might have
11366  * been a perfectly spec-compliant multi-argument
11367  * UNNEST().
11368  */
11369  all_unnest = true;
11370  foreach(lc, rte->functions)
11371  {
11372  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11373 
11374  if (!IsA(rtfunc->funcexpr, FuncExpr) ||
11375  ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
11376  rtfunc->funccolnames != NIL)
11377  {
11378  all_unnest = false;
11379  break;
11380  }
11381  }
11382 
11383  if (all_unnest)
11384  {
11385  List *allargs = NIL;
11386 
11387  foreach(lc, rte->functions)
11388  {
11389  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11390  List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
11391 
11392  allargs = list_concat(allargs, args);
11393  }
11394 
11395  appendStringInfoString(buf, "UNNEST(");
11396  get_rule_expr((Node *) allargs, context, true);
11397  appendStringInfoChar(buf, ')');
11398  }
11399  else
11400  {
11401  int funcno = 0;
11402 
11403  appendStringInfoString(buf, "ROWS FROM(");
11404  foreach(lc, rte->functions)
11405  {
11406  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11407 
11408  if (funcno > 0)
11409  appendStringInfoString(buf, ", ");
11410  get_rule_expr_funccall(rtfunc->funcexpr, context, true);
11411  if (rtfunc->funccolnames != NIL)
11412  {
11413  /* Reconstruct the column definition list */
11414  appendStringInfoString(buf, " AS ");
11416  NULL,
11417  context);
11418  }
11419  funcno++;
11420  }
11421  appendStringInfoChar(buf, ')');
11422  }
11423  /* prevent printing duplicate coldeflist below */
11424  rtfunc1 = NULL;
11425  }
11426  if (rte->funcordinality)
11427  appendStringInfoString(buf, " WITH ORDINALITY");
11428  break;
11429  case RTE_TABLEFUNC:
11430  get_tablefunc(rte->tablefunc, context, true);
11431  break;
11432  case RTE_VALUES:
11433  /* Values list RTE */
11434  appendStringInfoChar(buf, '(');
11435  get_values_def(rte->values_lists, context);
11436  appendStringInfoChar(buf, ')');
11437  break;
11438  case RTE_CTE:
11440  break;
11441  default:
11442  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
11443  break;
11444  }
11445 
11446  /* Print the relation alias, if needed */
11447  get_rte_alias(rte, varno, false, context);
11448 
11449  /* Print the column definitions or aliases, if needed */
11450  if (rtfunc1 && rtfunc1->funccolnames != NIL)
11451  {
11452  /* Reconstruct the columndef list, which is also the aliases */
11453  get_from_clause_coldeflist(rtfunc1, colinfo, context);
11454  }
11455  else
11456  {
11457  /* Else print column aliases as needed */
11458  get_column_alias_list(colinfo, context);
11459  }
11460 
11461  /* Tablesample clause must go after any alias */
11462  if (rte->rtekind == RTE_RELATION && rte->tablesample)
11463  get_tablesample_def(rte->tablesample, context);
11464  }
11465  else if (IsA(jtnode, JoinExpr))
11466  {
11467  JoinExpr *j = (JoinExpr *) jtnode;
11468  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
11469  bool need_paren_on_right;
11470 
11471  need_paren_on_right = PRETTY_PAREN(context) &&
11472  !IsA(j->rarg, RangeTblRef) &&
11473  !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
11474 
11475  if (!PRETTY_PAREN(context) || j->alias != NULL)
11476  appendStringInfoChar(buf, '(');
11477 
11478  get_from_clause_item(j->larg, query, context);
11479 
11480  switch (j->jointype)
11481  {
11482  case JOIN_INNER:
11483  if (j->quals)
11484  appendContextKeyword(context, " JOIN ",
11488  else
11489  appendContextKeyword(context, " CROSS JOIN ",
11493  break;
11494  case JOIN_LEFT:
11495  appendContextKeyword(context, " LEFT JOIN ",
11499  break;
11500  case JOIN_FULL:
11501  appendContextKeyword(context, " FULL JOIN ",
11505  break;
11506  case JOIN_RIGHT:
11507  appendContextKeyword(context, " RIGHT JOIN ",
11511  break;
11512  default:
11513  elog(ERROR, "unrecognized join type: %d",
11514  (int) j->jointype);
11515  }
11516 
11517  if (need_paren_on_right)
11518  appendStringInfoChar(buf, '(');
11519  get_from_clause_item(j->rarg, query, context);
11520  if (need_paren_on_right)
11521  appendStringInfoChar(buf, ')');
11522 
11523  if (j->usingClause)
11524  {
11525  ListCell *lc;
11526  bool first = true;
11527 
11528  appendStringInfoString(buf, " USING (");
11529  /* Use the assigned names, not what's in usingClause */
11530  foreach(lc, colinfo->usingNames)
11531  {
11532  char *colname = (char *) lfirst(lc);
11533 
11534  if (first)
11535  first = false;
11536  else
11537  appendStringInfoString(buf, ", ");
11539  }
11540  appendStringInfoChar(buf, ')');
11541 
11542  if (j->join_using_alias)
11543  appendStringInfo(buf, " AS %s",
11544  quote_identifier(j->join_using_alias->aliasname));
11545  }
11546  else if (j->quals)
11547  {
11548  appendStringInfoString(buf, " ON ");
11549  if (!PRETTY_PAREN(context))
11550  appendStringInfoChar(buf, '(');
11551  get_rule_expr(j->quals, context, false);
11552  if (!PRETTY_PAREN(context))
11553  appendStringInfoChar(buf, ')');
11554  }
11555  else if (j->jointype != JOIN_INNER)
11556  {
11557  /* If we didn't say CROSS JOIN above, we must provide an ON */
11558  appendStringInfoString(buf, " ON TRUE");
11559  }
11560 
11561  if (!PRETTY_PAREN(context) || j->alias != NULL)
11562  appendStringInfoChar(buf, ')');
11563 
11564  /* Yes, it's correct to put alias after the right paren ... */
11565  if (j->alias != NULL)
11566  {
11567  /*
11568  * Note that it's correct to emit an alias clause if and only if
11569  * there was one originally. Otherwise we'd be converting a named
11570  * join to unnamed or vice versa, which creates semantic
11571  * subtleties we don't want. However, we might print a different
11572  * alias name than was there originally.
11573  */
11574  appendStringInfo(buf, " %s",
11576  context)));
11577  get_column_alias_list(colinfo, context);
11578  }
11579  }
11580  else
11581  elog(ERROR, "unrecognized node type: %d",
11582  (int) nodeTag(jtnode));
11583 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ JOIN_FULL
Definition: nodes.h:306
@ JOIN_INNER
Definition: nodes.h:304
@ JOIN_RIGHT
Definition: nodes.h:307
@ JOIN_LEFT
Definition: nodes.h:305
@ RTE_CTE
Definition: parsenodes.h:1019
@ RTE_VALUES
Definition: parsenodes.h:1018
@ RTE_SUBQUERY
Definition: parsenodes.h:1014
@ RTE_FUNCTION
Definition: parsenodes.h:1016
@ RTE_TABLEFUNC
Definition: parsenodes.h:1017
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition: ruleutils.c:4944
#define PRETTYINDENT_JOIN
Definition: ruleutils.c:84
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
Definition: ruleutils.c:5429
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Definition: ruleutils.c:11753
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:11662
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:11702
static void get_rule_expr_funccall(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:9882
#define deparse_columns_fetch(rangetable_index, dpns)
Definition: ruleutils.c:297
static void get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11101
Definition: pg_list.h:54
char * ctename
Definition: parsenodes.h:1163
TableFunc * tablefunc
Definition: parsenodes.h:1153
bool funcordinality
Definition: parsenodes.h:1148
struct TableSampleClause * tablesample
Definition: parsenodes.h:1074
Query * subquery
Definition: parsenodes.h:1080
List * functions
Definition: parsenodes.h:1147
List * usingNames
Definition: ruleutils.c:293

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), generate_unaccent_rules::args, deparse_context::buf, buf, 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(), deparse_context::indentLevel, IsA, j, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, RangeTblEntry::lateral, lfirst, linitial, list_concat(), list_length(), deparse_context::namespaces, NIL, nodeTag, only_marker, PRETTY_PAREN, deparse_context::prettyFlags, 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, RangeTblEntry::values_lists, and deparse_context::wrapColumn.

Referenced by get_from_clause().

◆ get_func_expr()

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

Definition at line 9973 of file ruleutils.c.

9975 {
9976  StringInfo buf = context->buf;
9977  Oid funcoid = expr->funcid;
9978  Oid argtypes[FUNC_MAX_ARGS];
9979  int nargs;
9980  List *argnames;
9981  bool use_variadic;
9982  ListCell *l;
9983 
9984  /*
9985  * If the function call came from an implicit coercion, then just show the
9986  * first argument --- unless caller wants to see implicit coercions.
9987  */
9988  if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
9989  {
9990  get_rule_expr_paren((Node *) linitial(expr->args), context,
9991  false, (Node *) expr);
9992  return;
9993  }
9994 
9995  /*
9996  * If the function call came from a cast, then show the first argument
9997  * plus an explicit cast operation.
9998  */
9999  if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10000  expr->funcformat == COERCE_IMPLICIT_CAST)
10001  {
10002  Node *arg = linitial(expr->args);
10003  Oid rettype = expr->funcresulttype;
10004  int32 coercedTypmod;
10005 
10006  /* Get the typmod if this is a length-coercion function */
10007  (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10008 
10009  get_coercion_expr(arg, context,
10010  rettype, coercedTypmod,
10011  (Node *) expr);
10012 
10013  return;
10014  }
10015 
10016  /*
10017  * If the function was called using one of the SQL spec's random special
10018  * syntaxes, try to reproduce that. If we don't recognize the function,
10019  * fall through.
10020  */
10021  if (expr->funcformat == COERCE_SQL_SYNTAX)
10022  {
10023  if (get_func_sql_syntax(expr, context))
10024  return;
10025  }
10026 
10027  /*
10028  * Normal function: display as proname(args). First we need to extract
10029  * the argument datatypes.
10030  */
10031  if (list_length(expr->args) > FUNC_MAX_ARGS)
10032  ereport(ERROR,
10033  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10034  errmsg("too many arguments")));
10035  nargs = 0;
10036  argnames = NIL;
10037  foreach(l, expr->args)
10038  {
10039  Node *arg = (Node *) lfirst(l);
10040 
10041  if (IsA(arg, NamedArgExpr))
10042  argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10043  argtypes[nargs] = exprType(arg);
10044  nargs++;
10045  }
10046 
10047  appendStringInfo(buf, "%s(",
10048  generate_function_name(funcoid, nargs,
10049  argnames, argtypes,
10050  expr->funcvariadic,
10051  &use_variadic,
10052  context->special_exprkind));
10053  nargs = 0;
10054  foreach(l, expr->args)
10055  {
10056  if (nargs++ > 0)
10057  appendStringInfoString(buf, ", ");
10058  if (use_variadic && lnext(expr->args, l) == NULL)
10059  appendStringInfoString(buf, "VARIADIC ");
10060  get_rule_expr((Node *) lfirst(l), context, true);
10061  }
10062  appendStringInfoChar(buf, ')');
10063 }
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ereport(elevel,...)
Definition: elog.h:149
List * lappend(List *list, void *datum)
Definition: list.c:338
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:522
@ COERCE_SQL_SYNTAX
Definition: primnodes.h:664
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:663
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:662
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Definition: ruleutils.c:10327
static void get_coercion_expr(Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
Definition: ruleutils.c:10569
Oid funcid
Definition: primnodes.h:677
List * args
Definition: primnodes.h:695

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, FuncExpr::args, deparse_context::buf, buf, COERCE_EXPLICIT_CAST, COERCE_IMPLICIT_CAST, COERCE_SQL_SYNTAX, 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(), NIL, and deparse_context::special_exprkind.

Referenced by get_rule_expr().

◆ get_func_sql_syntax()

static bool get_func_sql_syntax ( FuncExpr expr,
deparse_context context 
)
static

Definition at line 10327 of file ruleutils.c.

10328 {
10329  StringInfo buf = context->buf;
10330  Oid funcoid = expr->funcid;
10331 
10332  switch (funcoid)
10333  {
10334  case F_TIMEZONE_INTERVAL_TIMESTAMP:
10335  case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
10336  case F_TIMEZONE_INTERVAL_TIMETZ:
10337  case F_TIMEZONE_TEXT_TIMESTAMP:
10338  case F_TIMEZONE_TEXT_TIMESTAMPTZ:
10339  case F_TIMEZONE_TEXT_TIMETZ:
10340  /* AT TIME ZONE ... note reversed argument order */
10341  appendStringInfoChar(buf, '(');
10342  get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
10343  (Node *) expr);
10344  appendStringInfoString(buf, " AT TIME ZONE ");
10345  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10346  (Node *) expr);
10347  appendStringInfoChar(buf, ')');
10348  return true;
10349 
10350  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
10351  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
10352  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
10353  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
10354  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
10355  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
10356  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
10357  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
10358  case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
10359  case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
10360  case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
10361  case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
10362  case F_OVERLAPS_TIME_TIME_TIME_TIME:
10363  /* (x1, x2) OVERLAPS (y1, y2) */
10364  appendStringInfoString(buf, "((");
10365  get_rule_expr((Node *) linitial(expr->args), context, false);
10366  appendStringInfoString(buf, ", ");
10367  get_rule_expr((Node *) lsecond(expr->args), context, false);
10368  appendStringInfoString(buf, ") OVERLAPS (");
10369  get_rule_expr((Node *) lthird(expr->args), context, false);
10370  appendStringInfoString(buf, ", ");
10371  get_rule_expr((Node *) lfourth(expr->args), context, false);
10372  appendStringInfoString(buf, "))");
10373  return true;
10374 
10375  case F_EXTRACT_TEXT_DATE:
10376  case F_EXTRACT_TEXT_TIME:
10377  case F_EXTRACT_TEXT_TIMETZ:
10378  case F_EXTRACT_TEXT_TIMESTAMP:
10379  case F_EXTRACT_TEXT_TIMESTAMPTZ:
10380  case F_EXTRACT_TEXT_INTERVAL:
10381  /* EXTRACT (x FROM y) */
10382  appendStringInfoString(buf, "EXTRACT(");
10383  {
10384  Const *con = (Const *) linitial(expr->args);
10385 
10386  Assert(IsA(con, Const) &&
10387  con->consttype == TEXTOID &&
10388  !con->constisnull);
10389  appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
10390  }
10391  appendStringInfoString(buf, " FROM ");
10392  get_rule_expr((Node *) lsecond(expr->args), context, false);
10393  appendStringInfoChar(buf, ')');
10394  return true;
10395 
10396  case F_IS_NORMALIZED:
10397  /* IS xxx NORMALIZED */
10399  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10400  (Node *) expr);
10401  appendStringInfoString(buf, " IS");
10402  if (list_length(expr->args) == 2)
10403  {
10404  Const *con = (Const *) lsecond(expr->args);
10405 
10406  Assert(IsA(con, Const) &&
10407  con->consttype == TEXTOID &&
10408  !con->constisnull);
10409  appendStringInfo(buf, " %s",
10410  TextDatumGetCString(con->constvalue));
10411  }
10412  appendStringInfoString(buf, " NORMALIZED)");
10413  return true;
10414 
10415  case F_PG_COLLATION_FOR:
10416  /* COLLATION FOR */
10417  appendStringInfoString(buf, "COLLATION FOR (");
10418  get_rule_expr((Node *) linitial(expr->args), context, false);
10419  appendStringInfoChar(buf, ')');
10420  return true;
10421 
10422  case F_NORMALIZE:
10423  /* NORMALIZE() */
10424  appendStringInfoString(buf, "NORMALIZE(");
10425  get_rule_expr((Node *) linitial(expr->args), context, false);
10426  if (list_length(expr->args) == 2)
10427  {
10428  Const *con = (Const *) lsecond(expr->args);
10429 
10430  Assert(IsA(con, Const) &&
10431  con->consttype == TEXTOID &&
10432  !con->constisnull);
10433  appendStringInfo(buf, ", %s",
10434  TextDatumGetCString(con->constvalue));
10435  }
10436  appendStringInfoChar(buf, ')');
10437  return true;
10438 
10439  case F_OVERLAY_BIT_BIT_INT4:
10440  case F_OVERLAY_BIT_BIT_INT4_INT4:
10441  case F_OVERLAY_BYTEA_BYTEA_INT4:
10442  case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
10443  case F_OVERLAY_TEXT_TEXT_INT4:
10444  case F_OVERLAY_TEXT_TEXT_INT4_INT4:
10445  /* OVERLAY() */
10446  appendStringInfoString(buf, "OVERLAY(");
10447  get_rule_expr((Node *) linitial(expr->args), context, false);
10448  appendStringInfoString(buf, " PLACING ");
10449  get_rule_expr((Node *) lsecond(expr->args), context, false);
10450  appendStringInfoString(buf, " FROM ");
10451  get_rule_expr((Node *) lthird(expr->args), context, false);
10452  if (list_length(expr->args) == 4)
10453  {
10454  appendStringInfoString(buf, " FOR ");
10455  get_rule_expr((Node *) lfourth(expr->args), context, false);
10456  }
10457  appendStringInfoChar(buf, ')');
10458  return true;
10459 
10460  case F_POSITION_BIT_BIT:
10461  case F_POSITION_BYTEA_BYTEA:
10462  case F_POSITION_TEXT_TEXT:
10463  /* POSITION() ... extra parens since args are b_expr not a_expr */
10464  appendStringInfoString(buf, "POSITION((");
10465  get_rule_expr((Node *) lsecond(expr->args), context, false);
10466  appendStringInfoString(buf, ") IN (");
10467  get_rule_expr((Node *) linitial(expr->args), context, false);
10468  appendStringInfoString(buf, "))");
10469  return true;
10470 
10471  case F_SUBSTRING_BIT_INT4:
10472  case F_SUBSTRING_BIT_INT4_INT4:
10473  case F_SUBSTRING_BYTEA_INT4:
10474  case F_SUBSTRING_BYTEA_INT4_INT4:
10475  case F_SUBSTRING_TEXT_INT4:
10476  case F_SUBSTRING_TEXT_INT4_INT4:
10477  /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
10478  appendStringInfoString(buf, "SUBSTRING(");
10479  get_rule_expr((Node *) linitial(expr->args), context, false);
10480  appendStringInfoString(buf, " FROM ");
10481  get_rule_expr((Node *) lsecond(expr->args), context, false);
10482  if (list_length(expr->args) == 3)
10483  {
10484  appendStringInfoString(buf, " FOR ");
10485  get_rule_expr((Node *) lthird(expr->args), context, false);
10486  }
10487  appendStringInfoChar(buf, ')');
10488  return true;
10489 
10490  case F_SUBSTRING_TEXT_TEXT_TEXT:
10491  /* SUBSTRING SIMILAR/ESCAPE */
10492  appendStringInfoString(buf, "SUBSTRING(");
10493  get_rule_expr((Node *) linitial(expr->args), context, false);
10494  appendStringInfoString(buf, " SIMILAR ");
10495  get_rule_expr((Node *) lsecond(expr->args), context, false);
10496  appendStringInfoString(buf, " ESCAPE ");
10497  get_rule_expr((Node *) lthird(expr->args), context, false);
10498  appendStringInfoChar(buf, ')');
10499  return true;
10500 
10501  case F_BTRIM_BYTEA_BYTEA:
10502  case F_BTRIM_TEXT:
10503  case F_BTRIM_TEXT_TEXT:
10504  /* TRIM() */
10505  appendStringInfoString(buf, "TRIM(BOTH");
10506  if (list_length(expr->args) == 2)
10507  {
10508  appendStringInfoChar(buf, ' ');
10509  get_rule_expr((Node *) lsecond(expr->args), context, false);
10510  }
10511  appendStringInfoString(buf, " FROM ");
10512  get_rule_expr((Node *) linitial(expr->args), context, false);
10513  appendStringInfoChar(buf, ')');
10514  return true;
10515 
10516  case F_LTRIM_BYTEA_BYTEA:
10517  case F_LTRIM_TEXT:
10518  case F_LTRIM_TEXT_TEXT:
10519  /* TRIM() */
10520  appendStringInfoString(buf, "TRIM(LEADING");
10521  if (list_length(expr->args) == 2)
10522  {
10523  appendStringInfoChar(buf, ' ');
10524  get_rule_expr((Node *) lsecond(expr->args), context, false);
10525  }
10526  appendStringInfoString(buf, " FROM ");
10527  get_rule_expr((Node *) linitial(expr->args), context, false);
10528  appendStringInfoChar(buf, ')');
10529  return true;
10530 
10531  case F_RTRIM_BYTEA_BYTEA:
10532  case F_RTRIM_TEXT:
10533  case F_RTRIM_TEXT_TEXT:
10534  /* TRIM() */
10535  appendStringInfoString(buf, "TRIM(TRAILING");
10536  if (list_length(expr->args) == 2)
10537  {
10538  appendStringInfoChar(buf, ' ');
10539  get_rule_expr((Node *) lsecond(expr->args), context, false);
10540  }
10541  appendStringInfoString(buf, " FROM ");
10542  get_rule_expr((Node *) linitial(expr->args), context, false);
10543  appendStringInfoChar(buf, ')');
10544  return true;
10545 
10546  case F_SYSTEM_USER:
10547  appendStringInfoString(buf, "SYSTEM_USER");
10548  return true;
10549 
10550  case F_XMLEXISTS:
10551  /* XMLEXISTS ... extra parens because args are c_expr */
10552  appendStringInfoString(buf, "XMLEXISTS((");
10553  get_rule_expr((Node *) linitial(expr->args), context, false);
10554  appendStringInfoString(buf, ") PASSING (");
10555  get_rule_expr((Node *) lsecond(expr->args), context, false);
10556  appendStringInfoString(buf, "))");
10557  return true;
10558  }
10559  return false;
10560 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
#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(), deparse_context::buf, buf, Const::consttype, 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 6610 of file ruleutils.c.

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

References OnConflictExpr::action, appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), OnConflictExpr::arbiterElems, OnConflictExpr::arbiterWhere, Assert(), deparse_context::buf, buf, OnConflictExpr::constraint, 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(), deparse_context::indentLevel, lappend(), lfirst, deparse_context::namespaces, NIL, OidIsValid, Query::onConflict, ONCONFLICT_NOTHING, OnConflictExpr::onConflictSet, OnConflictExpr::onConflictWhere, OVERRIDING_SYSTEM_VALUE, OVERRIDING_USER_VALUE, PRETTY_INDENT, deparse_context::prettyFlags, 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, RangeTblEntry::values_lists, deparse_context::varprefix, and deparse_context::wrapColumn.

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 10924 of file ruleutils.c.

10926 {
10928 
10931 
10932  if (IsA(ctor->func, Aggref))
10933  get_agg_expr_helper((Aggref *) ctor->func, context,
10934  (Aggref *) ctor->func,
10935  funcname, options.data, is_json_objectagg);
10936  else if (IsA(ctor->func, WindowFunc))
10937  get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
10938  funcname, options.data,
10939  is_json_objectagg);
10940  else
10941  elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
10942  nodeTag(ctor->func));
10943 }
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:10234
static void get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
Definition: ruleutils.c:10894

References 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_constructor()

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

Definition at line 10828 of file ruleutils.c.

10830 {
10831  StringInfo buf = context->buf;
10832  const char *funcname;
10833  bool is_json_object;
10834  int curridx;
10835  ListCell *lc;
10836 
10837  if (ctor->type == JSCTOR_JSON_OBJECTAGG)
10838  {
10839  get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
10840  return;
10841  }
10842  else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
10843  {
10844  get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
10845  return;
10846  }
10847 
10848  switch (ctor->type)
10849  {
10850  case JSCTOR_JSON_OBJECT:
10851  funcname = "JSON_OBJECT";
10852  break;
10853  case JSCTOR_JSON_ARRAY:
10854  funcname = "JSON_ARRAY";
10855  break;
10856  case JSCTOR_JSON_PARSE:
10857  funcname = "JSON";
10858  break;
10859  case JSCTOR_JSON_SCALAR:
10860  funcname = "JSON_SCALAR";
10861  break;
10862  case JSCTOR_JSON_SERIALIZE:
10863  funcname = "JSON_SERIALIZE";
10864  break;
10865  default:
10866  elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
10867  }
10868 
10869  appendStringInfo(buf, "%s(", funcname);
10870 
10871  is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
10872  foreach(lc, ctor->args)
10873  {
10874  curridx = foreach_current_index(lc);
10875  if (curridx > 0)
10876  {
10877  const char *sep;
10878 
10879  sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
10881  }
10882 
10883  get_rule_expr((Node *) lfirst(lc), context, true);
10884  }
10885 
10887  appendStringInfo(buf, ")");
10888 }
#define foreach_current_index(cell)
Definition: pg_list.h:403
@ JSCTOR_JSON_SERIALIZE
Definition: primnodes.h:1619
@ JSCTOR_JSON_ARRAYAGG
Definition: primnodes.h:1616
@ JSCTOR_JSON_PARSE
Definition: primnodes.h:1617
@ JSCTOR_JSON_OBJECT
Definition: primnodes.h:1613
@ JSCTOR_JSON_SCALAR
Definition: primnodes.h:1618
@ JSCTOR_JSON_ARRAY
Definition: primnodes.h:1614
@ JSCTOR_JSON_OBJECTAGG
Definition: primnodes.h:1615
static void get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
Definition: ruleutils.c:10924
JsonConstructorType type
Definition: primnodes.h:1629

References appendStringInfo(), appendStringInfoString(), JsonConstructorExpr::args, deparse_context::buf, buf, 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 10894 of file ruleutils.c.

10895 {
10896  if (ctor->absent_on_null)
10897  {
10898  if (ctor->type == JSCTOR_JSON_OBJECT ||
10899  ctor->type == JSCTOR_JSON_OBJECTAGG)
10900  appendStringInfoString(buf, " ABSENT ON NULL");
10901  }
10902  else
10903  {
10904  if (ctor->type == JSCTOR_JSON_ARRAY ||
10905  ctor->type == JSCTOR_JSON_ARRAYAGG)
10906  appendStringInfoString(buf, " NULL ON NULL");
10907  }
10908 
10909  if (ctor->unique)
10910  appendStringInfoString(buf, " WITH UNIQUE KEYS");
10911 
10912  /*
10913  * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
10914  * support one.
10915  */
10916  if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
10917  get_json_returning(ctor->returning, buf, true);
10918 }
static void get_json_returning(JsonReturning *returning, StringInfo buf, bool json_format_by_default)
Definition: ruleutils.c:10808
JsonReturning * returning
Definition: primnodes.h:1633

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_format()

static void get_json_format ( JsonFormat format,
StringInfo  buf 
)
static

Definition at line 10783 of file ruleutils.c.

10784 {
10785  if (format->format_type == JS_FORMAT_DEFAULT)
10786  return;
10787 
10789  format->format_type == JS_FORMAT_JSONB ?
10790  " FORMAT JSONB" : " FORMAT JSON");
10791 
10792  if (format->encoding != JS_ENC_DEFAULT)
10793  {
10794  const char *encoding;
10795 
10796  encoding =
10797  format->encoding == JS_ENC_UTF16 ? "UTF16" :
10798  format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
10799 
10800  appendStringInfo(buf, " ENCODING %s", encoding);
10801  }
10802 }
static char format
int32 encoding
Definition: pg_database.h:41
@ JS_FORMAT_JSONB
Definition: primnodes.h:1567
@ JS_FORMAT_DEFAULT
Definition: primnodes.h:1565
@ JS_ENC_DEFAULT
Definition: primnodes.h:1553
@ JS_ENC_UTF32
Definition: primnodes.h:1556
@ JS_ENC_UTF16
Definition: primnodes.h:1555

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_returning()

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

Definition at line 10808 of file ruleutils.c.

10810 {
10811  if (!OidIsValid(returning->typid))
10812  return;
10813 
10814  appendStringInfo(buf, " RETURNING %s",
10815  format_type_with_typemod(returning->typid,
10816  returning->typmod));
10817 
10818  if (!json_format_by_default ||
10819  returning->format->format_type !=
10820  (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
10821  get_json_format(returning->format, buf);
10822 }
@ JS_FORMAT_JSON
Definition: primnodes.h:1566
static void get_json_format(JsonFormat *format, StringInfo buf)
Definition: ruleutils.c:10783
JsonFormatType format_type
Definition: primnodes.h:1578
JsonFormat * format
Definition: primnodes.h:1590

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().

◆ get_merge_query_def()

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

Definition at line 7088 of file ruleutils.c.

7090 {
7091  StringInfo buf = context->buf;
7092  RangeTblEntry *rte;
7093  ListCell *lc;
7094 
7095  /* Insert the WITH clause if given */
7096  get_with_clause(query, context);
7097 
7098  /*
7099  * Start the query with MERGE INTO relname
7100  */
7101  rte = rt_fetch(query->resultRelation, query->rtable);
7102  Assert(rte->rtekind == RTE_RELATION);
7103  if (PRETTY_INDENT(context))
7104  {
7105  appendStringInfoChar(buf, ' ');
7106  context->indentLevel += PRETTYINDENT_STD;
7107  }
7108  appendStringInfo(buf, "MERGE INTO %s%s",
7109  only_marker(rte),
7111 
7112  /* Print the relation alias, if needed */
7113  get_rte_alias(rte, query->resultRelation, false, context);
7114 
7115  /* Print the source relation and join clause */
7116  get_from_clause(query, " USING ", context);
7117  appendContextKeyword(context, " ON ",
7119  get_rule_expr(query->jointree->quals, context, false);
7120 
7121  /* Print each merge action */
7122  foreach(lc, query->mergeActionList)
7123  {
7125 
7126  appendContextKeyword(context, " WHEN ",
7128  appendStringInfo(buf, "%sMATCHED", action->matched ? "" : "NOT ");
7129 
7130  if (action->qual)
7131  {
7132  appendContextKeyword(context, " AND ",
7134  get_rule_expr(action->qual, context, false);
7135  }
7136  appendContextKeyword(context, " THEN ",
7138 
7139  if (action->commandType == CMD_INSERT)
7140  {
7141  /* This generally matches get_insert_query_def() */
7142  List *strippedexprs = NIL;
7143  const char *sep = "";
7144  ListCell *lc2;
7145 
7146  appendStringInfoString(buf, "INSERT");
7147 
7148  if (action->targetList)
7149  appendStringInfoString(buf, " (");
7150  foreach(lc2, action->targetList)
7151  {
7152  TargetEntry *tle = (TargetEntry *) lfirst(lc2);
7153 
7154  Assert(!tle->resjunk);
7155 
7157  sep = ", ";
7158 
7161  tle->resno,
7162  false)));
7163  strippedexprs = lappend(strippedexprs,
7164  processIndirection((Node *) tle->expr,
7165  context));
7166  }
7167  if (action->targetList)
7168  appendStringInfoChar(buf, ')');
7169 
7170  if (action->override)
7171  {
7172  if (action->override == OVERRIDING_SYSTEM_VALUE)
7173  appendStringInfoString(buf, " OVERRIDING SYSTEM VALUE");
7174  else if (action->override == OVERRIDING_USER_VALUE)
7175  appendStringInfoString(buf, " OVERRIDING USER VALUE");
7176  }
7177 
7178  if (strippedexprs)
7179  {
7180  appendContextKeyword(context, " VALUES (",
7182  get_rule_list_toplevel(strippedexprs, context, false);
7183  appendStringInfoChar(buf, ')');
7184  }
7185  else
7186  appendStringInfoString(buf, " DEFAULT VALUES");
7187  }
7188  else if (action->commandType == CMD_UPDATE)
7189  {
7190  appendStringInfoString(buf, "UPDATE SET ");
7191  get_update_query_targetlist_def(query, action->targetList,
7192  context, rte);
7193  }
7194  else if (action->commandType == CMD_DELETE)
7195  appendStringInfoString(buf, "DELETE");
7196  else if (action->commandType == CMD_NOTHING)
7197  appendStringInfoString(buf, "DO NOTHING");
7198  }
7199 
7200  /* No RETURNING support in MERGE yet */
7201  Assert(query->returningList == NIL);
7202 }
@ CMD_INSERT
Definition: nodes.h:278
@ CMD_DELETE
Definition: nodes.h:279
@ CMD_UPDATE
Definition: nodes.h:277
@ CMD_NOTHING
Definition: nodes.h:283
List * mergeActionList
Definition: parsenodes.h:184

References generate_unaccent_rules::action, appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), deparse_context::buf, buf, CMD_DELETE, CMD_INSERT, CMD_NOTHING, CMD_UPDATE, TargetEntry::expr, generate_relation_name(), get_attname(), get_from_clause(), get_rte_alias(), get_rule_expr(), get_rule_list_toplevel(), get_update_query_targetlist_def(), get_with_clause(), deparse_context::indentLevel, Query::jointree, lappend(), lfirst, lfirst_node, Query::mergeActionList, NIL, only_marker, OVERRIDING_SYSTEM_VALUE, OVERRIDING_USER_VALUE, PRETTY_INDENT, PRETTYINDENT_STD, processIndirection(), FromExpr::quals, 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 7618 of file ruleutils.c.

7620 {
7621  RangeTblEntry *rte;
7623  int netlevelsup;
7624  deparse_namespace *dpns;
7625  int varno;
7626  AttrNumber varattno;
7627  TupleDesc tupleDesc;
7628  Node *expr;
7629 
7630  /*
7631  * If it's a RowExpr that was expanded from a whole-row Var, use the
7632  * column names attached to it. (We could let get_expr_result_tupdesc()
7633  * handle this, but it's much cheaper to just pull out the name we need.)
7634  */
7635  if (IsA(var, RowExpr))
7636  {
7637  RowExpr *r = (RowExpr *) var;
7638 
7639  if (fieldno > 0 && fieldno <= list_length(r->colnames))
7640  return strVal(list_nth(r->colnames, fieldno - 1));
7641  }
7642 
7643  /*
7644  * If it's a Param of type RECORD, try to find what the Param refers to.
7645  */
7646  if (IsA(var, Param))
7647  {
7648  Param *param = (Param *) var;
7649  ListCell *ancestor_cell;
7650 
7651  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7652  if (expr)
7653  {
7654  /* Found a match, so recurse to decipher the field name */
7655  deparse_namespace save_dpns;
7656  const char *result;
7657 
7658  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7659  result = get_name_for_var_field((Var *) expr, fieldno,
7660  0, context);
7661  pop_ancestor_plan(dpns, &save_dpns);
7662  return result;
7663  }
7664  }
7665 
7666  /*
7667  * If it's a Var of type RECORD, we have to find what the Var refers to;
7668  * if not, we can use get_expr_result_tupdesc().
7669  */
7670  if (!IsA(var, Var) ||
7671  var->vartype != RECORDOID)
7672  {
7673  tupleDesc = get_expr_result_tupdesc((Node *) var, false);
7674  /* Got the tupdesc, so we can extract the field name */
7675  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7676  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7677  }
7678 
7679  /* Find appropriate nesting depth */
7680  netlevelsup = var->varlevelsup + levelsup;
7681  if (netlevelsup >= list_length(context->namespaces))
7682  elog(ERROR, "bogus varlevelsup: %d offset %d",
7683  var->varlevelsup, levelsup);
7684  dpns = (deparse_namespace *) list_nth(context->namespaces,
7685  netlevelsup);
7686 
7687  /*
7688  * If we have a syntactic referent for the Var, and we're working from a
7689  * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7690  * on the semantic referent. (See comments in get_variable().)
7691  */
7692  if (var->varnosyn > 0 && dpns->plan == NULL)
7693  {
7694  varno = var->varnosyn;
7695  varattno = var->varattnosyn;
7696  }
7697  else
7698  {
7699  varno = var->varno;
7700  varattno = var->varattno;
7701  }
7702 
7703  /*
7704  * Try to find the relevant RTE in this rtable. In a plan tree, it's
7705  * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7706  * down into the subplans, or INDEX_VAR, which is resolved similarly.
7707  *
7708  * Note: unlike get_variable and resolve_special_varno, we need not worry
7709  * about inheritance mapping: a child Var should have the same datatype as
7710  * its parent, and here we're really only interested in the Var's type.
7711  */
7712  if (varno >= 1 && varno <= list_length(dpns->rtable))
7713  {
7714  rte = rt_fetch(varno, dpns->rtable);
7715  attnum = varattno;
7716  }
7717  else if (varno == OUTER_VAR && dpns->outer_tlist)
7718  {
7719  TargetEntry *tle;
7720  deparse_namespace save_dpns;
7721  const char *result;
7722 
7723  tle = get_tle_by_resno(dpns->outer_tlist, varattno);
7724  if (!tle)
7725  elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
7726 
7727  Assert(netlevelsup == 0);
7728  push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7729 
7730  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7731  levelsup, context);
7732 
7733  pop_child_plan(dpns, &save_dpns);
7734  return result;
7735  }
7736  else if (varno == INNER_VAR && dpns->inner_tlist)
7737  {
7738  TargetEntry *tle;
7739  deparse_namespace save_dpns;
7740  const char *result;
7741 
7742  tle = get_tle_by_resno(dpns->inner_tlist, varattno);
7743  if (!tle)
7744  elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
7745 
7746  Assert(netlevelsup == 0);
7747  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7748 
7749  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7750  levelsup, context);
7751 
7752  pop_child_plan(dpns, &save_dpns);
7753  return result;
7754  }
7755  else if (varno == INDEX_VAR && dpns->index_tlist)
7756  {
7757  TargetEntry *tle;
7758  const char *result;
7759 
7760  tle = get_tle_by_resno(dpns->index_tlist, varattno);
7761  if (!tle)
7762  elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
7763 
7764  Assert(netlevelsup == 0);
7765 
7766  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7767  levelsup, context);
7768 
7769  return result;
7770  }
7771  else
7772  {
7773  elog(ERROR, "bogus varno: %d", varno);
7774  return NULL; /* keep compiler quiet */
7775  }
7776 
7777  if (attnum == InvalidAttrNumber)
7778  {
7779  /* Var is whole-row reference to RTE, so select the right field */
7780  return get_rte_attribute_name(rte, fieldno);
7781  }
7782 
7783  /*
7784  * This part has essentially the same logic as the parser's
7785  * expandRecordVariable() function, but we are dealing with a different
7786  * representation of the input context, and we only need one field name
7787  * not a TupleDesc. Also, we need special cases for finding subquery and
7788  * CTE subplans when deparsing Plan trees.
7789  */
7790  expr = (Node *) var; /* default if we can't drill down */
7791 
7792  switch (rte->rtekind)
7793  {
7794  case RTE_RELATION:
7795  case RTE_VALUES:
7796  case RTE_NAMEDTUPLESTORE:
7797  case RTE_RESULT:
7798 
7799  /*
7800  * This case should not occur: a column of a table, values list,
7801  * or ENR shouldn't have type RECORD. Fall through and fail (most
7802  * likely) at the bottom.
7803  */
7804  break;
7805  case RTE_SUBQUERY:
7806  /* Subselect-in-FROM: examine sub-select's output expr */
7807  {
7808  if (rte->subquery)
7809  {
7811  attnum);
7812 
7813  if (ste == NULL || ste->resjunk)
7814  elog(ERROR, "subquery %s does not have attribute %d",
7815  rte->eref->aliasname, attnum);
7816  expr = (Node *) ste->expr;
7817  if (IsA(expr, Var))
7818  {
7819  /*
7820  * Recurse into the sub-select to see what its Var
7821  * refers to. We have to build an additional level of
7822  * namespace to keep in step with varlevelsup in the
7823  * subselect; furthermore, the subquery RTE might be
7824  * from an outer query level, in which case the
7825  * namespace for the subselect must have that outer
7826  * level as parent namespace.
7827  */
7828  List *save_nslist = context->namespaces;
7829  List *parent_namespaces;
7830  deparse_namespace mydpns;
7831  const char *result;
7832 
7833  parent_namespaces = list_copy_tail(context->namespaces,
7834  netlevelsup);
7835 
7836  set_deparse_for_query(&mydpns, rte->subquery,
7837  parent_namespaces);
7838 
7839  context->namespaces = lcons(&mydpns, parent_namespaces);
7840 
7841  result = get_name_for_var_field((Var *) expr, fieldno,
7842  0, context);
7843 
7844  context->namespaces = save_nslist;
7845 
7846  return result;
7847  }
7848  /* else fall through to inspect the expression */
7849  }
7850  else
7851  {
7852  /*
7853  * We're deparsing a Plan tree so we don't have complete
7854  * RTE entries (in particular, rte->subquery is NULL). But
7855  * the only place we'd see a Var directly referencing a
7856  * SUBQUERY RTE is in a SubqueryScan plan node, and we can
7857  * look into the child plan's tlist instead.
7858  */
7859  TargetEntry *tle;
7860  deparse_namespace save_dpns;
7861  const char *result;
7862 
7863  if (!dpns->inner_plan)
7864  elog(ERROR, "failed to find plan for subquery %s",
7865  rte->eref->aliasname);
7866  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7867  if (!tle)
7868  elog(ERROR, "bogus varattno for subquery var: %d",
7869  attnum);
7870  Assert(netlevelsup == 0);
7871  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7872 
7873  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7874  levelsup, context);
7875 
7876  pop_child_plan(dpns, &save_dpns);
7877  return result;
7878  }
7879  }
7880  break;
7881  case RTE_JOIN:
7882  /* Join RTE --- recursively inspect the alias variable */
7883  if (rte->joinaliasvars == NIL)
7884  elog(ERROR, "cannot decompile join alias var in plan tree");
7885  Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
7886  expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
7887  Assert(expr != NULL);
7888  /* we intentionally don't strip implicit coercions here */
7889  if (IsA(expr, Var))
7890  return get_name_for_var_field((Var *) expr, fieldno,
7891  var->varlevelsup + levelsup,
7892  context);
7893  /* else fall through to inspect the expression */
7894  break;
7895  case RTE_FUNCTION:
7896  case RTE_TABLEFUNC:
7897 
7898  /*
7899  * We couldn't get here unless a function is declared with one of
7900  * its result columns as RECORD, which is not allowed.
7901  */
7902  break;
7903  case RTE_CTE:
7904  /* CTE reference: examine subquery's output expr */
7905  {
7906  CommonTableExpr *cte = NULL;
7907  Index ctelevelsup;
7908  ListCell *lc;
7909 
7910  /*
7911  * Try to find the referenced CTE using the namespace stack.
7912  */
7913  ctelevelsup = rte->ctelevelsup + netlevelsup;
7914  if (ctelevelsup >= list_length(context->namespaces))
7915  lc = NULL;
7916  else
7917  {
7918  deparse_namespace *ctedpns;
7919 
7920  ctedpns = (deparse_namespace *)
7921  list_nth(context->namespaces, ctelevelsup);
7922  foreach(lc, ctedpns->ctes)
7923  {
7924  cte = (CommonTableExpr *) lfirst(lc);
7925  if (strcmp(cte->ctename, rte->ctename) == 0)
7926  break;
7927  }
7928  }
7929  if (lc != NULL)
7930  {
7931  Query *ctequery = (Query *) cte->ctequery;
7933  attnum);
7934 
7935  if (ste == NULL || ste->resjunk)
7936  elog(ERROR, "CTE %s does not have attribute %d",
7937  rte->eref->aliasname, attnum);
7938  expr = (Node *) ste->expr;
7939  if (IsA(expr, Var))
7940  {
7941  /*
7942  * Recurse into the CTE to see what its Var refers to.
7943  * We have to build an additional level of namespace
7944  * to keep in step with varlevelsup in the CTE;
7945  * furthermore it could be an outer CTE (compare
7946  * SUBQUERY case above).
7947  */
7948  List *save_nslist = context->namespaces;
7949  List *parent_namespaces;
7950  deparse_namespace mydpns;
7951  const char *result;
7952 
7953  parent_namespaces = list_copy_tail(context->namespaces,
7954  ctelevelsup);
7955 
7956  set_deparse_for_query(&mydpns, ctequery,
7957  parent_namespaces);
7958 
7959  context->namespaces = lcons(&mydpns, parent_namespaces);
7960 
7961  result = get_name_for_var_field((Var *) expr, fieldno,
7962  0, context);
7963 
7964  context->namespaces = save_nslist;
7965 
7966  return result;
7967  }
7968  /* else fall through to inspect the expression */
7969  }
7970  else
7971  {
7972  /*
7973  * We're deparsing a Plan tree so we don't have a CTE
7974  * list. But the only places we'd see a Var directly
7975  * referencing a CTE RTE are in CteScan or WorkTableScan
7976  * plan nodes. For those cases, set_deparse_plan arranged
7977  * for dpns->inner_plan to be the plan node that emits the
7978  * CTE or RecursiveUnion result, and we can look at its
7979  * tlist instead.
7980  */
7981  TargetEntry *tle;
7982  deparse_namespace save_dpns;
7983  const char *result;
7984 
7985  if (!dpns->inner_plan)
7986  elog(ERROR, "failed to find plan for CTE %s",
7987  rte->eref->aliasname);
7988  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7989  if (!tle)
7990  elog(ERROR, "bogus varattno for subquery var: %d",
7991  attnum);
7992  Assert(netlevelsup == 0);
7993  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7994 
7995  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7996  levelsup, context);
7997 
7998  pop_child_plan(dpns, &save_dpns);
7999  return result;
8000  }
8001  }
8002  break;
8003  }
8004 
8005  /*
8006  * We now have an expression we can't expand any more, so see if
8007  * get_expr_result_tupdesc() can do anything with it.
8008  */
8009  tupleDesc = get_expr_result_tupdesc(expr, false);
8010  /* Got the tupdesc, so we can extract the field name */
8011  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8012  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8013 }
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
TupleDesc get_expr_result_tupdesc(Node *expr, bool noError)
Definition: funcapi.c:543
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * list_copy_tail(const List *oldlist, int nskip)
Definition: list.c:1612
List * lcons(void *datum, List *list)
Definition: list.c:494
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
char * get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
#define GetCTETargetList(cte)
Definition: parsenodes.h:1660
@ RTE_JOIN
Definition: parsenodes.h:1015
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1020
@ RTE_RESULT
Definition: parsenodes.h:1021
int16 attnum
Definition: pg_attribute.h:74
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define OUTER_VAR
Definition: primnodes.h:215
#define INNER_VAR
Definition: primnodes.h:214
#define INDEX_VAR
Definition: primnodes.h:216
static void set_deparse_for_query(deparse_namespace *dpns, Query *query, List *parent_namespaces)
Definition: ruleutils.c:3971
static void pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5139
static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns)
Definition: ruleutils.c:5118
static Node * find_param_referent(Param *param, deparse_context *context, deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
Definition: ruleutils.c:8024
static void pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5088
static const char * get_name_for_var_field(Var *var, int fieldno, int levelsup, deparse_context *context)
Definition: ruleutils.c:7618
static void push_child_plan(deparse_namespace *dpns, Plan *plan, deparse_namespace *save_dpns)
Definition: ruleutils.c:5071
char * aliasname
Definition: primnodes.h:42
Index ctelevelsup
Definition: parsenodes.h:1164
List * joinaliasvars
Definition: parsenodes.h:1128
Definition: primnodes.h:226
AttrNumber varattno
Definition: primnodes.h:238
int varno
Definition: primnodes.h:233
Index varlevelsup
Definition: primnodes.h:258
List * inner_tlist
Definition: ruleutils.c:179
List * outer_tlist
Definition: ruleutils.c:178
List * index_tlist
Definition: ruleutils.c:180
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References Alias::aliasname, Assert(), attname, attnum, RangeTblEntry::ctelevelsup, RangeTblEntry::ctename, CommonTableExpr::ctename, CommonTableExpr::ctequery, deparse_namespace::ctes, elog(), RangeTblEntry::eref, ERROR, TargetEntry::expr, find_param_referent(), get_expr_result_tupdesc(), get_rte_attribute_name(), get_tle_by_resno(), GetCTETargetList, if(), deparse_namespace::index_tlist, INDEX_VAR, deparse_namespace::inner_plan, deparse_namespace::inner_tlist, INNER_VAR, InvalidAttrNumber, IsA, RangeTblEntry::joinaliasvars, lcons(), lfirst, list_copy_tail(), list_length(), list_nth(), deparse_context::namespaces, NameStr, NIL, deparse_namespace::outer_plan, deparse_namespace::outer_tlist, OUTER_VAR, deparse_namespace::plan, pop_ancestor_plan(), pop_child_plan(), push_ancestor_plan(), push_child_plan(), rt_fetch, deparse_namespace::rtable, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, set_deparse_for_query(), strVal, RangeTblEntry::subquery, Query::targetList, TupleDescAttr, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by get_rule_expr().

◆ get_opclass_name()

static void get_opclass_name ( Oid  opclass,
Oid  actual_datatype,
StringInfo  buf 
)
static

Definition at line 11797 of file ruleutils.c.

11799 {
11800  HeapTuple ht_opc;
11801  Form_pg_opclass opcrec;
11802  char *opcname;
11803  char *nspname;
11804 
11805  ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
11806  if (!HeapTupleIsValid(ht_opc))
11807  elog(ERROR, "cache lookup failed for opclass %u", opclass);
11808  opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
11809 
11810  if (!OidIsValid(actual_datatype) ||
11811  GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
11812  {
11813  /* Okay, we need the opclass name. Do we need to qualify it? */
11814  opcname = NameStr(opcrec->opcname);
11815  if (OpclassIsVisible(opclass))
11816  appendStringInfo(buf, " %s", quote_identifier(opcname));
11817  else
11818  {
11819  nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
11820  appendStringInfo(buf, " %s.%s",
11821  quote_identifier(nspname),
11822  quote_identifier(opcname));
11823  }
11824  }
11825  ReleaseSysCache(ht_opc);
11826 }
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2310
bool OpclassIsVisible(Oid opcid)
Definition: namespace.c:1858
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
@ CLAOID
Definition: syscache.h:48

References appendStringInfo(), buf, CLAOID, elog(), ERROR, get_namespace_name_or_temp(), GetDefaultOpClass(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), OidIsValid, OpclassIsVisible(), quote_identifier(), ReleaseSysCache(), and SearchSysCache1().

Referenced by generate_opclass_name(), get_rule_expr(), pg_get_indexdef_worker(), and pg_get_partkeydef_worker().

◆ get_oper_expr()

static void get_oper_expr ( OpExpr expr,
deparse_context context 
)
static

Definition at line 9933 of file ruleutils.c.

9934 {
9935  StringInfo buf = context->buf;
9936  Oid opno = expr->opno;
9937  List *args = expr->args;
9938 
9939  if (!PRETTY_PAREN(context))
9940  appendStringInfoChar(buf, '(');
9941  if (list_length(args) == 2)
9942  {
9943  /* binary operator */
9944  Node *arg1 = (Node *) linitial(args);
9945  Node *arg2 = (Node *) lsecond(args);
9946 
9947  get_rule_expr_paren(arg1, context, true, (Node *) expr);
9948  appendStringInfo(buf, " %s ",
9950  exprType(arg1),
9951  exprType(arg2)));
9952  get_rule_expr_paren(arg2, context, true, (Node *) expr);
9953  }
9954  else
9955  {
9956  /* prefix operator */
9957  Node *arg = (Node *) linitial(args);
9958 
9959  appendStringInfo(buf, "%s ",
9961  InvalidOid,
9962  exprType(arg)));
9963  get_rule_expr_paren(arg, context, true, (Node *) expr);
9964  }
9965  if (!PRETTY_PAREN(context))
9966  appendStringInfoChar(buf, ')');
9967 }
static char * generate_operator_name(Oid operid, Oid arg1, Oid arg2)
Definition: ruleutils.c:12296
Oid opno
Definition: primnodes.h:745
List * args
Definition: primnodes.h:763

References appendStringInfo(), appendStringInfoChar(), arg, generate_unaccent_rules::args, OpExpr::args, deparse_context::buf, buf, exprType(), generate_operator_name(), get_rule_expr_paren(), InvalidOid, linitial, list_length(), lsecond, OpExpr::opno, and PRETTY_PAREN.

Referenced by get_rule_expr().

◆ get_parameter()

static void get_parameter ( Param param,
deparse_context context 
)
static

Definition at line 8134 of file ruleutils.c.

8135 {
8136  Node *expr;
8137  deparse_namespace *dpns;
8138  ListCell *ancestor_cell;
8139 
8140  /*
8141  * If it's a PARAM_EXEC parameter, try to locate the expression from which
8142  * the parameter was computed. Note that failing to find a referent isn't
8143  * an error, since the Param might well be a subplan output rather than an
8144  * input.
8145  */
8146  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8147  if (expr)
8148  {
8149  /* Found a match, so print it */
8150  deparse_namespace save_dpns;
8151  bool save_varprefix;
8152  bool need_paren;
8153 
8154  /* Switch attention to the ancestor plan node */
8155  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8156 
8157  /*
8158  * Force prefixing of Vars, since they won't belong to the relation
8159  * being scanned in the original plan node.
8160  */
8161  save_varprefix = context->varprefix;
8162  context->varprefix = true;
8163 
8164  /*
8165  * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8166  * upper-level Param, which wouldn't need extra parentheses.
8167  * Otherwise, insert parens to ensure the expression looks atomic.
8168  */
8169  need_paren = !(IsA(expr, Var) ||
8170  IsA(expr, Aggref) ||
8171  IsA(expr, GroupingFunc) ||
8172  IsA(expr, Param));
8173  if (need_paren)
8174  appendStringInfoChar(context->buf, '(');
8175 
8176  get_rule_expr(expr, context, false);
8177 
8178  if (need_paren)
8179  appendStringInfoChar(context->buf, ')');
8180 
8181  context->varprefix = save_varprefix;
8182 
8183  pop_ancestor_plan(dpns, &save_dpns);
8184 
8185  return;
8186  }
8187 
8188  /*
8189  * If it's an external parameter, see if the outermost namespace provides
8190  * function argument names.
8191  */
8192  if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8193  {
8194  dpns = llast(context->namespaces);
8195  if (dpns->argnames &&
8196  param->paramid > 0 &&
8197  param->paramid <= dpns->numargs)
8198  {
8199  char *argname = dpns->argnames[param->paramid - 1];
8200 
8201  if (argname)
8202  {
8203  bool should_qualify = false;
8204  ListCell *lc;
8205 
8206  /*
8207  * Qualify the parameter name if there are any other deparse
8208  * namespaces with range tables. This avoids qualifying in
8209  * trivial cases like "RETURN a + b", but makes it safe in all
8210  * other cases.
8211  */
8212  foreach(lc, context->namespaces)
8213  {
8214  deparse_namespace *depns = lfirst(lc);
8215 
8216  if (depns->rtable_names != NIL)
8217  {
8218  should_qualify = true;
8219  break;
8220  }
8221  }
8222  if (should_qualify)
8223  {
8225  appendStringInfoChar(context->buf, '.');
8226  }
8227 
8228  appendStringInfoString(context->buf, quote_identifier(argname));
8229  return;
8230  }
8231  }
8232  }
8233 
8234  /*
8235  * Not PARAM_EXEC, or couldn't find referent: just print $N.
8236  */
8237  appendStringInfo(context->buf, "$%d", param->paramid);
8238 }
#define llast(l)
Definition: pg_list.h:198
@ PARAM_EXTERN
Definition: primnodes.h:345
char ** argnames
Definition: ruleutils.c:184

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), deparse_namespace::argnames, deparse_context::buf, find_param_referent(), deparse_namespace::funcname, get_rule_expr(), IsA, lfirst, llast, deparse_context::namespaces, NIL, deparse_namespace::numargs, PARAM_EXTERN, Param::paramid, Param::paramkind, pop_ancestor_plan(), push_ancestor_plan(), quote_identifier(), deparse_namespace::rtable_names, and deparse_context::varprefix.

Referenced by get_rule_expr().

◆ get_query_def()

static void get_query_def ( Query query,
StringInfo  buf,
List parentnamespace,
TupleDesc  resultDesc,
bool  colNamesVisible,
int  prettyFlags,
int  wrapColumn,
int  startIndent 
)
static

Definition at line 5429 of file ruleutils.c.

5432 {
5433  deparse_context context;
5434  deparse_namespace dpns;
5435 
5436  /* Guard against excessively long or deeply-nested queries */
5439 
5440  /*
5441  * Before we begin to examine the query, acquire locks on referenced
5442  * relations, and fix up deleted columns in JOIN RTEs. This ensures
5443  * consistent results. Note we assume it's OK to scribble on the passed
5444  * querytree!
5445  *
5446  * We are only deparsing the query (we are not about to execute it), so we
5447  * only need AccessShareLock on the relations it mentions.
5448  */
5449  AcquireRewriteLocks(query, false, false);
5450 
5451  context.buf = buf;
5452  context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5453  context.windowClause = NIL;
5454  context.windowTList = NIL;
5455  context.varprefix = (parentnamespace != NIL ||
5456  list_length(query->rtable) != 1);
5457  context.prettyFlags = prettyFlags;
5458  context.wrapColumn = wrapColumn;
5459  context.indentLevel = startIndent;
5460  context.special_exprkind = EXPR_KIND_NONE;
5461  context.appendparents = NULL;
5462 
5463  set_deparse_for_query(&dpns, query, parentnamespace);
5464 
5465  switch (query->commandType)
5466  {
5467  case CMD_SELECT:
5468  get_select_query_def(query, &context, resultDesc, colNamesVisible);
5469  break;
5470 
5471  case CMD_UPDATE:
5472  get_update_query_def(query, &context, colNamesVisible);
5473  break;
5474 
5475  case CMD_INSERT:
5476  get_insert_query_def(query, &context, colNamesVisible);
5477  break;
5478 
5479  case CMD_DELETE:
5480  get_delete_query_def(query, &context, colNamesVisible);
5481  break;
5482 
5483  case CMD_MERGE:
5484  get_merge_query_def(query, &context, colNamesVisible);
5485  break;
5486 
5487  case CMD_NOTHING:
5488  appendStringInfoString(buf, "NOTHING");
5489  break;
5490 
5491  case CMD_UTILITY:
5492  get_utility_query_def(query, &context);
5493  break;
5494 
5495  default:
5496  elog(ERROR, "unrecognized query command type: %d",
5497  query->commandType);
5498  break;
5499  }
5500 }
List * list_copy(const List *oldlist)
Definition: list.c:1572
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
@ CMD_MERGE
Definition: nodes.h:280
@ CMD_UTILITY
Definition: nodes.h:281
@ CMD_SELECT
Definition: nodes.h:276
void check_stack_depth(void)
Definition: postgres.c:3523
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
static void get_select_query_def(Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:5689
static void get_delete_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:7036
static void get_utility_query_def(Query *query, deparse_context *context)
Definition: ruleutils.c:7210
static void get_merge_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:7088
static void get_insert_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:6610
static void get_update_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:6827
CmdType commandType
Definition: parsenodes.h:127

References AcquireRewriteLocks(), deparse_context::appendparents, appendStringInfoString(), deparse_context::buf, buf, CHECK_FOR_INTERRUPTS, check_stack_depth(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_SELECT, CMD_UPDATE, CMD_UTILITY, Query::commandType, elog(), ERROR, EXPR_KIND_NONE, get_delete_query_def(), get_insert_query_def(), get_merge_query_def(), get_select_query_def(), get_update_query_def(), get_utility_query_def(), deparse_context::indentLevel, lcons(), list_copy(), list_length(), deparse_context::namespaces, NIL, deparse_context::prettyFlags, Query::rtable, set_deparse_for_query(), deparse_context::special_exprkind, deparse_context::varprefix, deparse_context::windowClause, deparse_context::windowTList, and deparse_context::wrapColumn.

Referenced by get_from_clause_item(), get_insert_query_def(), get_setop_query(), get_sublink_expr(), get_with_clause(), make_ruledef(), make_viewdef(), pg_get_querydef(), and print_function_sqlbody().

◆ get_range_partbound_string()

char* get_range_partbound_string ( List bound_datums)

Definition at line 12610 of file ruleutils.c.

12611 {
12612  deparse_context context;
12614  ListCell *cell;
12615  char *sep;
12616 
12617  memset(&context, 0, sizeof(deparse_context));
12618  context.buf = buf;
12619 
12620  appendStringInfoChar(buf, '(');
12621  sep = "";
12622  foreach(cell, bound_datums)
12623  {
12624  PartitionRangeDatum *datum =
12626 
12628  if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
12629  appendStringInfoString(buf, "MINVALUE");
12630  else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
12631  appendStringInfoString(buf, "MAXVALUE");
12632  else
12633  {
12634  Const *val = castNode(Const, datum->value);
12635 
12636  get_const_expr(val, &context, -1);
12637  }
12638  sep = ", ";
12639  }
12640  appendStringInfoChar(buf, ')');
12641 
12642  return buf->data;
12643 }
long val
Definition: informix.c:664
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition: parsenodes.h:920
@ PARTITION_RANGE_DATUM_MINVALUE
Definition: parsenodes.h:918
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
PartitionRangeDatumKind kind
Definition: parsenodes.h:927

References appendStringInfoChar(), appendStringInfoString(), deparse_context::buf, buf, castNode, get_const_expr(), PartitionRangeDatum::kind, lfirst_node, makeStringInfo(), PARTITION_RANGE_DATUM_MAXVALUE, PARTITION_RANGE_DATUM_MINVALUE, val, and PartitionRangeDatum::value.

Referenced by check_new_partition_bound(), and get_rule_expr().

◆ get_relation_name()

static char * get_relation_name ( Oid  relid)
static

Definition at line 12069 of file ruleutils.c.

12070 {
12071  char *relname = get_rel_name(relid);
12072 
12073  if (!relname)
12074  elog(ERROR, "cache lookup failed for relation %u", relid);
12075  return relname;
12076 }
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1932

References elog(), ERROR, get_rel_name(), and relname.

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

◆ get_reloptions()

static void get_reloptions ( StringInfo  buf,
Datum  reloptions 
)
static

Definition at line 12522 of file ruleutils.c.

12523 {
12524  Datum *options;
12525  int noptions;
12526  int i;
12527 
12528  deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
12529  &options, NULL, &noptions);
12530 
12531  for (i = 0; i < noptions; i++)
12532  {
12533  char *option = TextDatumGetCString(options[i]);
12534  char *name;
12535  char *separator;
12536  char *value;
12537 
12538  /*
12539  * Each array element should have the form name=value. If the "=" is
12540  * missing for some reason, treat it like an empty value.
12541  */
12542  name = option;
12543  separator = strchr(option, '=');
12544  if (separator)
12545  {
12546  *separator = '\0';
12547  value = separator + 1;
12548  }
12549  else
12550  value = "";
12551 
12552  if (i > 0)
12553  appendStringInfoString(buf, ", ");
12555 
12556  /*
12557  * In general we need to quote the value; but to avoid unnecessary
12558  * clutter, do not quote if it is an identifier that would not need
12559  * quoting. (We could also allow numbers, but that is a bit trickier
12560  * than it looks --- for example, are leading zeroes significant? We
12561  * don't want to assume very much here about what custom reloptions
12562  * might mean.)
12563  */
12564  if (quote_identifier(value) == value)
1256