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/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_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_combine_expr (Node *node, deparse_context *context, void *callback_arg)
 
static void get_windowfunc_expr (WindowFunc *wfunc, deparse_context *context)
 
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_json_constructor (JsonConstructorExpr *ctor, deparse_context *context, bool showimplicit)
 
static void get_json_agg_constructor (JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
 
static void get_const_collation (Const *constval, deparse_context *context)
 
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_column_alias_list (deparse_columns *colinfo, deparse_context *context)
 
static void get_from_clause_coldeflist (RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
 
static void get_tablesample_def (TableSampleClause *tablesample, deparse_context *context)
 
static void get_opclass_name (Oid opclass, Oid actual_datatype, StringInfo buf)
 
static NodeprocessIndirection (Node *node, deparse_context *context)
 
static void printSubscripts (SubscriptingRef *sbsref, deparse_context *context)
 
static char * get_relation_name (Oid relid)
 
static char * generate_relation_name (Oid relid, List *namespaces)
 
static char * generate_qualified_relation_name (Oid relid)
 
static char * generate_function_name (Oid funcid, int nargs, List *argnames, Oid *argtypes, bool has_variadic, bool *use_variadic_p, ParseExprKind special_exprkind)
 
static char * generate_operator_name (Oid operid, Oid arg1, Oid arg2)
 
static void add_cast_to (StringInfo buf, Oid typid)
 
static char * generate_qualified_type_name (Oid typid)
 
static textstring_to_text (char *str)
 
static char * flatten_reloptions (Oid relid)
 
static void get_reloptions (StringInfo buf, Datum reloptions)
 
static void get_json_path_spec (Node *path_spec, deparse_context *context, bool showimplicit)
 
static void get_json_table_columns (TableFunc *tf, JsonTableParent *node, deparse_context *context, bool showimplicit)
 
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_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_format (JsonFormat *format, StringInfo buf)
 
static void get_json_returning (JsonReturning *returning, StringInfo buf, bool json_format_by_default)
 
static void get_json_behavior (JsonBehavior *behavior, deparse_context *context, const char *on)
 
static void get_json_expr_options (JsonExpr *jsexpr, deparse_context *context, JsonBehaviorType default_behavior)
 
static void get_json_constructor_options (JsonConstructorExpr *ctor, StringInfo buf)
 
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_windowfunc_expr_helper (WindowFunc *wfunc, deparse_context *context, const char *funcname, const char *options, bool is_json_objectagg)
 
static void get_xmltable (TableFunc *tf, deparse_context *context, bool showimplicit)
 
static void get_json_table_nested_columns (TableFunc *tf, Node *node, deparse_context *context, bool showimplicit, bool needcomma)
 
static void get_json_table_plan (TableFunc *tf, Node *node, deparse_context *context, bool parenthesize)
 
static void get_json_table (TableFunc *tf, deparse_context *context, bool showimplicit)
 
char * generate_opclass_name (Oid opclass)
 
const char * quote_identifier (const char *ident)
 
char * quote_qualified_identifier (const char *qualifier, const char *ident)
 
void generate_operator_clause (StringInfo buf, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype)
 
char * generate_collation_name (Oid collid)
 
char * get_range_partbound_string (List *bound_datums)
 

Variables

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

Macro Definition Documentation

◆ deparse_columns_fetch

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

Definition at line 296 of file ruleutils.c.

◆ GET_PRETTY_FLAGS

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

Definition at line 94 of file ruleutils.c.

◆ only_marker

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

Definition at line 512 of file ruleutils.c.

◆ PRETTY_INDENT

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

Definition at line 103 of file ruleutils.c.

◆ PRETTY_PAREN

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

Definition at line 102 of file ruleutils.c.

◆ PRETTY_SCHEMA

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

Definition at line 104 of file ruleutils.c.

◆ PRETTYFLAG_INDENT

#define PRETTYFLAG_INDENT   0x0002

Definition at line 90 of file ruleutils.c.

◆ PRETTYFLAG_PAREN

#define PRETTYFLAG_PAREN   0x0001

Definition at line 89 of file ruleutils.c.

◆ PRETTYFLAG_SCHEMA

#define PRETTYFLAG_SCHEMA   0x0004

Definition at line 91 of file ruleutils.c.

◆ PRETTYINDENT_JOIN

#define PRETTYINDENT_JOIN   4

Definition at line 83 of file ruleutils.c.

◆ PRETTYINDENT_LIMIT

#define PRETTYINDENT_LIMIT   40 /* wrap limit */

Definition at line 86 of file ruleutils.c.

◆ PRETTYINDENT_STD

#define PRETTYINDENT_STD   8

Definition at line 82 of file ruleutils.c.

◆ PRETTYINDENT_VAR

#define PRETTYINDENT_VAR   4

Definition at line 84 of file ruleutils.c.

◆ WRAP_COLUMN_DEFAULT

#define WRAP_COLUMN_DEFAULT   0

Definition at line 99 of file ruleutils.c.

Typedef Documentation

◆ rsv_callback

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

Definition at line 309 of file ruleutils.c.

Function Documentation

◆ add_cast_to()

static void add_cast_to ( StringInfo  buf,
Oid  typid 
)
static

Definition at line 12640 of file ruleutils.c.

12641 {
12642  HeapTuple typetup;
12643  Form_pg_type typform;
12644  char *typname;
12645  char *nspname;
12646 
12647  typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
12648  if (!HeapTupleIsValid(typetup))
12649  elog(ERROR, "cache lookup failed for type %u", typid);
12650  typform = (Form_pg_type) GETSTRUCT(typetup);
12651 
12652  typname = NameStr(typform->typname);
12653  nspname = get_namespace_name_or_temp(typform->typnamespace);
12654 
12655  appendStringInfo(buf, "::%s.%s",
12657 
12658  ReleaseSysCache(typetup);
12659 }
#define NameStr(name)
Definition: c.h:681
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3350
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
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12192
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ 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 8371 of file ruleutils.c.

8373 {
8374  StringInfo buf = context->buf;
8375 
8376  if (PRETTY_INDENT(context))
8377  {
8378  int indentAmount;
8379 
8380  context->indentLevel += indentBefore;
8381 
8382  /* remove any trailing spaces currently in the buffer ... */
8384  /* ... then add a newline and some spaces */
8385  appendStringInfoChar(buf, '\n');
8386 
8387  if (context->indentLevel < PRETTYINDENT_LIMIT)
8388  indentAmount = Max(context->indentLevel, 0) + indentPlus;
8389  else
8390  {
8391  /*
8392  * If we're indented more than PRETTYINDENT_LIMIT characters, try
8393  * to conserve horizontal space by reducing the per-level
8394  * indentation. For best results the scale factor here should
8395  * divide all the indent amounts that get added to indentLevel
8396  * (PRETTYINDENT_STD, etc). It's important that the indentation
8397  * not grow unboundedly, else deeply-nested trees use O(N^2)
8398  * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8399  */
8400  indentAmount = PRETTYINDENT_LIMIT +
8401  (context->indentLevel - PRETTYINDENT_LIMIT) /
8402  (PRETTYINDENT_STD / 2);
8403  indentAmount %= PRETTYINDENT_LIMIT;
8404  /* scale/wrap logic affects indentLevel, but not indentPlus */
8405  indentAmount += indentPlus;
8406  }
8407  appendStringInfoSpaces(buf, indentAmount);
8408 
8410 
8411  context->indentLevel += indentAfter;
8412  if (context->indentLevel < 0)
8413  context->indentLevel = 0;
8414  }
8415  else
8417 }
#define Max(x, y)
Definition: c.h:980
static void removeStringInfoSpaces(StringInfo str)
Definition: ruleutils.c:8425
#define PRETTYINDENT_LIMIT
Definition: ruleutils.c:86
#define PRETTYINDENT_STD
Definition: ruleutils.c:82
#define PRETTY_INDENT(context)
Definition: ruleutils.c:103
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c: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:115

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_json_table(), get_json_table_columns(), get_json_table_nested_columns(), 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 4750 of file ruleutils.c.

4752 {
4753  int i;
4754  ListCell *lc;
4755 
4756  /* Check against already-assigned column aliases within RTE */
4757  for (i = 0; i < colinfo->num_cols; i++)
4758  {
4759  char *oldname = colinfo->colnames[i];
4760 
4761  if (oldname && strcmp(oldname, colname) == 0)
4762  return false;
4763  }
4764 
4765  /*
4766  * If we're building a new_colnames array, check that too (this will be
4767  * partially but not completely redundant with the previous checks)
4768  */
4769  for (i = 0; i < colinfo->num_new_cols; i++)
4770  {
4771  char *oldname = colinfo->new_colnames[i];
4772 
4773  if (oldname && strcmp(oldname, colname) == 0)
4774  return false;
4775  }
4776 
4777  /* Also check against USING-column names that must be globally unique */
4778  foreach(lc, dpns->using_names)
4779  {
4780  char *oldname = (char *) lfirst(lc);
4781 
4782  if (strcmp(oldname, colname) == 0)
4783  return false;
4784  }
4785 
4786  /* Also check against names already assigned for parent-join USING cols */
4787  foreach(lc, colinfo->parentUsing)
4788  {
4789  char *oldname = (char *) lfirst(lc);
4790 
4791  if (strcmp(oldname, colname) == 0)
4792  return false;
4793  }
4794 
4795  return true;
4796 }
int i
Definition: isn.c:73
#define lfirst(lc)
Definition: pg_list.h:169
List * parentUsing
Definition: ruleutils.c:269
char ** new_colnames
Definition: ruleutils.c:262
char ** colnames
Definition: ruleutils.c:245
List * using_names
Definition: ruleutils.c:171

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

Referenced by make_colname_unique().

◆ decompile_column_index_array()

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

Definition at line 2582 of file ruleutils.c.

2584 {
2585  Datum *keys;
2586  int nKeys;
2587  int j;
2588 
2589  /* Extract data from array of int16 */
2590  deconstruct_array(DatumGetArrayTypeP(column_index_array),
2591  INT2OID, 2, true, TYPALIGN_SHORT,
2592  &keys, NULL, &nKeys);
2593 
2594  for (j = 0; j < nKeys; j++)
2595  {
2596  char *colName;
2597 
2598  colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2599 
2600  if (j == 0)
2602  else
2603  appendStringInfo(buf, ", %s", quote_identifier(colName));
2604  }
2605 
2606  return nKeys;
2607 }
#define DatumGetArrayTypeP(X)
Definition: array.h:254
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3491
int j
Definition: isn.c:74
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:825
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetInt16(X)
Definition: postgres.h:488

References appendStringInfo(), appendStringInfoString(), buf, DatumGetArrayTypeP, DatumGetInt16, deconstruct_array(), 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 3670 of file ruleutils.c.

3671 {
3672  deparse_namespace *dpns;
3673  RangeTblEntry *rte;
3674 
3675  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3676 
3677  /* Build a minimal RTE for the rel */
3678  rte = makeNode(RangeTblEntry);
3679  rte->rtekind = RTE_RELATION;
3680  rte->relid = relid;
3681  rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3683  rte->alias = makeAlias(aliasname, NIL);
3684  rte->eref = rte->alias;
3685  rte->lateral = false;
3686  rte->inh = false;
3687  rte->inFromCl = true;
3688 
3689  /* Build one-element rtable */
3690  dpns->rtable = list_make1(rte);
3691  dpns->subplans = NIL;
3692  dpns->ctes = NIL;
3693  dpns->appendrels = NULL;
3694  set_rtable_names(dpns, NIL, NULL);
3696 
3697  /* Return a one-deep namespace stack */
3698  return list_make1(dpns);
3699 }
#define AccessShareLock
Definition: lockdefs.h:36
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:388
void * palloc0(Size size)
Definition: mcxt.c:1099
#define makeNode(_type_)
Definition: nodes.h:621
@ RTE_RELATION
Definition: parsenodes.h:998
#define NIL
Definition: pg_list.h:65
#define list_make1(x1)
Definition: pg_list.h:206
static void set_simple_column_names(deparse_namespace *dpns)
Definition: ruleutils.c:4046
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
Definition: ruleutils.c:3836
Alias * eref
Definition: parsenodes.h:1161
Alias * alias
Definition: parsenodes.h:1160
RTEKind rtekind
Definition: parsenodes.h:1015
AppendRelInfo ** appendrels
Definition: ruleutils.c:168

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

3716 {
3717  deparse_namespace *dpns;
3718 
3719  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3720 
3721  /* Initialize fields that stay the same across the whole plan tree */
3722  dpns->rtable = pstmt->rtable;
3723  dpns->rtable_names = rtable_names;
3724  dpns->subplans = pstmt->subplans;
3725  dpns->ctes = NIL;
3726  if (pstmt->appendRelations)
3727  {
3728  /* Set up the array, indexed by child relid */
3729  int ntables = list_length(dpns->rtable);
3730  ListCell *lc;
3731 
3732  dpns->appendrels = (AppendRelInfo **)
3733  palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3734  foreach(lc, pstmt->appendRelations)
3735  {
3736  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3737  Index crelid = appinfo->child_relid;
3738 
3739  Assert(crelid > 0 && crelid <= ntables);
3740  Assert(dpns->appendrels[crelid] == NULL);
3741  dpns->appendrels[crelid] = appinfo;
3742  }
3743  }
3744  else
3745  dpns->appendrels = NULL; /* don't need it */
3746 
3747  /*
3748  * Set up column name aliases. We will get rather bogus results for join
3749  * RTEs, but that doesn't matter because plan trees don't contain any join
3750  * alias Vars.
3751  */
3753 
3754  /* Return a one-deep namespace stack */
3755  return list_make1(dpns);
3756 }
unsigned int Index
Definition: c.h:549
Assert(fmt[strlen(fmt) - 1] !='\n')
#define lfirst_node(type, lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:149
Index child_relid
Definition: pathnodes.h:2327
List * appendRelations
Definition: plannodes.h:72
List * subplans
Definition: plannodes.h:74
List * rtable
Definition: plannodes.h:67
List * rtable_names
Definition: ruleutils.c:164

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

Referenced by ExplainPrintPlan().

◆ deparse_expression()

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

Definition at line 3610 of file ruleutils.c.

3612 {
3613  return deparse_expression_pretty(expr, dpcontext, forceprefix,
3614  showimplicit, 0, 0);
3615 }
static char * deparse_expression_pretty(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
Definition: ruleutils.c:3637

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

3640 {
3642  deparse_context context;
3643 
3644  initStringInfo(&buf);
3645  context.buf = &buf;
3646  context.namespaces = dpcontext;
3647  context.windowClause = NIL;
3648  context.windowTList = NIL;
3649  context.varprefix = forceprefix;
3650  context.prettyFlags = prettyFlags;
3651  context.wrapColumn = WRAP_COLUMN_DEFAULT;
3652  context.indentLevel = startIndent;
3653  context.special_exprkind = EXPR_KIND_NONE;
3654  context.appendparents = NULL;
3655 
3656  get_rule_expr(expr, &context, showimplicit);
3657 
3658  return buf.data;
3659 }
@ EXPR_KIND_NONE
Definition: parse_node.h:40
#define WRAP_COLUMN_DEFAULT
Definition: ruleutils.c:99
static void get_rule_expr(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:8592
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
List * namespaces
Definition: ruleutils.c:116
List * windowClause
Definition: ruleutils.c:117
List * windowTList
Definition: ruleutils.c:118
Bitmapset * appendparents
Definition: ruleutils.c:125
ParseExprKind special_exprkind
Definition: ruleutils.c:123

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

4844 {
4845  if (n > colinfo->num_cols)
4846  {
4847  if (colinfo->colnames == NULL)
4848  colinfo->colnames = (char **) palloc0(n * sizeof(char *));
4849  else
4850  {
4851  colinfo->colnames = (char **) repalloc(colinfo->colnames,
4852  n * sizeof(char *));
4853  memset(colinfo->colnames + colinfo->num_cols, 0,
4854  (n - colinfo->num_cols) * sizeof(char *));
4855  }
4856  colinfo->num_cols = n;
4857  }
4858 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1188

References deparse_columns::colnames, deparse_columns::num_cols, palloc0(), and repalloc().

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

7873 {
7874  /* Initialize output parameters to prevent compiler warnings */
7875  *dpns_p = NULL;
7876  *ancestor_cell_p = NULL;
7877 
7878  /*
7879  * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
7880  * SubPlan argument. This will necessarily be in some ancestor of the
7881  * current expression's Plan node.
7882  */
7883  if (param->paramkind == PARAM_EXEC)
7884  {
7885  deparse_namespace *dpns;
7886  Plan *child_plan;
7887  bool in_same_plan_level;
7888  ListCell *lc;
7889 
7890  dpns = (deparse_namespace *) linitial(context->namespaces);
7891  child_plan = dpns->plan;
7892  in_same_plan_level = true;
7893 
7894  foreach(lc, dpns->ancestors)
7895  {
7896  Node *ancestor = (Node *) lfirst(lc);
7897  ListCell *lc2;
7898 
7899  /*
7900  * NestLoops transmit params to their inner child only; also, once
7901  * we've crawled up out of a subplan, this couldn't possibly be
7902  * the right match.
7903  */
7904  if (IsA(ancestor, NestLoop) &&
7905  child_plan == innerPlan(ancestor) &&
7906  in_same_plan_level)
7907  {
7908  NestLoop *nl = (NestLoop *) ancestor;
7909 
7910  foreach(lc2, nl->nestParams)
7911  {
7912  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
7913 
7914  if (nlp->paramno == param->paramid)
7915  {
7916  /* Found a match, so return it */
7917  *dpns_p = dpns;
7918  *ancestor_cell_p = lc;
7919  return (Node *) nlp->paramval;
7920  }
7921  }
7922  }
7923 
7924  /*
7925  * If ancestor is a SubPlan, check the arguments it provides.
7926  */
7927  if (IsA(ancestor, SubPlan))
7928  {
7929  SubPlan *subplan = (SubPlan *) ancestor;
7930  ListCell *lc3;
7931  ListCell *lc4;
7932 
7933  forboth(lc3, subplan->parParam, lc4, subplan->args)
7934  {
7935  int paramid = lfirst_int(lc3);
7936  Node *arg = (Node *) lfirst(lc4);
7937 
7938  if (paramid == param->paramid)
7939  {
7940  /*
7941  * Found a match, so return it. But, since Vars in
7942  * the arg are to be evaluated in the surrounding
7943  * context, we have to point to the next ancestor item
7944  * that is *not* a SubPlan.
7945  */
7946  ListCell *rest;
7947 
7948  for_each_cell(rest, dpns->ancestors,
7949  lnext(dpns->ancestors, lc))
7950  {
7951  Node *ancestor2 = (Node *) lfirst(rest);
7952 
7953  if (!IsA(ancestor2, SubPlan))
7954  {
7955  *dpns_p = dpns;
7956  *ancestor_cell_p = rest;
7957  return arg;
7958  }
7959  }
7960  elog(ERROR, "SubPlan cannot be outermost ancestor");
7961  }
7962  }
7963 
7964  /* We have emerged from a subplan. */
7965  in_same_plan_level = false;
7966 
7967  /* SubPlan isn't a kind of Plan, so skip the rest */
7968  continue;
7969  }
7970 
7971  /*
7972  * Check to see if we're emerging from an initplan of the current
7973  * ancestor plan. Initplans never have any parParams, so no need
7974  * to search that list, but we need to know if we should reset
7975  * in_same_plan_level.
7976  */
7977  foreach(lc2, ((Plan *) ancestor)->initPlan)
7978  {
7979  SubPlan *subplan = lfirst_node(SubPlan, lc2);
7980 
7981  if (child_plan != (Plan *) list_nth(dpns->subplans,
7982  subplan->plan_id - 1))
7983  continue;
7984 
7985  /* No parameters to be had here. */
7986  Assert(subplan->parParam == NIL);
7987 
7988  /* We have emerged from an initplan. */
7989  in_same_plan_level = false;
7990  break;
7991  }
7992 
7993  /* No luck, crawl up to next ancestor */
7994  child_plan = (Plan *) ancestor;
7995  }
7996  }
7997 
7998  /* No referent found */
7999  return NULL;
8000 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
void * arg
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
#define lfirst_int(lc)
Definition: pg_list.h:170
#define for_each_cell(cell, lst, initcell)
Definition: pg_list.h:417
#define linitial(l)
Definition: pg_list.h:174
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define innerPlan(node)
Definition: plannodes.h:171
@ PARAM_EXEC
Definition: primnodes.h:268
Var * paramval
Definition: plannodes.h:763
List * nestParams
Definition: plannodes.h:756
Definition: nodes.h:574
int paramid
Definition: primnodes.h:277
ParamKind paramkind
Definition: primnodes.h:276
int plan_id
Definition: primnodes.h:761
List * args
Definition: primnodes.h:782
List * parParam
Definition: primnodes.h:781

References deparse_namespace::ancestors, arg, SubPlan::args, Assert(), elog, ERROR, for_each_cell, forboth, innerPlan, IsA, lfirst, lfirst_int, lfirst_node, linitial, list_nth(), lnext(), deparse_context::namespaces, NestLoop::nestParams, NIL, PARAM_EXEC, Param::paramid, Param::paramkind, NestLoopParam::paramno, NestLoopParam::paramval, SubPlan::parParam, deparse_namespace::plan, SubPlan::plan_id, and deparse_namespace::subplans.

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

5033 {
5034  ListCell *lc;
5035 
5036  foreach(lc, dpns->ancestors)
5037  {
5038  Plan *ancestor = (Plan *) lfirst(lc);
5039 
5040  if (IsA(ancestor, RecursiveUnion) &&
5041  ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5042  return ancestor;
5043  }
5044  elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5045  wtscan->wtParam);
5046  return NULL;
5047 }

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

12806 {
12807  char *result = NULL;
12808  HeapTuple tuple;
12809  Datum reloptions;
12810  bool isnull;
12811 
12812  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12813  if (!HeapTupleIsValid(tuple))
12814  elog(ERROR, "cache lookup failed for relation %u", relid);
12815 
12816  reloptions = SysCacheGetAttr(RELOID, tuple,
12817  Anum_pg_class_reloptions, &isnull);
12818  if (!isnull)
12819  {
12821 
12822  initStringInfo(&buf);
12823  get_reloptions(&buf, reloptions);
12824 
12825  result = buf.data;
12826  }
12827 
12828  ReleaseSysCache(tuple);
12829 
12830  return result;
12831 }
static void get_reloptions(StringInfo buf, Datum reloptions)
Definition: ruleutils.c:12749
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
@ 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 12704 of file ruleutils.c.

12705 {
12706  HeapTuple tp;
12707  Form_pg_collation colltup;
12708  char *collname;
12709  char *nspname;
12710  char *result;
12711 
12712  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
12713  if (!HeapTupleIsValid(tp))
12714  elog(ERROR, "cache lookup failed for collation %u", collid);
12715  colltup = (Form_pg_collation) GETSTRUCT(tp);
12716  collname = NameStr(colltup->collname);
12717 
12718  if (!CollationIsVisible(collid))
12719  nspname = get_namespace_name_or_temp(colltup->collnamespace);
12720  else
12721  nspname = NULL;
12722 
12723  result = quote_qualified_identifier(nspname, collname);
12724 
12725  ReleaseSysCache(tp);
12726 
12727  return result;
12728 }
bool CollationIsVisible(Oid collid)
Definition: namespace.c:2094
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:57
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:12276
@ COLLOID
Definition: syscache.h:50

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

12421 {
12422  char *result;
12423  HeapTuple proctup;
12424  Form_pg_proc procform;
12425  char *proname;
12426  bool use_variadic;
12427  char *nspname;
12428  FuncDetailCode p_result;
12429  Oid p_funcid;
12430  Oid p_rettype;
12431  bool p_retset;
12432  int p_nvargs;
12433  Oid p_vatype;
12434  Oid *p_true_typeids;
12435  bool force_qualify = false;
12436 
12437  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
12438  if (!HeapTupleIsValid(proctup))
12439  elog(ERROR, "cache lookup failed for function %u", funcid);
12440  procform = (Form_pg_proc) GETSTRUCT(proctup);
12441  proname = NameStr(procform->proname);
12442 
12443  /*
12444  * Due to parser hacks to avoid needing to reserve CUBE, we need to force
12445  * qualification in some special cases.
12446  */
12447  if (special_exprkind == EXPR_KIND_GROUP_BY)
12448  {
12449  if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
12450  force_qualify = true;
12451  }
12452 
12453  /*
12454  * Determine whether VARIADIC should be printed. We must do this first
12455  * since it affects the lookup rules in func_get_detail().
12456  *
12457  * We always print VARIADIC if the function has a merged variadic-array
12458  * argument. Note that this is always the case for functions taking a
12459  * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
12460  * and printed the array elements as separate arguments, the call could
12461  * match a newer non-VARIADIC function.
12462  */
12463  if (use_variadic_p)
12464  {
12465  /* Parser should not have set funcvariadic unless fn is variadic */
12466  Assert(!has_variadic || OidIsValid(procform->provariadic));
12467  use_variadic = has_variadic;
12468  *use_variadic_p = use_variadic;
12469  }
12470  else
12471  {
12472  Assert(!has_variadic);
12473  use_variadic = false;
12474  }
12475 
12476  /*
12477  * The idea here is to schema-qualify only if the parser would fail to
12478  * resolve the correct function given the unqualified func name with the
12479  * specified argtypes and VARIADIC flag. But if we already decided to
12480  * force qualification, then we can skip the lookup and pretend we didn't
12481  * find it.
12482  */
12483  if (!force_qualify)
12485  NIL, argnames, nargs, argtypes,
12486  !use_variadic, true, false,
12487  &p_funcid, &p_rettype,
12488  &p_retset, &p_nvargs, &p_vatype,
12489  &p_true_typeids, NULL);
12490  else
12491  {
12492  p_result = FUNCDETAIL_NOTFOUND;
12493  p_funcid = InvalidOid;
12494  }
12495 
12496  if ((p_result == FUNCDETAIL_NORMAL ||
12497  p_result == FUNCDETAIL_AGGREGATE ||
12498  p_result == FUNCDETAIL_WINDOWFUNC) &&
12499  p_funcid == funcid)
12500  nspname = NULL;
12501  else
12502  nspname = get_namespace_name_or_temp(procform->pronamespace);
12503 
12504  result = quote_qualified_identifier(nspname, proname);
12505 
12506  ReleaseSysCache(proctup);
12507 
12508  return result;
12509 }
#define OidIsValid(objectId)
Definition: c.h:710
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:1393
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 12062 of file ruleutils.c.

12063 {
12065 
12066  initStringInfo(&buf);
12067  get_opclass_name(opclass, InvalidOid, &buf);
12068 
12069  return &buf.data[1]; /* get_opclass_name() prepends space */
12070 }
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Definition: ruleutils.c:12024

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

12604 {
12605  HeapTuple opertup;
12606  Form_pg_operator operform;
12607  char *oprname;
12608  char *nspname;
12609 
12610  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
12611  if (!HeapTupleIsValid(opertup))
12612  elog(ERROR, "cache lookup failed for operator %u", opoid);
12613  operform = (Form_pg_operator) GETSTRUCT(opertup);
12614  Assert(operform->oprkind == 'b');
12615  oprname = NameStr(operform->oprname);
12616 
12617  nspname = get_namespace_name(operform->oprnamespace);
12618 
12619  appendStringInfoString(buf, leftop);
12620  if (leftoptype != operform->oprleft)
12621  add_cast_to(buf, operform->oprleft);
12622  appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
12623  appendStringInfoString(buf, oprname);
12624  appendStringInfo(buf, ") %s", rightop);
12625  if (rightoptype != operform->oprright)
12626  add_cast_to(buf, operform->oprright);
12627 
12628  ReleaseSysCache(opertup);
12629 }
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3326
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static void add_cast_to(StringInfo buf, Oid typid)
Definition: ruleutils.c:12640
@ 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 12523 of file ruleutils.c.

12524 {
12526  HeapTuple opertup;
12527  Form_pg_operator operform;
12528  char *oprname;
12529  char *nspname;
12530  Operator p_result;
12531 
12532  initStringInfo(&buf);
12533 
12534  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
12535  if (!HeapTupleIsValid(opertup))
12536  elog(ERROR, "cache lookup failed for operator %u", operid);
12537  operform = (Form_pg_operator) GETSTRUCT(opertup);
12538  oprname = NameStr(operform->oprname);
12539 
12540  /*
12541  * The idea here is to schema-qualify only if the parser would fail to
12542  * resolve the correct operator given the unqualified op name with the
12543  * specified argtypes.
12544  */
12545  switch (operform->oprkind)
12546  {
12547  case 'b':
12548  p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
12549  true, -1);
12550  break;
12551  case 'l':
12552  p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
12553  true, -1);
12554  break;
12555  default:
12556  elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
12557  p_result = NULL; /* keep compiler quiet */
12558  break;
12559  }
12560 
12561  if (p_result != NULL && oprid(p_result) == operid)
12562  nspname = NULL;
12563  else
12564  {
12565  nspname = get_namespace_name_or_temp(operform->oprnamespace);
12566  appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
12567  }
12568 
12569  appendStringInfoString(&buf, oprname);
12570 
12571  if (nspname)
12572  appendStringInfoChar(&buf, ')');
12573 
12574  if (p_result != NULL)
12575  ReleaseSysCache(p_result);
12576 
12577  ReleaseSysCache(opertup);
12578 
12579  return buf.data;
12580 }
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 12376 of file ruleutils.c.

12377 {
12378  HeapTuple tp;
12379  Form_pg_class reltup;
12380  char *relname;
12381  char *nspname;
12382  char *result;
12383 
12384  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12385  if (!HeapTupleIsValid(tp))
12386  elog(ERROR, "cache lookup failed for relation %u", relid);
12387  reltup = (Form_pg_class) GETSTRUCT(tp);
12388  relname = NameStr(reltup->relname);
12389 
12390  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12391  if (!nspname)
12392  elog(ERROR, "cache lookup failed for namespace %u",
12393  reltup->relnamespace);
12394 
12395  result = quote_qualified_identifier(nspname, relname);
12396 
12397  ReleaseSysCache(tp);
12398 
12399  return result;
12400 }
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 12671 of file ruleutils.c.

12672 {
12673  HeapTuple tp;
12674  Form_pg_type typtup;
12675  char *typname;
12676  char *nspname;
12677  char *result;
12678 
12680  if (!HeapTupleIsValid(tp))
12681  elog(ERROR, "cache lookup failed for type %u", typid);
12682  typtup = (Form_pg_type) GETSTRUCT(tp);
12683  typname = NameStr(typtup->typname);
12684 
12685  nspname = get_namespace_name_or_temp(typtup->typnamespace);
12686  if (!nspname)
12687  elog(ERROR, "cache lookup failed for namespace %u",
12688  typtup->typnamespace);
12689 
12690  result = quote_qualified_identifier(nspname, typname);
12691 
12692  ReleaseSysCache(tp);
12693 
12694  return result;
12695 }

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

12317 {
12318  HeapTuple tp;
12319  Form_pg_class reltup;
12320  bool need_qual;
12321  ListCell *nslist;
12322  char *relname;
12323  char *nspname;
12324  char *result;
12325 
12326  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12327  if (!HeapTupleIsValid(tp))
12328  elog(ERROR, "cache lookup failed for relation %u", relid);
12329  reltup = (Form_pg_class) GETSTRUCT(tp);
12330  relname = NameStr(reltup->relname);
12331 
12332  /* Check for conflicting CTE name */
12333  need_qual = false;
12334  foreach(nslist, namespaces)
12335  {
12336  deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
12337  ListCell *ctlist;
12338 
12339  foreach(ctlist, dpns->ctes)
12340  {
12341  CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
12342 
12343  if (strcmp(cte->ctename, relname) == 0)
12344  {
12345  need_qual = true;
12346  break;
12347  }
12348  }
12349  if (need_qual)
12350  break;
12351  }
12352 
12353  /* Otherwise, qualify the name if not visible in search path */
12354  if (!need_qual)
12355  need_qual = !RelationIsVisible(relid);
12356 
12357  if (need_qual)
12358  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12359  else
12360  nspname = NULL;
12361 
12362  result = quote_qualified_identifier(nspname, relname);
12363 
12364  ReleaseSysCache(tp);
12365 
12366  return result;
12367 }
bool RelationIsVisible(Oid relid)
Definition: namespace.c:710

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

10338 {
10339  Aggref *aggref;
10340  Aggref *original_aggref = callback_arg;
10341 
10342  if (!IsA(node, Aggref))
10343  elog(ERROR, "combining Aggref does not point to an Aggref");
10344 
10345  aggref = (Aggref *) node;
10346  get_agg_expr(aggref, context, original_aggref);
10347 }
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
Definition: ruleutils.c:10325

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

10326 {
10327  get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10328  false);
10329 }
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:10204

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

10207 {
10208  StringInfo buf = context->buf;
10209  Oid argtypes[FUNC_MAX_ARGS];
10210  int nargs;
10211  bool use_variadic = false;
10212 
10213  /*
10214  * For a combining aggregate, we look up and deparse the corresponding
10215  * partial aggregate instead. This is necessary because our input
10216  * argument list has been replaced; the new argument list always has just
10217  * one element, which will point to a partial Aggref that supplies us with
10218  * transition states to combine.
10219  */
10220  if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10221  {
10222  TargetEntry *tle;
10223 
10224  Assert(list_length(aggref->args) == 1);
10225  tle = linitial_node(TargetEntry, aggref->args);
10226  resolve_special_varno((Node *) tle->expr, context,
10227  get_agg_combine_expr, original_aggref);
10228  return;
10229  }
10230 
10231  /*
10232  * Mark as PARTIAL, if appropriate. We look to the original aggref so as
10233  * to avoid printing this when recursing from the code just above.
10234  */
10235  if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10236  appendStringInfoString(buf, "PARTIAL ");
10237 
10238  /* Extract the argument types as seen by the parser */
10239  nargs = get_aggregate_argtypes(aggref, argtypes);
10240 
10241  if (!funcname)
10242  funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10243  argtypes, aggref->aggvariadic,
10244  &use_variadic,
10245  context->special_exprkind);
10246 
10247  /* Print the aggregate name, schema-qualified if needed */
10248  appendStringInfo(buf, "%s(%s", funcname,
10249  (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10250 
10251  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10252  {
10253  /*
10254  * Ordered-set aggregates do not use "*" syntax. Also, we needn't
10255  * worry about inserting VARIADIC. So we can just dump the direct
10256  * args as-is.
10257  */
10258  Assert(!aggref->aggvariadic);
10259  get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10260  Assert(aggref->aggorder != NIL);
10261  appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10262  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10263  }
10264  else
10265  {
10266  /* aggstar can be set only in zero-argument aggregates */
10267  if (aggref->aggstar)
10268  appendStringInfoChar(buf, '*');
10269  else
10270  {
10271  ListCell *l;
10272  int i;
10273 
10274  i = 0;
10275  foreach(l, aggref->args)
10276  {
10277  TargetEntry *tle = (TargetEntry *) lfirst(l);
10278  Node *arg = (Node *) tle->expr;
10279 
10280  Assert(!IsA(arg, NamedArgExpr));
10281  if (tle->resjunk)
10282  continue;
10283  if (i++ > 0)
10284  {
10285  if (is_json_objectagg)
10286  {
10287  if (i > 2)
10288  break; /* skip ABSENT ON NULL and WITH UNIQUE
10289  * args */
10290 
10291  appendStringInfoString(buf, " : ");
10292  }
10293  else
10294  appendStringInfoString(buf, ", ");
10295  }
10296  if (use_variadic && i == nargs)
10297  appendStringInfoString(buf, "VARIADIC ");
10298  get_rule_expr(arg, context, true);
10299  }
10300  }
10301 
10302  if (aggref->aggorder != NIL)
10303  {
10304  appendStringInfoString(buf, " ORDER BY ");
10305  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10306  }
10307  }
10308 
10309  if (options)
10311 
10312  if (aggref->aggfilter != NULL)
10313  {
10314  appendStringInfoString(buf, ") FILTER (WHERE ");
10315  get_rule_expr((Node *) aggref->aggfilter, context, false);
10316  }
10317 
10318  appendStringInfoChar(buf, ')');
10319 }
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:839
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:838
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1890
#define FUNC_MAX_ARGS
#define linitial_node(type, l)
Definition: pg_list.h:177
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:12418
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:10337
static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6398
static void resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
Definition: ruleutils.c:7365
bool aggstar
Definition: primnodes.h:343
Oid aggfnoid
Definition: primnodes.h:332
List * aggdistinct
Definition: primnodes.h:341
List * aggdirectargs
Definition: primnodes.h:338
bool aggvariadic
Definition: primnodes.h:344
char aggkind
Definition: primnodes.h:346
List * args
Definition: primnodes.h:339
Expr * aggfilter
Definition: primnodes.h:342
List * aggorder
Definition: primnodes.h:340
AggSplit aggsplit
Definition: primnodes.h:348
Expr * expr
Definition: primnodes.h:1716
bool resjunk
Definition: primnodes.h:1723

References Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggkind, Aggref::aggorder, Aggref::aggsplit, Aggref::aggstar, Aggref::aggvariadic, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, Aggref::args, Assert(), deparse_context::buf, buf, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_SKIPFINAL, TargetEntry::expr, FUNC_MAX_ARGS, generate_function_name(), get_agg_combine_expr(), get_aggregate_argtypes(), get_rule_expr(), get_rule_orderby(), i, IsA, lfirst, linitial_node, list_length(), NIL, TargetEntry::resjunk, 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 5877 of file ruleutils.c.

5879 {
5880  StringInfo buf = context->buf;
5881  RangeTblEntry *values_rte;
5882  char *sep;
5883  ListCell *l;
5884 
5885  if (PRETTY_INDENT(context))
5886  {
5887  context->indentLevel += PRETTYINDENT_STD;
5888  appendStringInfoChar(buf, ' ');
5889  }
5890 
5891  /*
5892  * If the query looks like SELECT * FROM (VALUES ...), then print just the
5893  * VALUES part. This reverses what transformValuesClause() did at parse
5894  * time.
5895  */
5896  values_rte = get_simple_values_rte(query, resultDesc);
5897  if (values_rte)
5898  {
5899  get_values_def(values_rte->values_lists, context);
5900  return;
5901  }
5902 
5903  /*
5904  * Build up the query string - first we say SELECT
5905  */
5906  if (query->isReturn)
5907  appendStringInfoString(buf, "RETURN");
5908  else
5909  appendStringInfoString(buf, "SELECT");
5910 
5911  /* Add the DISTINCT clause if given */
5912  if (query->distinctClause != NIL)
5913  {
5914  if (query->hasDistinctOn)
5915  {
5916  appendStringInfoString(buf, " DISTINCT ON (");
5917  sep = "";
5918  foreach(l, query->distinctClause)
5919  {
5920  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5921 
5924  false, context);
5925  sep = ", ";
5926  }
5927  appendStringInfoChar(buf, ')');
5928  }
5929  else
5930  appendStringInfoString(buf, " DISTINCT");
5931  }
5932 
5933  /* Then we tell what to select (the targetlist) */
5934  get_target_list(query->targetList, context, resultDesc, colNamesVisible);
5935 
5936  /* Add the FROM clause if needed */
5937  get_from_clause(query, " FROM ", context);
5938 
5939  /* Add the WHERE clause if given */
5940  if (query->jointree->quals != NULL)
5941  {
5942  appendContextKeyword(context, " WHERE ",
5944  get_rule_expr(query->jointree->quals, context, false);
5945  }
5946 
5947  /* Add the GROUP BY clause if given */
5948  if (query->groupClause != NULL || query->groupingSets != NULL)
5949  {
5950  ParseExprKind save_exprkind;
5951 
5952  appendContextKeyword(context, " GROUP BY ",
5954  if (query->groupDistinct)
5955  appendStringInfoString(buf, "DISTINCT ");
5956 
5957  save_exprkind = context->special_exprkind;
5959 
5960  if (query->groupingSets == NIL)
5961  {
5962  sep = "";
5963  foreach(l, query->groupClause)
5964  {
5965  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
5966 
5969  false, context);
5970  sep = ", ";
5971  }
5972  }
5973  else
5974  {
5975  sep = "";
5976  foreach(l, query->groupingSets)
5977  {
5978  GroupingSet *grp = lfirst(l);
5979 
5981  get_rule_groupingset(grp, query->targetList, true, context);
5982  sep = ", ";
5983  }
5984  }
5985 
5986  context->special_exprkind = save_exprkind;
5987  }
5988 
5989  /* Add the HAVING clause if given */
5990  if (query->havingQual != NULL)
5991  {
5992  appendContextKeyword(context, " HAVING ",
5994  get_rule_expr(query->havingQual, context, false);
5995  }
5996 
5997  /* Add the WINDOW clause if needed */
5998  if (query->windowClause != NIL)
5999  get_rule_windowclause(query, context);
6000 }
ParseExprKind
Definition: parse_node.h:39
static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
Definition: ruleutils.c:8371
static void get_values_def(List *values_lists, deparse_context *context)
Definition: ruleutils.c:5494
static void get_from_clause(Query *query, const char *prefix, deparse_context *context)
Definition: ruleutils.c:11454
static void get_target_list(List *targetList, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6011
static void get_rule_groupingset(GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context)
Definition: ruleutils.c:6338
static Node * get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6281
static void get_rule_windowclause(Query *query, deparse_context *context)
Definition: ruleutils.c:6456
static RangeTblEntry * get_simple_values_rte(Query *query, TupleDesc resultDesc)
Definition: ruleutils.c:5808
Node * quals
Definition: primnodes.h:1826
bool groupDistinct
Definition: parsenodes.h:164
FromExpr * jointree
Definition: parsenodes.h:149
List * groupClause
Definition: parsenodes.h:163
Node * havingQual
Definition: parsenodes.h:168
bool hasDistinctOn
Definition: parsenodes.h:138
List * windowClause
Definition: parsenodes.h:170
List * targetList
Definition: parsenodes.h:155
List * groupingSets
Definition: parsenodes.h:166
bool isReturn
Definition: parsenodes.h:144
List * distinctClause
Definition: parsenodes.h:172
List * values_lists
Definition: parsenodes.h:1120
Index tleSortGroupRef
Definition: parsenodes.h:1305

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::hasDistinctOn, Query::havingQual, deparse_context::indentLevel, Query::isReturn, 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 10720 of file ruleutils.c.

10723 {
10724  StringInfo buf = context->buf;
10725 
10726  /*
10727  * Since parse_coerce.c doesn't immediately collapse application of
10728  * length-coercion functions to constants, what we'll typically see in
10729  * such cases is a Const with typmod -1 and a length-coercion function
10730  * right above it. Avoid generating redundant output. However, beware of
10731  * suppressing casts when the user actually wrote something like
10732  * 'foo'::text::char(3).
10733  *
10734  * Note: it might seem that we are missing the possibility of needing to
10735  * print a COLLATE clause for such a Const. However, a Const could only
10736  * have nondefault collation in a post-constant-folding tree, in which the
10737  * length coercion would have been folded too. See also the special
10738  * handling of CollateExpr in coerce_to_target_type(): any collation
10739  * marking will be above the coercion node, not below it.
10740  */
10741  if (arg && IsA(arg, Const) &&
10742  ((Const *) arg)->consttype == resulttype &&
10743  ((Const *) arg)->consttypmod == -1)
10744  {
10745  /* Show the constant without normal ::typename decoration */
10746  get_const_expr((Const *) arg, context, -1);
10747  }
10748  else
10749  {
10750  if (!PRETTY_PAREN(context))
10751  appendStringInfoChar(buf, '(');
10752  get_rule_expr_paren(arg, context, false, parentNode);
10753  if (!PRETTY_PAREN(context))
10754  appendStringInfoChar(buf, ')');
10755  }
10756 
10757  /*
10758  * Never emit resulttype(arg) functional notation. A pg_proc entry could
10759  * take precedence, and a resulttype in pg_temp would require schema
10760  * qualification that format_type_with_typemod() would usually omit. We've
10761  * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
10762  * would work fine.
10763  */
10764  appendStringInfo(buf, "::%s",
10765  format_type_with_typemod(resulttype, resulttypmod));
10766 }
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:8444
#define PRETTY_PAREN(context)
Definition: ruleutils.c:102
static void get_const_expr(Const *constval, deparse_context *context, int showtype)
Definition: ruleutils.c:10784

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

11890 {
11891  StringInfo buf = context->buf;
11892  int i;
11893  bool first = true;
11894 
11895  /* Don't print aliases if not needed */
11896  if (!colinfo->printaliases)
11897  return;
11898 
11899  for (i = 0; i < colinfo->num_new_cols; i++)
11900  {
11901  char *colname = colinfo->new_colnames[i];
11902 
11903  if (first)
11904  {
11905  appendStringInfoChar(buf, '(');
11906  first = false;
11907  }
11908  else
11909  appendStringInfoString(buf, ", ");
11911  }
11912  if (!first)
11913  appendStringInfoChar(buf, ')');
11914 }

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

10915 {
10916  StringInfo buf = context->buf;
10917 
10918  if (OidIsValid(constval->constcollid))
10919  {
10920  Oid typcollation = get_typcollation(constval->consttype);
10921 
10922  if (constval->constcollid != typcollation)
10923  {
10924  appendStringInfo(buf, " COLLATE %s",
10926  }
10927  }
10928 }
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3013
char * generate_collation_name(Oid collid)
Definition: ruleutils.c:12704
Oid constcollid
Definition: primnodes.h:226
Oid consttype
Definition: primnodes.h:224

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

10785 {
10786  StringInfo buf = context->buf;
10787  Oid typoutput;
10788  bool typIsVarlena;
10789  char *extval;
10790  bool needlabel = false;
10791 
10792  if (constval->constisnull)
10793  {
10794  /*
10795  * Always label the type of a NULL constant to prevent misdecisions
10796  * about type when reparsing.
10797  */
10798  appendStringInfoString(buf, "NULL");
10799  if (showtype >= 0)
10800  {
10801  appendStringInfo(buf, "::%s",
10803  constval->consttypmod));
10804  get_const_collation(constval, context);
10805  }
10806  return;
10807  }
10808 
10809  getTypeOutputInfo(constval->consttype,
10810  &typoutput, &typIsVarlena);
10811 
10812  extval = OidOutputFunctionCall(typoutput, constval->constvalue);
10813 
10814  switch (constval->consttype)
10815  {
10816  case INT4OID:
10817 
10818  /*
10819  * INT4 can be printed without any decoration, unless it is
10820  * negative; in that case print it as '-nnn'::integer to ensure
10821  * that the output will re-parse as a constant, not as a constant
10822  * plus operator. In most cases we could get away with printing
10823  * (-nnn) instead, because of the way that gram.y handles negative
10824  * literals; but that doesn't work for INT_MIN, and it doesn't
10825  * seem that much prettier anyway.
10826  */
10827  if (extval[0] != '-')
10828  appendStringInfoString(buf, extval);
10829  else
10830  {
10831  appendStringInfo(buf, "'%s'", extval);
10832  needlabel = true; /* we must attach a cast */
10833  }
10834  break;
10835 
10836  case NUMERICOID:
10837 
10838  /*
10839  * NUMERIC can be printed without quotes if it looks like a float
10840  * constant (not an integer, and not Infinity or NaN) and doesn't
10841  * have a leading sign (for the same reason as for INT4).
10842  */
10843  if (isdigit((unsigned char) extval[0]) &&
10844  strcspn(extval, "eE.") != strlen(extval))
10845  {
10846  appendStringInfoString(buf, extval);
10847  }
10848  else
10849  {
10850  appendStringInfo(buf, "'%s'", extval);
10851  needlabel = true; /* we must attach a cast */
10852  }
10853  break;
10854 
10855  case BOOLOID:
10856  if (strcmp(extval, "t") == 0)
10857  appendStringInfoString(buf, "true");
10858  else
10859  appendStringInfoString(buf, "false");
10860  break;
10861 
10862  default:
10863  simple_quote_literal(buf, extval);
10864  break;
10865  }
10866 
10867  pfree(extval);
10868 
10869  if (showtype < 0)
10870  return;
10871 
10872  /*
10873  * For showtype == 0, append ::typename unless the constant will be
10874  * implicitly typed as the right type when it is read in.
10875  *
10876  * XXX this code has to be kept in sync with the behavior of the parser,
10877  * especially make_const.
10878  */
10879  switch (constval->consttype)
10880  {
10881  case BOOLOID:
10882  case UNKNOWNOID:
10883  /* These types can be left unlabeled */
10884  needlabel = false;
10885  break;
10886  case INT4OID:
10887  /* We determined above whether a label is needed */
10888  break;
10889  case NUMERICOID:
10890 
10891  /*
10892  * Float-looking constants will be typed as numeric, which we
10893  * checked above; but if there's a nondefault typmod we need to
10894  * show it.
10895  */
10896  needlabel |= (constval->consttypmod >= 0);
10897  break;
10898  default:
10899  needlabel = true;
10900  break;
10901  }
10902  if (needlabel || showtype > 0)
10903  appendStringInfo(buf, "::%s",
10905  constval->consttypmod));
10906 
10907  get_const_collation(constval, context);
10908 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1639
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2864
void pfree(void *pointer)
Definition: mcxt.c:1175
static void simple_quote_literal(StringInfo buf, const char *val)
Definition: ruleutils.c:10934
static void get_const_collation(Const *constval, deparse_context *context)
Definition: ruleutils.c:10914
Datum constvalue
Definition: primnodes.h:228
bool constisnull
Definition: primnodes.h:229
int32 consttypmod
Definition: primnodes.h:225

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

Referenced by get_coercion_expr(), get_json_path_spec(), get_json_table(), get_json_table_nested_columns(), get_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 7020 of file ruleutils.c.

7022 {
7023  StringInfo buf = context->buf;
7024  RangeTblEntry *rte;
7025 
7026  /* Insert the WITH clause if given */
7027  get_with_clause(query, context);
7028 
7029  /*
7030  * Start the query with DELETE FROM relname
7031  */
7032  rte = rt_fetch(query->resultRelation, query->rtable);
7033  Assert(rte->rtekind == RTE_RELATION);
7034  if (PRETTY_INDENT(context))
7035  {
7036  appendStringInfoChar(buf, ' ');
7037  context->indentLevel += PRETTYINDENT_STD;
7038  }
7039  appendStringInfo(buf, "DELETE FROM %s%s",
7040  only_marker(rte),
7042  if (rte->alias != NULL)
7043  appendStringInfo(buf, " %s",
7045 
7046  /* Add the USING clause if given */
7047  get_from_clause(query, " USING ", context);
7048 
7049  /* Add a WHERE clause if given */
7050  if (query->jointree->quals != NULL)
7051  {
7052  appendContextKeyword(context, " WHERE ",
7054  get_rule_expr(query->jointree->quals, context, false);
7055  }
7056 
7057  /* Add RETURNING if present */
7058  if (query->returningList)
7059  {
7060  appendContextKeyword(context, " RETURNING",
7062  get_target_list(query->returningList, context, NULL, colNamesVisible);
7063  }
7064 }
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define only_marker(rte)
Definition: ruleutils.c:512
static void get_with_clause(Query *query, deparse_context *context)
Definition: ruleutils.c:5537
static char * generate_relation_name(Oid relid, List *namespaces)
Definition: ruleutils.c:12316
char * aliasname
Definition: primnodes.h:42
List * returningList
Definition: parsenodes.h:161
List * rtable
Definition: parsenodes.h:148
int resultRelation
Definition: parsenodes.h:131

References RangeTblEntry::alias, Alias::aliasname, appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), Assert(), deparse_context::buf, buf, generate_relation_name(), get_from_clause(), get_rule_expr(), get_target_list(), get_with_clause(), deparse_context::indentLevel, Query::jointree, NIL, only_marker, PRETTY_INDENT, PRETTYINDENT_STD, FromExpr::quals, quote_identifier(), RangeTblEntry::relid, Query::resultRelation, 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 11454 of file ruleutils.c.

11455 {
11456  StringInfo buf = context->buf;
11457  bool first = true;
11458  ListCell *l;
11459 
11460  /*
11461  * We use the query's jointree as a guide to what to print. However, we
11462  * must ignore auto-added RTEs that are marked not inFromCl. (These can
11463  * only appear at the top level of the jointree, so it's sufficient to
11464  * check here.) This check also ensures we ignore the rule pseudo-RTEs
11465  * for NEW and OLD.
11466  */
11467  foreach(l, query->jointree->fromlist)
11468  {
11469  Node *jtnode = (Node *) lfirst(l);
11470 
11471  if (IsA(jtnode, RangeTblRef))
11472  {
11473  int varno = ((RangeTblRef *) jtnode)->rtindex;
11474  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11475 
11476  if (!rte->inFromCl)
11477  continue;
11478  }
11479 
11480  if (first)
11481  {
11482  appendContextKeyword(context, prefix,
11484  first = false;
11485 
11486  get_from_clause_item(jtnode, query, context);
11487  }
11488  else
11489  {
11490  StringInfoData itembuf;
11491 
11492  appendStringInfoString(buf, ", ");
11493 
11494  /*
11495  * Put the new FROM item's text into itembuf so we can decide
11496  * after we've got it whether or not it needs to go on a new line.
11497  */
11498  initStringInfo(&itembuf);
11499  context->buf = &itembuf;
11500 
11501  get_from_clause_item(jtnode, query, context);
11502 
11503  /* Restore context's output buffer */
11504  context->buf = buf;
11505 
11506  /* Consider line-wrapping if enabled */
11507  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
11508  {
11509  /* Does the new item start with a new line? */
11510  if (itembuf.len > 0 && itembuf.data[0] == '\n')
11511  {
11512  /* If so, we shouldn't add anything */
11513  /* instead, remove any trailing spaces currently in buf */
11515  }
11516  else
11517  {
11518  char *trailing_nl;
11519 
11520  /* Locate the start of the current line in the buffer */
11521  trailing_nl = strrchr(buf->data, '\n');
11522  if (trailing_nl == NULL)
11523  trailing_nl = buf->data;
11524  else
11525  trailing_nl++;
11526 
11527  /*
11528  * Add a newline, plus some indentation, if the new item
11529  * would cause an overflow.
11530  */
11531  if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
11532  appendContextKeyword(context, "", -PRETTYINDENT_STD,
11535  }
11536  }
11537 
11538  /* Add the new item */
11539  appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
11540 
11541  /* clean up */
11542  pfree(itembuf.data);
11543  }
11544  }
11545 }
#define PRETTYINDENT_VAR
Definition: ruleutils.c:84
static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
Definition: ruleutils.c:11548
void appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
Definition: stringinfo.c:227
List * fromlist
Definition: primnodes.h:1825

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(), 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 11929 of file ruleutils.c.

11932 {
11933  StringInfo buf = context->buf;
11934  ListCell *l1;
11935  ListCell *l2;
11936  ListCell *l3;
11937  ListCell *l4;
11938  int i;
11939 
11940  appendStringInfoChar(buf, '(');
11941 
11942  i = 0;
11943  forfour(l1, rtfunc->funccoltypes,
11944  l2, rtfunc->funccoltypmods,
11945  l3, rtfunc->funccolcollations,
11946  l4, rtfunc->funccolnames)
11947  {
11948  Oid atttypid = lfirst_oid(l1);
11949  int32 atttypmod = lfirst_int(l2);
11950  Oid attcollation = lfirst_oid(l3);
11951  char *attname;
11952 
11953  if (colinfo)
11954  attname = colinfo->colnames[i];
11955  else
11956  attname = strVal(lfirst(l4));
11957 
11958  Assert(attname); /* shouldn't be any dropped columns here */
11959 
11960  if (i > 0)
11961  appendStringInfoString(buf, ", ");
11962  appendStringInfo(buf, "%s %s",
11964  format_type_with_typemod(atttypid, atttypmod));
11965  if (OidIsValid(attcollation) &&
11966  attcollation != get_typcollation(atttypid))
11967  appendStringInfo(buf, " COLLATE %s",
11968  generate_collation_name(attcollation));
11969 
11970  i++;
11971  }
11972 
11973  appendStringInfoChar(buf, ')');
11974 }
signed int int32
Definition: c.h:429
NameData attname
Definition: pg_attribute.h:41
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:503
#define lfirst_oid(lc)
Definition: pg_list.h:171
List * funccolcollations
Definition: parsenodes.h:1200
List * funccoltypmods
Definition: parsenodes.h:1199
#define strVal(v)
Definition: value.h:72

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), attname, deparse_context::buf, buf, deparse_columns::colnames, forfour, format_type_with_typemod(), RangeTblFunction::funccolcollations, RangeTblFunction::funccolnames, RangeTblFunction::funccoltypes, RangeTblFunction::funccoltypmods, 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 11548 of file ruleutils.c.

11549 {
11550  StringInfo buf = context->buf;
11552 
11553  if (IsA(jtnode, RangeTblRef))
11554  {
11555  int varno = ((RangeTblRef *) jtnode)->rtindex;
11556  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11557  char *refname = get_rtable_name(varno, context);
11558  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
11559  RangeTblFunction *rtfunc1 = NULL;
11560  bool printalias;
11561 
11562  if (rte->lateral)
11563  appendStringInfoString(buf, "LATERAL ");
11564 
11565  /* Print the FROM item proper */
11566  switch (rte->rtekind)
11567  {
11568  case RTE_RELATION:
11569  /* Normal relation RTE */
11570  appendStringInfo(buf, "%s%s",
11571  only_marker(rte),
11573  context->namespaces));
11574  break;
11575  case RTE_SUBQUERY:
11576  /* Subquery RTE */
11577  appendStringInfoChar(buf, '(');
11578  get_query_def(rte->subquery, buf, context->namespaces, NULL,
11579  true,
11580  context->prettyFlags, context->wrapColumn,
11581  context->indentLevel);
11582  appendStringInfoChar(buf, ')');
11583  break;
11584  case RTE_FUNCTION:
11585  /* Function RTE */
11586  rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
11587 
11588  /*
11589  * Omit ROWS FROM() syntax for just one function, unless it
11590  * has both a coldeflist and WITH ORDINALITY. If it has both,
11591  * we must use ROWS FROM() syntax to avoid ambiguity about
11592  * whether the coldeflist includes the ordinality column.
11593  */
11594  if (list_length(rte->functions) == 1 &&
11595  (rtfunc1->funccolnames == NIL || !rte->funcordinality))
11596  {
11597  get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
11598  /* we'll print the coldeflist below, if it has one */
11599  }
11600  else
11601  {
11602  bool all_unnest;
11603  ListCell *lc;
11604 
11605  /*
11606  * If all the function calls in the list are to unnest,
11607  * and none need a coldeflist, then collapse the list back
11608  * down to UNNEST(args). (If we had more than one
11609  * built-in unnest function, this would get more
11610  * difficult.)
11611  *
11612  * XXX This is pretty ugly, since it makes not-terribly-
11613  * future-proof assumptions about what the parser would do
11614  * with the output; but the alternative is to emit our
11615  * nonstandard ROWS FROM() notation for what might have
11616  * been a perfectly spec-compliant multi-argument
11617  * UNNEST().
11618  */
11619  all_unnest = true;
11620  foreach(lc, rte->functions)
11621  {
11622  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11623 
11624  if (!IsA(rtfunc->funcexpr, FuncExpr) ||
11625  ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
11626  rtfunc->funccolnames != NIL)
11627  {
11628  all_unnest = false;
11629  break;
11630  }
11631  }
11632 
11633  if (all_unnest)
11634  {
11635  List *allargs = NIL;
11636 
11637  foreach(lc, rte->functions)
11638  {
11639  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11640  List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
11641 
11642  allargs = list_concat(allargs, args);
11643  }
11644 
11645  appendStringInfoString(buf, "UNNEST(");
11646  get_rule_expr((Node *) allargs, context, true);
11647  appendStringInfoChar(buf, ')');
11648  }
11649  else
11650  {
11651  int funcno = 0;
11652 
11653  appendStringInfoString(buf, "ROWS FROM(");
11654  foreach(lc, rte->functions)
11655  {
11656  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11657 
11658  if (funcno > 0)
11659  appendStringInfoString(buf, ", ");
11660  get_rule_expr_funccall(rtfunc->funcexpr, context, true);
11661  if (rtfunc->funccolnames != NIL)
11662  {
11663  /* Reconstruct the column definition list */
11664  appendStringInfoString(buf, " AS ");
11666  NULL,
11667  context);
11668  }
11669  funcno++;
11670  }
11671  appendStringInfoChar(buf, ')');
11672  }
11673  /* prevent printing duplicate coldeflist below */
11674  rtfunc1 = NULL;
11675  }
11676  if (rte->funcordinality)
11677  appendStringInfoString(buf, " WITH ORDINALITY");
11678  break;
11679  case RTE_TABLEFUNC:
11680  get_tablefunc(rte->tablefunc, context, true);
11681  break;
11682  case RTE_VALUES:
11683  /* Values list RTE */
11684  appendStringInfoChar(buf, '(');
11685  get_values_def(rte->values_lists, context);
11686  appendStringInfoChar(buf, ')');
11687  break;
11688  case RTE_CTE:
11690  break;
11691  default:
11692  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
11693  break;
11694  }
11695 
11696  /* Print the relation alias, if needed */
11697  printalias = false;
11698  if (rte->alias != NULL)
11699  {
11700  /* Always print alias if user provided one */
11701  printalias = true;
11702  }
11703  else if (colinfo->printaliases)
11704  {
11705  /* Always print alias if we need to print column aliases */
11706  printalias = true;
11707  }
11708  else if (rte->rtekind == RTE_RELATION)
11709  {
11710  /*
11711  * No need to print alias if it's same as relation name (this
11712  * would normally be the case, but not if set_rtable_names had to
11713  * resolve a conflict).
11714  */
11715  if (strcmp(refname, get_relation_name(rte->relid)) != 0)
11716  printalias = true;
11717  }
11718  else if (rte->rtekind == RTE_FUNCTION)
11719  {
11720  /*
11721  * For a function RTE, always print alias. This covers possible
11722  * renaming of the function and/or instability of the
11723  * FigureColname rules for things that aren't simple functions.
11724  * Note we'd need to force it anyway for the columndef list case.
11725  */
11726  printalias = true;
11727  }
11728  else if (rte->rtekind == RTE_SUBQUERY ||
11729  rte->rtekind == RTE_VALUES)
11730  {
11731  /* Alias is syntactically required for SUBQUERY and VALUES */
11732  printalias = true;
11733  }
11734  else if (rte->rtekind == RTE_CTE)
11735  {
11736  /*
11737  * No need to print alias if it's same as CTE name (this would
11738  * normally be the case, but not if set_rtable_names had to
11739  * resolve a conflict).
11740  */
11741  if (strcmp(refname, rte->ctename) != 0)
11742  printalias = true;
11743  }
11744  if (printalias)
11745  appendStringInfo(buf, " %s", quote_identifier(refname));
11746 
11747  /* Print the column definitions or aliases, if needed */
11748  if (rtfunc1 && rtfunc1->funccolnames != NIL)
11749  {
11750  /* Reconstruct the columndef list, which is also the aliases */
11751  get_from_clause_coldeflist(rtfunc1, colinfo, context);
11752  }
11753  else
11754  {
11755  /* Else print column aliases as needed */
11756  get_column_alias_list(colinfo, context);
11757  }
11758 
11759  /* Tablesample clause must go after any alias */
11760  if (rte->rtekind == RTE_RELATION && rte->tablesample)
11761  get_tablesample_def(rte->tablesample, context);
11762  }
11763  else if (IsA(jtnode, JoinExpr))
11764  {
11765  JoinExpr *j = (JoinExpr *) jtnode;
11766  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
11767  bool need_paren_on_right;
11768 
11769  need_paren_on_right = PRETTY_PAREN(context) &&
11770  !IsA(j->rarg, RangeTblRef) &&
11771  !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
11772 
11773  if (!PRETTY_PAREN(context) || j->alias != NULL)
11774  appendStringInfoChar(buf, '(');
11775 
11776  get_from_clause_item(j->larg, query, context);
11777 
11778  switch (j->jointype)
11779  {
11780  case JOIN_INNER:
11781  if (j->quals)
11782  appendContextKeyword(context, " JOIN ",
11786  else
11787  appendContextKeyword(context, " CROSS JOIN ",
11791  break;
11792  case JOIN_LEFT:
11793  appendContextKeyword(context, " LEFT JOIN ",
11797  break;
11798  case JOIN_FULL:
11799  appendContextKeyword(context, " FULL JOIN ",
11803  break;
11804  case JOIN_RIGHT:
11805  appendContextKeyword(context, " RIGHT JOIN ",
11809  break;
11810  default:
11811  elog(ERROR, "unrecognized join type: %d",
11812  (int) j->jointype);
11813  }
11814 
11815  if (need_paren_on_right)
11816  appendStringInfoChar(buf, '(');
11817  get_from_clause_item(j->rarg, query, context);
11818  if (need_paren_on_right)
11819  appendStringInfoChar(buf, ')');
11820 
11821  if (j->usingClause)
11822  {
11823  ListCell *lc;
11824  bool first = true;
11825 
11826  appendStringInfoString(buf, " USING (");
11827  /* Use the assigned names, not what's in usingClause */
11828  foreach(lc, colinfo->usingNames)
11829  {
11830  char *colname = (char *) lfirst(lc);
11831 
11832  if (first)
11833  first = false;
11834  else
11835  appendStringInfoString(buf, ", ");
11837  }
11838  appendStringInfoChar(buf, ')');
11839 
11840  if (j->join_using_alias)
11841  appendStringInfo(buf, " AS %s",
11842  quote_identifier(j->join_using_alias->aliasname));
11843  }
11844  else if (j->quals)
11845  {
11846  appendStringInfoString(buf, " ON ");
11847  if (!PRETTY_PAREN(context))
11848  appendStringInfoChar(buf, '(');
11849  get_rule_expr(j->quals, context, false);
11850  if (!PRETTY_PAREN(context))
11851  appendStringInfoChar(buf, ')');
11852  }
11853  else if (j->jointype != JOIN_INNER)
11854  {
11855  /* If we didn't say CROSS JOIN above, we must provide an ON */
11856  appendStringInfoString(buf, " ON TRUE");
11857  }
11858 
11859  if (!PRETTY_PAREN(context) || j->alias != NULL)
11860  appendStringInfoChar(buf, ')');
11861 
11862  /* Yes, it's correct to put alias after the right paren ... */
11863  if (j->alias != NULL)
11864  {
11865  /*
11866  * Note that it's correct to emit an alias clause if and only if
11867  * there was one originally. Otherwise we'd be converting a named
11868  * join to unnamed or vice versa, which creates semantic
11869  * subtleties we don't want. However, we might print a different
11870  * alias name than was there originally.
11871  */
11872  appendStringInfo(buf, " %s",
11874  context)));
11875  get_column_alias_list(colinfo, context);
11876  }
11877  }
11878  else
11879  elog(ERROR, "unrecognized node type: %d",
11880  (int) nodeTag(jtnode));
11881 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:540
#define nodeTag(nodeptr)
Definition: nodes.h:578
@ JOIN_FULL
Definition: nodes.h:751
@ JOIN_INNER
Definition: nodes.h:749
@ JOIN_RIGHT
Definition: nodes.h:752
@ JOIN_LEFT
Definition: nodes.h:750
@ RTE_CTE
Definition: parsenodes.h:1004
@ RTE_VALUES
Definition: parsenodes.h:1003
@ RTE_SUBQUERY
Definition: parsenodes.h:999
@ RTE_FUNCTION
Definition: parsenodes.h:1001
@ RTE_TABLEFUNC
Definition: parsenodes.h:1002
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition: ruleutils.c:4935
#define PRETTYINDENT_JOIN
Definition: ruleutils.c:83
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
Definition: ruleutils.c:5420
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Definition: ruleutils.c:11980
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:11889
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:11929
static void get_rule_expr_funccall(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:9931
#define deparse_columns_fetch(rangetable_index, dpns)
Definition: ruleutils.c:296
static char * get_relation_name(Oid relid)
Definition: ruleutils.c:12296
static void get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11435
Definition: pg_list.h:51
char * ctename
Definition: parsenodes.h:1125
TableFunc * tablefunc
Definition: parsenodes.h:1115
bool funcordinality
Definition: parsenodes.h:1110
struct TableSampleClause * tablesample
Definition: parsenodes.h:1045
Query * subquery
Definition: parsenodes.h:1050
List * functions
Definition: parsenodes.h:1109
List * usingNames
Definition: ruleutils.c:292

References RangeTblEntry::alias, appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), generate_unaccent_rules::args, deparse_context::buf, buf, RangeTblEntry::ctename, deparse_columns_fetch, elog, ERROR, RangeTblFunction::funccolnames, RangeTblFunction::funcexpr, RangeTblEntry::funcordinality, RangeTblEntry::functions, generate_relation_name(), get_column_alias_list(), get_from_clause_coldeflist(), get_query_def(), get_relation_name(), get_rtable_name(), 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, deparse_columns::printaliases, 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 10023 of file ruleutils.c.

10025 {
10026  StringInfo buf = context->buf;
10027  Oid funcoid = expr->funcid;
10028  Oid argtypes[FUNC_MAX_ARGS];
10029  int nargs;
10030  List *argnames;
10031  bool use_variadic;
10032  ListCell *l;
10033 
10034  /*
10035  * If the function call came from an implicit coercion, then just show the
10036  * first argument --- unless caller wants to see implicit coercions.
10037  */
10038  if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
10039  {
10040  get_rule_expr_paren((Node *) linitial(expr->args), context,
10041  false, (Node *) expr);
10042  return;
10043  }
10044 
10045  /*
10046  * If the function call came from a cast, then show the first argument
10047  * plus an explicit cast operation.
10048  */
10049  if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10051  {
10052  Node *arg = linitial(expr->args);
10053  Oid rettype = expr->funcresulttype;
10054  int32 coercedTypmod;
10055 
10056  /* Get the typmod if this is a length-coercion function */
10057  (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10058 
10059  get_coercion_expr(arg, context,
10060  rettype, coercedTypmod,
10061  (Node *) expr);
10062 
10063  return;
10064  }
10065 
10066  /*
10067  * If the function was called using one of the SQL spec's random special
10068  * syntaxes, try to reproduce that. If we don't recognize the function,
10069  * fall through.
10070  */
10071  if (expr->funcformat == COERCE_SQL_SYNTAX)
10072  {
10073  if (get_func_sql_syntax(expr, context))
10074  return;
10075  }
10076 
10077  /*
10078  * Normal function: display as proname(args). First we need to extract
10079  * the argument datatypes.
10080  */
10081  if (list_length(expr->args) > FUNC_MAX_ARGS)
10082  ereport(ERROR,
10083  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10084  errmsg("too many arguments")));
10085  nargs = 0;
10086  argnames = NIL;
10087  foreach(l, expr->args)
10088  {
10089  Node *arg = (Node *) lfirst(l);
10090 
10091  if (IsA(arg, NamedArgExpr))
10092  argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10093  argtypes[nargs] = exprType(arg);
10094  nargs++;
10095  }
10096 
10097  appendStringInfo(buf, "%s(",
10098  generate_function_name(funcoid, nargs,
10099  argnames, argtypes,
10100  expr->funcvariadic,
10101  &use_variadic,
10102  context->special_exprkind));
10103  nargs = 0;
10104  foreach(l, expr->args)
10105  {
10106  if (nargs++ > 0)
10107  appendStringInfoString(buf, ", ");
10108  if (use_variadic && lnext(expr->args, l) == NULL)
10109  appendStringInfoString(buf, "VARIADIC ");
10110  get_rule_expr((Node *) lfirst(l), context, true);
10111  }
10112  appendStringInfoChar(buf, ')');
10113 }
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ereport(elevel,...)
Definition: elog.h:143
List * lappend(List *list, void *datum)
Definition: list.c:336
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:530
@ COERCE_SQL_SYNTAX
Definition: primnodes.h:495
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:494
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:493
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Definition: ruleutils.c:10455
static void get_coercion_expr(Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
Definition: ruleutils.c:10720
Oid funcid
Definition: primnodes.h:504
bool funcvariadic
Definition: primnodes.h:507
List * args
Definition: primnodes.h:512
CoercionForm funcformat
Definition: primnodes.h:509
Oid funcresulttype
Definition: primnodes.h:505

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::funcformat, FuncExpr::funcid, FuncExpr::funcresulttype, FuncExpr::funcvariadic, 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 10455 of file ruleutils.c.

10456 {
10457  StringInfo buf = context->buf;
10458  Oid funcoid = expr->funcid;
10459 
10460  switch (funcoid)
10461  {
10462  case F_TIMEZONE_INTERVAL_TIMESTAMP:
10463  case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
10464  case F_TIMEZONE_INTERVAL_TIMETZ:
10465  case F_TIMEZONE_TEXT_TIMESTAMP:
10466  case F_TIMEZONE_TEXT_TIMESTAMPTZ:
10467  case F_TIMEZONE_TEXT_TIMETZ:
10468  /* AT TIME ZONE ... note reversed argument order */
10469  appendStringInfoChar(buf, '(');
10470  get_rule_expr((Node *) lsecond(expr->args), context, false);
10471  appendStringInfoString(buf, " AT TIME ZONE ");
10472  get_rule_expr((Node *) linitial(expr->args), context, false);
10473  appendStringInfoChar(buf, ')');
10474  return true;
10475 
10476  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
10477  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
10478  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
10479  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
10480  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
10481  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
10482  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
10483  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
10484  case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
10485  case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
10486  case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
10487  case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
10488  case F_OVERLAPS_TIME_TIME_TIME_TIME:
10489  /* (x1, x2) OVERLAPS (y1, y2) */
10490  appendStringInfoString(buf, "((");
10491  get_rule_expr((Node *) linitial(expr->args), context, false);
10492  appendStringInfoString(buf, ", ");
10493  get_rule_expr((Node *) lsecond(expr->args), context, false);
10494  appendStringInfoString(buf, ") OVERLAPS (");
10495  get_rule_expr((Node *) lthird(expr->args), context, false);
10496  appendStringInfoString(buf, ", ");
10497  get_rule_expr((Node *) lfourth(expr->args), context, false);
10498  appendStringInfoString(buf, "))");
10499  return true;
10500 
10501  case F_EXTRACT_TEXT_DATE:
10502  case F_EXTRACT_TEXT_TIME:
10503  case F_EXTRACT_TEXT_TIMETZ:
10504  case F_EXTRACT_TEXT_TIMESTAMP:
10505  case F_EXTRACT_TEXT_TIMESTAMPTZ:
10506  case F_EXTRACT_TEXT_INTERVAL:
10507  /* EXTRACT (x FROM y) */
10508  appendStringInfoString(buf, "EXTRACT(");
10509  {
10510  Const *con = (Const *) linitial(expr->args);
10511 
10512  Assert(IsA(con, Const) &&
10513  con->consttype == TEXTOID &&
10514  !con->constisnull);
10516  }
10517  appendStringInfoString(buf, " FROM ");
10518  get_rule_expr((Node *) lsecond(expr->args), context, false);
10519  appendStringInfoChar(buf, ')');
10520  return true;
10521 
10522  case F_IS_NORMALIZED:
10523  /* IS xxx NORMALIZED */
10524  appendStringInfoString(buf, "((");
10525  get_rule_expr((Node *) linitial(expr->args), context, false);
10526  appendStringInfoString(buf, ") IS");
10527  if (list_length(expr->args) == 2)
10528  {
10529  Const *con = (Const *) lsecond(expr->args);
10530 
10531  Assert(IsA(con, Const) &&
10532  con->consttype == TEXTOID &&
10533  !con->constisnull);
10534  appendStringInfo(buf, " %s",
10536  }
10537  appendStringInfoString(buf, " NORMALIZED)");
10538  return true;
10539 
10540  case F_PG_COLLATION_FOR:
10541  /* COLLATION FOR */
10542  appendStringInfoString(buf, "COLLATION FOR (");
10543  get_rule_expr((Node *) linitial(expr->args), context, false);
10544  appendStringInfoChar(buf, ')');
10545  return true;
10546 
10547  /*
10548  * XXX EXTRACT, a/k/a date_part(), is intentionally not covered
10549  * yet. Add it after we change the return type to numeric.
10550  */
10551 
10552  case F_NORMALIZE:
10553  /* NORMALIZE() */
10554  appendStringInfoString(buf, "NORMALIZE(");
10555  get_rule_expr((Node *) linitial(expr->args), context, false);
10556  if (list_length(expr->args) == 2)
10557  {
10558  Const *con = (Const *) lsecond(expr->args);
10559 
10560  Assert(IsA(con, Const) &&
10561  con->consttype == TEXTOID &&
10562  !con->constisnull);
10563  appendStringInfo(buf, ", %s",
10565  }
10566  appendStringInfoChar(buf, ')');
10567  return true;
10568 
10569  case F_OVERLAY_BIT_BIT_INT4:
10570  case F_OVERLAY_BIT_BIT_INT4_INT4:
10571  case F_OVERLAY_BYTEA_BYTEA_INT4:
10572  case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
10573  case F_OVERLAY_TEXT_TEXT_INT4:
10574  case F_OVERLAY_TEXT_TEXT_INT4_INT4:
10575  /* OVERLAY() */
10576  appendStringInfoString(buf, "OVERLAY(");
10577  get_rule_expr((Node *) linitial(expr->args), context, false);
10578  appendStringInfoString(buf, " PLACING ");
10579  get_rule_expr((Node *) lsecond(expr->args), context, false);
10580  appendStringInfoString(buf, " FROM ");
10581  get_rule_expr((Node *) lthird(expr->args), context, false);
10582  if (list_length(expr->args) == 4)
10583  {
10584  appendStringInfoString(buf, " FOR ");
10585  get_rule_expr((Node *) lfourth(expr->args), context, false);
10586  }
10587  appendStringInfoChar(buf, ')');
10588  return true;
10589 
10590  case F_POSITION_BIT_BIT:
10591  case F_POSITION_BYTEA_BYTEA:
10592  case F_POSITION_TEXT_TEXT:
10593  /* POSITION() ... extra parens since args are b_expr not a_expr */
10594  appendStringInfoString(buf, "POSITION((");
10595  get_rule_expr((Node *) lsecond(expr->args), context, false);
10596  appendStringInfoString(buf, ") IN (");
10597  get_rule_expr((Node *) linitial(expr->args), context, false);
10598  appendStringInfoString(buf, "))");
10599  return true;
10600 
10601  case F_SUBSTRING_BIT_INT4:
10602  case F_SUBSTRING_BIT_INT4_INT4:
10603  case F_SUBSTRING_BYTEA_INT4:
10604  case F_SUBSTRING_BYTEA_INT4_INT4:
10605  case F_SUBSTRING_TEXT_INT4:
10606  case F_SUBSTRING_TEXT_INT4_INT4:
10607  /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
10608  appendStringInfoString(buf, "SUBSTRING(");
10609  get_rule_expr((Node *) linitial(expr->args), context, false);
10610  appendStringInfoString(buf, " FROM ");
10611  get_rule_expr((Node *) lsecond(expr->args), context, false);
10612  if (list_length(expr->args) == 3)
10613  {
10614  appendStringInfoString(buf, " FOR ");
10615  get_rule_expr((Node *) lthird(expr->args), context, false);
10616  }
10617  appendStringInfoChar(buf, ')');
10618  return true;
10619 
10620  case F_SUBSTRING_TEXT_TEXT_TEXT:
10621  /* SUBSTRING SIMILAR/ESCAPE */
10622  appendStringInfoString(buf, "SUBSTRING(");
10623  get_rule_expr((Node *) linitial(expr->args), context, false);
10624  appendStringInfoString(buf, " SIMILAR ");
10625  get_rule_expr((Node *) lsecond(expr->args), context, false);
10626  appendStringInfoString(buf, " ESCAPE ");
10627  get_rule_expr((Node *) lthird(expr->args), context, false);
10628  appendStringInfoChar(buf, ')');
10629  return true;
10630 
10631  case F_BTRIM_BYTEA_BYTEA:
10632  case F_BTRIM_TEXT:
10633  case F_BTRIM_TEXT_TEXT:
10634  /* TRIM() */
10635  appendStringInfoString(buf, "TRIM(BOTH");
10636  if (list_length(expr->args) == 2)
10637  {
10638  appendStringInfoChar(buf, ' ');
10639  get_rule_expr((Node *) lsecond(expr->args), context, false);
10640  }
10641  appendStringInfoString(buf, " FROM ");
10642  get_rule_expr((Node *) linitial(expr->args), context, false);
10643  appendStringInfoChar(buf, ')');
10644  return true;
10645 
10646  case F_LTRIM_BYTEA_BYTEA:
10647  case F_LTRIM_TEXT:
10648  case F_LTRIM_TEXT_TEXT:
10649  /* TRIM() */
10650  appendStringInfoString(buf, "TRIM(LEADING");
10651  if (list_length(expr->args) == 2)
10652  {
10653  appendStringInfoChar(buf, ' ');
10654  get_rule_expr((Node *) lsecond(expr->args), context, false);
10655  }
10656  appendStringInfoString(buf, " FROM ");
10657  get_rule_expr((Node *) linitial(expr->args), context, false);
10658  appendStringInfoChar(buf, ')');
10659  return true;
10660 
10661  case F_RTRIM_BYTEA_BYTEA:
10662  case F_RTRIM_TEXT:
10663  case F_RTRIM_TEXT_TEXT:
10664  /* TRIM() */
10665  appendStringInfoString(buf, "TRIM(TRAILING");
10666  if (list_length(expr->args) == 2)
10667  {
10668  appendStringInfoChar(buf, ' ');
10669  get_rule_expr((Node *) lsecond(expr->args), context, false);
10670  }
10671  appendStringInfoString(buf, " FROM ");
10672  get_rule_expr((Node *) linitial(expr->args), context, false);
10673  appendStringInfoChar(buf, ')');
10674  return true;
10675 
10676  case F_XMLEXISTS:
10677  /* XMLEXISTS ... extra parens because args are c_expr */
10678  appendStringInfoString(buf, "XMLEXISTS((");
10679  get_rule_expr((Node *) linitial(expr->args), context, false);
10680  appendStringInfoString(buf, ") PASSING (");
10681  get_rule_expr((Node *) lsecond(expr->args), context, false);
10682  appendStringInfoString(buf, "))");
10683  return true;
10684  }
10685  return false;
10686 }
#define TextDatumGetCString(d)
Definition: builtins.h:86
#define lthird(l)
Definition: pg_list.h:184
#define lsecond(l)
Definition: pg_list.h:179
#define lfourth(l)
Definition: pg_list.h:189

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), FuncExpr::args, Assert(), deparse_context::buf, buf, Const::constisnull, Const::consttype, Const::constvalue, FuncExpr::funcid, get_rule_expr(), 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 6597 of file ruleutils.c.

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

References OnConflictExpr::action, RangeTblEntry::alias, Alias::aliasname, 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_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, Query::override, OVERRIDING_SYSTEM_VALUE, OVERRIDING_USER_VALUE, PRETTY_INDENT, deparse_context::prettyFlags, PRETTYINDENT_STD, processIndirection(), quote_identifier(), RangeTblEntry::relid, TargetEntry::resjunk, TargetEntry::resno, Query::resultRelation, 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 10692 of file ruleutils.c.

10694 {
10696 
10699 
10700  if (IsA(ctor->func, Aggref))
10701  get_agg_expr_helper((Aggref *) ctor->func, context,
10702  (Aggref *) ctor->func,
10703  funcname, options.data, is_json_objectagg);
10704  else if (IsA(ctor->func, WindowFunc))
10705  get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
10706  funcname, options.data,
10707  is_json_objectagg);
10708  else
10709  elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
10710  nodeTag(ctor->func));
10711 }
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:10353
static void get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
Definition: ruleutils.c:10116

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

Referenced by get_json_constructor().

◆ get_json_behavior()

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

Definition at line 8518 of file ruleutils.c.

8520 {
8521  /*
8522  * The order of array elements must correspond to the order of
8523  * JsonBehaviorType members.
8524  */
8525  const char *behavior_names[] =
8526  {
8527  " NULL",
8528  " ERROR",
8529  " EMPTY",
8530  " TRUE",
8531  " FALSE",
8532  " UNKNOWN",
8533  " EMPTY ARRAY",
8534  " EMPTY OBJECT",
8535  " DEFAULT "
8536  };
8537 
8538  if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
8539  elog(ERROR, "invalid json behavior type: %d", behavior->btype);
8540 
8541  appendStringInfoString(context->buf, behavior_names[behavior->btype]);
8542 
8543  if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
8544  get_rule_expr(behavior->default_expr, context, false);
8545 
8546  appendStringInfo(context->buf, " ON %s", on);
8547 }
#define lengthof(array)
Definition: c.h:734
@ JSON_BEHAVIOR_DEFAULT
Definition: primnodes.h:1298
JsonBehaviorType btype
Definition: primnodes.h:1409
Node * default_expr
Definition: primnodes.h:1410

References appendStringInfo(), appendStringInfoString(), JsonBehavior::btype, deparse_context::buf, JsonBehavior::default_expr, elog, ERROR, get_rule_expr(), JSON_BEHAVIOR_DEFAULT, and lengthof.

Referenced by get_json_expr_options(), and get_json_table().

◆ get_json_constructor()

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

Definition at line 10141 of file ruleutils.c.

10143 {
10144  StringInfo buf = context->buf;
10145  const char *funcname;
10146  int nargs;
10147  ListCell *lc;
10148 
10149  switch (ctor->type)
10150  {
10151  case JSCTOR_JSON_PARSE:
10152  funcname = "JSON";
10153  break;
10154  case JSCTOR_JSON_SCALAR:
10155  funcname = "JSON_SCALAR";
10156  break;
10157  case JSCTOR_JSON_SERIALIZE:
10158  funcname = "JSON_SERIALIZE";
10159  break;
10160  case JSCTOR_JSON_OBJECT:
10161  funcname = "JSON_OBJECT";
10162  break;
10163  case JSCTOR_JSON_ARRAY:
10164  funcname = "JSON_ARRAY";
10165  break;
10166  case JSCTOR_JSON_OBJECTAGG:
10167  get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
10168  return;
10169  case JSCTOR_JSON_ARRAYAGG:
10170  get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
10171  return;
10172  default:
10173  elog(ERROR, "invalid JsonConstructorExprType %d", ctor->type);
10174  }
10175 
10176  appendStringInfo(buf, "%s(", funcname);
10177 
10178  nargs = 0;
10179  foreach(lc, ctor->args)
10180  {
10181  if (nargs > 0)
10182  {
10183  const char *sep = ctor->type == JSCTOR_JSON_OBJECT &&
10184  (nargs % 2) != 0 ? " : " : ", ";
10185 
10187  }
10188 
10189  get_rule_expr((Node *) lfirst(lc), context, true);
10190 
10191  nargs++;
10192  }
10193 
10195 
10196  appendStringInfo(buf, ")");
10197 }
@ JSCTOR_JSON_SERIALIZE
Definition: primnodes.h:1355
@ JSCTOR_JSON_ARRAYAGG
Definition: primnodes.h:1353
@ JSCTOR_JSON_PARSE
Definition: primnodes.h:1356
@ JSCTOR_JSON_OBJECT
Definition: primnodes.h:1350
@ JSCTOR_JSON_SCALAR
Definition: primnodes.h:1354
@ JSCTOR_JSON_ARRAY
Definition: primnodes.h:1351
@ JSCTOR_JSON_OBJECTAGG
Definition: primnodes.h:1352
static void get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
Definition: ruleutils.c:10692
JsonConstructorType type
Definition: primnodes.h:1366

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

10117 {
10118  if (ctor->absent_on_null)
10119  {
10120  if (ctor->type == JSCTOR_JSON_OBJECT ||
10121  ctor->type == JSCTOR_JSON_OBJECTAGG)
10122  appendStringInfoString(buf, " ABSENT ON NULL");
10123  }
10124  else
10125  {
10126  if (ctor->type == JSCTOR_JSON_ARRAY ||
10127  ctor->type == JSCTOR_JSON_ARRAYAGG)
10128  appendStringInfoString(buf, " NULL ON NULL");
10129  }
10130 
10131  if (ctor->unique)
10132  appendStringInfoString(buf, " WITH UNIQUE KEYS");
10133 
10134  if (!((ctor->type == JSCTOR_JSON_PARSE ||
10135  ctor->type == JSCTOR_JSON_SCALAR) &&
10136  ctor->returning->typid == JSONOID))
10137  get_json_returning(ctor->returning, buf, true);
10138 }
static void get_json_returning(JsonReturning *returning, StringInfo buf, bool json_format_by_default)
Definition: ruleutils.c:8501
JsonReturning * returning
Definition: primnodes.h:1370

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, JsonReturning::typid, and JsonConstructorExpr::unique.

Referenced by get_json_agg_constructor(), and get_json_constructor().

◆ get_json_expr_options()

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

Definition at line 8556 of file ruleutils.c.

8558 {
8559  if (jsexpr->op == JSON_QUERY_OP)
8560  {
8561  if (jsexpr->wrapper == JSW_CONDITIONAL)
8562  appendStringInfo(context->buf, " WITH CONDITIONAL WRAPPER");
8563  else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
8564  appendStringInfo(context->buf, " WITH UNCONDITIONAL WRAPPER");
8565 
8566  if (jsexpr->omit_quotes)
8567  appendStringInfo(context->buf, " OMIT QUOTES");
8568  }
8569 
8570  if (jsexpr->op != JSON_EXISTS_OP &&
8571  jsexpr->on_empty->btype != default_behavior)
8572  get_json_behavior(jsexpr->on_empty, context, "EMPTY");
8573 
8574  if (jsexpr->on_error->btype != default_behavior)
8575  get_json_behavior(jsexpr->on_error, context, "ERROR");
8576 }
@ JSW_UNCONDITIONAL
Definition: primnodes.h:1309
@ JSW_CONDITIONAL
Definition: primnodes.h:1308
@ JSON_QUERY_OP
Definition: primnodes.h:1252
@ JSON_EXISTS_OP
Definition: primnodes.h:1253
static void get_json_behavior(JsonBehavior *behavior, deparse_context *context, const char *on)
Definition: ruleutils.c:8518
JsonBehavior * on_empty
Definition: primnodes.h:1461
JsonWrapper wrapper
Definition: primnodes.h:1464
JsonExprOp op
Definition: primnodes.h:1453
JsonBehavior * on_error
Definition: primnodes.h:1462
bool omit_quotes
Definition: primnodes.h:1465

References appendStringInfo(), JsonBehavior::btype, deparse_context::buf, get_json_behavior(), JSON_EXISTS_OP, JSON_QUERY_OP, JSW_CONDITIONAL, JSW_UNCONDITIONAL, JsonExpr::omit_quotes, JsonExpr::on_empty, JsonExpr::on_error, JsonExpr::op, and JsonExpr::wrapper.

Referenced by get_json_table_columns(), and get_rule_expr().

◆ get_json_format()

static void get_json_format ( JsonFormat format,
StringInfo  buf 
)
static

Definition at line 8478 of file ruleutils.c.

8479 {
8480  if (format->format_type == JS_FORMAT_DEFAULT)
8481  return;
8482 
8484  format->format_type == JS_FORMAT_JSONB ?
8485  " FORMAT JSONB" : " FORMAT JSON");
8486 
8487  if (format->encoding != JS_ENC_DEFAULT)
8488  {
8489  const char *encoding =
8490  format->encoding == JS_ENC_UTF16 ? "UTF16" :
8491  format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
8492 
8493  appendStringInfo(buf, " ENCODING %s", encoding);
8494  }
8495 }
static char format
int32 encoding
Definition: pg_database.h:41
@ JS_FORMAT_JSONB
Definition: primnodes.h:1277
@ JS_FORMAT_DEFAULT
Definition: primnodes.h:1275
@ JS_ENC_DEFAULT
Definition: primnodes.h:1263
@ JS_ENC_UTF32
Definition: primnodes.h:1266
@ JS_ENC_UTF16
Definition: primnodes.h:1265

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

Referenced by get_json_returning(), and get_rule_expr().

◆ get_json_path_spec()

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

Definition at line 8466 of file ruleutils.c.

8467 {
8468  if (IsA(path_spec, Const))
8469  get_const_expr((Const *) path_spec, context, -1);
8470  else
8471  get_rule_expr(path_spec, context, showimplicit);
8472 }

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

Referenced by get_json_table_columns(), and get_rule_expr().

◆ get_json_returning()

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

Definition at line 8501 of file ruleutils.c.

8503 {
8504  if (!OidIsValid(returning->typid))
8505  return;
8506 
8507  appendStringInfo(buf, " RETURNING %s",
8508  format_type_with_typemod(returning->typid,
8509  returning->typmod));
8510 
8511  if (!json_format_by_default ||
8512  returning->format->format_type !=
8513  (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
8514  get_json_format(returning->format, buf);
8515 }
@ JS_FORMAT_JSON
Definition: primnodes.h:1276
static void get_json_format(JsonFormat *format, StringInfo buf)
Definition: ruleutils.c:8478
JsonFormatType format_type
Definition: primnodes.h:1319
JsonFormat * format
Definition: primnodes.h:1331

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

Referenced by get_json_constructor_options(), and get_rule_expr().

◆ get_json_table()

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

Definition at line 11363 of file ruleutils.c.

11364 {
11365  StringInfo buf = context->buf;
11366  JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
11368 
11369  appendStringInfoString(buf, "JSON_TABLE(");
11370 
11371  if (PRETTY_INDENT(context))
11372  context->indentLevel += PRETTYINDENT_VAR;
11373 
11374  appendContextKeyword(context, "", 0, 0, 0);
11375 
11376  get_rule_expr(jexpr->formatted_expr, context, showimplicit);
11377 
11378  appendStringInfoString(buf, ", ");
11379 
11380  get_const_expr(root->path, context, -1);
11381 
11382  appendStringInfo(buf, " AS %s", quote_identifier(root->name));
11383 
11384  if (jexpr->passing_values)
11385  {
11386  ListCell *lc1,
11387  *lc2;
11388  bool needcomma = false;
11389 
11390  appendStringInfoChar(buf, ' ');
11391  appendContextKeyword(context, "PASSING ", 0, 0, 0);
11392 
11393  if (PRETTY_INDENT(context))
11394  context->indentLevel += PRETTYINDENT_VAR;
11395 
11396  forboth(lc1, jexpr->passing_names,
11397  lc2, jexpr->passing_values)
11398  {
11399  if (needcomma)
11400  appendStringInfoString(buf, ", ");
11401  needcomma = true;
11402 
11403  appendContextKeyword(context, "", 0, 0, 0);
11404 
11405  get_rule_expr((Node *) lfirst(lc2), context, false);
11406  appendStringInfo(buf, " AS %s",
11407  quote_identifier((lfirst_node(String, lc1))->sval)
11408  );
11409  }
11410 
11411  if (PRETTY_INDENT(context))
11412  context->indentLevel -= PRETTYINDENT_VAR;
11413  }
11414 
11415  get_json_table_columns(tf, root, context, showimplicit);
11416 
11417  appendStringInfoChar(buf, ' ');
11418  appendContextKeyword(context, "PLAN ", 0, 0, 0);
11419  get_json_table_plan(tf, (Node *) root, context, true);
11420 
11421  if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY)
11422  get_json_behavior(jexpr->on_error, context, "ERROR");
11423 
11424  if (PRETTY_INDENT(context))
11425  context->indentLevel -= PRETTYINDENT_VAR;
11426 
11427  appendContextKeyword(context, ")", 0, 0, 0);
11428 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:642
@ JSON_BEHAVIOR_EMPTY
Definition: primnodes.h:1292
static void get_json_table_plan(TableFunc *tf, Node *node, deparse_context *context, bool parenthesize)
Definition: ruleutils.c:11215
static void get_json_table_columns(TableFunc *tf, JsonTableParent *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11258
Node * formatted_expr
Definition: primnodes.h:1454
List * passing_values
Definition: primnodes.h:1459
List * passing_names
Definition: primnodes.h:1458
Definition: value.h:58
Node * docexpr
Definition: primnodes.h:94
Node * plan
Definition: primnodes.h:104

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), JsonBehavior::btype, deparse_context::buf, buf, castNode, TableFunc::docexpr, forboth, JsonExpr::formatted_expr, get_const_expr(), get_json_behavior(), get_json_table_columns(), get_json_table_plan(), get_rule_expr(), deparse_context::indentLevel, JSON_BEHAVIOR_EMPTY, lfirst, lfirst_node, JsonTableParent::name, JsonExpr::on_error, JsonExpr::passing_names, JsonExpr::passing_values, JsonTableParent::path, TableFunc::plan, PRETTY_INDENT, PRETTYINDENT_VAR, and quote_identifier().

Referenced by get_tablefunc().

◆ get_json_table_columns()

static void get_json_table_columns ( TableFunc tf,
JsonTableParent node,
deparse_context context,
bool  showimplicit 
)
static

Definition at line 11258 of file ruleutils.c.

11260 {
11261  StringInfo buf = context->buf;
11262  JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
11263  ListCell *lc_colname;
11264  ListCell *lc_coltype;
11265  ListCell *lc_coltypmod;
11266  ListCell *lc_colvarexpr;
11267  int colnum = 0;
11268 
11269  appendStringInfoChar(buf, ' ');
11270  appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
11271 
11272  if (PRETTY_INDENT(context))
11273  context->indentLevel += PRETTYINDENT_VAR;
11274 
11275  forfour(lc_colname, tf->colnames,
11276  lc_coltype, tf->coltypes,
11277  lc_coltypmod, tf->coltypmods,
11278  lc_colvarexpr, tf->colvalexprs)
11279  {
11280  char *colname = strVal(lfirst(lc_colname));
11281  JsonExpr *colexpr;
11282  Oid typid;
11283  int32 typmod;
11284  bool ordinality;
11285  JsonBehaviorType default_behavior;
11286 
11287  typid = lfirst_oid(lc_coltype);
11288  typmod = lfirst_int(lc_coltypmod);
11289  colexpr = castNode(JsonExpr, lfirst(lc_colvarexpr));
11290 
11291  if (colnum < node->colMin)
11292  {
11293  colnum++;
11294  continue;
11295  }
11296 
11297  if (colnum > node->colMax)
11298  break;
11299 
11300  if (colnum > node->colMin)
11301  appendStringInfoString(buf, ", ");
11302 
11303  colnum++;
11304 
11305  ordinality = !colexpr;
11306 
11307  appendContextKeyword(context, "", 0, 0, 0);
11308 
11309  appendStringInfo(buf, "%s %s", quote_identifier(colname),
11310  ordinality ? "FOR ORDINALITY" :
11311  format_type_with_typemod(typid, typmod));
11312  if (ordinality)
11313  continue;
11314 
11315  if (colexpr->op == JSON_EXISTS_OP)
11316  {
11317  appendStringInfoString(buf, " EXISTS");
11318  default_behavior = JSON_BEHAVIOR_FALSE;
11319  }
11320  else
11321  {
11322  if (colexpr->op == JSON_QUERY_OP)
11323  {
11324  char typcategory;
11325  bool typispreferred;
11326 
11327  get_type_category_preferred(typid, &typcategory, &typispreferred);
11328 
11329  if (typcategory == TYPCATEGORY_STRING)
11331  colexpr->format->format_type == JS_FORMAT_JSONB ?
11332  " FORMAT JSONB" : " FORMAT JSON");
11333  }
11334 
11335  default_behavior = JSON_BEHAVIOR_NULL;
11336  }
11337 
11338  if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
11339  default_behavior = JSON_BEHAVIOR_ERROR;
11340 
11341  appendStringInfoString(buf, " PATH ");
11342 
11343  get_json_path_spec(colexpr->path_spec, context, showimplicit);
11344 
11345  get_json_expr_options(colexpr, context, default_behavior);
11346  }
11347 
11348  if (node->child)
11349  get_json_table_nested_columns(tf, node->child, context, showimplicit,
11350  node->colMax >= node->colMin);
11351 
11352  if (PRETTY_INDENT(context))
11353  context->indentLevel -= PRETTYINDENT_VAR;
11354 
11355  appendContextKeyword(context, ")", 0, 0, 0);
11356 }
void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
Definition: lsyscache.c:2667
JsonBehaviorType
Definition: primnodes.h:1289
@ JSON_BEHAVIOR_ERROR
Definition: primnodes.h:1291
@ JSON_BEHAVIOR_FALSE
Definition: primnodes.h:1294
@ JSON_BEHAVIOR_NULL
Definition: primnodes.h:1290
static void get_json_table_nested_columns(TableFunc *tf, Node *node, deparse_context *context, bool showimplicit, bool needcomma)
Definition: ruleutils.c:11184
static void get_json_expr_options(JsonExpr *jsexpr, deparse_context *context, JsonBehaviorType default_behavior)
Definition: ruleutils.c:8556
static void get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:8466
JsonFormat * format
Definition: primnodes.h:1456
Node * path_spec
Definition: primnodes.h:1457
List * colvalexprs
Definition: primnodes.h:102
List * coltypmods
Definition: primnodes.h:98
List * coltypes
Definition: primnodes.h:97
List * colnames
Definition: primnodes.h:96

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

Referenced by get_json_table(), and get_json_table_nested_columns().

◆ get_json_table_nested_columns()

static void get_json_table_nested_columns ( TableFunc tf,
Node node,
deparse_context context,
bool  showimplicit,
bool  needcomma 
)
static

Definition at line 11184 of file ruleutils.c.

11187 {
11188  if (IsA(node, JsonTableSibling))
11189  {
11190  JsonTableSibling *n = (JsonTableSibling *) node;
11191 
11192  get_json_table_nested_columns(tf, n->larg, context, showimplicit,
11193  needcomma);
11194  get_json_table_nested_columns(tf, n->rarg, context, showimplicit, true);
11195  }
11196  else
11197  {
11199 
11200  if (needcomma)
11201  appendStringInfoChar(context->buf, ',');
11202 
11203  appendStringInfoChar(context->buf, ' ');
11204  appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
11205  get_const_expr(n->path, context, -1);
11206  appendStringInfo(context->buf, " AS %s", quote_identifier(n->name));
11207  get_json_table_columns(tf, n, context, showimplicit);
11208  }
11209 }

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), deparse_context::buf, castNode, get_const_expr(), get_json_table_columns(), IsA, JsonTableSibling::larg, JsonTableParent::name, JsonTableParent::path, quote_identifier(), and JsonTableSibling::rarg.

Referenced by get_json_table_columns().

◆ get_json_table_plan()

static void get_json_table_plan ( TableFunc tf,
Node node,
deparse_context context,
bool  parenthesize 
)
static

Definition at line 11215 of file ruleutils.c.

11217 {
11218  if (parenthesize)
11219  appendStringInfoChar(context->buf, '(');
11220 
11221  if (IsA(node, JsonTableSibling))
11222  {
11223  JsonTableSibling *n = (JsonTableSibling *) node;
11224 
11225  get_json_table_plan(tf, n->larg, context,
11226  IsA(n->larg, JsonTableSibling) ||
11227  castNode(JsonTableParent, n->larg)->child);
11228 
11229  appendStringInfoString(context->buf, n->cross ? " CROSS " : " UNION ");
11230 
11231  get_json_table_plan(tf, n->rarg, context,
11232  IsA(n->rarg, JsonTableSibling) ||
11233  castNode(JsonTableParent, n->rarg)->child);
11234  }
11235  else
11236  {
11238 
11240 
11241  if (n->child)
11242  {
11243  appendStringInfoString(context->buf,
11244  n->outerJoin ? " OUTER " : " INNER ");
11245  get_json_table_plan(tf, n->child, context,
11246  IsA(n->child, JsonTableSibling));
11247  }
11248  }
11249 
11250  if (parenthesize)
11251  appendStringInfoChar(context->buf, ')');
11252 }

References appendStringInfoChar(), appendStringInfoString(), deparse_context::buf, castNode, JsonTableParent::child, JsonTableSibling::cross, IsA, JsonTableSibling::larg, JsonTableParent::name, JsonTableParent::outerJoin, quote_identifier(), and JsonTableSibling::rarg.

Referenced by get_json_table().

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

7475 {
7476  RangeTblEntry *rte;
7478  int netlevelsup;
7479  deparse_namespace *dpns;
7480  int varno;
7481  AttrNumber varattno;
7482  TupleDesc tupleDesc;
7483  Node *expr;
7484 
7485  /*
7486  * If it's a RowExpr that was expanded from a whole-row Var, use the
7487  * column names attached to it.
7488  */
7489  if (IsA(var, RowExpr))
7490  {
7491  RowExpr *r = (RowExpr *) var;
7492 
7493  if (fieldno > 0 && fieldno <= list_length(r->colnames))
7494  return strVal(list_nth(r->colnames, fieldno - 1));
7495  }
7496 
7497  /*
7498  * If it's a Param of type RECORD, try to find what the Param refers to.
7499  */
7500  if (IsA(var, Param))
7501  {
7502  Param *param = (Param *) var;
7503  ListCell *ancestor_cell;
7504 
7505  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7506  if (expr)
7507  {
7508  /* Found a match, so recurse to decipher the field name */
7509  deparse_namespace save_dpns;
7510  const char *result;
7511 
7512  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7513  result = get_name_for_var_field((Var *) expr, fieldno,
7514  0, context);
7515  pop_ancestor_plan(dpns, &save_dpns);
7516  return result;
7517  }
7518  }
7519 
7520  /*
7521  * If it's a Var of type RECORD, we have to find what the Var refers to;
7522  * if not, we can use get_expr_result_tupdesc().
7523  */
7524  if (!IsA(var, Var) ||
7525  var->vartype != RECORDOID)
7526  {
7527  tupleDesc = get_expr_result_tupdesc((Node *) var, false);
7528  /* Got the tupdesc, so we can extract the field name */
7529  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7530  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7531  }
7532 
7533  /* Find appropriate nesting depth */
7534  netlevelsup = var->varlevelsup + levelsup;
7535  if (netlevelsup >= list_length(context->namespaces))
7536  elog(ERROR, "bogus varlevelsup: %d offset %d",
7537  var->varlevelsup, levelsup);
7538  dpns = (deparse_namespace *) list_nth(context->namespaces,
7539  netlevelsup);
7540 
7541  /*
7542  * If we have a syntactic referent for the Var, and we're working from a
7543  * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7544  * on the semantic referent. (See comments in get_variable().)
7545  */
7546  if (var->varnosyn > 0 && dpns->plan == NULL)
7547  {
7548  varno = var->varnosyn;
7549  varattno = var->varattnosyn;
7550  }
7551  else
7552  {
7553  varno = var->varno;
7554  varattno = var->varattno;
7555  }
7556 
7557  /*
7558  * Try to find the relevant RTE in this rtable. In a plan tree, it's
7559  * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7560  * down into the subplans, or INDEX_VAR, which is resolved similarly.
7561  *
7562  * Note: unlike get_variable and resolve_special_varno, we need not worry
7563  * about inheritance mapping: a child Var should have the same datatype as
7564  * its parent, and here we're really only interested in the Var's type.
7565  */
7566  if (varno >= 1 && varno <= list_length(dpns->rtable))
7567  {
7568  rte = rt_fetch(varno, dpns->rtable);
7569  attnum = varattno;
7570  }
7571  else if (varno == OUTER_VAR && dpns->outer_tlist)
7572  {
7573  TargetEntry *tle;
7574  deparse_namespace save_dpns;
7575  const char *result;
7576 
7577  tle = get_tle_by_resno(dpns->outer_tlist, varattno);
7578  if (!tle)
7579  elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
7580 
7581  Assert(netlevelsup == 0);
7582  push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7583 
7584  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7585  levelsup, context);
7586 
7587  pop_child_plan(dpns, &save_dpns);
7588  return result;
7589  }
7590  else if (varno == INNER_VAR && dpns->inner_tlist)
7591  {
7592  TargetEntry *tle;
7593  deparse_namespace save_dpns;
7594  const char *result;
7595 
7596  tle = get_tle_by_resno(dpns->inner_tlist, varattno);
7597  if (!tle)
7598  elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
7599 
7600  Assert(netlevelsup == 0);
7601  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7602 
7603  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7604  levelsup, context);
7605 
7606  pop_child_plan(dpns, &save_dpns);
7607  return result;
7608  }
7609  else if (varno == INDEX_VAR && dpns->index_tlist)
7610  {
7611  TargetEntry *tle;
7612  const char *result;
7613 
7614  tle = get_tle_by_resno(dpns->index_tlist, varattno);
7615  if (!tle)
7616  elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
7617 
7618  Assert(netlevelsup == 0);
7619 
7620  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7621  levelsup, context);
7622 
7623  return result;
7624  }
7625  else
7626  {
7627  elog(ERROR, "bogus varno: %d", varno);
7628  return NULL; /* keep compiler quiet */
7629  }
7630 
7631  if (attnum == InvalidAttrNumber)
7632  {
7633  /* Var is whole-row reference to RTE, so select the right field */
7634  return get_rte_attribute_name(rte, fieldno);
7635  }
7636 
7637  /*
7638  * This part has essentially the same logic as the parser's
7639  * expandRecordVariable() function, but we are dealing with a different
7640  * representation of the input context, and we only need one field name
7641  * not a TupleDesc. Also, we need special cases for finding subquery and
7642  * CTE subplans when deparsing Plan trees.
7643  */
7644  expr = (Node *) var; /* default if we can't drill down */
7645 
7646  switch (rte->rtekind)
7647  {
7648  case RTE_RELATION:
7649  case RTE_VALUES:
7650  case RTE_NAMEDTUPLESTORE:
7651  case RTE_RESULT:
7652 
7653  /*
7654  * This case should not occur: a column of a table, values list,
7655  * or ENR shouldn't have type RECORD. Fall through and fail (most
7656  * likely) at the bottom.
7657  */
7658  break;
7659  case RTE_SUBQUERY:
7660  /* Subselect-in-FROM: examine sub-select's output expr */
7661  {
7662  if (rte->subquery)
7663  {
7665  attnum);
7666 
7667  if (ste == NULL || ste->resjunk)
7668  elog(ERROR, "subquery %s does not have attribute %d",
7669  rte->eref->aliasname, attnum);
7670  expr = (Node *) ste->expr;
7671  if (IsA(expr, Var))
7672  {
7673  /*
7674  * Recurse into the sub-select to see what its Var
7675  * refers to. We have to build an additional level of
7676  * namespace to keep in step with varlevelsup in the
7677  * subselect.
7678  */
7679  deparse_namespace mydpns;
7680  const char *result;
7681 
7682  set_deparse_for_query(&mydpns, rte->subquery,
7683  context->namespaces);
7684 
7685  context->namespaces = lcons(&mydpns,
7686  context->namespaces);
7687 
7688  result = get_name_for_var_field((Var *) expr, fieldno,
7689  0, context);
7690 
7691  context->namespaces =
7692  list_delete_first(context->namespaces);
7693 
7694  return result;
7695  }
7696  /* else fall through to inspect the expression */
7697  }
7698  else
7699  {
7700  /*
7701  * We're deparsing a Plan tree so we don't have complete
7702  * RTE entries (in particular, rte->subquery is NULL). But
7703  * the only place we'd see a Var directly referencing a
7704  * SUBQUERY RTE is in a SubqueryScan plan node, and we can
7705  * look into the child plan's tlist instead.
7706  */
7707  TargetEntry *tle;
7708  deparse_namespace save_dpns;
7709  const char *result;
7710 
7711  if (!dpns->inner_plan)
7712  elog(ERROR, "failed to find plan for subquery %s",
7713  rte->eref->aliasname);
7714  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7715  if (!tle)
7716  elog(ERROR, "bogus varattno for subquery var: %d",
7717  attnum);
7718  Assert(netlevelsup == 0);
7719  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7720 
7721  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7722  levelsup, context);
7723 
7724  pop_child_plan(dpns, &save_dpns);
7725  return result;
7726  }
7727  }
7728  break;
7729  case RTE_JOIN:
7730  /* Join RTE --- recursively inspect the alias variable */
7731  if (rte->joinaliasvars == NIL)
7732  elog(ERROR, "cannot decompile join alias var in plan tree");
7733  Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
7734  expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
7735  Assert(expr != NULL);
7736  /* we intentionally don't strip implicit coercions here */
7737  if (IsA(expr, Var))
7738  return get_name_for_var_field((Var *) expr, fieldno,
7739  var->varlevelsup + levelsup,
7740  context);
7741  /* else fall through to inspect the expression */
7742  break;
7743  case RTE_FUNCTION:
7744  case RTE_TABLEFUNC:
7745 
7746  /*
7747  * We couldn't get here unless a function is declared with one of
7748  * its result columns as RECORD, which is not allowed.
7749  */
7750  break;
7751  case RTE_CTE:
7752  /* CTE reference: examine subquery's output expr */
7753  {
7754  CommonTableExpr *cte = NULL;
7755  Index ctelevelsup;
7756  ListCell *lc;
7757 
7758  /*
7759  * Try to find the referenced CTE using the namespace stack.
7760  */
7761  ctelevelsup = rte->ctelevelsup + netlevelsup;
7762  if (ctelevelsup >= list_length(context->namespaces))
7763  lc = NULL;
7764  else
7765  {
7766  deparse_namespace *ctedpns;
7767 
7768  ctedpns = (deparse_namespace *)
7769  list_nth(context->namespaces, ctelevelsup);
7770  foreach(lc, ctedpns->ctes)
7771  {
7772  cte = (CommonTableExpr *) lfirst(lc);
7773  if (strcmp(cte->ctename, rte->ctename) == 0)
7774  break;
7775  }
7776  }
7777  if (lc != NULL)
7778  {
7779  Query *ctequery = (Query *) cte->ctequery;
7781  attnum);
7782 
7783  if (ste == NULL || ste->resjunk)
7784  elog(ERROR, "subquery %s does not have attribute %d",
7785  rte->eref->aliasname, attnum);
7786  expr = (Node *) ste->expr;
7787  if (IsA(expr, Var))
7788  {
7789  /*
7790  * Recurse into the CTE to see what its Var refers to.
7791  * We have to build an additional level of namespace
7792  * to keep in step with varlevelsup in the CTE.
7793  * Furthermore it could be an outer CTE, so we may
7794  * have to delete some levels of namespace.
7795  */
7796  List *save_nslist = context->namespaces;
7797  List *new_nslist;
7798  deparse_namespace mydpns;
7799  const char *result;
7800 
7801  set_deparse_for_query(&mydpns, ctequery,
7802  context->namespaces);
7803 
7804  new_nslist = list_copy_tail(context->namespaces,
7805  ctelevelsup);
7806  context->namespaces = lcons(&mydpns, new_nslist);
7807 
7808  result = get_name_for_var_field((Var *) expr, fieldno,
7809  0, context);
7810 
7811  context->namespaces = save_nslist;
7812 
7813  return result;
7814  }
7815  /* else fall through to inspect the expression */
7816  }
7817  else
7818  {
7819  /*
7820  * We're deparsing a Plan tree so we don't have a CTE
7821  * list. But the only places we'd see a Var directly
7822  * referencing a CTE RTE are in CteScan or WorkTableScan
7823  * plan nodes. For those cases, set_deparse_plan arranged
7824  * for dpns->inner_plan to be the plan node that emits the
7825  * CTE or RecursiveUnion result, and we can look at its
7826  * tlist instead.
7827  */
7828  TargetEntry *tle;
7829  deparse_namespace save_dpns;
7830  const char *result;
7831 
7832  if (!dpns->inner_plan)
7833  elog(ERROR, "failed to find plan for CTE %s",
7834  rte->eref->aliasname);
7835  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7836  if (!tle)
7837  elog(ERROR, "bogus varattno for subquery var: %d",
7838  attnum);
7839  Assert(netlevelsup == 0);
7840  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7841 
7842  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7843  levelsup, context);
7844 
7845  pop_child_plan(dpns, &save_dpns);
7846  return result;
7847  }
7848  }
7849  break;
7850  }
7851 
7852  /*
7853  * We now have an expression we can't expand any more, so see if
7854  * get_expr_result_tupdesc() can do anything with it.
7855  */
7856  tupleDesc = get_expr_result_tupdesc(expr, false);
7857  /* Got the tupdesc, so we can extract the field name */
7858  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7859  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7860 }
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
TupleDesc get_expr_result_tupdesc(Node *expr, bool noError)
Definition: funcapi.c:509
List * list_delete_first(List *list)
Definition: list.c:902
List * list_copy_tail(const List *oldlist, int nskip)
Definition: list.c:1551
List * lcons(void *datum, List *list)
Definition: list.c:474
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
char * get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
#define GetCTETargetList(cte)
Definition: parsenodes.h:1542
@ RTE_JOIN
Definition: parsenodes.h:1000
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1005
@ RTE_RESULT
Definition: parsenodes.h:1006
int16 attnum
Definition: pg_attribute.h:83
#define OUTER_VAR
Definition: primnodes.h:185
#define INNER_VAR
Definition: primnodes.h:184
#define INDEX_VAR
Definition: primnodes.h:186
static void set_deparse_for_query(deparse_namespace *dpns, Query *query, List *parent_namespaces)
Definition: ruleutils.c:3981
static void pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5130
static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns)
Definition: ruleutils.c:5109
static Node * find_param_referent(Param *param, deparse_context *context, deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
Definition: ruleutils.c:7871
static void pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5079
static const char * get_name_for_var_field(Var *var, int fieldno, int levelsup, deparse_context *context)
Definition: ruleutils.c:7473
static void push_child_plan(deparse_namespace *dpns, Plan *plan, deparse_namespace *save_dpns)
Definition: ruleutils.c:5062
Index ctelevelsup
Definition: parsenodes.h:1126
List * joinaliasvars
Definition: parsenodes.h:1090
List * colnames
Definition: primnodes.h:1091
Definition: primnodes.h:196
Oid vartype
Definition: primnodes.h:202
AttrNumber varattno
Definition: primnodes.h:200
AttrNumber varattnosyn
Definition: primnodes.h:209
int varno
Definition: primnodes.h:198
Index varlevelsup
Definition: primnodes.h:205
Index varnosyn
Definition: primnodes.h:208
List * inner_tlist
Definition: ruleutils.c:178
List * outer_tlist
Definition: ruleutils.c:177
List * index_tlist
Definition: ruleutils.c:179
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References Alias::aliasname, Assert(), attname, attnum, RowExpr::colnames, 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_delete_first(), 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(), TargetEntry::resjunk, 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::varattnosyn, Var::varlevelsup, Var::varno, Var::varnosyn, and Var::vartype.

Referenced by get_rule_expr().

◆ get_opclass_name()

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

Definition at line 12024 of file ruleutils.c.

12026 {
12027  HeapTuple ht_opc;
12028  Form_pg_opclass opcrec;
12029  char *opcname;
12030  char *nspname;
12031 
12032  ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
12033  if (!HeapTupleIsValid(ht_opc))
12034  elog(ERROR, "cache lookup failed for opclass %u", opclass);
12035  opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
12036 
12037  if (!OidIsValid(actual_datatype) ||
12038  GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
12039  {
12040  /* Okay, we need the opclass name. Do we need to qualify it? */
12041  opcname = NameStr(opcrec->o