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

Go to the source code of this file.

Data Structures

struct  deparse_context
 
struct  deparse_namespace
 
struct  deparse_columns
 
struct  NameHashEntry
 

Macros

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

Typedefs

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

Functions

static char * deparse_expression_pretty (Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
 
static char * pg_get_viewdef_worker (Oid viewoid, int prettyFlags, int wrapColumn)
 
static char * pg_get_triggerdef_worker (Oid trigid, bool pretty)
 
static int decompile_column_index_array (Datum column_index_array, Oid relId, StringInfo buf)
 
static char * pg_get_ruledef_worker (Oid ruleoid, int prettyFlags)
 
static char * pg_get_indexdef_worker (Oid indexrelid, int colno, const Oid *excludeOps, bool attrsOnly, bool keysOnly, bool showTblSpc, bool inherits, int prettyFlags, bool missing_ok)
 
static char * pg_get_statisticsobj_worker (Oid statextid, bool columns_only, bool missing_ok)
 
static char * pg_get_partkeydef_worker (Oid relid, int prettyFlags, bool attrsOnly, bool missing_ok)
 
static char * pg_get_constraintdef_worker (Oid constraintId, bool fullCommand, int prettyFlags, bool missing_ok)
 
static textpg_get_expr_worker (text *expr, Oid relid, const char *relname, int prettyFlags)
 
static int print_function_arguments (StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults)
 
static void print_function_rettype (StringInfo buf, HeapTuple proctup)
 
static void print_function_trftypes (StringInfo buf, HeapTuple proctup)
 
static void print_function_sqlbody (StringInfo buf, HeapTuple proctup)
 
static void set_rtable_names (deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
 
static void set_deparse_for_query (deparse_namespace *dpns, Query *query, List *parent_namespaces)
 
static void set_simple_column_names (deparse_namespace *dpns)
 
static bool has_dangerous_join_using (deparse_namespace *dpns, Node *jtnode)
 
static void set_using_names (deparse_namespace *dpns, Node *jtnode, List *parentUsing)
 
static void set_relation_column_names (deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
 
static void set_join_column_names (deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
 
static bool colname_is_unique (const char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
 
static char * make_colname_unique (char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
 
static void expand_colnames_array_to (deparse_columns *colinfo, int n)
 
static void identify_join_columns (JoinExpr *j, RangeTblEntry *jrte, deparse_columns *colinfo)
 
static char * get_rtable_name (int rtindex, deparse_context *context)
 
static void set_deparse_plan (deparse_namespace *dpns, Plan *plan)
 
static Planfind_recursive_union (deparse_namespace *dpns, WorkTableScan *wtscan)
 
static void push_child_plan (deparse_namespace *dpns, Plan *plan, deparse_namespace *save_dpns)
 
static void pop_child_plan (deparse_namespace *dpns, deparse_namespace *save_dpns)
 
static void push_ancestor_plan (deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns)
 
static void pop_ancestor_plan (deparse_namespace *dpns, deparse_namespace *save_dpns)
 
static void make_ruledef (StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
 
static void make_viewdef (StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags, int wrapColumn)
 
static void get_query_def (Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
 
static void get_values_def (List *values_lists, deparse_context *context)
 
static void get_with_clause (Query *query, deparse_context *context)
 
static void get_select_query_def (Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
 
static void get_insert_query_def (Query *query, deparse_context *context, bool colNamesVisible)
 
static void get_update_query_def (Query *query, deparse_context *context, bool colNamesVisible)
 
static void get_update_query_targetlist_def (Query *query, List *targetList, deparse_context *context, RangeTblEntry *rte)
 
static void get_delete_query_def (Query *query, deparse_context *context, bool colNamesVisible)
 
static void get_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_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_rte_alias (RangeTblEntry *rte, int varno, bool use_as, deparse_context *context)
 
static void get_column_alias_list (deparse_columns *colinfo, deparse_context *context)
 
static void get_from_clause_coldeflist (RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
 
static void get_tablesample_def (TableSampleClause *tablesample, deparse_context *context)
 
static void get_opclass_name (Oid opclass, Oid actual_datatype, StringInfo buf)
 
static NodeprocessIndirection (Node *node, deparse_context *context)
 
static void printSubscripts (SubscriptingRef *sbsref, deparse_context *context)
 
static char * get_relation_name (Oid relid)
 
static char * generate_relation_name (Oid relid, List *namespaces)
 
static char * generate_qualified_relation_name (Oid relid)
 
static char * generate_function_name (Oid funcid, int nargs, List *argnames, Oid *argtypes, bool has_variadic, bool *use_variadic_p, ParseExprKind special_exprkind)
 
static char * generate_operator_name (Oid operid, Oid arg1, Oid arg2)
 
static void add_cast_to (StringInfo buf, Oid typid)
 
static char * generate_qualified_type_name (Oid typid)
 
static textstring_to_text (char *str)
 
static char * flatten_reloptions (Oid relid)
 
static void get_reloptions (StringInfo buf, Datum reloptions)
 
Datum pg_get_ruledef (PG_FUNCTION_ARGS)
 
Datum pg_get_ruledef_ext (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef_ext (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef_wrap (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef_name (PG_FUNCTION_ARGS)
 
Datum pg_get_viewdef_name_ext (PG_FUNCTION_ARGS)
 
Datum pg_get_triggerdef (PG_FUNCTION_ARGS)
 
Datum pg_get_triggerdef_ext (PG_FUNCTION_ARGS)
 
Datum pg_get_indexdef (PG_FUNCTION_ARGS)
 
Datum pg_get_indexdef_ext (PG_FUNCTION_ARGS)
 
char * pg_get_indexdef_string (Oid indexrelid)
 
char * pg_get_indexdef_columns (Oid indexrelid, bool pretty)
 
char * pg_get_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_func_sql_syntax_time (List *args, deparse_context *context)
 
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 297 of file ruleutils.c.

◆ GET_PRETTY_FLAGS

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

Definition at line 95 of file ruleutils.c.

◆ only_marker

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

Definition at line 505 of file ruleutils.c.

◆ PRETTY_INDENT

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

Definition at line 104 of file ruleutils.c.

◆ PRETTY_PAREN

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

Definition at line 103 of file ruleutils.c.

◆ PRETTY_SCHEMA

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

Definition at line 105 of file ruleutils.c.

◆ PRETTYFLAG_INDENT

#define PRETTYFLAG_INDENT   0x0002

Definition at line 91 of file ruleutils.c.

◆ PRETTYFLAG_PAREN

#define PRETTYFLAG_PAREN   0x0001

Definition at line 90 of file ruleutils.c.

◆ PRETTYFLAG_SCHEMA

#define PRETTYFLAG_SCHEMA   0x0004

Definition at line 92 of file ruleutils.c.

◆ PRETTYINDENT_JOIN

#define PRETTYINDENT_JOIN   4

Definition at line 84 of file ruleutils.c.

◆ PRETTYINDENT_LIMIT

#define PRETTYINDENT_LIMIT   40 /* wrap limit */

Definition at line 87 of file ruleutils.c.

◆ PRETTYINDENT_STD

#define PRETTYINDENT_STD   8

Definition at line 83 of file ruleutils.c.

◆ PRETTYINDENT_VAR

#define PRETTYINDENT_VAR   4

Definition at line 85 of file ruleutils.c.

◆ WRAP_COLUMN_DEFAULT

#define WRAP_COLUMN_DEFAULT   0

Definition at line 100 of file ruleutils.c.

Typedef Documentation

◆ rsv_callback

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

Definition at line 310 of file ruleutils.c.

Function Documentation

◆ add_cast_to()

static void add_cast_to ( StringInfo  buf,
Oid  typid 
)
static

Definition at line 11999 of file ruleutils.c.

12000 {
12001  HeapTuple typetup;
12002  Form_pg_type typform;
12003  char *typname;
12004  char *nspname;
12005 
12006  typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
12007  if (!HeapTupleIsValid(typetup))
12008  elog(ERROR, "cache lookup failed for type %u", typid);
12009  typform = (Form_pg_type) GETSTRUCT(typetup);
12010 
12011  typname = NameStr(typform->typname);
12012  nspname = get_namespace_name_or_temp(typform->typnamespace);
12013 
12014  appendStringInfo(buf, "::%s.%s",
12016 
12017  ReleaseSysCache(typetup);
12018 }
#define NameStr(name)
Definition: c.h:730
#define ERROR
Definition: elog.h:39
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3355
static char * buf
Definition: pg_test_fsync.c:67
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
NameData typname
Definition: pg_type.h:41
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:11551
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:865
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:817
@ 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 8355 of file ruleutils.c.

8357 {
8358  StringInfo buf = context->buf;
8359 
8360  if (PRETTY_INDENT(context))
8361  {
8362  int indentAmount;
8363 
8364  context->indentLevel += indentBefore;
8365 
8366  /* remove any trailing spaces currently in the buffer ... */
8368  /* ... then add a newline and some spaces */
8369  appendStringInfoChar(buf, '\n');
8370 
8371  if (context->indentLevel < PRETTYINDENT_LIMIT)
8372  indentAmount = Max(context->indentLevel, 0) + indentPlus;
8373  else
8374  {
8375  /*
8376  * If we're indented more than PRETTYINDENT_LIMIT characters, try
8377  * to conserve horizontal space by reducing the per-level
8378  * indentation. For best results the scale factor here should
8379  * divide all the indent amounts that get added to indentLevel
8380  * (PRETTYINDENT_STD, etc). It's important that the indentation
8381  * not grow unboundedly, else deeply-nested trees use O(N^2)
8382  * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8383  */
8384  indentAmount = PRETTYINDENT_LIMIT +
8385  (context->indentLevel - PRETTYINDENT_LIMIT) /
8386  (PRETTYINDENT_STD / 2);
8387  indentAmount %= PRETTYINDENT_LIMIT;
8388  /* scale/wrap logic affects indentLevel, but not indentPlus */
8389  indentAmount += indentPlus;
8390  }
8391  appendStringInfoSpaces(buf, indentAmount);
8392 
8394 
8395  context->indentLevel += indentAfter;
8396  if (context->indentLevel < 0)
8397  context->indentLevel = 0;
8398  }
8399  else
8401 }
#define Max(x, y)
Definition: c.h:982
static void removeStringInfoSpaces(StringInfo str)
Definition: ruleutils.c:8409
#define PRETTYINDENT_LIMIT
Definition: ruleutils.c:87
#define PRETTYINDENT_STD
Definition: ruleutils.c:83
#define PRETTY_INDENT(context)
Definition: ruleutils.c:104
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
StringInfo buf
Definition: ruleutils.c:116

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

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

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

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

Referenced by make_colname_unique().

◆ decompile_column_index_array()

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

Definition at line 2571 of file ruleutils.c.

2573 {
2574  Datum *keys;
2575  int nKeys;
2576  int j;
2577 
2578  /* Extract data from array of int16 */
2579  deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2580  &keys, NULL, &nKeys);
2581 
2582  for (j = 0; j < nKeys; j++)
2583  {
2584  char *colName;
2585 
2586  colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2587 
2588  if (j == 0)
2590  else
2591  appendStringInfo(buf, ", %s", quote_identifier(colName));
2592  }
2593 
2594  return nKeys;
2595 }
#define DatumGetArrayTypeP(X)
Definition: array.h:254
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3668
int j
Definition: isn.c:74
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:826
uintptr_t Datum
Definition: postgres.h:64
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:162

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

Referenced by pg_get_constraintdef_worker().

◆ deparse_context_for()

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

Definition at line 3658 of file ruleutils.c.

3659 {
3660  deparse_namespace *dpns;
3661  RangeTblEntry *rte;
3662 
3663  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3664 
3665  /* Build a minimal RTE for the rel */
3666  rte = makeNode(RangeTblEntry);
3667  rte->rtekind = RTE_RELATION;
3668  rte->relid = relid;
3669  rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3671  rte->alias = makeAlias(aliasname, NIL);
3672  rte->eref = rte->alias;
3673  rte->lateral = false;
3674  rte->inh = false;
3675  rte->inFromCl = true;
3676 
3677  /* Build one-element rtable */
3678  dpns->rtable = list_make1(rte);
3679  dpns->subplans = NIL;
3680  dpns->ctes = NIL;
3681  dpns->appendrels = NULL;
3682  set_rtable_names(dpns, NIL, NULL);
3684 
3685  /* Return a one-deep namespace stack */
3686  return list_make1(dpns);
3687 }
#define AccessShareLock
Definition: lockdefs.h:36
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:389
void * palloc0(Size size)
Definition: mcxt.c:1241
#define makeNode(_type_)
Definition: nodes.h:176
@ RTE_RELATION
Definition: parsenodes.h:1014
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
static void set_simple_column_names(deparse_namespace *dpns)
Definition: ruleutils.c:4034
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
Definition: ruleutils.c:3824
Alias * eref
Definition: parsenodes.h:1200
Alias * alias
Definition: parsenodes.h:1199
RTEKind rtekind
Definition: parsenodes.h:1033
AppendRelInfo ** appendrels
Definition: ruleutils.c:169

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

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

◆ deparse_context_for_plan_tree()

List* deparse_context_for_plan_tree ( PlannedStmt pstmt,
List rtable_names 
)

Definition at line 3703 of file ruleutils.c.

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

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

Referenced by ExplainPrintPlan().

◆ deparse_expression()

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

Definition at line 3598 of file ruleutils.c.

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

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

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

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

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

◆ expand_colnames_array_to()

static void expand_colnames_array_to ( deparse_columns colinfo,
int  n 
)
static

Definition at line 4855 of file ruleutils.c.

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

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

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

◆ find_param_referent()

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

Definition at line 7888 of file ruleutils.c.

7890 {
7891  /* Initialize output parameters to prevent compiler warnings */
7892  *dpns_p = NULL;
7893  *ancestor_cell_p = NULL;
7894 
7895  /*
7896  * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
7897  * SubPlan argument. This will necessarily be in some ancestor of the
7898  * current expression's Plan node.
7899  */
7900  if (param->paramkind == PARAM_EXEC)
7901  {
7902  deparse_namespace *dpns;
7903  Plan *child_plan;
7904  ListCell *lc;
7905 
7906  dpns = (deparse_namespace *) linitial(context->namespaces);
7907  child_plan = dpns->plan;
7908 
7909  foreach(lc, dpns->ancestors)
7910  {
7911  Node *ancestor = (Node *) lfirst(lc);
7912  ListCell *lc2;
7913 
7914  /*
7915  * NestLoops transmit params to their inner child only.
7916  */
7917  if (IsA(ancestor, NestLoop) &&
7918  child_plan == innerPlan(ancestor))
7919  {
7920  NestLoop *nl = (NestLoop *) ancestor;
7921 
7922  foreach(lc2, nl->nestParams)
7923  {
7924  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
7925 
7926  if (nlp->paramno == param->paramid)
7927  {
7928  /* Found a match, so return it */
7929  *dpns_p = dpns;
7930  *ancestor_cell_p = lc;
7931  return (Node *) nlp->paramval;
7932  }
7933  }
7934  }
7935 
7936  /*
7937  * If ancestor is a SubPlan, check the arguments it provides.
7938  */
7939  if (IsA(ancestor, SubPlan))
7940  {
7941  SubPlan *subplan = (SubPlan *) ancestor;
7942  ListCell *lc3;
7943  ListCell *lc4;
7944 
7945  forboth(lc3, subplan->parParam, lc4, subplan->args)
7946  {
7947  int paramid = lfirst_int(lc3);
7948  Node *arg = (Node *) lfirst(lc4);
7949 
7950  if (paramid == param->paramid)
7951  {
7952  /*
7953  * Found a match, so return it. But, since Vars in
7954  * the arg are to be evaluated in the surrounding
7955  * context, we have to point to the next ancestor item
7956  * that is *not* a SubPlan.
7957  */
7958  ListCell *rest;
7959 
7960  for_each_cell(rest, dpns->ancestors,
7961  lnext(dpns->ancestors, lc))
7962  {
7963  Node *ancestor2 = (Node *) lfirst(rest);
7964 
7965  if (!IsA(ancestor2, SubPlan))
7966  {
7967  *dpns_p = dpns;
7968  *ancestor_cell_p = rest;
7969  return arg;
7970  }
7971  }
7972  elog(ERROR, "SubPlan cannot be outermost ancestor");
7973  }
7974  }
7975 
7976  /* SubPlan isn't a kind of Plan, so skip the rest */
7977  continue;
7978  }
7979 
7980  /*
7981  * We need not consider the ancestor's initPlan list, since
7982  * initplans never have any parParams.
7983  */
7984 
7985  /* No luck, crawl up to next ancestor */
7986  child_plan = (Plan *) ancestor;
7987  }
7988  }
7989 
7990  /* No referent found */
7991  return NULL;
7992 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
void * arg
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
#define lfirst_int(lc)
Definition: pg_list.h:173
#define for_each_cell(cell, lst, initcell)
Definition: pg_list.h:438
#define linitial(l)
Definition: pg_list.h:178
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define innerPlan(node)
Definition: plannodes.h:185
@ PARAM_EXEC
Definition: primnodes.h:346
Var * paramval
Definition: plannodes.h:820
List * nestParams
Definition: plannodes.h:811
Definition: nodes.h:129
int paramid
Definition: primnodes.h:355
ParamKind paramkind
Definition: primnodes.h:354
List * args
Definition: primnodes.h:1018
List * parParam
Definition: primnodes.h:1017

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

Referenced by get_name_for_var_field(), and get_parameter().

◆ find_recursive_union()

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

Definition at line 5039 of file ruleutils.c.

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

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

12164 {
12165  char *result = NULL;
12166  HeapTuple tuple;
12167  Datum reloptions;
12168  bool isnull;
12169 
12170  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12171  if (!HeapTupleIsValid(tuple))
12172  elog(ERROR, "cache lookup failed for relation %u", relid);
12173 
12174  reloptions = SysCacheGetAttr(RELOID, tuple,
12175  Anum_pg_class_reloptions, &isnull);
12176  if (!isnull)
12177  {
12179 
12180  initStringInfo(&buf);
12181  get_reloptions(&buf, reloptions);
12182 
12183  result = buf.data;
12184  }
12185 
12186  ReleaseSysCache(tuple);
12187 
12188  return result;
12189 }
static void get_reloptions(StringInfo buf, Datum reloptions)
Definition: ruleutils.c:12108
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1078
@ 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 12063 of file ruleutils.c.

12064 {
12065  HeapTuple tp;
12066  Form_pg_collation colltup;
12067  char *collname;
12068  char *nspname;
12069  char *result;
12070 
12072  if (!HeapTupleIsValid(tp))
12073  elog(ERROR, "cache lookup failed for collation %u", collid);
12074  colltup = (Form_pg_collation) GETSTRUCT(tp);
12075  collname = NameStr(colltup->collname);
12076 
12077  if (!CollationIsVisible(collid))
12078  nspname = get_namespace_name_or_temp(colltup->collnamespace);
12079  else
12080  nspname = NULL;
12081 
12082  result = quote_qualified_identifier(nspname, collname);
12083 
12084  ReleaseSysCache(tp);
12085 
12086  return result;
12087 }
Oid collid
bool CollationIsVisible(Oid collid)
Definition: namespace.c:2091
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:58
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:11635
@ COLLOID
Definition: syscache.h:50

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

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

◆ generate_function_name()

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

Definition at line 11777 of file ruleutils.c.

11780 {
11781  char *result;
11782  HeapTuple proctup;
11783  Form_pg_proc procform;
11784  char *proname;
11785  bool use_variadic;
11786  char *nspname;
11787  FuncDetailCode p_result;
11788  Oid p_funcid;
11789  Oid p_rettype;
11790  bool p_retset;
11791  int p_nvargs;
11792  Oid p_vatype;
11793  Oid *p_true_typeids;
11794  bool force_qualify = false;
11795 
11796  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
11797  if (!HeapTupleIsValid(proctup))
11798  elog(ERROR, "cache lookup failed for function %u", funcid);
11799  procform = (Form_pg_proc) GETSTRUCT(proctup);
11800  proname = NameStr(procform->proname);
11801 
11802  /*
11803  * Due to parser hacks to avoid needing to reserve CUBE, we need to force
11804  * qualification in some special cases.
11805  */
11806  if (special_exprkind == EXPR_KIND_GROUP_BY)
11807  {
11808  if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
11809  force_qualify = true;
11810  }
11811 
11812  /*
11813  * Determine whether VARIADIC should be printed. We must do this first
11814  * since it affects the lookup rules in func_get_detail().
11815  *
11816  * We always print VARIADIC if the function has a merged variadic-array
11817  * argument. Note that this is always the case for functions taking a
11818  * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
11819  * and printed the array elements as separate arguments, the call could
11820  * match a newer non-VARIADIC function.
11821  */
11822  if (use_variadic_p)
11823  {
11824  /* Parser should not have set funcvariadic unless fn is variadic */
11825  Assert(!has_variadic || OidIsValid(procform->provariadic));
11826  use_variadic = has_variadic;
11827  *use_variadic_p = use_variadic;
11828  }
11829  else
11830  {
11831  Assert(!has_variadic);
11832  use_variadic = false;
11833  }
11834 
11835  /*
11836  * The idea here is to schema-qualify only if the parser would fail to
11837  * resolve the correct function given the unqualified func name with the
11838  * specified argtypes and VARIADIC flag. But if we already decided to
11839  * force qualification, then we can skip the lookup and pretend we didn't
11840  * find it.
11841  */
11842  if (!force_qualify)
11844  NIL, argnames, nargs, argtypes,
11845  !use_variadic, true, false,
11846  &p_funcid, &p_rettype,
11847  &p_retset, &p_nvargs, &p_vatype,
11848  &p_true_typeids, NULL);
11849  else
11850  {
11851  p_result = FUNCDETAIL_NOTFOUND;
11852  p_funcid = InvalidOid;
11853  }
11854 
11855  if ((p_result == FUNCDETAIL_NORMAL ||
11856  p_result == FUNCDETAIL_AGGREGATE ||
11857  p_result == FUNCDETAIL_WINDOWFUNC) &&
11858  p_funcid == funcid)
11859  nspname = NULL;
11860  else
11861  nspname = get_namespace_name_or_temp(procform->pronamespace);
11862 
11863  result = quote_qualified_identifier(nspname, proname);
11864 
11865  ReleaseSysCache(proctup);
11866 
11867  return result;
11868 }
#define OidIsValid(objectId)
Definition: c.h:759
FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, bool include_out_arguments, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, Oid **true_typeids, List **argdefaults)
Definition: parse_func.c:1394
FuncDetailCode
Definition: parse_func.h:23
@ FUNCDETAIL_NORMAL
Definition: parse_func.h:26
@ FUNCDETAIL_WINDOWFUNC
Definition: parse_func.h:29
@ FUNCDETAIL_NOTFOUND
Definition: parse_func.h:24
@ FUNCDETAIL_AGGREGATE
Definition: parse_func.h:28
@ EXPR_KIND_GROUP_BY
Definition: parse_node.h:59
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
NameData proname
Definition: pg_proc.h:35
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
@ PROCOID
Definition: syscache.h:79
String * makeString(char *str)
Definition: value.c:63

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

Referenced by get_agg_expr(), get_func_expr(), get_tablesample_def(), get_windowfunc_expr(), pg_get_functiondef(), and pg_get_triggerdef_worker().

◆ generate_opclass_name()

char* generate_opclass_name ( Oid  opclass)

Definition at line 11421 of file ruleutils.c.

11422 {
11424 
11425  initStringInfo(&buf);
11426  get_opclass_name(opclass, InvalidOid, &buf);
11427 
11428  return &buf.data[1]; /* get_opclass_name() prepends space */
11429 }
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Definition: ruleutils.c:11383

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

11963 {
11964  HeapTuple opertup;
11965  Form_pg_operator operform;
11966  char *oprname;
11967  char *nspname;
11968 
11969  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
11970  if (!HeapTupleIsValid(opertup))
11971  elog(ERROR, "cache lookup failed for operator %u", opoid);
11972  operform = (Form_pg_operator) GETSTRUCT(opertup);
11973  Assert(operform->oprkind == 'b');
11974  oprname = NameStr(operform->oprname);
11975 
11976  nspname = get_namespace_name(operform->oprnamespace);
11977 
11978  appendStringInfoString(buf, leftop);
11979  if (leftoptype != operform->oprleft)
11980  add_cast_to(buf, operform->oprleft);
11981  appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
11982  appendStringInfoString(buf, oprname);
11983  appendStringInfo(buf, ") %s", rightop);
11984  if (rightoptype != operform->oprright)
11985  add_cast_to(buf, operform->oprright);
11986 
11987  ReleaseSysCache(opertup);
11988 }
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static void add_cast_to(StringInfo buf, Oid typid)
Definition: ruleutils.c:11999
@ 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 11882 of file ruleutils.c.

11883 {
11885  HeapTuple opertup;
11886  Form_pg_operator operform;
11887  char *oprname;
11888  char *nspname;
11889  Operator p_result;
11890 
11891  initStringInfo(&buf);
11892 
11893  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
11894  if (!HeapTupleIsValid(opertup))
11895  elog(ERROR, "cache lookup failed for operator %u", operid);
11896  operform = (Form_pg_operator) GETSTRUCT(opertup);
11897  oprname = NameStr(operform->oprname);
11898 
11899  /*
11900  * The idea here is to schema-qualify only if the parser would fail to
11901  * resolve the correct operator given the unqualified op name with the
11902  * specified argtypes.
11903  */
11904  switch (operform->oprkind)
11905  {
11906  case 'b':
11907  p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
11908  true, -1);
11909  break;
11910  case 'l':
11911  p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
11912  true, -1);
11913  break;
11914  default:
11915  elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
11916  p_result = NULL; /* keep compiler quiet */
11917  break;
11918  }
11919 
11920  if (p_result != NULL && oprid(p_result) == operid)
11921  nspname = NULL;
11922  else
11923  {
11924  nspname = get_namespace_name_or_temp(operform->oprnamespace);
11925  appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
11926  }
11927 
11928  appendStringInfoString(&buf, oprname);
11929 
11930  if (nspname)
11931  appendStringInfoChar(&buf, ')');
11932 
11933  if (p_result != NULL)
11934  ReleaseSysCache(p_result);
11935 
11936  ReleaseSysCache(opertup);
11937 
11938  return buf.data;
11939 }
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 11735 of file ruleutils.c.

11736 {
11737  HeapTuple tp;
11738  Form_pg_class reltup;
11739  char *relname;
11740  char *nspname;
11741  char *result;
11742 
11743  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11744  if (!HeapTupleIsValid(tp))
11745  elog(ERROR, "cache lookup failed for relation %u", relid);
11746  reltup = (Form_pg_class) GETSTRUCT(tp);
11747  relname = NameStr(reltup->relname);
11748 
11749  nspname = get_namespace_name_or_temp(reltup->relnamespace);
11750  if (!nspname)
11751  elog(ERROR, "cache lookup failed for namespace %u",
11752  reltup->relnamespace);
11753 
11754  result = quote_qualified_identifier(nspname, relname);
11755 
11756  ReleaseSysCache(tp);
11757 
11758  return result;
11759 }
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 12030 of file ruleutils.c.

12031 {
12032  HeapTuple tp;
12033  Form_pg_type typtup;
12034  char *typname;
12035  char *nspname;
12036  char *result;
12037 
12039  if (!HeapTupleIsValid(tp))
12040  elog(ERROR, "cache lookup failed for type %u", typid);
12041  typtup = (Form_pg_type) GETSTRUCT(tp);
12042  typname = NameStr(typtup->typname);
12043 
12044  nspname = get_namespace_name_or_temp(typtup->typnamespace);
12045  if (!nspname)
12046  elog(ERROR, "cache lookup failed for namespace %u",
12047  typtup->typnamespace);
12048 
12049  result = quote_qualified_identifier(nspname, typname);
12050 
12051  ReleaseSysCache(tp);
12052 
12053  return result;
12054 }

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

11676 {
11677  HeapTuple tp;
11678  Form_pg_class reltup;
11679  bool need_qual;
11680  ListCell *nslist;
11681  char *relname;
11682  char *nspname;
11683  char *result;
11684 
11685  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11686  if (!HeapTupleIsValid(tp))
11687  elog(ERROR, "cache lookup failed for relation %u", relid);
11688  reltup = (Form_pg_class) GETSTRUCT(tp);
11689  relname = NameStr(reltup->relname);
11690 
11691  /* Check for conflicting CTE name */
11692  need_qual = false;
11693  foreach(nslist, namespaces)
11694  {
11695  deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
11696  ListCell *ctlist;
11697 
11698  foreach(ctlist, dpns->ctes)
11699  {
11700  CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
11701 
11702  if (strcmp(cte->ctename, relname) == 0)
11703  {
11704  need_qual = true;
11705  break;
11706  }
11707  }
11708  if (need_qual)
11709  break;
11710  }
11711 
11712  /* Otherwise, qualify the name if not visible in search path */
11713  if (!need_qual)
11714  need_qual = !RelationIsVisible(relid);
11715 
11716  if (need_qual)
11717  nspname = get_namespace_name_or_temp(reltup->relnamespace);
11718  else
11719  nspname = NULL;
11720 
11721  result = quote_qualified_identifier(nspname, relname);
11722 
11723  ReleaseSysCache(tp);
11724 
11725  return result;
11726 }
bool RelationIsVisible(Oid relid)
Definition: namespace.c:711

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

9922 {
9923  Aggref *aggref;
9924  Aggref *original_aggref = callback_arg;
9925 
9926  if (!IsA(node, Aggref))
9927  elog(ERROR, "combining Aggref does not point to an Aggref");
9928 
9929  aggref = (Aggref *) node;
9930  get_agg_expr(aggref, context, original_aggref);
9931 }
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
Definition: ruleutils.c:9814

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

Referenced by get_agg_expr().

◆ get_agg_expr()

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

Definition at line 9814 of file ruleutils.c.

9816 {
9817  StringInfo buf = context->buf;
9818  Oid argtypes[FUNC_MAX_ARGS];
9819  int nargs;
9820  bool use_variadic;
9821 
9822  /*
9823  * For a combining aggregate, we look up and deparse the corresponding
9824  * partial aggregate instead. This is necessary because our input
9825  * argument list has been replaced; the new argument list always has just
9826  * one element, which will point to a partial Aggref that supplies us with
9827  * transition states to combine.
9828  */
9829  if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
9830  {
9831  TargetEntry *tle;
9832 
9833  Assert(list_length(aggref->args) == 1);
9834  tle = linitial_node(TargetEntry, aggref->args);
9835  resolve_special_varno((Node *) tle->expr, context,
9836  get_agg_combine_expr, original_aggref);
9837  return;
9838  }
9839 
9840  /*
9841  * Mark as PARTIAL, if appropriate. We look to the original aggref so as
9842  * to avoid printing this when recursing from the code just above.
9843  */
9844  if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
9845  appendStringInfoString(buf, "PARTIAL ");
9846 
9847  /* Extract the argument types as seen by the parser */
9848  nargs = get_aggregate_argtypes(aggref, argtypes);
9849 
9850  /* Print the aggregate name, schema-qualified if needed */
9851  appendStringInfo(buf, "%s(%s",
9852  generate_function_name(aggref->aggfnoid, nargs,
9853  NIL, argtypes,
9854  aggref->aggvariadic,
9855  &use_variadic,
9856  context->special_exprkind),
9857  (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
9858 
9859  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
9860  {
9861  /*
9862  * Ordered-set aggregates do not use "*" syntax. Also, we needn't
9863  * worry about inserting VARIADIC. So we can just dump the direct
9864  * args as-is.
9865  */
9866  Assert(!aggref->aggvariadic);
9867  get_rule_expr((Node *) aggref->aggdirectargs, context, true);
9868  Assert(aggref->aggorder != NIL);
9869  appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
9870  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
9871  }
9872  else
9873  {
9874  /* aggstar can be set only in zero-argument aggregates */
9875  if (aggref->aggstar)
9876  appendStringInfoChar(buf, '*');
9877  else
9878  {
9879  ListCell *l;
9880  int i;
9881 
9882  i = 0;
9883  foreach(l, aggref->args)
9884  {
9885  TargetEntry *tle = (TargetEntry *) lfirst(l);
9886  Node *arg = (Node *) tle->expr;
9887 
9888  Assert(!IsA(arg, NamedArgExpr));
9889  if (tle->resjunk)
9890  continue;
9891  if (i++ > 0)
9892  appendStringInfoString(buf, ", ");
9893  if (use_variadic && i == nargs)
9894  appendStringInfoString(buf, "VARIADIC ");
9895  get_rule_expr(arg, context, true);
9896  }
9897  }
9898 
9899  if (aggref->aggorder != NIL)
9900  {
9901  appendStringInfoString(buf, " ORDER BY ");
9902  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
9903  }
9904  }
9905 
9906  if (aggref->aggfilter != NULL)
9907  {
9908  appendStringInfoString(buf, ") FILTER (WHERE ");
9909  get_rule_expr((Node *) aggref->aggfilter, context, false);
9910  }
9911 
9912  appendStringInfoChar(buf, ')');
9913 }
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:394
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:393
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1894
#define FUNC_MAX_ARGS
#define linitial_node(type, l)
Definition: pg_list.h:181
static char * generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, bool has_variadic, bool *use_variadic_p, ParseExprKind special_exprkind)
Definition: ruleutils.c:11777
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:9921
static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6404
static void resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
Definition: ruleutils.c:7381
Oid aggfnoid
Definition: primnodes.h:422
List * aggdistinct
Definition: primnodes.h:452
List * aggdirectargs
Definition: primnodes.h:443
List * args
Definition: primnodes.h:446
Expr * aggfilter
Definition: primnodes.h:455
List * aggorder
Definition: primnodes.h:449
Expr * expr
Definition: primnodes.h:1731

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

Referenced by get_agg_combine_expr(), and get_rule_expr().

◆ get_basic_select_query()

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

Definition at line 5884 of file ruleutils.c.

5886 {
5887  StringInfo buf = context->buf;
5888  RangeTblEntry *values_rte;
5889  char *sep;
5890  ListCell *l;
5891 
5892  if (PRETTY_INDENT(context))
5893  {
5894  context->indentLevel += PRETTYINDENT_STD;
5895  appendStringInfoChar(buf, ' ');
5896  }
5897 
5898  /*
5899  * If the query looks like SELECT * FROM (VALUES ...), then print just the
5900  * VALUES part. This reverses what transformValuesClause() did at parse
5901  * time.
5902  */
5903  values_rte = get_simple_values_rte(query, resultDesc);
5904  if (values_rte)
5905  {
5906  get_values_def(values_rte->values_lists, context);
5907  return;
5908  }
5909 
5910  /*
5911  * Build up the query string - first we say SELECT
5912  */
5913  if (query->isReturn)
5914  appendStringInfoString(buf, "RETURN");
5915  else
5916  appendStringInfoString(buf, "SELECT");
5917 
5918  /* Add the DISTINCT clause if given */
5919  if (query->distinctClause != NIL)
5920  {
5921  if (query->hasDistinctOn)
5922  {
5923  appendStringInfoString(buf, " DISTINCT ON (");
5924  sep = "";
5925  foreach(l, query->distinctClause)
5926  {
5927  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5928 
5931  false, context);
5932  sep = ", ";
5933  }
5934  appendStringInfoChar(buf, ')');
5935  }
5936  else
5937  appendStringInfoString(buf, " DISTINCT");
5938  }
5939 
5940  /* Then we tell what to select (the targetlist) */
5941  get_target_list(query->targetList, context, resultDesc, colNamesVisible);
5942 
5943  /* Add the FROM clause if needed */
5944  get_from_clause(query, " FROM ", context);
5945 
5946  /* Add the WHERE clause if given */
5947  if (query->jointree->quals != NULL)
5948  {
5949  appendContextKeyword(context, " WHERE ",
5951  get_rule_expr(query->jointree->quals, context, false);
5952  }
5953 
5954  /* Add the GROUP BY clause if given */
5955  if (query->groupClause != NULL || query->groupingSets != NULL)
5956  {
5957  ParseExprKind save_exprkind;
5958 
5959  appendContextKeyword(context, " GROUP BY ",
5961  if (query->groupDistinct)
5962  appendStringInfoString(buf, "DISTINCT ");
5963 
5964  save_exprkind = context->special_exprkind;
5966 
5967  if (query->groupingSets == NIL)
5968  {
5969  sep = "";
5970  foreach(l, query->groupClause)
5971  {
5972  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
5973 
5976  false, context);
5977  sep = ", ";
5978  }
5979  }
5980  else
5981  {
5982  sep = "";
5983  foreach(l, query->groupingSets)
5984  {
5985  GroupingSet *grp = lfirst(l);
5986 
5988  get_rule_groupingset(grp, query->targetList, true, context);
5989  sep = ", ";
5990  }
5991  }
5992 
5993  context->special_exprkind = save_exprkind;
5994  }
5995 
5996  /* Add the HAVING clause if given */
5997  if (query->havingQual != NULL)
5998  {
5999  appendContextKeyword(context, " HAVING ",
6001  get_rule_expr(query->havingQual, context, false);
6002  }
6003 
6004  /* Add the WINDOW clause if needed */
6005  if (query->windowClause != NIL)
6006  get_rule_windowclause(query, context);
6007 }
ParseExprKind
Definition: parse_node.h:39
static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
Definition: ruleutils.c:8355
static void get_values_def(List *values_lists, deparse_context *context)
Definition: ruleutils.c:5501
static void get_from_clause(Query *query, const char *prefix, deparse_context *context)
Definition: ruleutils.c:10792
static void get_target_list(List *targetList, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6018
static void get_rule_groupingset(GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context)
Definition: ruleutils.c:6344
static Node * get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6288
static void get_rule_windowclause(Query *query, deparse_context *context)
Definition: ruleutils.c:6462
static RangeTblEntry * get_simple_values_rte(Query *query, TupleDesc resultDesc)
Definition: ruleutils.c:5815
Node * quals
Definition: primnodes.h:1850
bool groupDistinct
Definition: parsenodes.h:199
FromExpr * jointree
Definition: parsenodes.h:182
List * groupClause
Definition: parsenodes.h:198
Node * havingQual
Definition: parsenodes.h:203
List * windowClause
Definition: parsenodes.h:205
List * targetList
Definition: parsenodes.h:189
List * groupingSets
Definition: parsenodes.h:201
List * distinctClause
Definition: parsenodes.h:207
List * values_lists
Definition: parsenodes.h:1159
Index tleSortGroupRef
Definition: parsenodes.h:1393

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

Referenced by get_select_query_def().

◆ get_coercion_expr()

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

Definition at line 10321 of file ruleutils.c.

10324 {
10325  StringInfo buf = context->buf;
10326 
10327  /*
10328  * Since parse_coerce.c doesn't immediately collapse application of
10329  * length-coercion functions to constants, what we'll typically see in
10330  * such cases is a Const with typmod -1 and a length-coercion function
10331  * right above it. Avoid generating redundant output. However, beware of
10332  * suppressing casts when the user actually wrote something like
10333  * 'foo'::text::char(3).
10334  *
10335  * Note: it might seem that we are missing the possibility of needing to
10336  * print a COLLATE clause for such a Const. However, a Const could only
10337  * have nondefault collation in a post-constant-folding tree, in which the
10338  * length coercion would have been folded too. See also the special
10339  * handling of CollateExpr in coerce_to_target_type(): any collation
10340  * marking will be above the coercion node, not below it.
10341  */
10342  if (arg && IsA(arg, Const) &&
10343  ((Const *) arg)->consttype == resulttype &&
10344  ((Const *) arg)->consttypmod == -1)
10345  {
10346  /* Show the constant without normal ::typename decoration */
10347  get_const_expr((Const *) arg, context, -1);
10348  }
10349  else
10350  {
10351  if (!PRETTY_PAREN(context))
10352  appendStringInfoChar(buf, '(');
10353  get_rule_expr_paren(arg, context, false, parentNode);
10354  if (!PRETTY_PAREN(context))
10355  appendStringInfoChar(buf, ')');
10356  }
10357 
10358  /*
10359  * Never emit resulttype(arg) functional notation. A pg_proc entry could
10360  * take precedence, and a resulttype in pg_temp would require schema
10361  * qualification that format_type_with_typemod() would usually omit. We've
10362  * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
10363  * would work fine.
10364  */
10365  appendStringInfo(buf, "::%s",
10366  format_type_with_typemod(resulttype, resulttypmod));
10367 }
char * format_type_with_typemod(Oid type_oid, int32 typemod)
Definition: format_type.c:358
static void get_rule_expr_paren(Node *node, deparse_context *context, bool showimplicit, Node *parentNode)
Definition: ruleutils.c:8428
#define PRETTY_PAREN(context)
Definition: ruleutils.c:103
static void get_const_expr(Const *constval, deparse_context *context, int showtype)
Definition: ruleutils.c:10385

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

11249 {
11250  StringInfo buf = context->buf;
11251  int i;
11252  bool first = true;
11253 
11254  /* Don't print aliases if not needed */
11255  if (!colinfo->printaliases)
11256  return;
11257 
11258  for (i = 0; i < colinfo->num_new_cols; i++)
11259  {
11260  char *colname = colinfo->new_colnames[i];
11261 
11262  if (first)
11263  {
11264  appendStringInfoChar(buf, '(');
11265  first = false;
11266  }
11267  else
11268  appendStringInfoString(buf, ", ");
11270  }
11271  if (!first)
11272  appendStringInfoChar(buf, ')');
11273 }

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

10516 {
10517  StringInfo buf = context->buf;
10518 
10519  if (OidIsValid(constval->constcollid))
10520  {
10521  Oid typcollation = get_typcollation(constval->consttype);
10522 
10523  if (constval->constcollid != typcollation)
10524  {
10525  appendStringInfo(buf, " COLLATE %s",
10526  generate_collation_name(constval->constcollid));
10527  }
10528  }
10529 }
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3014
char * generate_collation_name(Oid collid)
Definition: ruleutils.c:12063
Oid consttype
Definition: primnodes.h:290

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

Referenced by get_const_expr().

◆ get_const_expr()

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

Definition at line 10385 of file ruleutils.c.

10386 {
10387  StringInfo buf = context->buf;
10388  Oid typoutput;
10389  bool typIsVarlena;
10390  char *extval;
10391  bool needlabel = false;
10392 
10393  if (constval->constisnull)
10394  {
10395  /*
10396  * Always label the type of a NULL constant to prevent misdecisions
10397  * about type when reparsing.
10398  */
10399  appendStringInfoString(buf, "NULL");
10400  if (showtype >= 0)
10401  {
10402  appendStringInfo(buf, "::%s",
10404  constval->consttypmod));
10405  get_const_collation(constval, context);
10406  }
10407  return;
10408  }
10409 
10410  getTypeOutputInfo(constval->consttype,
10411  &typoutput, &typIsVarlena);
10412 
10413  extval = OidOutputFunctionCall(typoutput, constval->constvalue);
10414 
10415  switch (constval->consttype)
10416  {
10417  case INT4OID:
10418 
10419  /*
10420  * INT4 can be printed without any decoration, unless it is
10421  * negative; in that case print it as '-nnn'::integer to ensure
10422  * that the output will re-parse as a constant, not as a constant
10423  * plus operator. In most cases we could get away with printing
10424  * (-nnn) instead, because of the way that gram.y handles negative
10425  * literals; but that doesn't work for INT_MIN, and it doesn't
10426  * seem that much prettier anyway.
10427  */
10428  if (extval[0] != '-')
10429  appendStringInfoString(buf, extval);
10430  else
10431  {
10432  appendStringInfo(buf, "'%s'", extval);
10433  needlabel = true; /* we must attach a cast */
10434  }
10435  break;
10436 
10437  case NUMERICOID:
10438 
10439  /*
10440  * NUMERIC can be printed without quotes if it looks like a float
10441  * constant (not an integer, and not Infinity or NaN) and doesn't
10442  * have a leading sign (for the same reason as for INT4).
10443  */
10444  if (isdigit((unsigned char) extval[0]) &&
10445  strcspn(extval, "eE.") != strlen(extval))
10446  {
10447  appendStringInfoString(buf, extval);
10448  }
10449  else
10450  {
10451  appendStringInfo(buf, "'%s'", extval);
10452  needlabel = true; /* we must attach a cast */
10453  }
10454  break;
10455 
10456  case BOOLOID:
10457  if (strcmp(extval, "t") == 0)
10458  appendStringInfoString(buf, "true");
10459  else
10460  appendStringInfoString(buf, "false");
10461  break;
10462 
10463  default:
10464  simple_quote_literal(buf, extval);
10465  break;
10466  }
10467 
10468  pfree(extval);
10469 
10470  if (showtype < 0)
10471  return;
10472 
10473  /*
10474  * For showtype == 0, append ::typename unless the constant will be
10475  * implicitly typed as the right type when it is read in.
10476  *
10477  * XXX this code has to be kept in sync with the behavior of the parser,
10478  * especially make_const.
10479  */
10480  switch (constval->consttype)
10481  {
10482  case BOOLOID:
10483  case UNKNOWNOID:
10484  /* These types can be left unlabeled */
10485  needlabel = false;
10486  break;
10487  case INT4OID:
10488  /* We determined above whether a label is needed */
10489  break;
10490  case NUMERICOID:
10491 
10492  /*
10493  * Float-looking constants will be typed as numeric, which we
10494  * checked above; but if there's a nondefault typmod we need to
10495  * show it.
10496  */
10497  needlabel |= (constval->consttypmod >= 0);
10498  break;
10499  default:
10500  needlabel = true;
10501  break;
10502  }
10503  if (needlabel || showtype > 0)
10504  appendStringInfo(buf, "::%s",
10506  constval->consttypmod));
10507 
10508  get_const_collation(constval, context);
10509 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1750
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2865
void pfree(void *pointer)
Definition: mcxt.c:1436
static void simple_quote_literal(StringInfo buf, const char *val)
Definition: ruleutils.c:10535
static void get_const_collation(Const *constval, deparse_context *context)
Definition: ruleutils.c:10515

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

Referenced by get_coercion_expr(), get_range_partbound_string(), get_rule_expr(), and get_rule_sortgroupclause().

◆ get_delete_query_def()

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

Definition at line 7029 of file ruleutils.c.

7031 {
7032  StringInfo buf = context->buf;
7033  RangeTblEntry *rte;
7034 
7035  /* Insert the WITH clause if given */
7036  get_with_clause(query, context);
7037 
7038  /*
7039  * Start the query with DELETE FROM relname
7040  */
7041  rte = rt_fetch(query->resultRelation, query->rtable);
7042  Assert(rte->rtekind == RTE_RELATION);
7043  if (PRETTY_INDENT(context))
7044  {
7045  appendStringInfoChar(buf, ' ');
7046  context->indentLevel += PRETTYINDENT_STD;
7047  }
7048  appendStringInfo(buf, "DELETE FROM %s%s",
7049  only_marker(rte),
7051 
7052  /* Print the relation alias, if needed */
7053  get_rte_alias(rte, query->resultRelation, false, context);
7054 
7055  /* Add the USING clause if given */
7056  get_from_clause(query, " USING ", context);
7057 
7058  /* Add a WHERE clause if given */
7059  if (query->jointree->quals != NULL)
7060  {
7061  appendContextKeyword(context, " WHERE ",
7063  get_rule_expr(query->jointree->quals, context, false);
7064  }
7065 
7066  /* Add RETURNING if present */
7067  if (query->returningList)
7068  {
7069  appendContextKeyword(context, " RETURNING",
7071  get_target_list(query->returningList, context, NULL, colNamesVisible);
7072  }
7073 }
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as, deparse_context *context)
Definition: ruleutils.c:11177
#define only_marker(rte)
Definition: ruleutils.c:505
static void get_with_clause(Query *query, deparse_context *context)
Definition: ruleutils.c:5544
static char * generate_relation_name(Oid relid, List *namespaces)
Definition: ruleutils.c:11675
List * returningList
Definition: parsenodes.h:196
List * rtable
Definition: parsenodes.h:175

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

Referenced by get_query_def().

◆ get_from_clause()

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

Definition at line 10792 of file ruleutils.c.

10793 {
10794  StringInfo buf = context->buf;
10795  bool first = true;
10796  ListCell *l;
10797 
10798  /*
10799  * We use the query's jointree as a guide to what to print. However, we
10800  * must ignore auto-added RTEs that are marked not inFromCl. (These can
10801  * only appear at the top level of the jointree, so it's sufficient to
10802  * check here.) This check also ensures we ignore the rule pseudo-RTEs
10803  * for NEW and OLD.
10804  */
10805  foreach(l, query->jointree->fromlist)
10806  {
10807  Node *jtnode = (Node *) lfirst(l);
10808 
10809  if (IsA(jtnode, RangeTblRef))
10810  {
10811  int varno = ((RangeTblRef *) jtnode)->rtindex;
10812  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
10813 
10814  if (!rte->inFromCl)
10815  continue;
10816  }
10817 
10818  if (first)
10819  {
10820  appendContextKeyword(context, prefix,
10822  first = false;
10823 
10824  get_from_clause_item(jtnode, query, context);
10825  }
10826  else
10827  {
10828  StringInfoData itembuf;
10829 
10830  appendStringInfoString(buf, ", ");
10831 
10832  /*
10833  * Put the new FROM item's text into itembuf so we can decide
10834  * after we've got it whether or not it needs to go on a new line.
10835  */
10836  initStringInfo(&itembuf);
10837  context->buf = &itembuf;
10838 
10839  get_from_clause_item(jtnode, query, context);
10840 
10841  /* Restore context's output buffer */
10842  context->buf = buf;
10843 
10844  /* Consider line-wrapping if enabled */
10845  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
10846  {
10847  /* Does the new item start with a new line? */
10848  if (itembuf.len > 0 && itembuf.data[0] == '\n')
10849  {
10850  /* If so, we shouldn't add anything */
10851  /* instead, remove any trailing spaces currently in buf */
10853  }
10854  else
10855  {
10856  char *trailing_nl;
10857 
10858  /* Locate the start of the current line in the buffer */
10859  trailing_nl = strrchr(buf->data, '\n');
10860  if (trailing_nl == NULL)
10861  trailing_nl = buf->data;
10862  else
10863  trailing_nl++;
10864 
10865  /*
10866  * Add a newline, plus some indentation, if the new item
10867  * would cause an overflow.
10868  */
10869  if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
10870  appendContextKeyword(context, "", -PRETTYINDENT_STD,
10873  }
10874  }
10875 
10876  /* Add the new item */
10877  appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
10878 
10879  /* clean up */
10880  pfree(itembuf.data);
10881  }
10882  }
10883 }
#define PRETTYINDENT_VAR
Definition: ruleutils.c:85
static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
Definition: ruleutils.c:10886
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:227
List * fromlist
Definition: primnodes.h:1849

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

11291 {
11292  StringInfo buf = context->buf;
11293  ListCell *l1;
11294  ListCell *l2;
11295  ListCell *l3;
11296  ListCell *l4;
11297  int i;
11298 
11299  appendStringInfoChar(buf, '(');
11300 
11301  i = 0;
11302  forfour(l1, rtfunc->funccoltypes,
11303  l2, rtfunc->funccoltypmods,
11304  l3, rtfunc->funccolcollations,
11305  l4, rtfunc->funccolnames)
11306  {
11307  Oid atttypid = lfirst_oid(l1);
11308  int32 atttypmod = lfirst_int(l2);
11309  Oid attcollation = lfirst_oid(l3);
11310  char *attname;
11311 
11312  if (colinfo)
11313  attname = colinfo->colnames[i];
11314  else
11315  attname = strVal(lfirst(l4));
11316 
11317  Assert(attname); /* shouldn't be any dropped columns here */
11318 
11319  if (i > 0)
11320  appendStringInfoString(buf, ", ");
11321  appendStringInfo(buf, "%s %s",
11323  format_type_with_typemod(atttypid, atttypmod));
11324  if (OidIsValid(attcollation) &&
11325  attcollation != get_typcollation(atttypid))
11326  appendStringInfo(buf, " COLLATE %s",
11327  generate_collation_name(attcollation));
11328 
11329  i++;
11330  }
11331 
11332  appendStringInfoChar(buf, ')');
11333 }
signed int int32
Definition: c.h:478
NameData attname
Definition: pg_attribute.h:41
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:524
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define strVal(v)
Definition: value.h:82

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

Referenced by get_from_clause_item().

◆ get_from_clause_item()

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

Definition at line 10886 of file ruleutils.c.

10887 {
10888  StringInfo buf = context->buf;
10890 
10891  if (IsA(jtnode, RangeTblRef))
10892  {
10893  int varno = ((RangeTblRef *) jtnode)->rtindex;
10894  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
10895  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
10896  RangeTblFunction *rtfunc1 = NULL;
10897 
10898  if (rte->lateral)
10899  appendStringInfoString(buf, "LATERAL ");
10900 
10901  /* Print the FROM item proper */
10902  switch (rte->rtekind)
10903  {
10904  case RTE_RELATION:
10905  /* Normal relation RTE */
10906  appendStringInfo(buf, "%s%s",
10907  only_marker(rte),
10909  context->namespaces));
10910  break;
10911  case RTE_SUBQUERY:
10912  /* Subquery RTE */
10913  appendStringInfoChar(buf, '(');
10914  get_query_def(rte->subquery, buf, context->namespaces, NULL,
10915  true,
10916  context->prettyFlags, context->wrapColumn,
10917  context->indentLevel);
10918  appendStringInfoChar(buf, ')');
10919  break;
10920  case RTE_FUNCTION:
10921  /* Function RTE */
10922  rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
10923 
10924  /*
10925  * Omit ROWS FROM() syntax for just one function, unless it
10926  * has both a coldeflist and WITH ORDINALITY. If it has both,
10927  * we must use ROWS FROM() syntax to avoid ambiguity about
10928  * whether the coldeflist includes the ordinality column.
10929  */
10930  if (list_length(rte->functions) == 1 &&
10931  (rtfunc1->funccolnames == NIL || !rte->funcordinality))
10932  {
10933  get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
10934  /* we'll print the coldeflist below, if it has one */
10935  }
10936  else
10937  {
10938  bool all_unnest;
10939  ListCell *lc;
10940 
10941  /*
10942  * If all the function calls in the list are to unnest,
10943  * and none need a coldeflist, then collapse the list back
10944  * down to UNNEST(args). (If we had more than one
10945  * built-in unnest function, this would get more
10946  * difficult.)
10947  *
10948  * XXX This is pretty ugly, since it makes not-terribly-
10949  * future-proof assumptions about what the parser would do
10950  * with the output; but the alternative is to emit our
10951  * nonstandard ROWS FROM() notation for what might have
10952  * been a perfectly spec-compliant multi-argument
10953  * UNNEST().
10954  */
10955  all_unnest = true;
10956  foreach(lc, rte->functions)
10957  {
10958  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
10959 
10960  if (!IsA(rtfunc->funcexpr, FuncExpr) ||
10961  ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
10962  rtfunc->funccolnames != NIL)
10963  {
10964  all_unnest = false;
10965  break;
10966  }
10967  }
10968 
10969  if (all_unnest)
10970  {
10971  List *allargs = NIL;
10972 
10973  foreach(lc, rte->functions)
10974  {
10975  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
10976  List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
10977 
10978  allargs = list_concat(allargs, args);
10979  }
10980 
10981  appendStringInfoString(buf, "UNNEST(");
10982  get_rule_expr((Node *) allargs, context, true);
10983  appendStringInfoChar(buf, ')');
10984  }
10985  else
10986  {
10987  int funcno = 0;
10988 
10989  appendStringInfoString(buf, "ROWS FROM(");
10990  foreach(lc, rte->functions)
10991  {
10992  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
10993 
10994  if (funcno > 0)
10995  appendStringInfoString(buf, ", ");
10996  get_rule_expr_funccall(rtfunc->funcexpr, context, true);
10997  if (rtfunc->funccolnames != NIL)
10998  {
10999  /* Reconstruct the column definition list */
11000  appendStringInfoString(buf, " AS ");
11002  NULL,
11003  context);
11004  }
11005  funcno++;
11006  }
11007  appendStringInfoChar(buf, ')');
11008  }
11009  /* prevent printing duplicate coldeflist below */
11010  rtfunc1 = NULL;
11011  }
11012  if (rte->funcordinality)
11013  appendStringInfoString(buf, " WITH ORDINALITY");
11014  break;
11015  case RTE_TABLEFUNC:
11016  get_tablefunc(rte->tablefunc, context, true);
11017  break;
11018  case RTE_VALUES:
11019  /* Values list RTE */
11020  appendStringInfoChar(buf, '(');
11021  get_values_def(rte->values_lists, context);
11022  appendStringInfoChar(buf, ')');
11023  break;
11024  case RTE_CTE:
11026  break;
11027  default:
11028  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
11029  break;
11030  }
11031 
11032  /* Print the relation alias, if needed */
11033  get_rte_alias(rte, varno, false, context);
11034 
11035  /* Print the column definitions or aliases, if needed */
11036  if (rtfunc1 && rtfunc1->funccolnames != NIL)
11037  {
11038  /* Reconstruct the columndef list, which is also the aliases */
11039  get_from_clause_coldeflist(rtfunc1, colinfo, context);
11040  }
11041  else
11042  {
11043  /* Else print column aliases as needed */
11044  get_column_alias_list(colinfo, context);
11045  }
11046 
11047  /* Tablesample clause must go after any alias */
11048  if (rte->rtekind == RTE_RELATION && rte->tablesample)
11049  get_tablesample_def(rte->tablesample, context);
11050  }
11051  else if (IsA(jtnode, JoinExpr))
11052  {
11053  JoinExpr *j = (JoinExpr *) jtnode;
11054  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
11055  bool need_paren_on_right;
11056 
11057  need_paren_on_right = PRETTY_PAREN(context) &&
11058  !IsA(j->rarg, RangeTblRef) &&
11059  !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
11060 
11061  if (!PRETTY_PAREN(context) || j->alias != NULL)
11062  appendStringInfoChar(buf, '(');
11063 
11064  get_from_clause_item(j->larg, query, context);
11065 
11066  switch (j->jointype)
11067  {
11068  case JOIN_INNER:
11069  if (j->quals)
11070  appendContextKeyword(context, " JOIN ",
11074  else
11075  appendContextKeyword(context, " CROSS JOIN ",
11079  break;
11080  case JOIN_LEFT:
11081  appendContextKeyword(context, " LEFT JOIN ",
11085  break;
11086  case JOIN_FULL:
11087  appendContextKeyword(context, " FULL JOIN ",
11091  break;
11092  case JOIN_RIGHT:
11093  appendContextKeyword(context, " RIGHT JOIN ",
11097  break;
11098  default:
11099  elog(ERROR, "unrecognized join type: %d",
11100  (int) j->jointype);
11101  }
11102 
11103  if (need_paren_on_right)
11104  appendStringInfoChar(buf, '(');
11105  get_from_clause_item(j->rarg, query, context);
11106  if (need_paren_on_right)
11107  appendStringInfoChar(buf, ')');
11108 
11109  if (j->usingClause)
11110  {
11111  ListCell *lc;
11112  bool first = true;
11113 
11114  appendStringInfoString(buf, " USING (");
11115  /* Use the assigned names, not what's in usingClause */
11116  foreach(lc, colinfo->usingNames)
11117  {
11118  char *colname = (char *) lfirst(lc);
11119 
11120  if (first)
11121  first = false;
11122  else
11123  appendStringInfoString(buf, ", ");
11125  }
11126  appendStringInfoChar(buf, ')');
11127 
11128  if (j->join_using_alias)
11129  appendStringInfo(buf, " AS %s",
11130  quote_identifier(j->join_using_alias->aliasname));
11131  }
11132  else if (j->quals)
11133  {
11134  appendStringInfoString(buf, " ON ");
11135  if (!PRETTY_PAREN(context))
11136  appendStringInfoChar(buf, '(');
11137  get_rule_expr(j->quals, context, false);
11138  if (!PRETTY_PAREN(context))
11139  appendStringInfoChar(buf, ')');
11140  }
11141  else if (j->jointype != JOIN_INNER)
11142  {
11143  /* If we didn't say CROSS JOIN above, we must provide an ON */
11144  appendStringInfoString(buf, " ON TRUE");
11145  }
11146 
11147  if (!PRETTY_PAREN(context) || j->alias != NULL)
11148  appendStringInfoChar(buf, ')');
11149 
11150  /* Yes, it's correct to put alias after the right paren ... */
11151  if (j->alias != NULL)
11152  {
11153  /*
11154  * Note that it's correct to emit an alias clause if and only if
11155  * there was one originally. Otherwise we'd be converting a named
11156  * join to unnamed or vice versa, which creates semantic
11157  * subtleties we don't want. However, we might print a different
11158  * alias name than was there originally.
11159  */
11160  appendStringInfo(buf, " %s",
11162  context)));
11163  get_column_alias_list(colinfo, context);
11164  }
11165  }
11166  else
11167  elog(ERROR, "unrecognized node type: %d",
11168  (int) nodeTag(jtnode));
11169 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
#define nodeTag(nodeptr)
Definition: nodes.h:133
@ JOIN_FULL
Definition: nodes.h:306
@ JOIN_INNER
Definition: nodes.h:304
@ JOIN_RIGHT
Definition: nodes.h:307
@ JOIN_LEFT
Definition: nodes.h:305
@ RTE_CTE
Definition: parsenodes.h:1020
@ RTE_VALUES
Definition: parsenodes.h:1019
@ RTE_SUBQUERY
Definition: parsenodes.h:1015
@ RTE_FUNCTION
Definition: parsenodes.h:1017
@ RTE_TABLEFUNC
Definition: parsenodes.h:1018
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition: ruleutils.c:4942
#define PRETTYINDENT_JOIN
Definition: ruleutils.c:84
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
Definition: ruleutils.c:5427
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Definition: ruleutils.c:11339
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:11248
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:11288
static void get_rule_expr_funccall(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:9628
#define deparse_columns_fetch(rangetable_index, dpns)
Definition: ruleutils.c:297
static void get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10687
Definition: pg_list.h:54
char * ctename
Definition: parsenodes.h:1164
TableFunc * tablefunc
Definition: parsenodes.h:1154
bool funcordinality
Definition: parsenodes.h:1149
struct TableSampleClause * tablesample
Definition: parsenodes.h:1075
Query * subquery
Definition: parsenodes.h:1081
List * functions
Definition: parsenodes.h:1148
List * usingNames
Definition: ruleutils.c:293

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

Referenced by get_from_clause().

◆ get_func_expr()

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

Definition at line 9718 of file ruleutils.c.

9720 {
9721  StringInfo buf = context->buf;
9722  Oid funcoid = expr->funcid;
9723  Oid argtypes[FUNC_MAX_ARGS];
9724  int nargs;
9725  List *argnames;
9726  bool use_variadic;
9727  ListCell *l;
9728 
9729  /*
9730  * If the function call came from an implicit coercion, then just show the
9731  * first argument --- unless caller wants to see implicit coercions.
9732  */
9733  if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
9734  {
9735  get_rule_expr_paren((Node *) linitial(expr->args), context,
9736  false, (Node *) expr);
9737  return;
9738  }
9739 
9740  /*
9741  * If the function call came from a cast, then show the first argument
9742  * plus an explicit cast operation.
9743  */
9744  if (expr->funcformat == COERCE_EXPLICIT_CAST ||
9745  expr->funcformat == COERCE_IMPLICIT_CAST)
9746  {
9747  Node *arg = linitial(expr->args);
9748  Oid rettype = expr->funcresulttype;
9749  int32 coercedTypmod;
9750 
9751  /* Get the typmod if this is a length-coercion function */
9752  (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
9753 
9754  get_coercion_expr(arg, context,
9755  rettype, coercedTypmod,
9756  (Node *) expr);
9757 
9758  return;
9759  }
9760 
9761  /*
9762  * If the function was called using one of the SQL spec's random special
9763  * syntaxes, try to reproduce that. If we don't recognize the function,
9764  * fall through.
9765  */
9766  if (expr->funcformat == COERCE_SQL_SYNTAX)
9767  {
9768  if (get_func_sql_syntax(expr, context))
9769  return;
9770  }
9771 
9772  /*
9773  * Normal function: display as proname(args). First we need to extract
9774  * the argument datatypes.
9775  */
9776  if (list_length(expr->args) > FUNC_MAX_ARGS)
9777  ereport(ERROR,
9778  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
9779  errmsg("too many arguments")));
9780  nargs = 0;
9781  argnames = NIL;
9782  foreach(l, expr->args)
9783  {
9784  Node *arg = (Node *) lfirst(l);
9785 
9786  if (IsA(arg, NamedArgExpr))
9787  argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
9788  argtypes[nargs] = exprType(arg);
9789  nargs++;
9790  }
9791 
9792  appendStringInfo(buf, "%s(",
9793  generate_function_name(funcoid, nargs,
9794  argnames, argtypes,
9795  expr->funcvariadic,
9796  &use_variadic,
9797  context->special_exprkind));
9798  nargs = 0;
9799  foreach(l, expr->args)
9800  {
9801  if (nargs++ > 0)
9802  appendStringInfoString(buf, ", ");
9803  if (use_variadic && lnext(expr->args, l) == NULL)
9804  appendStringInfoString(buf, "VARIADIC ");
9805  get_rule_expr((Node *) lfirst(l), context, true);
9806  }
9807  appendStringInfoChar(buf, ')');
9808 }
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ereport(elevel,...)
Definition: elog.h:149
List * lappend(List *list, void *datum)
Definition: list.c:338
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:500
@ COERCE_SQL_SYNTAX
Definition: primnodes.h:664
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:663
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:662
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Definition: ruleutils.c:10041
static void get_coercion_expr(Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
Definition: ruleutils.c:10321
Oid funcid
Definition: primnodes.h:677
List * args
Definition: primnodes.h:695

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

Referenced by get_rule_expr().

◆ get_func_sql_syntax()

static bool get_func_sql_syntax ( FuncExpr expr,
deparse_context context 
)
static

Definition at line 10041 of file ruleutils.c.

10042 {
10043  StringInfo buf = context->buf;
10044  Oid funcoid = expr->funcid;
10045 
10046  switch (funcoid)
10047  {
10048  case F_TIMEZONE_INTERVAL_TIMESTAMP:
10049  case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
10050  case F_TIMEZONE_INTERVAL_TIMETZ:
10051  case F_TIMEZONE_TEXT_TIMESTAMP:
10052  case F_TIMEZONE_TEXT_TIMESTAMPTZ:
10053  case F_TIMEZONE_TEXT_TIMETZ:
10054  /* AT TIME ZONE ... note reversed argument order */
10055  appendStringInfoChar(buf, '(');
10056  get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
10057  (Node *) expr);
10058  appendStringInfoString(buf, " AT TIME ZONE ");
10059  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10060  (Node *) expr);
10061  appendStringInfoChar(buf, ')');
10062  return true;
10063 
10064  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
10065  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
10066  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
10067  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
10068  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
10069  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
10070  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
10071  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
10072  case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
10073  case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
10074  case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
10075  case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
10076  case F_OVERLAPS_TIME_TIME_TIME_TIME:
10077  /* (x1, x2) OVERLAPS (y1, y2) */
10078  appendStringInfoString(buf, "((");
10079  get_rule_expr((Node *) linitial(expr->args), context, false);
10080  appendStringInfoString(buf, ", ");
10081  get_rule_expr((Node *) lsecond(expr->args), context, false);
10082  appendStringInfoString(buf, ") OVERLAPS (");
10083  get_rule_expr((Node *) lthird(expr->args), context, false);
10084  appendStringInfoString(buf, ", ");
10085  get_rule_expr((Node *) lfourth(expr->args), context, false);
10086  appendStringInfoString(buf, "))");
10087  return true;
10088 
10089  case F_EXTRACT_TEXT_DATE:
10090  case F_EXTRACT_TEXT_TIME:
10091  case F_EXTRACT_TEXT_TIMETZ:
10092  case F_EXTRACT_TEXT_TIMESTAMP:
10093  case F_EXTRACT_TEXT_TIMESTAMPTZ:
10094  case F_EXTRACT_TEXT_INTERVAL:
10095  /* EXTRACT (x FROM y) */
10096  appendStringInfoString(buf, "EXTRACT(");
10097  {
10098  Const *con = (Const *) linitial(expr->args);
10099 
10100  Assert(IsA(con, Const) &&
10101  con->consttype == TEXTOID &&
10102  !con->constisnull);
10103  appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
10104  }
10105  appendStringInfoString(buf, " FROM ");
10106  get_rule_expr((Node *) lsecond(expr->args), context, false);
10107  appendStringInfoChar(buf, ')');
10108  return true;
10109 
10110  case F_IS_NORMALIZED:
10111  /* IS xxx NORMALIZED */
10113  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10114  (Node *) expr);
10115  appendStringInfoString(buf, " IS");
10116  if (list_length(expr->args) == 2)
10117  {
10118  Const *con = (Const *) lsecond(expr->args);
10119 
10120  Assert(IsA(con, Const) &&
10121  con->consttype == TEXTOID &&
10122  !con->constisnull);
10123  appendStringInfo(buf, " %s",
10124  TextDatumGetCString(con->constvalue));
10125  }
10126  appendStringInfoString(buf, " NORMALIZED)");
10127  return true;
10128 
10129  case F_PG_COLLATION_FOR:
10130  /* COLLATION FOR */
10131  appendStringInfoString(buf, "COLLATION FOR (");
10132  get_rule_expr((Node *) linitial(expr->args), context, false);
10133  appendStringInfoChar(buf, ')');
10134  return true;
10135 
10136  case F_NORMALIZE:
10137  /* NORMALIZE() */
10138  appendStringInfoString(buf, "NORMALIZE(");
10139  get_rule_expr((Node *) linitial(expr->args), context, false);
10140  if (list_length(expr->args) == 2)
10141  {
10142  Const *con = (Const *) lsecond(expr->args);
10143 
10144  Assert(IsA(con, Const) &&
10145  con->consttype == TEXTOID &&
10146  !con->constisnull);
10147  appendStringInfo(buf, ", %s",
10148  TextDatumGetCString(con->constvalue));
10149  }
10150  appendStringInfoChar(buf, ')');
10151  return true;
10152 
10153  case F_OVERLAY_BIT_BIT_INT4:
10154  case F_OVERLAY_BIT_BIT_INT4_INT4:
10155  case F_OVERLAY_BYTEA_BYTEA_INT4:
10156  case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
10157  case F_OVERLAY_TEXT_TEXT_INT4:
10158  case F_OVERLAY_TEXT_TEXT_INT4_INT4:
10159  /* OVERLAY() */
10160  appendStringInfoString(buf, "OVERLAY(");
10161  get_rule_expr((Node *) linitial(expr->args), context, false);
10162  appendStringInfoString(buf, " PLACING ");
10163  get_rule_expr((Node *) lsecond(expr->args), context, false);
10164  appendStringInfoString(buf, " FROM ");
10165  get_rule_expr((Node *) lthird(expr->args), context, false);
10166  if (list_length(expr->args) == 4)
10167  {
10168  appendStringInfoString(buf, " FOR ");
10169  get_rule_expr((Node *) lfourth(expr->args), context, false);
10170  }
10171  appendStringInfoChar(buf, ')');
10172  return true;
10173 
10174  case F_POSITION_BIT_BIT:
10175  case F_POSITION_BYTEA_BYTEA:
10176  case F_POSITION_TEXT_TEXT:
10177  /* POSITION() ... extra parens since args are b_expr not a_expr */
10178  appendStringInfoString(buf, "POSITION((");
10179  get_rule_expr((Node *) lsecond(expr->args), context, false);
10180  appendStringInfoString(buf, ") IN (");
10181  get_rule_expr((Node *) linitial(expr->args), context, false);
10182  appendStringInfoString(buf, "))");
10183  return true;
10184 
10185  case F_SUBSTRING_BIT_INT4:
10186  case F_SUBSTRING_BIT_INT4_INT4:
10187  case F_SUBSTRING_BYTEA_INT4:
10188  case F_SUBSTRING_BYTEA_INT4_INT4:
10189  case F_SUBSTRING_TEXT_INT4:
10190  case F_SUBSTRING_TEXT_INT4_INT4:
10191  /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
10192  appendStringInfoString(buf, "SUBSTRING(");
10193  get_rule_expr((Node *) linitial(expr->args), context, false);
10194  appendStringInfoString(buf, " FROM ");
10195  get_rule_expr((Node *) lsecond(expr->args), context, false);
10196  if (list_length(expr->args) == 3)
10197  {
10198  appendStringInfoString(buf, " FOR ");
10199  get_rule_expr((Node *) lthird(expr->args), context, false);
10200  }
10201  appendStringInfoChar(buf, ')');
10202  return true;
10203 
10204  case F_SUBSTRING_TEXT_TEXT_TEXT:
10205  /* SUBSTRING SIMILAR/ESCAPE */
10206  appendStringInfoString(buf, "SUBSTRING(");
10207  get_rule_expr((Node *) linitial(expr->args), context, false);
10208  appendStringInfoString(buf, " SIMILAR ");
10209  get_rule_expr((Node *) lsecond(expr->args), context, false);
10210  appendStringInfoString(buf, " ESCAPE ");
10211  get_rule_expr((Node *) lthird(expr->args), context, false);
10212  appendStringInfoChar(buf, ')');
10213  return true;
10214 
10215  case F_BTRIM_BYTEA_BYTEA:
10216  case F_BTRIM_TEXT:
10217  case F_BTRIM_TEXT_TEXT:
10218  /* TRIM() */
10219  appendStringInfoString(buf, "TRIM(BOTH");
10220  if (list_length(expr->args) == 2)
10221  {
10222  appendStringInfoChar(buf, ' ');
10223  get_rule_expr((Node *) lsecond(expr->args), context, false);
10224  }
10225  appendStringInfoString(buf, " FROM ");
10226  get_rule_expr((Node *) linitial(expr->args), context, false);
10227  appendStringInfoChar(buf, ')');
10228  return true;
10229 
10230  case F_LTRIM_BYTEA_BYTEA:
10231  case F_LTRIM_TEXT:
10232  case F_LTRIM_TEXT_TEXT:
10233  /* TRIM() */
10234  appendStringInfoString(buf, "TRIM(LEADING");
10235  if (list_length(expr->args) == 2)
10236  {
10237  appendStringInfoChar(buf, ' ');
10238  get_rule_expr((Node *) lsecond(expr->args), context, false);
10239  }
10240  appendStringInfoString(buf, " FROM ");
10241  get_rule_expr((Node *) linitial(expr->args), context, false);
10242  appendStringInfoChar(buf, ')');
10243  return true;
10244 
10245  case F_RTRIM_BYTEA_BYTEA:
10246  case F_RTRIM_TEXT:
10247  case F_RTRIM_TEXT_TEXT:
10248  /* TRIM() */
10249  appendStringInfoString(buf, "TRIM(TRAILING");
10250  if (list_length(expr->args) == 2)
10251  {
10252  appendStringInfoChar(buf, ' ');
10253  get_rule_expr((Node *) lsecond(expr->args), context, false);
10254  }
10255  appendStringInfoString(buf, " FROM ");
10256  get_rule_expr((Node *) linitial(expr->args), context, false);
10257  appendStringInfoChar(buf, ')');
10258  return true;
10259 
10260  case F_CURRENT_CATALOG:
10261  appendStringInfoString(buf, "CURRENT_CATALOG");
10262  return true;
10263  case F_CURRENT_ROLE:
10264  appendStringInfoString(buf, "CURRENT_ROLE");
10265  return true;
10266  case F_CURRENT_SCHEMA:
10267  appendStringInfoString(buf, "CURRENT_SCHEMA");
10268  return true;
10269  case F_CURRENT_USER:
10270  appendStringInfoString(buf, "CURRENT_USER");
10271  return true;
10272  case F_USER:
10273  appendStringInfoString(buf, "USER");
10274  return true;
10275  case F_SESSION_USER:
10276  appendStringInfoString(buf, "SESSION_USER");
10277  return true;
10278  case F_SYSTEM_USER:
10279  appendStringInfoString(buf, "SYSTEM_USER");
10280  return true;
10281 
10282  case F_CURRENT_DATE:
10283  appendStringInfoString(buf, "CURRENT_DATE");
10284  return true;
10285  case F_CURRENT_TIME:
10286  appendStringInfoString(buf, "CURRENT_TIME");
10287  get_func_sql_syntax_time(expr->args, context);
10288  return true;
10289  case F_CURRENT_TIMESTAMP:
10290  appendStringInfoString(buf, "CURRENT_TIMESTAMP");
10291  get_func_sql_syntax_time(expr->args, context);
10292  return true;
10293  case F_LOCALTIME:
10294  appendStringInfoString(buf, "LOCALTIME");
10295  get_func_sql_syntax_time(expr->args, context);
10296  return true;
10297  case F_LOCALTIMESTAMP:
10298  appendStringInfoString(buf, "LOCALTIMESTAMP");
10299  get_func_sql_syntax_time(expr->args, context);
10300  return true;
10301 
10302  case F_XMLEXISTS:
10303  /* XMLEXISTS ... extra parens because args are c_expr */
10304  appendStringInfoString(buf, "XMLEXISTS((");
10305  get_rule_expr((Node *) linitial(expr->args), context, false);
10306  appendStringInfoString(buf, ") PASSING (");
10307  get_rule_expr((Node *) lsecond(expr->args), context, false);
10308  appendStringInfoString(buf, "))");
10309  return true;
10310  }
10311  return false;
10312 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
#define lthird(l)
Definition: pg_list.h:188
#define lsecond(l)
Definition: pg_list.h:183
#define lfourth(l)
Definition: pg_list.h:193
static void get_func_sql_syntax_time(List *args, deparse_context *context)
Definition: ruleutils.c:10015

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

Referenced by get_func_expr().

◆ get_func_sql_syntax_time()

static void get_func_sql_syntax_time ( List args,
deparse_context context 
)
static

Definition at line 10015 of file ruleutils.c.

10016 {
10017  StringInfo buf = context->buf;
10018  Const *cons;
10019 
10020  if (list_length(args) != 1)
10021  return;
10022 
10023  cons = (Const *) linitial(args);
10024  Assert(IsA(cons, Const));
10025 
10026  if (!cons->constisnull)
10027  {
10029  get_rule_expr((Node *) cons, context, false);
10031  }
10032 }

References appendStringInfoString(), generate_unaccent_rules::args, Assert(), deparse_context::buf, buf, get_rule_expr(), IsA, linitial, and list_length().

Referenced by get_func_sql_syntax().

◆ get_insert_query_def()

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

Definition at line 6603 of file ruleutils.c.

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

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

Referenced by get_query_def().

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

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

References Alias::aliasname, Assert(), attname, attnum, RangeTblEntry::ctelevelsup, RangeTblEntry::ctename, CommonTableExpr::ctename, CommonTableExpr::ctequery, deparse_namespace::ctes, elog(), RangeTblEntry::eref, ERROR, TargetEntry::expr, find_param_referent(), get_expr_result_tupdesc(), get_rte_attribute_name(), get_tle_by_resno(), GetCTETargetList, if(), deparse_namespace::index_tlist, INDEX_VAR, deparse_namespace::inner_plan, deparse_namespace::inner_tlist, INNER_VAR, InvalidAttrNumber, IsA, RangeTblEntry::joinaliasvars, lcons(), lfirst, list_copy_tail(), list_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(), rt_fetch, deparse_namespace::rtable, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, set_deparse_for_query(), strVal, RangeTblEntry::subquery, Query::targetList, TupleDescAttr, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by get_rule_expr().

◆ get_opclass_name()

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

Definition at line 11383 of file ruleutils.c.

11385 {
11386  HeapTuple ht_opc;
11387  Form_pg_opclass opcrec;
11388  char *opcname;
11389  char *nspname;
11390 
11391  ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
11392  if (!HeapTupleIsValid(ht_opc))
11393  elog(ERROR, "cache lookup failed for opclass %u", opclass);
11394  opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
11395 
11396  if (!OidIsValid(actual_datatype) ||
11397  GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
11398  {
11399  /* Okay, we need the opclass name. Do we need to qualify it? */
11400  opcname = NameStr(opcrec->opcname);
11401  if (OpclassIsVisible(opclass))
11402  appendStringInfo(buf, " %s", quote_identifier(opcname));
11403  else
11404  {
11405  nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
11406  appendStringInfo(buf, " %s.%s",
11407  quote_identifier(nspname),
11408  quote_identifier(opcname));
11409  }
11410  }
11411  ReleaseSysCache(ht_opc);
11412 }
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2229
bool OpclassIsVisible(Oid opcid)
Definition: namespace.c:1876
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
@ CLAOID
Definition: syscache.h:48

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

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

◆ get_oper_expr()

static void get_oper_expr ( OpExpr expr,
deparse_context context 
)
static

Definition at line 9678 of file ruleutils.c.

9679 {
9680  StringInfo buf = context->buf;
9681  Oid opno = expr->opno;
9682  List *args = expr->args;
9683 
9684  if (!PRETTY_PAREN(context))
9685  appendStringInfoChar(buf, '(');
9686  if (list_length(args) == 2)
9687  {
9688  /* binary operator */
9689  Node *arg1 = (Node *) linitial(args);
9690  Node *arg2 = (Node *) lsecond(args);
9691 
9692  get_rule_expr_paren(arg1, context, true, (Node *) expr);
9693  appendStringInfo(buf, " %s ",
9695  exprType(arg1),
9696  exprType(arg2)));
9697  get_rule_expr_paren(arg2, context, true, (Node *) expr);
9698  }
9699  else
9700  {
9701  /* prefix operator */
9702  Node *arg = (Node *) linitial(args);
9703 
9704  appendStringInfo(buf, "%s ",
9706  InvalidOid,
9707  exprType(arg)));
9708  get_rule_expr_paren(arg, context, true, (Node *) expr);
9709  }
9710  if (!PRETTY_PAREN(context))
9711  appendStringInfoChar(buf, ')');
9712 }
static char * generate_operator_name(Oid operid, Oid arg1, Oid arg2)
Definition: ruleutils.c:11882
Oid opno
Definition: primnodes.h:745
List * args
Definition: primnodes.h:763

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

Referenced by get_rule_expr().

◆ get_parameter()

static void get_parameter ( Param param,
deparse_context context 
)
static

Definition at line 7998 of file ruleutils.c.

7999 {
8000  Node *expr;
8001  deparse_namespace *dpns;
8002  ListCell *ancestor_cell;
8003 
8004  /*
8005  * If it's a PARAM_EXEC parameter, try to locate the expression from which
8006  * the parameter was computed. Note that failing to find a referent isn't
8007  * an error, since the Param might well be a subplan output rather than an
8008  * input.
8009  */
8010  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8011  if (expr)
8012  {
8013  /* Found a match, so print it */
8014  deparse_namespace save_dpns;
8015  bool save_varprefix;
8016  bool need_paren;
8017 
8018  /* Switch attention to the ancestor plan node */
8019  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8020 
8021  /*
8022  * Force prefixing of Vars, since they won't belong to the relation
8023  * being scanned in the original plan node.
8024  */
8025  save_varprefix = context->varprefix;
8026  context->varprefix = true;
8027 
8028  /*
8029  * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8030  * upper-level Param, which wouldn't need extra parentheses.
8031  * Otherwise, insert parens to ensure the expression looks atomic.
8032  */
8033  need_paren = !(IsA(expr, Var) ||
8034  IsA(expr, Aggref) ||
8035  IsA(expr, GroupingFunc) ||
8036  IsA(expr, Param));
8037  if (need_paren)
8038  appendStringInfoChar(context->buf, '(');
8039 
8040  get_rule_expr(expr, context, false);
8041 
8042  if (need_paren)
8043  appendStringInfoChar(context->buf, ')');
8044 
8045  context->varprefix = save_varprefix;
8046 
8047  pop_ancestor_plan(dpns, &save_dpns);
8048 
8049  return;
8050  }
8051 
8052  /*
8053  * If it's an external parameter, see if the outermost namespace provides
8054  * function argument names.
8055  */
8056  if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8057  {
8058  dpns = llast(context->namespaces);
8059  if (dpns->argnames &&
8060  param->paramid > 0 &&
8061  param->paramid <= dpns->numargs)
8062  {
8063  char *argname = dpns->argnames[param->paramid - 1];
8064 
8065  if (argname)
8066  {
8067  bool should_qualify = false;
8068  ListCell *lc;
8069 
8070  /*
8071  * Qualify the parameter name if there are any other deparse
8072  * namespaces with range tables. This avoids qualifying in
8073  * trivial cases like "RETURN a + b", but makes it safe in all
8074  * other cases.
8075  */
8076  foreach(lc, context->namespaces)
8077  {
8078  deparse_namespace *depns = lfirst(lc);
8079 
8080  if (depns->rtable_names != NIL)
8081  {
8082  should_qualify = true;
8083  break;
8084  }
8085  }
8086  if (should_qualify)
8087  {
8089  appendStringInfoChar(context->buf, '.');
8090  }
8091 
8092  appendStringInfoString(context->buf, quote_identifier(argname));
8093  return;
8094  }
8095  }
8096  }
8097 
8098  /*
8099  * Not PARAM_EXEC, or couldn't find referent: just print $N.
8100  */
8101  appendStringInfo(context->buf, "$%d", param->paramid);
8102 }
#define llast(l)
Definition: pg_list.h:198
@ PARAM_EXTERN
Definition: primnodes.h:345
char ** argnames
Definition: ruleutils.c:184

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

Referenced by get_rule_expr().

◆ get_query_def()

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

Definition at line 5427 of file ruleutils.c.

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

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

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

◆ get_range_partbound_string()

char* get_range_partbound_string ( List bound_datums)

Definition at line 12196 of file ruleutils.c.

12197 {
12198  deparse_context context;
12200  ListCell *cell;
12201  char *sep;
12202 
12203  memset(&context, 0, sizeof(deparse_context));
12204  context.buf = buf;
12205 
12206  appendStringInfoChar(buf, '(');
12207  sep = "";
12208  foreach(cell, bound_datums)
12209  {
12210  PartitionRangeDatum *datum =
12212 
12214  if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
12215  appendStringInfoString(buf, "MINVALUE");
12216  else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
12217  appendStringInfoString(buf, "MAXVALUE");
12218  else
12219  {
12220  Const *val = castNode(Const, datum->value);
12221 
12222  get_const_expr(val, &context, -1);
12223  }
12224  sep = ", ";
12225  }
12226  appendStringInfoChar(buf, ')');
12227 
12228  return buf->data;
12229 }
long val
Definition: informix.c:664
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition: parsenodes.h:921
@ PARTITION_RANGE_DATUM_MINVALUE
Definition: parsenodes.h:919
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
PartitionRangeDatumKind kind
Definition: parsenodes.h:928

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

Referenced by check_new_partition_bound(), and get_rule_expr().

◆ get_relation_name()

static char * get_relation_name ( Oid  relid)
static

Definition at line 11655 of file ruleutils.c.

11656 {
11657  char *relname = get_rel_name(relid);
11658 
11659  if (!relname)
11660  elog(ERROR, "cache lookup failed for relation %u", relid);
11661  return relname;
11662 }
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1910

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

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

◆ get_reloptions()

static void get_reloptions ( StringInfo  buf,
Datum  reloptions 
)
static

Definition at line 12108 of file ruleutils.c.

12109 {
12110  Datum *options;
12111  int noptions;
12112  int i;
12113 
12114  deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
12115  &options, NULL, &noptions);
12116 
12117  for (i = 0; i < noptions; i++)
12118  {
12119  char *option = TextDatumGetCString(options[i]);
12120  char *name;
12121  char *separator;
12122  char *value;
12123 
12124  /*
12125  * Each array element should have the form name=value. If the "=" is
12126  * missing for some reason, treat it like an empty value.
12127  */
12128  name = option;
12129  separator = strchr(option, '=');
12130  if (separator)
12131  {
12132  *separator = '\0';
12133  value = separator + 1;
12134  }
12135  else
12136  value = "";
12137 
12138  if (i > 0)
12139  appendStringInfoString(buf, ", ");
12141 
12142  /*
12143  * In general we need to quote the value; but to avoid unnecessary
12144  * clutter, do not quote if it is an identifier that would not need
12145  * quoting. (We could also allow numbers, but that is a bit trickier
12146  * than it looks --- for example, are leading zeroes significant? We
12147  * don't want to assume very much here about what custom reloptions
12148  * might mean.)
12149  */
12150  if (quote_identifier(value) == value)
12152  else
12154 
12155  pfree(option);
12156  }
12157 }
const char * name
Definition: encode.c:571
static struct @143 value
static size_t noptions
static char ** options

References appendStringInfo(), appendStringInfoString(), buf, DatumGetArrayTypeP, deconstruct_array_builtin(), i, name, noptions, options, pfree(), quote_identifier(), simple_quote_literal(), TextDatumGetCString, and value.

Referenced by flatten_reloptions(), and pg_get_indexdef_worker().

◆ get_rtable_name()

static char * get_rtable_name ( int  rtindex,
deparse_context context 
)
static

Definition at line 4942 of file ruleutils.c.

4943 {
4945 
4946  Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
4947  return (char *) list_nth(dpns->rtable_names, rtindex - 1);
4948 }

References Assert(), linitial, list_length(), list_nth(), deparse_context::namespaces, and deparse_namespace::rtable_names.

Referenced by get_from_clause_item(), get_rte_alias(), and get_select_query_def().

◆ get_rte_alias()

static void get_rte_alias ( RangeTblEntry rte,
int  varno,
bool  use_as,
deparse_context context 
)
static

Definition at line 11177 of file ruleutils.c.

11179 {
11181  char *refname = get_rtable_name(varno, context);
11182  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
11183  bool printalias = false;
11184 
11185  if (rte->alias != NULL)
11186  {
11187  /* Always print alias if user provided one */
11188  printalias = true;
11189  }
11190  else if (colinfo->printaliases)
11191  {
11192  /* Always print alias if we need to print column aliases */
11193  printalias = true;
11194  }
11195  else if (rte->rtekind == RTE_RELATION)
11196  {
11197  /*
11198  * No need to print alias if it's same as relation name (this would
11199  * normally be the case, but not if set_rtable_names had to resolve a
11200  * conflict).
11201  */
11202  if (strcmp(refname, get_relation_name(rte->relid)) != 0)
11203  printalias = true;
11204  }
11205  else if (rte->rtekind == RTE_FUNCTION)
11206  {
11207  /*
11208  * For a function RTE, always print alias. This covers possible
11209  * renaming of the function and/or instability of the FigureColname
11210  * rules for things that aren't simple functions. Note we'd need to
11211  * force it anyway for the columndef list case.
11212  */
11213  printalias = true;
11214  }
11215  else if (rte->rtekind == RTE_SUBQUERY ||
11216  rte->rtekind == RTE_VALUES)
11217  {
11218  /*
11219  * For a subquery, always print alias. This makes the output
11220  * SQL-spec-compliant, even though we allow such aliases to be omitted
11221  * on input.
11222  */
11223  printalias = true;
11224  }
11225  else if (rte->rtekind == RTE_CTE)
11226  {
11227  /*
11228  * No need to print alias if it's same as CTE name (this would
11229  * normally be the case, but not if set_rtable_names had to resolve a
11230  * conflict).
11231  */
11232  if (strcmp(refname, rte->ctename) != 0)
11233  printalias = true;
11234  }
11235 
11236  if (printalias)
11237  appendStringInfo(context->buf, "%s%s",
11238  use_as ? " AS " : " ",
11239  quote_identifier(refname));
11240 }
static char * get_relation_name(Oid relid)
Definition: ruleutils.c:11655

References RangeTblEntry::alias, appendStringInfo(), deparse_context::buf, RangeTblEntry::ctename, deparse_columns_fetch, get_relation_name(), get_rtable_name(), linitial, deparse_context::namespaces, deparse_columns::printaliases, quote_identifier(), RangeTblEntry::relid, RTE_CTE, RTE_FUNCTION, RTE_RELATION, RTE_SUBQUERY, RTE_VALUES, and RangeTblEntry::rtekind.

Referenced by get_delete_query_def(), get_from_clause_item(), get_insert_query_def(), and get_update_query_def().

◆ get_rule_expr()

static void get_rule_expr ( Node node,
deparse_context context,
bool  showimplicit 
)
static

Definition at line 8460 of file ruleutils.c.

8462 {
8463  StringInfo buf = context->buf;
8464 
8465  if (node == NULL)
8466  return;
8467 
8468  /* Guard against excessively long or deeply-nested queries */
8471 
8472  /*
8473  * Each level of get_rule_expr must emit an indivisible term
8474  * (parenthesized if necessary) to ensure result is reparsed into the same
8475  * expression tree. The only exception is that when the input is a List,
8476  * we emit the component items comma-separated with no surrounding
8477  * decoration; this is convenient for most callers.
8478  */
8479  switch (nodeTag(node))
8480  {
8481  case T_Var:
8482  (void) get_variable((Var *) node, 0, false, context);
8483  break;
8484 
8485  case T_Const:
8486  get_const_expr((Const *) node, context, 0);
8487  break;
8488 
8489  case T_Param:
8490  get_parameter((Param *) node, context);
8491  break;
8492 
8493  case T_Aggref:
8494  get_agg_expr((Aggref *) node, context, (Aggref *) node);
8495  break;
8496 
8497  case T_GroupingFunc:
8498  {
8499  GroupingFunc *gexpr = (GroupingFunc *) node;
8500 
8501  appendStringInfoString(buf, "GROUPING(");
8502  get_rule_expr((Node *) gexpr->args, context, true);
8503  appendStringInfoChar(buf, ')');
8504  }
8505  break;
8506 
8507  case T_WindowFunc:
8508  get_windowfunc_expr((WindowFunc *) node, context);
8509  break;
8510 
8511  case T_SubscriptingRef:
8512  {
8513  SubscriptingRef *sbsref = (SubscriptingRef *) node;
8514  bool need_parens;
8515 
8516  /*
8517  * If the argument is a CaseTestExpr, we must be inside a
8518  * FieldStore, ie, we are assigning to an element of an array
8519  * within a composite column. Since we already punted on
8520  * displaying the FieldStore's target information, just punt
8521  * here too, and display only the assignment source
8522  * expression.
8523  */
8524  if (IsA(sbsref->refexpr, CaseTestExpr))
8525  {
8526  Assert(sbsref->refassgnexpr);
8527  get_rule_expr((Node *) sbsref->refassgnexpr,
8528  context, showimplicit);
8529  break;
8530  }
8531 
8532  /*
8533  * Parenthesize the argument unless it's a simple Var or a
8534  * FieldSelect. (In particular, if it's another
8535  * SubscriptingRef, we *must* parenthesize to avoid
8536  * confusion.)
8537  */
8538  need_parens = !IsA(sbsref->refexpr, Var) &&
8539  !IsA(sbsref->refexpr, FieldSelect);
8540  if (need_parens)
8541  appendStringInfoChar(buf, '(');
8542  get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
8543  if (need_parens)
8544  appendStringInfoChar(buf, ')');
8545 
8546  /*
8547  * If there's a refassgnexpr, we want to print the node in the
8548  * format "container[subscripts] := refassgnexpr". This is
8549  * not legal SQL, so decompilation of INSERT or UPDATE
8550  * statements should always use processIndirection as part of
8551  * the statement-level syntax. We should only see this when
8552  * EXPLAIN tries to print the targetlist of a plan resulting
8553  * from such a statement.
8554  */
8555  if (sbsref->refassgnexpr)
8556  {
8557  Node *refassgnexpr;
8558 
8559  /*
8560  * Use processIndirection to print this node's subscripts
8561  * as well as any additional field selections or
8562  * subscripting in immediate descendants. It returns the
8563  * RHS expr that is actually being "assigned".
8564  */
8565  refassgnexpr = processIndirection(node, context);
8566  appendStringInfoString(buf, " := ");
8567  get_rule_expr(refassgnexpr, context, showimplicit);
8568  }
8569  else
8570  {
8571  /* Just an ordinary container fetch, so print subscripts */
8572  printSubscripts(sbsref, context);
8573  }
8574  }
8575  break;
8576 
8577  case T_FuncExpr:
8578  get_func_expr((FuncExpr *) node, context, showimplicit);
8579  break;
8580 
8581  case T_NamedArgExpr:
8582  {
8583  NamedArgExpr *na = (NamedArgExpr *) node;
8584 
8585  appendStringInfo(buf, "%s => ", quote_identifier(na->name));
8586  get_rule_expr((Node *) na->arg, context, showimplicit);
8587  }
8588  break;
8589 
8590  case T_OpExpr:
8591  get_oper_expr((OpExpr *) node, context);
8592  break;
8593 
8594  case T_DistinctExpr:
8595  {
8596  DistinctExpr *expr = (DistinctExpr *) node;
8597  List *args = expr->args;
8598  Node *arg1 = (Node *) linitial(args);
8599  Node *arg2 = (Node *) lsecond(args);
8600 
8601  if (!PRETTY_PAREN(context))
8602  appendStringInfoChar(buf, '(');
8603  get_rule_expr_paren(arg1, context, true, node);
8604  appendStringInfoString(buf, " IS DISTINCT FROM ");
8605  get_rule_expr_paren(arg2, context, true, node);
8606  if (!PRETTY_PAREN(context))
8607  appendStringInfoChar(buf, ')');
8608  }
8609  break;
8610 
8611  case T_NullIfExpr:
8612  {
8613  NullIfExpr *nullifexpr = (NullIfExpr *) node;
8614 
8615  appendStringInfoString(buf, "NULLIF(");
8616  get_rule_expr((Node *) nullifexpr->args, context, true);
8617  appendStringInfoChar(buf, ')');
8618  }
8619  break;
8620 
8621  case T_ScalarArrayOpExpr:
8622  {
8623  ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
8624  List *args = expr->args;
8625  Node *arg1 = (Node *) linitial(args);
8626  Node *arg2 = (Node *) lsecond(args);
8627 
8628  if (!PRETTY_PAREN(context))
8629  appendStringInfoChar(buf, '(');
8630  get_rule_expr_paren(arg1, context, true, node);
8631  appendStringInfo(buf, " %s %s (",
8633  exprType(arg1),
8635  expr->useOr ? "ANY" : "ALL");
8636  get_rule_expr_paren(arg2, context, true, node);
8637 
8638  /*
8639  * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
8640  * a bare sub-SELECT. Since we're here, the sub-SELECT must
8641  * be meant as a scalar sub-SELECT yielding an array value to
8642  * be used in ScalarArrayOpExpr; but the grammar will
8643  * preferentially interpret such a construct as an ANY/ALL
8644  * SubLink. To prevent misparsing the output that way, insert
8645  * a dummy coercion (which will be stripped by parse analysis,
8646  * so no inefficiency is added in dump and reload). This is
8647  * indeed most likely what the user wrote to get the construct
8648  * accepted in the first place.
8649  */
8650  if (IsA(arg2, SubLink) &&
8651  ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
8652  appendStringInfo(buf, "::%s",
8654  exprTypmod(arg2)));
8655  appendStringInfoChar(buf, ')');
8656  if (!PRETTY_PAREN(context))
8657  appendStringInfoChar(buf, ')');
8658  }
8659  break;
8660 
8661  case T_BoolExpr:
8662  {
8663  BoolExpr *expr = (BoolExpr *) node;
8664  Node *first_arg = linitial(expr->args);
8665  ListCell *arg;
8666 
8667  switch (expr->boolop)
8668  {
8669  case AND_EXPR:
8670  if (!PRETTY_PAREN(context))
8671  appendStringInfoChar(buf, '(');
8672  get_rule_expr_paren(first_arg, context,
8673  false, node);
8674  for_each_from(arg, expr->args, 1)
8675  {
8676  appendStringInfoString(buf, " AND ");
8677  get_rule_expr_paren((Node *) lfirst(arg), context,
8678  false, node);
8679  }
8680  if (!PRETTY_PAREN(context))
8681  appendStringInfoChar(buf, ')');
8682  break;
8683 
8684  case OR_EXPR:
8685  if (!PRETTY_PAREN(context))
8686  appendStringInfoChar(buf, '(');
8687  get_rule_expr_paren(first_arg, context,
8688  false, node);
8689  for_each_from(arg, expr->args, 1)
8690  {
8691  appendStringInfoString(buf, " OR ");
8692  get_rule_expr_paren((Node *) lfirst(arg), context,
8693  false, node);
8694  }
8695  if (!PRETTY_PAREN(context))
8696  appendStringInfoChar(buf, ')');
8697  break;
8698 
8699  case NOT_EXPR:
8700  if (!PRETTY_PAREN(context))
8701  appendStringInfoChar(buf, '(');
8702  appendStringInfoString(buf, "NOT ");
8703  get_rule_expr_paren(first_arg, context,
8704  false, node);
8705  if (!PRETTY_PAREN(context))
8706  appendStringInfoChar(buf, ')');
8707  break;
8708 
8709  default:
8710  elog(ERROR, "unrecognized boolop: %d",
8711  (int) expr->boolop);
8712  }
8713  }
8714  break;
8715 
8716  case T_SubLink:
8717  get_sublink_expr((SubLink *) node, context);
8718  break;
8719 
8720  case T_SubPlan:
8721  {
8722  SubPlan *subplan = (SubPlan *) node;
8723 
8724  /*
8725  * We cannot see an already-planned subplan in rule deparsing,
8726  * only while EXPLAINing a query plan. We don't try to
8727  * reconstruct the original SQL, just reference the subplan
8728  * that appears elsewhere in EXPLAIN's result.
8729  */
8730  if (subplan->useHashTable)
8731  appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
8732  else
8733  appendStringInfo(buf, "(%s)", subplan->plan_name);
8734  }
8735  break;
8736 
8737  case T_AlternativeSubPlan:
8738  {
8739  AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
8740  ListCell *lc;
8741 
8742  /*
8743  * This case cannot be reached in normal usage, since no
8744  * AlternativeSubPlan can appear either in parsetrees or
8745  * finished plan trees. We keep it just in case somebody
8746  * wants to use this code to print planner data structures.
8747  */
8748  appendStringInfoString(buf, "(alternatives: ");
8749  foreach(lc, asplan->subplans)
8750  {
8751  SubPlan *splan = lfirst_node(SubPlan, lc);
8752 
8753  if (splan->useHashTable)
8754  appendStringInfo(buf, "hashed %s", splan->plan_name);
8755  else
8756  appendStringInfoString(buf, splan->plan_name);
8757  if (lnext(asplan->subplans, lc))
8758  appendStringInfoString(buf, " or ");
8759  }
8760  appendStringInfoChar(buf, ')');
8761  }
8762  break;
8763 
8764  case T_FieldSelect:
8765  {
8766  FieldSelect *fselect = (FieldSelect *) node;
8767  Node *arg = (Node *) fselect->arg;
8768  int fno = fselect->fieldnum;
8769  const char *fieldname;
8770  bool need_parens;
8771 
8772  /*
8773  * Parenthesize the argument unless it's an SubscriptingRef or
8774  * another FieldSelect. Note in particular that it would be
8775  * WRONG to not parenthesize a Var argument; simplicity is not
8776  * the issue here, having the right number of names is.
8777  */
8778  need_parens = !IsA(