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

11978 {
11979  HeapTuple typetup;
11980  Form_pg_type typform;
11981  char *typname;
11982  char *nspname;
11983 
11984  typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
11985  if (!HeapTupleIsValid(typetup))
11986  elog(ERROR, "cache lookup failed for type %u", typid);
11987  typform = (Form_pg_type) GETSTRUCT(typetup);
11988 
11989  typname = NameStr(typform->typname);
11990  nspname = get_namespace_name_or_temp(typform->typnamespace);
11991 
11992  appendStringInfo(buf, "::%s.%s",
11994 
11995  ReleaseSysCache(typetup);
11996 }
#define NameStr(name)
Definition: c.h:682
#define ERROR
Definition: elog.h:35
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c: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:600
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:11529
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ TYPEOID
Definition: syscache.h:114

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

Referenced by generate_operator_clause().

◆ appendContextKeyword()

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

Definition at line 8350 of file ruleutils.c.

8352 {
8353  StringInfo buf = context->buf;
8354 
8355  if (PRETTY_INDENT(context))
8356  {
8357  int indentAmount;
8358 
8359  context->indentLevel += indentBefore;
8360 
8361  /* remove any trailing spaces currently in the buffer ... */
8363  /* ... then add a newline and some spaces */
8364  appendStringInfoChar(buf, '\n');
8365 
8366  if (context->indentLevel < PRETTYINDENT_LIMIT)
8367  indentAmount = Max(context->indentLevel, 0) + indentPlus;
8368  else
8369  {
8370  /*
8371  * If we're indented more than PRETTYINDENT_LIMIT characters, try
8372  * to conserve horizontal space by reducing the per-level
8373  * indentation. For best results the scale factor here should
8374  * divide all the indent amounts that get added to indentLevel
8375  * (PRETTYINDENT_STD, etc). It's important that the indentation
8376  * not grow unboundedly, else deeply-nested trees use O(N^2)
8377  * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8378  */
8379  indentAmount = PRETTYINDENT_LIMIT +
8380  (context->indentLevel - PRETTYINDENT_LIMIT) /
8381  (PRETTYINDENT_STD / 2);
8382  indentAmount %= PRETTYINDENT_LIMIT;
8383  /* scale/wrap logic affects indentLevel, but not indentPlus */
8384  indentAmount += indentPlus;
8385  }
8386  appendStringInfoSpaces(buf, indentAmount);
8387 
8389 
8390  context->indentLevel += indentAfter;
8391  if (context->indentLevel < 0)
8392  context->indentLevel = 0;
8393  }
8394  else
8396 }
#define Max(x, y)
Definition: c.h:931
static void removeStringInfoSpaces(StringInfo str)
Definition: ruleutils.c:8404
#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 4760 of file ruleutils.c.

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

2571 {
2572  Datum *keys;
2573  int nKeys;
2574  int j;
2575 
2576  /* Extract data from array of int16 */
2577  deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2578  &keys, NULL, &nKeys);
2579 
2580  for (j = 0; j < nKeys; j++)
2581  {
2582  char *colName;
2583 
2584  colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2585 
2586  if (j == 0)
2588  else
2589  appendStringInfo(buf, ", %s", quote_identifier(colName));
2590  }
2591 
2592  return nKeys;
2593 }
#define DatumGetArrayTypeP(X)
Definition: array.h:254
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3642
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:412
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:510

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

3657 {
3658  deparse_namespace *dpns;
3659  RangeTblEntry *rte;
3660 
3661  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3662 
3663  /* Build a minimal RTE for the rel */
3664  rte = makeNode(RangeTblEntry);
3665  rte->rtekind = RTE_RELATION;
3666  rte->relid = relid;
3667  rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3669  rte->alias = makeAlias(aliasname, NIL);
3670  rte->eref = rte->alias;
3671  rte->lateral = false;
3672  rte->inh = false;
3673  rte->inFromCl = true;
3674 
3675  /* Build one-element rtable */
3676  dpns->rtable = list_make1(rte);
3677  dpns->subplans = NIL;
3678  dpns->ctes = NIL;
3679  dpns->appendrels = NULL;
3680  set_rtable_names(dpns, NIL, NULL);
3682 
3683  /* Return a one-deep namespace stack */
3684  return list_make1(dpns);
3685 }
#define AccessShareLock
Definition: lockdefs.h:36
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:387
void * palloc0(Size size)
Definition: mcxt.c:1230
#define makeNode(_type_)
Definition: nodes.h:165
@ RTE_RELATION
Definition: parsenodes.h:1011
#define NIL
Definition: pg_list.h:66
#define list_make1(x1)
Definition: pg_list.h:210
static void set_simple_column_names(deparse_namespace *dpns)
Definition: ruleutils.c:4032
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
Definition: ruleutils.c:3822
Alias * eref
Definition: parsenodes.h:1176
Alias * alias
Definition: parsenodes.h:1175
RTEKind rtekind
Definition: parsenodes.h:1030
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 3701 of file ruleutils.c.

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

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

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

3626 {
3628  deparse_context context;
3629 
3630  initStringInfo(&buf);
3631  context.buf = &buf;
3632  context.namespaces = dpcontext;
3633  context.windowClause = NIL;
3634  context.windowTList = NIL;
3635  context.varprefix = forceprefix;
3636  context.prettyFlags = prettyFlags;
3637  context.wrapColumn = WRAP_COLUMN_DEFAULT;
3638  context.indentLevel = startIndent;
3639  context.special_exprkind = EXPR_KIND_NONE;
3640  context.appendparents = NULL;
3641 
3642  get_rule_expr(expr, &context, showimplicit);
3643 
3644  return buf.data;
3645 }
@ 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:8455
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 4853 of file ruleutils.c.

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

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

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

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

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

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

12142 {
12143  char *result = NULL;
12144  HeapTuple tuple;
12145  Datum reloptions;
12146  bool isnull;
12147 
12148  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12149  if (!HeapTupleIsValid(tuple))
12150  elog(ERROR, "cache lookup failed for relation %u", relid);
12151 
12152  reloptions = SysCacheGetAttr(RELOID, tuple,
12153  Anum_pg_class_reloptions, &isnull);
12154  if (!isnull)
12155  {
12157 
12158  initStringInfo(&buf);
12159  get_reloptions(&buf, reloptions);
12160 
12161  result = buf.data;
12162  }
12163 
12164  ReleaseSysCache(tuple);
12165 
12166  return result;
12167 }
static void get_reloptions(StringInfo buf, Datum reloptions)
Definition: ruleutils.c:12086
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
@ RELOID
Definition: syscache.h:89

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

Referenced by pg_get_constraintdef_worker(), and pg_get_indexdef_worker().

◆ generate_collation_name()

char* generate_collation_name ( Oid  collid)

Definition at line 12041 of file ruleutils.c.

12042 {
12043  HeapTuple tp;
12044  Form_pg_collation colltup;
12045  char *collname;
12046  char *nspname;
12047  char *result;
12048 
12049  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
12050  if (!HeapTupleIsValid(tp))
12051  elog(ERROR, "cache lookup failed for collation %u", collid);
12052  colltup = (Form_pg_collation) GETSTRUCT(tp);
12053  collname = NameStr(colltup->collname);
12054 
12055  if (!CollationIsVisible(collid))
12056  nspname = get_namespace_name_or_temp(colltup->collnamespace);
12057  else
12058  nspname = NULL;
12059 
12060  result = quote_qualified_identifier(nspname, collname);
12061 
12062  ReleaseSysCache(tp);
12063 
12064  return result;
12065 }
bool CollationIsVisible(Oid collid)
Definition: namespace.c:2091
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:57
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:11613
@ COLLOID
Definition: syscache.h:50

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

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

◆ generate_function_name()

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

Definition at line 11755 of file ruleutils.c.

11758 {
11759  char *result;
11760  HeapTuple proctup;
11761  Form_pg_proc procform;
11762  char *proname;
11763  bool use_variadic;
11764  char *nspname;
11765  FuncDetailCode p_result;
11766  Oid p_funcid;
11767  Oid p_rettype;
11768  bool p_retset;
11769  int p_nvargs;
11770  Oid p_vatype;
11771  Oid *p_true_typeids;
11772  bool force_qualify = false;
11773 
11774  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
11775  if (!HeapTupleIsValid(proctup))
11776  elog(ERROR, "cache lookup failed for function %u", funcid);
11777  procform = (Form_pg_proc) GETSTRUCT(proctup);
11778  proname = NameStr(procform->proname);
11779 
11780  /*
11781  * Due to parser hacks to avoid needing to reserve CUBE, we need to force
11782  * qualification in some special cases.
11783  */
11784  if (special_exprkind == EXPR_KIND_GROUP_BY)
11785  {
11786  if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
11787  force_qualify = true;
11788  }
11789 
11790  /*
11791  * Determine whether VARIADIC should be printed. We must do this first
11792  * since it affects the lookup rules in func_get_detail().
11793  *
11794  * We always print VARIADIC if the function has a merged variadic-array
11795  * argument. Note that this is always the case for functions taking a
11796  * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
11797  * and printed the array elements as separate arguments, the call could
11798  * match a newer non-VARIADIC function.
11799  */
11800  if (use_variadic_p)
11801  {
11802  /* Parser should not have set funcvariadic unless fn is variadic */
11803  Assert(!has_variadic || OidIsValid(procform->provariadic));
11804  use_variadic = has_variadic;
11805  *use_variadic_p = use_variadic;
11806  }
11807  else
11808  {
11809  Assert(!has_variadic);
11810  use_variadic = false;
11811  }
11812 
11813  /*
11814  * The idea here is to schema-qualify only if the parser would fail to
11815  * resolve the correct function given the unqualified func name with the
11816  * specified argtypes and VARIADIC flag. But if we already decided to
11817  * force qualification, then we can skip the lookup and pretend we didn't
11818  * find it.
11819  */
11820  if (!force_qualify)
11822  NIL, argnames, nargs, argtypes,
11823  !use_variadic, true, false,
11824  &p_funcid, &p_rettype,
11825  &p_retset, &p_nvargs, &p_vatype,
11826  &p_true_typeids, NULL);
11827  else
11828  {
11829  p_result = FUNCDETAIL_NOTFOUND;
11830  p_funcid = InvalidOid;
11831  }
11832 
11833  if ((p_result == FUNCDETAIL_NORMAL ||
11834  p_result == FUNCDETAIL_AGGREGATE ||
11835  p_result == FUNCDETAIL_WINDOWFUNC) &&
11836  p_funcid == funcid)
11837  nspname = NULL;
11838  else
11839  nspname = get_namespace_name_or_temp(procform->pronamespace);
11840 
11841  result = quote_qualified_identifier(nspname, proname);
11842 
11843  ReleaseSysCache(proctup);
11844 
11845  return result;
11846 }
#define OidIsValid(objectId)
Definition: c.h:711
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 11399 of file ruleutils.c.

11400 {
11402 
11403  initStringInfo(&buf);
11404  get_opclass_name(opclass, InvalidOid, &buf);
11405 
11406  return &buf.data[1]; /* get_opclass_name() prepends space */
11407 }
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Definition: ruleutils.c:11361

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

11941 {
11942  HeapTuple opertup;
11943  Form_pg_operator operform;
11944  char *oprname;
11945  char *nspname;
11946 
11947  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
11948  if (!HeapTupleIsValid(opertup))
11949  elog(ERROR, "cache lookup failed for operator %u", opoid);
11950  operform = (Form_pg_operator) GETSTRUCT(opertup);
11951  Assert(operform->oprkind == 'b');
11952  oprname = NameStr(operform->oprname);
11953 
11954  nspname = get_namespace_name(operform->oprnamespace);
11955 
11956  appendStringInfoString(buf, leftop);
11957  if (leftoptype != operform->oprleft)
11958  add_cast_to(buf, operform->oprleft);
11959  appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
11960  appendStringInfoString(buf, oprname);
11961  appendStringInfo(buf, ") %s", rightop);
11962  if (rightoptype != operform->oprright)
11963  add_cast_to(buf, operform->oprright);
11964 
11965  ReleaseSysCache(opertup);
11966 }
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:11977
@ 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 11860 of file ruleutils.c.

11861 {
11863  HeapTuple opertup;
11864  Form_pg_operator operform;
11865  char *oprname;
11866  char *nspname;
11867  Operator p_result;
11868 
11869  initStringInfo(&buf);
11870 
11871  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
11872  if (!HeapTupleIsValid(opertup))
11873  elog(ERROR, "cache lookup failed for operator %u", operid);
11874  operform = (Form_pg_operator) GETSTRUCT(opertup);
11875  oprname = NameStr(operform->oprname);
11876 
11877  /*
11878  * The idea here is to schema-qualify only if the parser would fail to
11879  * resolve the correct operator given the unqualified op name with the
11880  * specified argtypes.
11881  */
11882  switch (operform->oprkind)
11883  {
11884  case 'b':
11885  p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
11886  true, -1);
11887  break;
11888  case 'l':
11889  p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
11890  true, -1);
11891  break;
11892  default:
11893  elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
11894  p_result = NULL; /* keep compiler quiet */
11895  break;
11896  }
11897 
11898  if (p_result != NULL && oprid(p_result) == operid)
11899  nspname = NULL;
11900  else
11901  {
11902  nspname = get_namespace_name_or_temp(operform->oprnamespace);
11903  appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
11904  }
11905 
11906  appendStringInfoString(&buf, oprname);
11907 
11908  if (nspname)
11909  appendStringInfoChar(&buf, ')');
11910 
11911  if (p_result != NULL)
11912  ReleaseSysCache(p_result);
11913 
11914  ReleaseSysCache(opertup);
11915 
11916  return buf.data;
11917 }
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 11713 of file ruleutils.c.

11714 {
11715  HeapTuple tp;
11716  Form_pg_class reltup;
11717  char *relname;
11718  char *nspname;
11719  char *result;
11720 
11721  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11722  if (!HeapTupleIsValid(tp))
11723  elog(ERROR, "cache lookup failed for relation %u", relid);
11724  reltup = (Form_pg_class) GETSTRUCT(tp);
11725  relname = NameStr(reltup->relname);
11726 
11727  nspname = get_namespace_name_or_temp(reltup->relnamespace);
11728  if (!nspname)
11729  elog(ERROR, "cache lookup failed for namespace %u",
11730  reltup->relnamespace);
11731 
11732  result = quote_qualified_identifier(nspname, relname);
11733 
11734  ReleaseSysCache(tp);
11735 
11736  return result;
11737 }
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 12008 of file ruleutils.c.

12009 {
12010  HeapTuple tp;
12011  Form_pg_type typtup;
12012  char *typname;
12013  char *nspname;
12014  char *result;
12015 
12017  if (!HeapTupleIsValid(tp))
12018  elog(ERROR, "cache lookup failed for type %u", typid);
12019  typtup = (Form_pg_type) GETSTRUCT(tp);
12020  typname = NameStr(typtup->typname);
12021 
12022  nspname = get_namespace_name_or_temp(typtup->typnamespace);
12023  if (!nspname)
12024  elog(ERROR, "cache lookup failed for namespace %u",
12025  typtup->typnamespace);
12026 
12027  result = quote_qualified_identifier(nspname, typname);
12028 
12029  ReleaseSysCache(tp);
12030 
12031  return result;
12032 }

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

11654 {
11655  HeapTuple tp;
11656  Form_pg_class reltup;
11657  bool need_qual;
11658  ListCell *nslist;
11659  char *relname;
11660  char *nspname;
11661  char *result;
11662 
11663  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11664  if (!HeapTupleIsValid(tp))
11665  elog(ERROR, "cache lookup failed for relation %u", relid);
11666  reltup = (Form_pg_class) GETSTRUCT(tp);
11667  relname = NameStr(reltup->relname);
11668 
11669  /* Check for conflicting CTE name */
11670  need_qual = false;
11671  foreach(nslist, namespaces)
11672  {
11673  deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
11674  ListCell *ctlist;
11675 
11676  foreach(ctlist, dpns->ctes)
11677  {
11678  CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
11679 
11680  if (strcmp(cte->ctename, relname) == 0)
11681  {
11682  need_qual = true;
11683  break;
11684  }
11685  }
11686  if (need_qual)
11687  break;
11688  }
11689 
11690  /* Otherwise, qualify the name if not visible in search path */
11691  if (!need_qual)
11692  need_qual = !RelationIsVisible(relid);
11693 
11694  if (need_qual)
11695  nspname = get_namespace_name_or_temp(reltup->relnamespace);
11696  else
11697  nspname = NULL;
11698 
11699  result = quote_qualified_identifier(nspname, relname);
11700 
11701  ReleaseSysCache(tp);
11702 
11703  return result;
11704 }
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 9916 of file ruleutils.c.

9917 {
9918  Aggref *aggref;
9919  Aggref *original_aggref = callback_arg;
9920 
9921  if (!IsA(node, Aggref))
9922  elog(ERROR, "combining Aggref does not point to an Aggref");
9923 
9924  aggref = (Aggref *) node;
9925  get_agg_expr(aggref, context, original_aggref);
9926 }
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
Definition: ruleutils.c:9809

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

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

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

Referenced by get_agg_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 5882 of file ruleutils.c.

5884 {
5885  StringInfo buf = context->buf;
5886  RangeTblEntry *values_rte;
5887  char *sep;
5888  ListCell *l;
5889 
5890  if (PRETTY_INDENT(context))
5891  {
5892  context->indentLevel += PRETTYINDENT_STD;
5893  appendStringInfoChar(buf, ' ');
5894  }
5895 
5896  /*
5897  * If the query looks like SELECT * FROM (VALUES ...), then print just the
5898  * VALUES part. This reverses what transformValuesClause() did at parse
5899  * time.
5900  */
5901  values_rte = get_simple_values_rte(query, resultDesc);
5902  if (values_rte)
5903  {
5904  get_values_def(values_rte->values_lists, context);
5905  return;
5906  }
5907 
5908  /*
5909  * Build up the query string - first we say SELECT
5910  */
5911  if (query->isReturn)
5912  appendStringInfoString(buf, "RETURN");
5913  else
5914  appendStringInfoString(buf, "SELECT");
5915 
5916  /* Add the DISTINCT clause if given */
5917  if (query->distinctClause != NIL)
5918  {
5919  if (query->hasDistinctOn)
5920  {
5921  appendStringInfoString(buf, " DISTINCT ON (");
5922  sep = "";
5923  foreach(l, query->distinctClause)
5924  {
5925  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5926 
5929  false, context);
5930  sep = ", ";
5931  }
5932  appendStringInfoChar(buf, ')');
5933  }
5934  else
5935  appendStringInfoString(buf, " DISTINCT");
5936  }
5937 
5938  /* Then we tell what to select (the targetlist) */
5939  get_target_list(query->targetList, context, resultDesc, colNamesVisible);
5940 
5941  /* Add the FROM clause if needed */
5942  get_from_clause(query, " FROM ", context);
5943 
5944  /* Add the WHERE clause if given */
5945  if (query->jointree->quals != NULL)
5946  {
5947  appendContextKeyword(context, " WHERE ",
5949  get_rule_expr(query->jointree->quals, context, false);
5950  }
5951 
5952  /* Add the GROUP BY clause if given */
5953  if (query->groupClause != NULL || query->groupingSets != NULL)
5954  {
5955  ParseExprKind save_exprkind;
5956 
5957  appendContextKeyword(context, " GROUP BY ",
5959  if (query->groupDistinct)
5960  appendStringInfoString(buf, "DISTINCT ");
5961 
5962  save_exprkind = context->special_exprkind;
5964 
5965  if (query->groupingSets == NIL)
5966  {
5967  sep = "";
5968  foreach(l, query->groupClause)
5969  {
5970  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
5971 
5974  false, context);
5975  sep = ", ";
5976  }
5977  }
5978  else
5979  {
5980  sep = "";
5981  foreach(l, query->groupingSets)
5982  {
5983  GroupingSet *grp = lfirst(l);
5984 
5986  get_rule_groupingset(grp, query->targetList, true, context);
5987  sep = ", ";
5988  }
5989  }
5990 
5991  context->special_exprkind = save_exprkind;
5992  }
5993 
5994  /* Add the HAVING clause if given */
5995  if (query->havingQual != NULL)
5996  {
5997  appendContextKeyword(context, " HAVING ",
5999  get_rule_expr(query->havingQual, context, false);
6000  }
6001 
6002  /* Add the WINDOW clause if needed */
6003  if (query->windowClause != NIL)
6004  get_rule_windowclause(query, context);
6005 }
ParseExprKind
Definition: parse_node.h:39
static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
Definition: ruleutils.c:8350
static void get_values_def(List *values_lists, deparse_context *context)
Definition: ruleutils.c:5499
static void get_from_clause(Query *query, const char *prefix, deparse_context *context)
Definition: ruleutils.c:10787
static void get_target_list(List *targetList, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6016
static void get_rule_groupingset(GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context)
Definition: ruleutils.c:6342
static Node * get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6286
static void get_rule_windowclause(Query *query, deparse_context *context)
Definition: ruleutils.c:6460
static RangeTblEntry * get_simple_values_rte(Query *query, TupleDesc resultDesc)
Definition: ruleutils.c:5813
Node * quals
Definition: primnodes.h:1665
bool groupDistinct
Definition: parsenodes.h:171
FromExpr * jointree
Definition: parsenodes.h:156
List * groupClause
Definition: parsenodes.h:170
Node * havingQual
Definition: parsenodes.h:175
bool hasDistinctOn
Definition: parsenodes.h:145
List * windowClause
Definition: parsenodes.h:177
List * targetList
Definition: parsenodes.h:162
List * groupingSets
Definition: parsenodes.h:173
bool isReturn
Definition: parsenodes.h:151
List * distinctClause
Definition: parsenodes.h:179
List * values_lists
Definition: parsenodes.h:1135
Index tleSortGroupRef
Definition: parsenodes.h:1320

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

Referenced by get_select_query_def().

◆ get_coercion_expr()

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

Definition at line 10316 of file ruleutils.c.

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

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

11227 {
11228  StringInfo buf = context->buf;
11229  int i;
11230  bool first = true;
11231 
11232  /* Don't print aliases if not needed */
11233  if (!colinfo->printaliases)
11234  return;
11235 
11236  for (i = 0; i < colinfo->num_new_cols; i++)
11237  {
11238  char *colname = colinfo->new_colnames[i];
11239 
11240  if (first)
11241  {
11242  appendStringInfoChar(buf, '(');
11243  first = false;
11244  }
11245  else
11246  appendStringInfoString(buf, ", ");
11248  }
11249  if (!first)
11250  appendStringInfoChar(buf, ')');
11251 }

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

10511 {
10512  StringInfo buf = context->buf;
10513 
10514  if (OidIsValid(constval->constcollid))
10515  {
10516  Oid typcollation = get_typcollation(constval->consttype);
10517 
10518  if (constval->constcollid != typcollation)
10519  {
10520  appendStringInfo(buf, " COLLATE %s",
10522  }
10523  }
10524 }
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3014
char * generate_collation_name(Oid collid)
Definition: ruleutils.c:12041
Oid constcollid
Definition: primnodes.h:261
Oid consttype
Definition: primnodes.h:259

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

Referenced by get_const_expr().

◆ get_const_expr()

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

Definition at line 10380 of file ruleutils.c.

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

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

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

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

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

Referenced by get_query_def().

◆ get_from_clause()

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

Definition at line 10787 of file ruleutils.c.

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

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

11269 {
11270  StringInfo buf = context->buf;
11271  ListCell *l1;
11272  ListCell *l2;
11273  ListCell *l3;
11274  ListCell *l4;
11275  int i;
11276 
11277  appendStringInfoChar(buf, '(');
11278 
11279  i = 0;
11280  forfour(l1, rtfunc->funccoltypes,
11281  l2, rtfunc->funccoltypmods,
11282  l3, rtfunc->funccolcollations,
11283  l4, rtfunc->funccolnames)
11284  {
11285  Oid atttypid = lfirst_oid(l1);
11286  int32 atttypmod = lfirst_int(l2);
11287  Oid attcollation = lfirst_oid(l3);
11288  char *attname;
11289 
11290  if (colinfo)
11291  attname = colinfo->colnames[i];
11292  else
11293  attname = strVal(lfirst(l4));
11294 
11295  Assert(attname); /* shouldn't be any dropped columns here */
11296 
11297  if (i > 0)
11298  appendStringInfoString(buf, ", ");
11299  appendStringInfo(buf, "%s %s",
11301  format_type_with_typemod(atttypid, atttypmod));
11302  if (OidIsValid(attcollation) &&
11303  attcollation != get_typcollation(atttypid))
11304  appendStringInfo(buf, " COLLATE %s",
11305  generate_collation_name(attcollation));
11306 
11307  i++;
11308  }
11309 
11310  appendStringInfoChar(buf, ')');
11311 }
signed int int32
Definition: c.h:430
NameData attname
Definition: pg_attribute.h:41
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:522
#define lfirst_oid(lc)
Definition: pg_list.h:172
List * funccolcollations
Definition: parsenodes.h:1215
List * funccoltypmods
Definition: parsenodes.h:1214
#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(), RangeTblFunction::funccolcollations, RangeTblFunction::funccolnames, RangeTblFunction::funccoltypes, RangeTblFunction::funccoltypmods, generate_collation_name(), get_typcollation(), i, lfirst, lfirst_int, lfirst_oid, OidIsValid, quote_identifier(), and strVal.

Referenced by get_from_clause_item().

◆ get_from_clause_item()

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

Definition at line 10881 of file ruleutils.c.

10882 {
10883  StringInfo buf = context->buf;
10885 
10886  if (IsA(jtnode, RangeTblRef))
10887  {
10888  int varno = ((RangeTblRef *) jtnode)->rtindex;
10889  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
10890  char *refname = get_rtable_name(varno, context);
10891  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
10892  RangeTblFunction *rtfunc1 = NULL;
10893  bool printalias;
10894 
10895  if (rte->lateral)
10896  appendStringInfoString(buf, "LATERAL ");
10897 
10898  /* Print the FROM item proper */
10899  switch (rte->rtekind)
10900  {
10901  case RTE_RELATION:
10902  /* Normal relation RTE */
10903  appendStringInfo(buf, "%s%s",
10904  only_marker(rte),
10906  context->namespaces));
10907  break;
10908  case RTE_SUBQUERY:
10909  /* Subquery RTE */
10910  appendStringInfoChar(buf, '(');
10911  get_query_def(rte->subquery, buf, context->namespaces, NULL,
10912  true,
10913  context->prettyFlags, context->wrapColumn,
10914  context->indentLevel);
10915  appendStringInfoChar(buf, ')');
10916  break;
10917  case RTE_FUNCTION:
10918  /* Function RTE */
10919  rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
10920 
10921  /*
10922  * Omit ROWS FROM() syntax for just one function, unless it
10923  * has both a coldeflist and WITH ORDINALITY. If it has both,
10924  * we must use ROWS FROM() syntax to avoid ambiguity about
10925  * whether the coldeflist includes the ordinality column.
10926  */
10927  if (list_length(rte->functions) == 1 &&
10928  (rtfunc1->funccolnames == NIL || !rte->funcordinality))
10929  {
10930  get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
10931  /* we'll print the coldeflist below, if it has one */
10932  }
10933  else
10934  {
10935  bool all_unnest;
10936  ListCell *lc;
10937 
10938  /*
10939  * If all the function calls in the list are to unnest,
10940  * and none need a coldeflist, then collapse the list back
10941  * down to UNNEST(args). (If we had more than one
10942  * built-in unnest function, this would get more
10943  * difficult.)
10944  *
10945  * XXX This is pretty ugly, since it makes not-terribly-
10946  * future-proof assumptions about what the parser would do
10947  * with the output; but the alternative is to emit our
10948  * nonstandard ROWS FROM() notation for what might have
10949  * been a perfectly spec-compliant multi-argument
10950  * UNNEST().
10951  */
10952  all_unnest = true;
10953  foreach(lc, rte->functions)
10954  {
10955  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
10956 
10957  if (!IsA(rtfunc->funcexpr, FuncExpr) ||
10958  ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
10959  rtfunc->funccolnames != NIL)
10960  {
10961  all_unnest = false;
10962  break;
10963  }
10964  }
10965 
10966  if (all_unnest)
10967  {
10968  List *allargs = NIL;
10969 
10970  foreach(lc, rte->functions)
10971  {
10972  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
10973  List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
10974 
10975  allargs = list_concat(allargs, args);
10976  }
10977 
10978  appendStringInfoString(buf, "UNNEST(");
10979  get_rule_expr((Node *) allargs, context, true);
10980  appendStringInfoChar(buf, ')');
10981  }
10982  else
10983  {
10984  int funcno = 0;
10985 
10986  appendStringInfoString(buf, "ROWS FROM(");
10987  foreach(lc, rte->functions)
10988  {
10989  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
10990 
10991  if (funcno > 0)
10992  appendStringInfoString(buf, ", ");
10993  get_rule_expr_funccall(rtfunc->funcexpr, context, true);
10994  if (rtfunc->funccolnames != NIL)
10995  {
10996  /* Reconstruct the column definition list */
10997  appendStringInfoString(buf, " AS ");
10999  NULL,
11000  context);
11001  }
11002  funcno++;
11003  }
11004  appendStringInfoChar(buf, ')');
11005  }
11006  /* prevent printing duplicate coldeflist below */
11007  rtfunc1 = NULL;
11008  }
11009  if (rte->funcordinality)
11010  appendStringInfoString(buf, " WITH ORDINALITY");
11011  break;
11012  case RTE_TABLEFUNC:
11013  get_tablefunc(rte->tablefunc, context, true);
11014  break;
11015  case RTE_VALUES:
11016  /* Values list RTE */
11017  appendStringInfoChar(buf, '(');
11018  get_values_def(rte->values_lists, context);
11019  appendStringInfoChar(buf, ')');
11020  break;
11021  case RTE_CTE:
11023  break;
11024  default:
11025  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
11026  break;
11027  }
11028 
11029  /* Print the relation alias, if needed */
11030  printalias = false;
11031  if (rte->alias != NULL)
11032  {
11033  /* Always print alias if user provided one */
11034  printalias = true;
11035  }
11036  else if (colinfo->printaliases)
11037  {
11038  /* Always print alias if we need to print column aliases */
11039  printalias = true;
11040  }
11041  else if (rte->rtekind == RTE_RELATION)
11042  {
11043  /*
11044  * No need to print alias if it's same as relation name (this
11045  * would normally be the case, but not if set_rtable_names had to
11046  * resolve a conflict).
11047  */
11048  if (strcmp(refname, get_relation_name(rte->relid)) != 0)
11049  printalias = true;
11050  }
11051  else if (rte->rtekind == RTE_FUNCTION)
11052  {
11053  /*
11054  * For a function RTE, always print alias. This covers possible
11055  * renaming of the function and/or instability of the
11056  * FigureColname rules for things that aren't simple functions.
11057  * Note we'd need to force it anyway for the columndef list case.
11058  */
11059  printalias = true;
11060  }
11061  else if (rte->rtekind == RTE_SUBQUERY ||
11062  rte->rtekind == RTE_VALUES)
11063  {
11064  /*
11065  * For a subquery, always print alias. This makes the output SQL
11066  * spec-compliant, even though we allow the alias to be omitted on
11067  * input.
11068  */
11069  printalias = true;
11070  }
11071  else if (rte->rtekind == RTE_CTE)
11072  {
11073  /*
11074  * No need to print alias if it's same as CTE name (this would
11075  * normally be the case, but not if set_rtable_names had to
11076  * resolve a conflict).
11077  */
11078  if (strcmp(refname, rte->ctename) != 0)
11079  printalias = true;
11080  }
11081  if (printalias)
11082  appendStringInfo(buf, " %s", quote_identifier(refname));
11083 
11084  /* Print the column definitions or aliases, if needed */
11085  if (rtfunc1 && rtfunc1->funccolnames != NIL)
11086  {
11087  /* Reconstruct the columndef list, which is also the aliases */
11088  get_from_clause_coldeflist(rtfunc1, colinfo, context);
11089  }
11090  else
11091  {
11092  /* Else print column aliases as needed */
11093  get_column_alias_list(colinfo, context);
11094  }
11095 
11096  /* Tablesample clause must go after any alias */
11097  if (rte->rtekind == RTE_RELATION && rte->tablesample)
11098  get_tablesample_def(rte->tablesample, context);
11099  }
11100  else if (IsA(jtnode, JoinExpr))
11101  {
11102  JoinExpr *j = (JoinExpr *) jtnode;
11103  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
11104  bool need_paren_on_right;
11105 
11106  need_paren_on_right = PRETTY_PAREN(context) &&
11107  !IsA(j->rarg, RangeTblRef) &&
11108  !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
11109 
11110  if (!PRETTY_PAREN(context) || j->alias != NULL)
11111  appendStringInfoChar(buf, '(');
11112 
11113  get_from_clause_item(j->larg, query, context);
11114 
11115  switch (j->jointype)
11116  {
11117  case JOIN_INNER:
11118  if (j->quals)
11119  appendContextKeyword(context, " JOIN ",
11123  else
11124  appendContextKeyword(context, " CROSS JOIN ",
11128  break;
11129  case JOIN_LEFT:
11130  appendContextKeyword(context, " LEFT JOIN ",
11134  break;
11135  case JOIN_FULL:
11136  appendContextKeyword(context, " FULL JOIN ",
11140  break;
11141  case JOIN_RIGHT:
11142  appendContextKeyword(context, " RIGHT JOIN ",
11146  break;
11147  default:
11148  elog(ERROR, "unrecognized join type: %d",
11149  (int) j->jointype);
11150  }
11151 
11152  if (need_paren_on_right)
11153  appendStringInfoChar(buf, '(');
11154  get_from_clause_item(j->rarg, query, context);
11155  if (need_paren_on_right)
11156  appendStringInfoChar(buf, ')');
11157 
11158  if (j->usingClause)
11159  {
11160  ListCell *lc;
11161  bool first = true;
11162 
11163  appendStringInfoString(buf, " USING (");
11164  /* Use the assigned names, not what's in usingClause */
11165  foreach(lc, colinfo->usingNames)
11166  {
11167  char *colname = (char *) lfirst(lc);
11168 
11169  if (first)
11170  first = false;
11171  else
11172  appendStringInfoString(buf, ", ");
11174  }
11175  appendStringInfoChar(buf, ')');
11176 
11177  if (j->join_using_alias)
11178  appendStringInfo(buf, " AS %s",
11179  quote_identifier(j->join_using_alias->aliasname));
11180  }
11181  else if (j->quals)
11182  {
11183  appendStringInfoString(buf, " ON ");
11184  if (!PRETTY_PAREN(context))
11185  appendStringInfoChar(buf, '(');
11186  get_rule_expr(j->quals, context, false);
11187  if (!PRETTY_PAREN(context))
11188  appendStringInfoChar(buf, ')');
11189  }
11190  else if (j->jointype != JOIN_INNER)
11191  {
11192  /* If we didn't say CROSS JOIN above, we must provide an ON */
11193  appendStringInfoString(buf, " ON TRUE");
11194  }
11195 
11196  if (!PRETTY_PAREN(context) || j->alias != NULL)
11197  appendStringInfoChar(buf, ')');
11198 
11199  /* Yes, it's correct to put alias after the right paren ... */
11200  if (j->alias != NULL)
11201  {
11202  /*
11203  * Note that it's correct to emit an alias clause if and only if
11204  * there was one originally. Otherwise we'd be converting a named
11205  * join to unnamed or vice versa, which creates semantic
11206  * subtleties we don't want. However, we might print a different
11207  * alias name than was there originally.
11208  */
11209  appendStringInfo(buf, " %s",
11211  context)));
11212  get_column_alias_list(colinfo, context);
11213  }
11214  }
11215  else
11216  elog(ERROR, "unrecognized node type: %d",
11217  (int) nodeTag(jtnode));
11218 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
#define nodeTag(nodeptr)
Definition: nodes.h:122
@ JOIN_FULL
Definition: nodes.h:295
@ JOIN_INNER
Definition: nodes.h:293
@ JOIN_RIGHT
Definition: nodes.h:296
@ JOIN_LEFT
Definition: nodes.h:294
@ RTE_CTE
Definition: parsenodes.h:1017
@ RTE_VALUES
Definition: parsenodes.h:1016
@ RTE_SUBQUERY
Definition: parsenodes.h:1012
@ RTE_FUNCTION
Definition: parsenodes.h:1014
@ RTE_TABLEFUNC
Definition: parsenodes.h:1015
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition: ruleutils.c:4940
#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:5425
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Definition: ruleutils.c:11317
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:11226
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:11266
static void get_rule_expr_funccall(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:9623
#define deparse_columns_fetch(rangetable_index, dpns)
Definition: ruleutils.c:297
static char * get_relation_name(Oid relid)
Definition: ruleutils.c:11633
static void get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10682
Definition: pg_list.h:52
char * ctename
Definition: parsenodes.h:1140
TableFunc * tablefunc
Definition: parsenodes.h:1130
bool funcordinality
Definition: parsenodes.h:1125
struct TableSampleClause * tablesample
Definition: parsenodes.h:1060
Query * subquery
Definition: parsenodes.h:1065
List * functions
Definition: parsenodes.h:1124
List * usingNames
Definition: ruleutils.c:293

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

Referenced by get_from_clause().

◆ get_func_expr()

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

Definition at line 9713 of file ruleutils.c.

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

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

Referenced by get_rule_expr().

◆ get_func_sql_syntax()

static bool get_func_sql_syntax ( FuncExpr expr,
deparse_context context 
)
static

Definition at line 10036 of file ruleutils.c.

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

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

10011 {
10012  StringInfo buf = context->buf;
10013  Const *cons;
10014 
10015  if (list_length(args) != 1)
10016  return;
10017 
10018  cons = (Const *) linitial(args);
10019  Assert(IsA(cons, Const));
10020 
10021  if (!cons->constisnull)
10022  {
10024  get_rule_expr((Node *) cons, context, false);
10026  }
10027 }

References appendStringInfoString(), generate_unaccent_rules::args, Assert(), deparse_context::buf, buf, Const::constisnull, 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 6601 of file ruleutils.c.

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

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

Referenced by get_query_def().

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

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

Referenced by get_rule_expr().

◆ get_opclass_name()

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

Definition at line 11361 of file ruleutils.c.

11363 {
11364  HeapTuple ht_opc;
11365  Form_pg_opclass opcrec;
11366  char *opcname;
11367  char *nspname;
11368 
11369  ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
11370  if (!HeapTupleIsValid(ht_opc))
11371  elog(ERROR, "cache lookup failed for opclass %u", opclass);
11372  opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
11373 
11374  if (!OidIsValid(actual_datatype) ||
11375  GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
11376  {
11377  /* Okay, we need the opclass name. Do we need to qualify it? */
11378  opcname = NameStr(opcrec->opcname);
11379  if (OpclassIsVisible(opclass))
11380  appendStringInfo(buf, " %s", quote_identifier(opcname));
11381  else
11382  {
11383  nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
11384  appendStringInfo(buf, " %s.%s",
11385  quote_identifier(nspname),
11386  quote_identifier(opcname));
11387  }
11388  }
11389  ReleaseSysCache(ht_opc);
11390 }
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2222
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 9673 of file ruleutils.c.

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

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

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

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

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

12175 {
12176  deparse_context context;
12178  ListCell *cell;
12179  char *sep;
12180 
12181  memset(&context, 0, sizeof(deparse_context));
12182  context.buf = buf;
12183 
12184  appendStringInfoChar(buf, '(');
12185  sep = "";
12186  foreach(cell, bound_datums)
12187  {
12188  PartitionRangeDatum *datum =
12190 
12192  if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
12193  appendStringInfoString(buf, "MINVALUE");
12194  else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
12195  appendStringInfoString(buf, "MAXVALUE");
12196  else
12197  {
12198  Const *val = castNode(Const, datum->value);
12199 
12200  get_const_expr(val, &context, -1);
12201  }
12202  sep = ", ";
12203  }
12204  appendStringInfoChar(buf, ')');
12205 
12206  return buf->data;
12207 }
long val
Definition: informix.c:664
#define castNode(_type_, nodeptr)
Definition: nodes.h:186
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition: parsenodes.h:887
@ PARTITION_RANGE_DATUM_MINVALUE
Definition: parsenodes.h:885
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
PartitionRangeDatumKind kind
Definition: parsenodes.h:894

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

11634 {
11635  char *relname = get_rel_name(relid);
11636 
11637  if (!relname)
11638  elog(ERROR, "cache lookup failed for relation %u", relid);
11639  return relname;
11640 }
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1910

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

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

12087 {
12088  Datum *options;
12089  int noptions;
12090  int i;
12091 
12092  deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
12093  &options, NULL, &noptions);
12094 
12095  for (i = 0; i < noptions; i++)
12096  {
12097  char *option = TextDatumGetCString(options[i]);
12098  char *name;
12099  char *separator;
12100  char *value;
12101 
12102  /*
12103  * Each array element should have the form name=value. If the "=" is
12104  * missing for some reason, treat it like an empty value.
12105  */
12106  name = option;
12107  separator = strchr(option, '=');
12108  if (separator)
12109  {
12110  *separator = '\0';
12111  value = separator + 1;
12112  }
12113  else
12114  value = "";
12115 
12116  if (i > 0)
12117  appendStringInfoString(buf, ", ");
12119 
12120  /*
12121  * In general we need to quote the value; but to avoid unnecessary
12122  * clutter, do not quote if it is an identifier that would not need
12123  * quoting. (We could also allow numbers, but that is a bit trickier
12124  * than it looks --- for example, are leading zeroes significant? We
12125  * don't want to assume very much here about what custom reloptions
12126  * might mean.)
12127  */
12128  if (quote_identifier(value) == value)
12130  else
12132 
12133  pfree(option);
12134  }
12135 }
const char * name
Definition: encode.c:561
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 4940 of file ruleutils.c.

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

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

Referenced by get_from_clause_item(), and get_select_query_def().

◆ get_rule_expr()

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

Definition at line 8455 of file ruleutils.c.

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