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

Go to the source code of this file.

Data Structures

struct  deparse_context
 
struct  deparse_namespace
 
struct  deparse_columns
 
struct  NameHashEntry
 

Macros

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

Typedefs

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

Functions

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

Variables

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

Macro Definition Documentation

◆ deparse_columns_fetch

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

Definition at line 296 of file ruleutils.c.

◆ GET_PRETTY_FLAGS

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

Definition at line 94 of file ruleutils.c.

◆ only_marker

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

Definition at line 535 of file ruleutils.c.

◆ PRETTY_INDENT

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

Definition at line 103 of file ruleutils.c.

◆ PRETTY_PAREN

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

Definition at line 102 of file ruleutils.c.

◆ PRETTY_SCHEMA

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

Definition at line 104 of file ruleutils.c.

◆ PRETTYFLAG_INDENT

#define PRETTYFLAG_INDENT   0x0002

Definition at line 90 of file ruleutils.c.

◆ PRETTYFLAG_PAREN

#define PRETTYFLAG_PAREN   0x0001

Definition at line 89 of file ruleutils.c.

◆ PRETTYFLAG_SCHEMA

#define PRETTYFLAG_SCHEMA   0x0004

Definition at line 91 of file ruleutils.c.

◆ PRETTYINDENT_JOIN

#define PRETTYINDENT_JOIN   4

Definition at line 83 of file ruleutils.c.

◆ PRETTYINDENT_LIMIT

#define PRETTYINDENT_LIMIT   40 /* wrap limit */

Definition at line 86 of file ruleutils.c.

◆ PRETTYINDENT_STD

#define PRETTYINDENT_STD   8

Definition at line 82 of file ruleutils.c.

◆ PRETTYINDENT_VAR

#define PRETTYINDENT_VAR   4

Definition at line 84 of file ruleutils.c.

◆ WRAP_COLUMN_DEFAULT

#define WRAP_COLUMN_DEFAULT   0

Definition at line 99 of file ruleutils.c.

Typedef Documentation

◆ rsv_callback

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

Definition at line 309 of file ruleutils.c.

Function Documentation

◆ add_cast_to()

static void add_cast_to ( StringInfo  buf,
Oid  typid 
)
static

Definition at line 13071 of file ruleutils.c.

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

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

Referenced by generate_operator_clause().

◆ appendContextKeyword()

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

Definition at line 8718 of file ruleutils.c.

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

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

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

◆ colname_is_unique()

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

Definition at line 4789 of file ruleutils.c.

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

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

Referenced by make_colname_unique().

◆ decompile_column_index_array()

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

Definition at line 2601 of file ruleutils.c.

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

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

Referenced by pg_get_constraintdef_worker().

◆ deparse_context_for()

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

Definition at line 3685 of file ruleutils.c.

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

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

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

◆ deparse_context_for_plan_tree()

List* deparse_context_for_plan_tree ( PlannedStmt pstmt,
List rtable_names 
)

Definition at line 3730 of file ruleutils.c.

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

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

Referenced by ExplainPrintPlan().

◆ deparse_expression()

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

Definition at line 3625 of file ruleutils.c.

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

References deparse_expression_pretty().

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

◆ deparse_expression_pretty()

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

Definition at line 3652 of file ruleutils.c.

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

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

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

◆ expand_colnames_array_to()

static void expand_colnames_array_to ( deparse_columns colinfo,
int  n 
)
static

Definition at line 4882 of file ruleutils.c.

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

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

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

◆ find_param_generator()

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

Definition at line 8208 of file ruleutils.c.

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

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

Referenced by get_parameter().

◆ find_param_generator_initplan()

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

Definition at line 8305 of file ruleutils.c.

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

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

Referenced by find_param_generator().

◆ find_param_referent()

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

Definition at line 8094 of file ruleutils.c.

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

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

Referenced by get_name_for_var_field(), and get_parameter().

◆ find_recursive_union()

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

Definition at line 5069 of file ruleutils.c.

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

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

Referenced by set_deparse_plan().

◆ flatten_reloptions()

static char * flatten_reloptions ( Oid  relid)
static

Definition at line 13235 of file ruleutils.c.

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

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

Referenced by pg_get_constraintdef_worker(), and pg_get_indexdef_worker().

◆ generate_collation_name()

char* generate_collation_name ( Oid  collid)

Definition at line 13135 of file ruleutils.c.

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

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

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

◆ generate_function_name()

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

Definition at line 12849 of file ruleutils.c.

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

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

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

◆ generate_opclass_name()

char* generate_opclass_name ( Oid  opclass)

Definition at line 12493 of file ruleutils.c.

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

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

Referenced by index_opclass_options().

◆ generate_operator_clause()

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

Definition at line 13031 of file ruleutils.c.

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

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

Referenced by refresh_by_match_merge(), and ri_GenerateQual().

◆ generate_operator_name()

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

Definition at line 12954 of file ruleutils.c.

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

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

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

◆ generate_qualified_relation_name()

static char * generate_qualified_relation_name ( Oid  relid)
static

Definition at line 12807 of file ruleutils.c.

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

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

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

◆ generate_qualified_type_name()

static char * generate_qualified_type_name ( Oid  typid)
static

Definition at line 13102 of file ruleutils.c.

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

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

Referenced by pg_get_constraintdef_worker().

◆ generate_relation_name()

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

Definition at line 12747 of file ruleutils.c.

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

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

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

◆ get_agg_combine_expr()

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

Definition at line 10624 of file ruleutils.c.

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

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

Referenced by get_agg_expr_helper().

◆ get_agg_expr()

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

Definition at line 10486 of file ruleutils.c.

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

References context, and get_agg_expr_helper().

Referenced by get_agg_combine_expr(), and get_rule_expr().

◆ get_agg_expr_helper()

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

Definition at line 10498 of file ruleutils.c.

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

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

Referenced by get_agg_expr(), and get_json_agg_constructor().

◆ get_basic_select_query()

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

Definition at line 5918 of file ruleutils.c.

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

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

Referenced by get_select_query_def().

◆ get_coercion_expr()

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

Definition at line 10996 of file ruleutils.c.

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

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

Referenced by get_func_expr(), and get_rule_expr().

◆ get_column_alias_list()

static void get_column_alias_list ( deparse_columns colinfo,
deparse_context context 
)
static

Definition at line 12320 of file ruleutils.c.

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

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

Referenced by get_from_clause_item().

◆ get_const_collation()

static void get_const_collation ( Const constval,
deparse_context context 
)
static

Definition at line 11190 of file ruleutils.c.

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

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

Referenced by get_const_expr().

◆ get_const_expr()

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

Definition at line 11060 of file ruleutils.c.

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

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

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

◆ get_delete_query_def()

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

Definition at line 7064 of file ruleutils.c.

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

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

Referenced by get_query_def().

◆ get_from_clause()

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

Definition at line 11864 of file ruleutils.c.

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

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

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

◆ get_from_clause_coldeflist()

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

Definition at line 12360 of file ruleutils.c.

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

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

Referenced by get_from_clause_item().

◆ get_from_clause_item()

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

Definition at line 11958 of file ruleutils.c.

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

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

Referenced by get_from_clause().

◆ get_func_expr()

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

Definition at line 10390 of file ruleutils.c.

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

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

Referenced by get_rule_expr().

◆ get_func_sql_syntax()

static bool get_func_sql_syntax ( FuncExpr expr,
deparse_context context 
)
static

Definition at line 10744 of file ruleutils.c.

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

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

Referenced by get_func_expr().

◆ get_insert_query_def()

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

Definition at line 6638 of file ruleutils.c.

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

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

Referenced by get_query_def().

◆ get_json_agg_constructor()

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

Definition at line 11363 of file ruleutils.c.

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

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

Referenced by get_json_constructor().

◆ get_json_behavior()

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

Definition at line 8809 of file ruleutils.c.

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

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

Referenced by get_json_expr_options(), and get_json_table().

◆ get_json_constructor()

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

Definition at line 11267 of file ruleutils.c.

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

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

Referenced by get_rule_expr().

◆ get_json_constructor_options()

static void get_json_constructor_options ( JsonConstructorExpr ctor,
StringInfo  buf 
)
static

Definition at line 11333 of file ruleutils.c.

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

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

Referenced by get_json_agg_constructor(), and get_json_constructor().

◆ get_json_expr_options()

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

Definition at line 8847 of file ruleutils.c.

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

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

Referenced by get_json_table_columns(), and get_rule_expr().

◆ get_json_format()

static void get_json_format ( JsonFormat format,
StringInfo  buf 
)
static

Definition at line 11222 of file ruleutils.c.

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

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

Referenced by get_json_returning(), and get_rule_expr().

◆ get_json_path_spec()

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

Definition at line 11210 of file ruleutils.c.

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

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

Referenced by get_json_table_columns(), and get_rule_expr().

◆ get_json_returning()

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

Definition at line 11247 of file ruleutils.c.

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

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

Referenced by get_json_constructor_options(), and get_rule_expr().

◆ get_json_table()

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

Definition at line 11776 of file ruleutils.c.

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

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

Referenced by get_tablefunc().

◆ get_json_table_columns()

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

Definition at line 11670 of file ruleutils.c.

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

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

Referenced by get_json_table(), and get_json_table_nested_columns().

◆ get_json_table_nested_columns()

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

Definition at line 11638 of file ruleutils.c.

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

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

Referenced by get_json_table_columns().

◆ get_list_partvalue_string()

char* get_list_partvalue_string ( Const val)

Definition at line 13308 of file ruleutils.c.

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

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

Referenced by check_parent_values_in_new_partitions().

◆ get_merge_query_def()

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

Definition at line 7116 of file ruleutils.c.

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

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

Referenced by get_query_def().

◆ get_name_for_var_field()

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

Definition at line 7688 of file ruleutils.c.

7690 {
7691  RangeTblEntry *rte;
7693  int netlevelsup;
7694  deparse_namespace *dpns;
7695  int varno;
7696  AttrNumber varattno;
7697  TupleDesc tupleDesc;
7698  Node *expr;
7699 
7700  /*
7701  * If it's a RowExpr that was expanded from a whole-row Var, use the
7702  * column names attached to it. (We could let get_expr_result_tupdesc()
7703  * handle this, but it's much cheaper to just pull out the name we need.)
7704  */
7705  if (IsA(var, RowExpr))
7706  {
7707  RowExpr *r = (RowExpr *) var;
7708 
7709  if (fieldno > 0 && fieldno <= list_length(r->colnames))
7710  return strVal(list_nth(r->colnames, fieldno - 1));
7711  }
7712 
7713  /*
7714  * If it's a Param of type RECORD, try to find what the Param refers to.
7715  */
7716  if (IsA(var, Param))
7717  {
7718  Param *param = (Param *) var;
7719  ListCell *ancestor_cell;
7720 
7721  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7722  if (expr)
7723  {
7724  /* Found a match, so recurse to decipher the field name */
7725  deparse_namespace save_dpns;
7726  const char *result;
7727 
7728  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7729  result = get_name_for_var_field((Var *) expr, fieldno,
7730  0, context);
7731  pop_ancestor_plan(dpns, &save_dpns);
7732  return result;
7733  }
7734  }
7735 
7736  /*
7737  * If it's a Var of type RECORD, we have to find what the Var refers to;
7738  * if not, we can use get_expr_result_tupdesc().
7739  */
7740  if (!IsA(var, Var) ||
7741  var->vartype != RECORDOID)
7742  {
7743  tupleDesc = get_expr_result_tupdesc((Node *) var, false);
7744  /* Got the tupdesc, so we can extract the field name */
7745  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7746  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7747  }
7748 
7749  /* Find appropriate nesting depth */
7750  netlevelsup = var->varlevelsup + levelsup;
7751  if (netlevelsup >= list_length(context->namespaces))
7752  elog(ERROR, "bogus varlevelsup: %d offset %d",
7753  var->varlevelsup, levelsup);
7754  dpns = (deparse_namespace *) list_nth(context->namespaces,
7755  netlevelsup);
7756 
7757  /*
7758  * If we have a syntactic referent for the Var, and we're working from a
7759  * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7760  * on the semantic referent. (See comments in get_variable().)
7761  */
7762  if (var->varnosyn > 0 && dpns->plan == NULL)
7763  {
7764  varno = var->varnosyn;
7765  varattno = var->varattnosyn;
7766  }
7767  else
7768  {
7769  varno = var->varno;
7770  varattno = var->varattno;
7771  }
7772 
7773  /*
7774  * Try to find the relevant RTE in this rtable. In a plan tree, it's
7775  * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7776  * down into the subplans, or INDEX_VAR, which is resolved similarly.
7777  *
7778  * Note: unlike get_variable and resolve_special_varno, we need not worry
7779  * about inheritance mapping: a child Var should have the same datatype as
7780  * its parent, and here we're really only interested in the Var's type.
7781  */
7782  if (varno >= 1 && varno <= list_length(dpns->rtable))
7783  {
7784  rte = rt_fetch(varno, dpns->rtable);
7785  attnum = varattno;
7786  }
7787  else if (varno == OUTER_VAR && dpns->outer_tlist)
7788  {
7789  TargetEntry *tle;
7790  deparse_namespace save_dpns;
7791  const char *result;
7792 
7793  tle = get_tle_by_resno(dpns->outer_tlist, varattno);
7794  if (!tle)
7795  elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
7796 
7797  Assert(netlevelsup == 0);
7798  push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7799 
7800  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7801  levelsup, context);
7802 
7803  pop_child_plan(dpns, &save_dpns);
7804  return result;
7805  }
7806  else if (varno == INNER_VAR && dpns->inner_tlist)
7807  {
7808  TargetEntry *tle;
7809  deparse_namespace save_dpns;
7810  const char *result;
7811 
7812  tle = get_tle_by_resno(dpns->inner_tlist, varattno);
7813  if (!tle)
7814  elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
7815 
7816  Assert(netlevelsup == 0);
7817  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7818 
7819  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7820  levelsup, context);
7821 
7822  pop_child_plan(dpns, &save_dpns);
7823  return result;
7824  }
7825  else if (varno == INDEX_VAR && dpns->index_tlist)
7826  {
7827  TargetEntry *tle;
7828  const char *result;
7829 
7830  tle = get_tle_by_resno(dpns->index_tlist, varattno);
7831  if (!tle)
7832  elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
7833 
7834  Assert(netlevelsup == 0);
7835 
7836  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7837  levelsup, context);
7838 
7839  return result;
7840  }
7841  else
7842  {
7843  elog(ERROR, "bogus varno: %d", varno);
7844  return NULL; /* keep compiler quiet */
7845  }
7846 
7847  if (attnum == InvalidAttrNumber)
7848  {
7849  /* Var is whole-row reference to RTE, so select the right field */
7850  return get_rte_attribute_name(rte, fieldno);
7851  }
7852 
7853  /*
7854  * This part has essentially the same logic as the parser's
7855  * expandRecordVariable() function, but we are dealing with a different
7856  * representation of the input context, and we only need one field name
7857  * not a TupleDesc. Also, we need special cases for finding subquery and
7858  * CTE subplans when deparsing Plan trees.
7859  */
7860  expr = (Node *) var; /* default if we can't drill down */
7861 
7862  switch (rte->rtekind)
7863  {
7864  case RTE_RELATION:
7865  case RTE_VALUES:
7866  case RTE_NAMEDTUPLESTORE:
7867  case RTE_RESULT:
7868 
7869  /*
7870  * This case should not occur: a column of a table, values list,
7871  * or ENR shouldn't have type RECORD. Fall through and fail (most
7872  * likely) at the bottom.
7873  */
7874  break;
7875  case RTE_SUBQUERY:
7876  /* Subselect-in-FROM: examine sub-select's output expr */
7877  {
7878  if (rte->subquery)
7879  {
7881  attnum);
7882 
7883  if (ste == NULL || ste->resjunk)
7884  elog(ERROR, "subquery %s does not have attribute %d",
7885  rte->eref->aliasname, attnum);
7886  expr = (Node *) ste->expr;
7887  if (IsA(expr, Var))
7888  {
7889  /*
7890  * Recurse into the sub-select to see what its Var
7891  * refers to. We have to build an additional level of
7892  * namespace to keep in step with varlevelsup in the
7893  * subselect; furthermore, the subquery RTE might be
7894  * from an outer query level, in which case the
7895  * namespace for the subselect must have that outer
7896  * level as parent namespace.
7897  */
7898  List *save_nslist = context->namespaces;
7899  List *parent_namespaces;
7900  deparse_namespace mydpns;
7901  const char *result;
7902 
7903  parent_namespaces = list_copy_tail(context->namespaces,
7904  netlevelsup);
7905 
7906  set_deparse_for_query(&mydpns, rte->subquery,
7907  parent_namespaces);
7908 
7909  context->namespaces = lcons(&mydpns, parent_namespaces);
7910 
7911  result = get_name_for_var_field((Var *) expr, fieldno,
7912  0, context);
7913 
7914  context->namespaces = save_nslist;
7915 
7916  return result;
7917  }
7918  /* else fall through to inspect the expression */
7919  }
7920  else
7921  {
7922  /*
7923  * We're deparsing a Plan tree so we don't have complete
7924  * RTE entries (in particular, rte->subquery is NULL). But
7925  * the only place we'd see a Var directly referencing a
7926  * SUBQUERY RTE is in a SubqueryScan plan node, and we can
7927  * look into the child plan's tlist instead.
7928  */
7929  TargetEntry *tle;
7930  deparse_namespace save_dpns;
7931  const char *result;
7932 
7933  if (!dpns->inner_plan)
7934  elog(ERROR, "failed to find plan for subquery %s",
7935  rte->eref->aliasname);
7936  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7937  if (!tle)
7938  elog(ERROR, "bogus varattno for subquery var: %d",
7939  attnum);
7940  Assert(netlevelsup == 0);
7941  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7942 
7943  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7944  levelsup, context);
7945 
7946  pop_child_plan(dpns, &save_dpns);
7947  return result;
7948  }
7949  }
7950  break;
7951  case RTE_JOIN:
7952  /* Join RTE --- recursively inspect the alias variable */
7953  if (rte->joinaliasvars == NIL)
7954  elog(ERROR, "cannot decompile join alias var in plan tree");
7955  Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
7956  expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
7957  Assert(expr != NULL);
7958  /* we intentionally don't strip implicit coercions here */
7959  if (IsA(expr, Var))
7960  return get_name_for_var_field((Var *) expr, fieldno,
7961  var->varlevelsup + levelsup,
7962  context);
7963  /* else fall through to inspect the expression */
7964  break;
7965  case RTE_FUNCTION:
7966  case RTE_TABLEFUNC:
7967 
7968  /*
7969  * We couldn't get here unless a function is declared with one of
7970  * its result columns as RECORD, which is not allowed.
7971  */
7972  break;
7973  case RTE_CTE:
7974  /* CTE reference: examine subquery's output expr */
7975  {
7976  CommonTableExpr *cte = NULL;
7977  Index ctelevelsup;
7978  ListCell *lc;
7979 
7980  /*
7981  * Try to find the referenced CTE using the namespace stack.
7982  */
7983  ctelevelsup = rte->ctelevelsup + netlevelsup;
7984  if (ctelevelsup >= list_length(context->namespaces))
7985  lc = NULL;
7986  else
7987  {
7988  deparse_namespace *ctedpns;
7989 
7990  ctedpns = (deparse_namespace *)
7991  list_nth(context->namespaces, ctelevelsup);
7992  foreach(lc, ctedpns->ctes)
7993  {
7994  cte = (CommonTableExpr *) lfirst(lc);
7995  if (strcmp(cte->ctename, rte->ctename) == 0)
7996  break;
7997  }
7998  }
7999  if (lc != NULL)
8000  {
8001  Query *ctequery = (Query *) cte->ctequery;
8003  attnum);
8004 
8005  if (ste == NULL || ste->resjunk)
8006  elog(ERROR, "CTE %s does not have attribute %d",
8007  rte->eref->aliasname, attnum);
8008  expr = (Node *) ste->expr;
8009  if (IsA(expr, Var))
8010  {
8011  /*
8012  * Recurse into the CTE to see what its Var refers to.
8013  * We have to build an additional level of namespace
8014  * to keep in step with varlevelsup in the CTE;
8015  * furthermore it could be an outer CTE (compare
8016  * SUBQUERY case above).
8017  */
8018  List *save_nslist = context->namespaces;
8019  List *parent_namespaces;
8020  deparse_namespace mydpns;
8021  const char *result;
8022 
8023  parent_namespaces = list_copy_tail(context->namespaces,
8024  ctelevelsup);
8025 
8026  set_deparse_for_query(&mydpns, ctequery,
8027  parent_namespaces);
8028 
8029  context->namespaces = lcons(&mydpns, parent_namespaces);
8030 
8031  result = get_name_for_var_field((Var *) expr, fieldno,
8032  0, context);
8033 
8034  context->namespaces = save_nslist;
8035 
8036  return result;
8037  }
8038  /* else fall through to inspect the expression */
8039  }
8040  else
8041  {
8042  /*
8043  * We're deparsing a Plan tree so we don't have a CTE
8044  * list. But the only places we'd see a Var directly
8045  * referencing a CTE RTE are in CteScan or WorkTableScan
8046  * plan nodes. For those cases, set_deparse_plan arranged
8047  * for dpns->inner_plan to be the plan node that emits the
8048  * CTE or RecursiveUnion result, and we can look at its
8049  * tlist instead.
8050  */
8051  TargetEntry *tle;
8052  deparse_namespace save_dpns;
8053  const char *result;
8054 
8055  if (!dpns->inner_plan)
8056  elog(ERROR, "failed to find plan for CTE %s",
8057  rte->eref->aliasname);
8058  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8059  if (!tle)
8060  elog(ERROR, "bogus varattno for subquery var: %d",
8061  attnum);
8062  Assert(netlevelsup == 0);
8063  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8064 
8065  result = get_name_for_var_field((Var *) tle->expr, fieldno,
8066  levelsup, context);
8067 
8068  pop_child_plan(dpns, &save_dpns);
8069  return result;
8070  }
8071  }
8072  break;
8073  }
8074 
8075  /*
8076  * We now have an expression we can't expand any more, so see if
8077  * get_expr_result_tupdesc() can do anything with it.
8078  */
8079  tupleDesc = get_expr_result_tupdesc(expr, false);
8080  /* Got the tupdesc, so we can extract the field name */
8081  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8082  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8083 }
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
TupleDesc get_expr_result_tupdesc(Node *expr, bool noError)
Definition: funcapi.c:551
List * list_copy_tail(const List *oldlist, int nskip)
Definition: list.c:1613
List * lcons(void *datum, List *list)
Definition: list.c:495
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
char * get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
#define GetCTETargetList(cte)
Definition: parsenodes.h:1710
@ RTE_JOIN
Definition: parsenodes.h:1030
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1035
@ RTE_RESULT
Definition: parsenodes.h:1036
int16 attnum
Definition: pg_attribute.h:74
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define OUTER_VAR
Definition: primnodes.h:237
#define INNER_VAR
Definition: primnodes.h:236
#define INDEX_VAR
Definition: primnodes.h:238
static void set_deparse_for_query(deparse_namespace *dpns, Query *query, List *parent_namespaces)
Definition: ruleutils.c:3996
static void pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5167
static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns)
Definition: ruleutils.c:5146
static Node * find_param_referent(Param *param, deparse_context *context, deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
Definition: ruleutils.c:8094
static void pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5116
static const char * get_name_for_var_field(Var *var, int fieldno, int levelsup, deparse_context *context)
Definition: ruleutils.c:7688
static void push_child_plan(deparse_namespace *dpns, Plan *plan, deparse_namespace *save_dpns)
Definition: ruleutils.c:5099
Index ctelevelsup
Definition: parsenodes.h:1208
Definition: primnodes.h:248
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
Index varlevelsup
Definition: primnodes.h:280
List * inner_tlist
Definition: ruleutils.c:178
List * outer_tlist
Definition: ruleutils.c:177
List * index_tlist
Definition: ruleutils.c:179
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References Assert, attname, attnum, context, RangeTblEntry::ctelevelsup, RangeTblEntry::ctename, CommonTableExpr::ctename, CommonTableExpr::ctequery, deparse_namespace::ctes, elog, 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, lcons(), lfirst, list_copy_tail(), list_length(), list_nth(), NameStr, NIL, deparse_namespace::outer_plan, deparse_namespace::outer_tlist, OUTER_VAR, deparse_namespace::plan, pop_ancestor_plan(), pop_child_plan(), push_ancestor_plan(), push_child_plan(), rt_fetch, deparse_namespace::rtable, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, set_deparse_for_query(), strVal, RangeTblEntry::subquery, Query::targetList, TupleDescAttr, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by get_rule_expr().

◆ get_opclass_name()

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

Definition at line 12455 of file ruleutils.c.

12457 {
12458  HeapTuple ht_opc;
12459  Form_pg_opclass opcrec;
12460  char *opcname;
12461  char *nspname;
12462 
12463  ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
12464  if (!HeapTupleIsValid(ht_opc))
12465  elog(ERROR, "cache lookup failed for opclass %u", opclass);
12466  opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
12467 
12468  if (!OidIsValid(actual_datatype) ||
12469  GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
12470  {
12471  /* Okay, we need the opclass name. Do we need to qualify it? */
12472  opcname = NameStr(opcrec->opcname);
12473  if (OpclassIsVisible(opclass))
12474  appendStringInfo(buf, " %s", quote_identifier(opcname));
12475  else
12476  {
12477  nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
12478  appendStringInfo(buf, " %s.%s",
12479  quote_identifier(nspname),
12480  quote_identifier(opcname));
12481  }
12482  }
12483  ReleaseSysCache(ht_opc);
12484 }
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2338
bool OpclassIsVisible(Oid opcid)
Definition: namespace.c:2139
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83

References appendStringInfo(), buf, 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 10350 of file ruleutils.c.

10351 {
10352  StringInfo buf = context->buf;
10353  Oid opno = expr->opno;
10354  List *args = expr->args;
10355 
10356  if (!PRETTY_PAREN(context))
10357  appendStringInfoChar(buf, '(');
10358  if (list_length(args) == 2)
10359  {
10360  /* binary operator */
10361  Node *arg1 = (Node *) linitial(args);
10362  Node *arg2 = (Node *) lsecond(args);
10363 
10364  get_rule_expr_paren(arg1, context, true, (Node *) expr);
10365  appendStringInfo(buf, " %s ",
10367  exprType(arg1),
10368  exprType(arg2)));
10369  get_rule_expr_paren(arg2, context, true, (Node *) expr);
10370  }
10371  else
10372  {
10373  /* prefix operator */
10374  Node *arg = (Node *) linitial(args);
10375 
10376  appendStringInfo(buf, "%s ",
10378  InvalidOid,
10379  exprType(arg)));
10380  get_rule_expr_paren(arg, context, true, (Node *) expr);
10381  }
10382  if (!PRETTY_PAREN(context))
10383  appendStringInfoChar(buf, ')');
10384 }
static char * generate_operator_name(Oid operid, Oid arg1, Oid arg2)
Definition: ruleutils.c:12954
Oid opno
Definition: primnodes.h:788
List * args
Definition: primnodes.h:806

References appendStringInfo(), appendStringInfoChar(), arg, generate_unaccent_rules::args, OpExpr::args, buf, context, 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 8326 of file ruleutils.c.

8327 {
8328  Node *expr;
8329  deparse_namespace *dpns;
8330  ListCell *ancestor_cell;
8331  SubPlan *subplan;
8332  int column;
8333 
8334  /*
8335  * If it's a PARAM_EXEC parameter, try to locate the expression from which
8336  * the parameter was computed. This stanza handles only cases in which
8337  * the Param represents an input to the subplan we are currently in.
8338  */
8339  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8340  if (expr)
8341  {
8342  /* Found a match, so print it */
8343  deparse_namespace save_dpns;
8344  bool save_varprefix;
8345  bool need_paren;
8346 
8347  /* Switch attention to the ancestor plan node */
8348  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8349 
8350  /*
8351  * Force prefixing of Vars, since they won't belong to the relation
8352  * being scanned in the original plan node.
8353  */
8354  save_varprefix = context->varprefix;
8355  context->varprefix = true;
8356 
8357  /*
8358  * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8359  * upper-level Param, which wouldn't need extra parentheses.
8360  * Otherwise, insert parens to ensure the expression looks atomic.
8361  */
8362  need_paren = !(IsA(expr, Var) ||
8363  IsA(expr, Aggref) ||
8364  IsA(expr, GroupingFunc) ||
8365  IsA(expr, Param));
8366  if (need_paren)
8367  appendStringInfoChar(context->buf, '(');
8368 
8369  get_rule_expr(expr, context, false);
8370 
8371  if (need_paren)
8372  appendStringInfoChar(context->buf, ')');
8373 
8374  context->varprefix = save_varprefix;
8375 
8376  pop_ancestor_plan(dpns, &save_dpns);
8377 
8378  return;
8379  }
8380 
8381  /*
8382  * Alternatively, maybe it's a subplan output, which we print as a
8383  * reference to the subplan. (We could drill down into the subplan and
8384  * print the relevant targetlist expression, but that has been deemed too
8385  * confusing since it would violate normal SQL scope rules. Also, we're
8386  * relying on this reference to show that the testexpr containing the
8387  * Param has anything to do with that subplan at all.)
8388  */
8389  subplan = find_param_generator(param, context, &column);
8390  if (subplan)
8391  {
8392  appendStringInfo(context->buf, "(%s%s).col%d",
8393  subplan->useHashTable ? "hashed " : "",
8394  subplan->plan_name, column + 1);
8395 
8396  return;
8397  }
8398 
8399  /*
8400  * If it's an external parameter, see if the outermost namespace provides
8401  * function argument names.
8402  */
8403  if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8404  {
8405  dpns = llast(context->namespaces);
8406  if (dpns->argnames &&
8407  param->paramid > 0 &&
8408  param->paramid <= dpns->numargs)
8409  {
8410  char *argname = dpns->argnames[param->paramid - 1];
8411 
8412  if (argname)
8413  {
8414  bool should_qualify = false;
8415  ListCell *lc;
8416 
8417  /*
8418  * Qualify the parameter name if there are any other deparse
8419  * namespaces with range tables. This avoids qualifying in
8420  * trivial cases like "RETURN a + b", but makes it safe in all
8421  * other cases.
8422  */
8423  foreach(lc, context->namespaces)
8424  {
8425  deparse_namespace *depns = lfirst(lc);
8426 
8427  if (depns->rtable_names != NIL)
8428  {
8429  should_qualify = true;
8430  break;
8431  }
8432  }
8433  if (should_qualify)
8434  {
8436  appendStringInfoChar(context->buf, '.');
8437  }
8438 
8440  return;
8441  }
8442  }
8443  }
8444 
8445  /*
8446  * Not PARAM_EXEC, or couldn't find referent: just print $N.
8447  *
8448  * It's a bug if we get here for anything except PARAM_EXTERN Params, but
8449  * in production builds printing $N seems more useful than failing.
8450  */
8451  Assert(param->paramkind == PARAM_EXTERN);
8452 
8453  appendStringInfo(context->buf, "$%d", param->paramid);
8454 }
#define llast(l)
Definition: pg_list.h:198
@ PARAM_EXTERN
Definition: primnodes.h:367
static SubPlan * find_param_generator(Param *param, deparse_context *context, int *column_p)
Definition: ruleutils.c:8208
char * plan_name
Definition: primnodes.h:1042
bool useHashTable
Definition: primnodes.h:1049
char ** argnames
Definition: ruleutils.c:183

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), deparse_namespace::argnames, Assert, context, find_param_generator(), find_param_referent(), deparse_namespace::funcname, get_rule_expr(), IsA, lfirst, llast, NIL, deparse_namespace::numargs, PARAM_EXTERN, Param::paramid, Param::paramkind, SubPlan::plan_name, pop_ancestor_plan(), push_ancestor_plan(), quote_identifier(), deparse_namespace::rtable_names, and SubPlan::useHashTable.

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

5460 {
5462  deparse_namespace dpns;
5463 
5464  /* Guard against excessively long or deeply-nested queries */
5467 
5468  /*
5469  * Before we begin to examine the query, acquire locks on referenced
5470  * relations, and fix up deleted columns in JOIN RTEs. This ensures
5471  * consistent results. Note we assume it's OK to scribble on the passed
5472  * querytree!
5473  *
5474  * We are only deparsing the query (we are not about to execute it), so we
5475  * only need AccessShareLock on the relations it mentions.
5476  */
5477  AcquireRewriteLocks(query, false, false);
5478 
5479  context.buf = buf;
5480  context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5481  context.windowClause = NIL;
5482  context.windowTList = NIL;
5483  context.varprefix = (parentnamespace != NIL ||
5484  list_length(query->rtable) != 1);
5485  context.prettyFlags = prettyFlags;
5486  context.wrapColumn = wrapColumn;
5487  context.indentLevel = startIndent;
5488  context.special_exprkind = EXPR_KIND_NONE;
5489  context.appendparents = NULL;
5490 
5491  set_deparse_for_query(&dpns, query, parentnamespace);
5492 
5493  switch (query->commandType)
5494  {
5495  case CMD_SELECT:
5496  get_select_query_def(query, &context, resultDesc, colNamesVisible);
5497  break;
5498 
5499  case CMD_UPDATE:
5500  get_update_query_def(query, &context, colNamesVisible);
5501  break;
5502 
5503  case CMD_INSERT:
5504  get_insert_query_def(query, &context, colNamesVisible);
5505  break;
5506 
5507  case CMD_DELETE:
5508  get_delete_query_def(query, &context, colNamesVisible);
5509  break;
5510 
5511  case CMD_MERGE:
5512  get_merge_query_def(query, &context, colNamesVisible);
5513  break;
5514 
5515  case CMD_NOTHING:
5516  appendStringInfoString(buf, "NOTHING");
5517  break;
5518 
5519  case CMD_UTILITY:
5520  get_utility_query_def(query, &context);
5521  break;
5522 
5523  default:
5524  elog(ERROR, "unrecognized query command type: %d",
5525  query->commandType);
5526  break;
5527  }
5528 }
List * list_copy(const List *oldlist)
Definition: list.c:1573
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_UTILITY
Definition: nodes.h:270
@ CMD_SELECT
Definition: nodes.h:265
void check_stack_depth(void)
Definition: postgres.c:3531
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:5717
static void get_delete_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:7064
static void get_utility_query_def(Query *query, deparse_context *context)
Definition: ruleutils.c:7280
static void get_merge_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:7116
static void get_insert_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:6638
static void get_update_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:6855
CmdType commandType
Definition: parsenodes.h:121

References AcquireRewriteLocks(), appendStringInfoString(), buf, CHECK_FOR_INTERRUPTS, check_stack_depth(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_NOTHING, CMD_SELECT, CMD_UPDATE, CMD_UTILITY, Query::commandType, context, elog, ERROR, EXPR_KIND_NONE, get_delete_query_def(), get_insert_query_def(), get_merge_query_def(), get_select_query_def(), get_update_query_def(), get_utility_query_def(), lcons(), list_copy(), list_length(), NIL, Query::rtable, and set_deparse_for_query().

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

13269 {
13272  ListCell *cell;
13273  char *sep;
13274 
13275  memset(&context, 0, sizeof(deparse_context));
13276  context.buf = buf;
13277 
13278  appendStringInfoChar(buf, '(');
13279  sep = "";
13280  foreach(cell, bound_datums)
13281  {
13282  PartitionRangeDatum *datum =
13284 
13286  if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
13287  appendStringInfoString(buf, "MINVALUE");
13288  else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
13289  appendStringInfoString(buf, "MAXVALUE");
13290  else
13291  {
13292  Const *val = castNode(Const, datum->value);
13293 
13294  get_const_expr(val, &context, -1);
13295  }
13296  sep = ", ";
13297  }
13298  appendStringInfoChar(buf, ')');
13299 
13300  return buf->data;
13301 }
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition: parsenodes.h:926
@ PARTITION_RANGE_DATUM_MINVALUE
Definition: parsenodes.h:924
PartitionRangeDatumKind kind
Definition: parsenodes.h:933

References appendStringInfoChar(), appendStringInfoString(), buf, castNode, context, 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(), check_partition_bounds_for_split_range(), and get_rule_expr().

◆ get_relation_name()

static char * get_relation_name ( Oid  relid)
static

Definition at line 12727 of file ruleutils.c.

12728 {
12729  char *relname = get_rel_name(relid);
12730 
12731  if (!relname)
12732  elog(ERROR, "cache lookup failed for relation %u", relid);
12733  return relname;
12734 }
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928

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

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

◆ get_reloptions()

static void get_reloptions ( StringInfo  buf,
Datum  reloptions 
)
static

Definition at line 13180 of file ruleutils.c.

13181 {
13182  Datum *options;
13183  int noptions;
13184  int i;
13185 
13186  deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
13187  &options, NULL, &noptions);
13188 
13189  for (i = 0; i < noptions; i++)
13190  {
13191  char *option = TextDatumGetCString(options[i]);
13192  char *name;
13193  char *separator;
13194  char *value;
13195 
13196  /*
13197  * Each array element should have the form name=value. If the "=" is
13198  * missing for some reason, treat it like an empty value.
13199  */
13200  name = option;
13201  separator = strchr(option, '=');
13202  if (separator)
13203  {
13204  *separator = '\0';
13205  value = separator + 1;
13206  }
13207  else
13208  value = "";
13209 
13210  if (i > 0)
13211  appendStringInfoString(buf, ", ");
13213 
13214  /*
13215  * In general we need to quote the value; but to avoid unnecessary
13216  * clutter, do not quote if it is an identifier that would not need
13217  * quoting. (We could also allow numbers, but that is a bit trickier
13218  * than it looks --- for example, are leading zeroes significant? We
13219  * don't want to assume very much here about what custom reloptions
13220  * might mean.)
13221  */
13222  if (quote_identifier(value) == value)
13224  else
13226 
13227  pfree(option);
13228  }
13229 }
static struct @155 value
static size_t noptions
const char * name

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

4970 {
4971  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
4972 
4973  Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
4974  return (char *) list_nth(dpns->rtable_names, rtindex - 1);
4975 }

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

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

◆ get_rte_alias()

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

Definition at line 12249 of file ruleutils.c.

12251 {
12252  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
12253  char *refname = get_rtable_name(varno, context);
12254  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12255  bool printalias = false;
12256 
12257  if (rte->alias != NULL)
12258  {
12259  /* Always print alias if user provided one */
12260  printalias = true;
12261  }
12262  else if (colinfo->printaliases)
12263  {
12264  /* Always print alias if we need to print column aliases */
12265  printalias = true;
12266  }
12267  else if (rte->rtekind == RTE_RELATION)
12268  {
12269  /*
12270  * No need to print alias if it's same as relation name (this would
12271  * normally be the case, but not if set_rtable_names had to resolve a
12272  * conflict).
12273  */
12274  if (strcmp(refname, get_relation_name(rte->relid)) != 0)
12275  printalias = true;
12276  }
12277  else if (rte->rtekind == RTE_FUNCTION)
12278  {
12279  /*
12280  * For a function RTE, always print alias. This covers possible
12281  * renaming of the function and/or instability of the FigureColname
12282  * rules for things that aren't simple functions. Note we'd need to
12283  * force it anyway for the columndef list case.
12284  */
12285  printalias = true;
12286  }
12287  else if (rte->rtekind == RTE_SUBQUERY ||
12288  rte->rtekind == RTE_VALUES)
12289  {
12290  /*
12291  * For a subquery, always print alias. This makes the output
12292  * SQL-spec-compliant, even though we allow such aliases to be omitted
12293  * on input.
12294  */
12295  printalias = true;
12296  }
12297  else if (rte->rtekind == RTE_CTE)
12298  {
12299  /*
12300  * No need to print alias if it's same as CTE name (this would
12301  * normally be the case, but not if set_rtable_names had to resolve a
12302  * conflict).
12303  */
12304  if (strcmp(refname, rte->ctename) != 0)
12305  printalias = true;
12306  }
12307 
12308  if (printalias)
12309  appendStringInfo(context->buf, "%s%s",
12310  use_as ? " AS " : " ",
12311  quote_identifier(refname));
12312 }
static char * get_relation_name(Oid relid)
Definition: ruleutils.c:12727

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

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

◆ get_rule_expr()

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

Definition at line 8888 of file ruleutils.c.

8890 {
8891  StringInfo buf = context->buf;
8892 
8893  if (node == NULL)
8894  return;
8895 
8896  /* Guard against excessively long or deeply-nested queries */
8899 
8900  /*
8901  * Each level of get_rule_expr must emit an indivisible term
8902  * (parenthesized if necessary) to ensure result is reparsed into the same
8903  * expression tree. The only exception is that when the input is a List,
8904  * we emit the component items comma-separated with no surrounding
8905  * decoration; this is convenient for most callers.
8906  */
8907  switch (nodeTag(node))
8908  {
8909  case T_Var:
8910  (void) get_variable((Var *) node, 0, false, context);
8911  break;
8912 
8913  case T_Const:
8914  get_const_expr((Const *) node, context, 0);
8915  break;
8916 
8917  case T_Param:
8918  get_parameter((Param *) node, context);
8919  break;
8920 
8921  case T_Aggref:
8922  get_agg_expr((Aggref *) node, context, (Aggref *) node);
8923  break;
8924 
8925  case T_GroupingFunc:
8926  {
8927  GroupingFunc *gexpr = (GroupingFunc *) node;
8928 
8929  appendStringInfoString(buf, "GROUPING(");
8930  get_rule_expr((Node *) gexpr->args, context, true);
8931  appendStringInfoChar(buf, ')');
8932  }
8933  break;
8934 
8935  case T_WindowFunc:
8937  break;
8938 
8939  case T_MergeSupportFunc:
8940  appendStringInfoString(buf, "MERGE_ACTION()");
8941  break;
8942 
8943  case T_SubscriptingRef:
8944  {
8945  SubscriptingRef *sbsref = (SubscriptingRef *) node;
8946  bool need_parens;
8947 
8948  /*
8949  * If the argument is a CaseTestExpr, we must be inside a
8950  * FieldStore, ie, we are assigning to an element of an array
8951  * within a composite column. Since we already punted on
8952  * displaying the FieldStore's target information, just punt
8953  * here too, and display only the assignment source
8954  * expression.
8955  */
8956  if (IsA(sbsref->refexpr, CaseTestExpr))
8957  {
8958  Assert(sbsref->refassgnexpr);
8959  get_rule_expr((Node *) sbsref->refassgnexpr,
8960  context, showimplicit);
8961  break;
8962  }
8963 
8964  /*
8965  * Parenthesize the argument unless it's a simple Var or a
8966  * FieldSelect. (In particular, if it's another
8967  * SubscriptingRef, we *must* parenthesize to avoid
8968  * confusion.)
8969  */
8970  need_parens = !IsA(sbsref->refexpr, Var) &&
8971  !IsA(sbsref->refexpr, FieldSelect);
8972  if (need_parens)
8973  appendStringInfoChar(buf, '(');
8974  get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
8975  if (need_parens)
8976  appendStringInfoChar(buf, ')');
8977 
8978  /*
8979  * If there's a refassgnexpr, we want to print the node in the
8980  * format "container[subscripts] := refassgnexpr". This is
8981  * not legal SQL, so decompilation of INSERT or UPDATE
8982  * statements should always use processIndirection as part of
8983  * the statement-level syntax. We should only see this when
8984  * EXPLAIN tries to print the targetlist of a plan resulting
8985  * from such a statement.
8986  */
8987  if (sbsref->refassgnexpr)
8988  {
8989  Node *refassgnexpr;
8990 
8991  /*
8992  * Use processIndirection to print this node's subscripts
8993  * as well as any additional field selections or
8994  * subscripting in immediate descendants. It returns the
8995  * RHS expr that is actually being "assigned".
8996  */
8997  refassgnexpr = processIndirection(node, context);
8998  appendStringInfoString(buf, " := ");
8999  get_rule_expr(refassgnexpr, context, showimplicit);
9000  }
9001  else
9002  {
9003  /* Just an ordinary container fetch, so print subscripts */
9004  printSubscripts(sbsref, context);
9005  }
9006  }
9007  break;
9008 
9009  case T_FuncExpr:
9010  get_func_expr((FuncExpr *) node, context, showimplicit);
9011  break;
9012 
9013  case T_NamedArgExpr:
9014  {
9015  NamedArgExpr *na = (NamedArgExpr *) node;
9016 
9017  appendStringInfo(buf, "%s => ", quote_identifier(na->name));
9018  get_rule_expr((Node *) na->arg, context, showimplicit);
9019  }
9020  break;
9021 
9022  case T_OpExpr:
9023  get_oper_expr((OpExpr *) node, context);
9024  break;
9025 
9026  case T_DistinctExpr:
9027  {
9028  DistinctExpr *expr = (DistinctExpr *) node;
9029  List *args = expr->args;
9030  Node *arg1 = (Node *) linitial(args);
9031  Node *arg2 = (Node *) lsecond(args);
9032 
9033  if (!PRETTY_PAREN(context))
9034  appendStringInfoChar(buf, '(');
9035  get_rule_expr_paren(arg1, context, true, node);
9036  appendStringInfoString(buf, " IS DISTINCT FROM ");
9037  get_rule_expr_paren(arg2, context, true, node);
9038  if (!PRETTY_PAREN(context))
9039  appendStringInfoChar(buf, ')');
9040  }
9041  break;
9042 
9043  case T_NullIfExpr:
9044  {
9045  NullIfExpr *nullifexpr = (NullIfExpr *) node;
9046 
9047  appendStringInfoString(buf, "NULLIF(");
9048  get_rule_expr((Node *) nullifexpr->args, context, true);
9049  appendStringInfoChar(buf, ')');
9050  }
9051  break;
9052 
9053  case T_ScalarArrayOpExpr:
9054  {
9055  ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
9056  List *args = expr->args;
9057  Node *arg1 = (Node *) linitial(args);
9058  Node *arg2 = (Node *) lsecond(args);
9059 
9060  if (!PRETTY_PAREN(context))
9061  appendStringInfoChar(buf, '(');
9062  get_rule_expr_paren(arg1, context, true, node);
9063  appendStringInfo(buf, " %s %s (",
9065  exprType(arg1),
9067  expr->useOr ? "ANY" : "ALL");
9068  get_rule_expr_paren(arg2, context, true, node);
9069 
9070  /*
9071  * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
9072  * a bare sub-SELECT. Since we're here, the sub-SELECT must
9073  * be meant as a scalar sub-SELECT yielding an array value to
9074  * be used in ScalarArrayOpExpr; but the grammar will
9075  * preferentially interpret such a construct as an ANY/ALL
9076  * SubLink. To prevent misparsing the output that way, insert
9077  * a dummy coercion (which will be stripped by parse analysis,
9078  * so no inefficiency is added in dump and reload). This is
9079  * indeed most likely what the user wrote to get the construct
9080  * accepted in the first place.
9081  */
9082  if (IsA(arg2, SubLink) &&
9083  ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
9084  appendStringInfo(buf, "::%s",
9086  exprTypmod(arg2)));
9087  appendStringInfoChar(buf, ')');
9088  if (!PRETTY_PAREN(context))
9089  appendStringInfoChar(buf, ')');
9090  }
9091  break;
9092 
9093  case T_BoolExpr:
9094  {
9095  BoolExpr *expr = (BoolExpr *) node;
9096  Node *first_arg = linitial(expr->args);
9097  ListCell *arg;
9098 
9099  switch (expr->boolop)
9100  {
9101  case AND_EXPR:
9102  if (!PRETTY_PAREN(context))
9103  appendStringInfoChar(buf, '(');
9104  get_rule_expr_paren(first_arg, context,
9105  false, node);
9106  for_each_from(arg, expr->args, 1)
9107  {
9108  appendStringInfoString(buf, " AND ");
9110  false, node);
9111  }
9112  if (!PRETTY_PAREN(context))
9113  appendStringInfoChar(buf, ')');
9114  break;
9115 
9116  case OR_EXPR:
9117  if (!PRETTY_PAREN(context))
9118  appendStringInfoChar(buf, '(');
9119  get_rule_expr_paren(first_arg, context,
9120  false, node);
9121  for_each_from(arg, expr->args, 1)
9122  {
9123  appendStringInfoString(buf, " OR ");
9125  false, node);
9126  }
9127  if (!PRETTY_PAREN(context))
9128  appendStringInfoChar(buf, ')');
9129  break;
9130 
9131  case NOT_EXPR:
9132  if (!PRETTY_PAREN(context))
9133  appendStringInfoChar(buf, '(');
9134  appendStringInfoString(buf, "NOT ");
9135  get_rule_expr_paren(first_arg, context,
9136  false, node);
9137  if (!PRETTY_PAREN(context))
9138  appendStringInfoChar(buf, ')');
9139  break;
9140 
9141  default:
9142  elog(ERROR, "unrecognized boolop: %d",
9143  (int) expr->boolop);
9144  }
9145  }
9146  break;
9147 
9148  case T_SubLink:
9149  get_sublink_expr((SubLink *) node, context);
9150  break;
9151 
9152  case T_SubPlan:
9153  {
9154  SubPlan *subplan = (SubPlan *) node;
9155 
9156  /*
9157  * We cannot see an already-planned subplan in rule deparsing,
9158  * only while EXPLAINing a query plan. We don't try to
9159  * reconstruct the original SQL, just reference the subplan
9160  * that appears elsewhere in EXPLAIN's result. It does seem
9161  * useful to show the subLinkType and testexpr (if any), and
9162  * we also note whether the subplan will be hashed.
9163  */
9164  switch (subplan->subLinkType)
9165  {
9166  case EXISTS_SUBLINK:
9167  appendStringInfoString(buf, "EXISTS(");
9168  Assert(subplan->testexpr == NULL);
9169  break;
9170  case ALL_SUBLINK:
9171  appendStringInfoString(buf, "(ALL ");
9172  Assert(subplan->testexpr != NULL);
9173  break;
9174  case ANY_SUBLINK:
9175  appendStringInfoString(buf, "(ANY ");
9176  Assert(subplan->testexpr != NULL);
9177  break;
9178  case ROWCOMPARE_SUBLINK:
9179  /* Parenthesizing the testexpr seems sufficient */
9180  appendStringInfoChar(buf, '(');
9181  Assert(subplan->testexpr != NULL);
9182  break;
9183  case EXPR_SUBLINK:
9184  /* No need to decorate these subplan references */
9185  appendStringInfoChar(buf, '(');
9186  Assert(subplan->testexpr == NULL);
9187  break;
9188  case MULTIEXPR_SUBLINK:
9189  /* MULTIEXPR isn't executed in the normal way */
9190  appendStringInfoString(buf, "(rescan ");
9191  Assert(subplan->testexpr == NULL);
9192  break;
9193  case ARRAY_SUBLINK:
9194  appendStringInfoString(buf, "ARRAY(");
9195  Assert(subplan->testexpr == NULL);
9196  break;
9197  case CTE_SUBLINK:
9198  /* This case is unreachable within expressions */
9199  appendStringInfoString(buf, "CTE(");
9200  Assert(subplan->testexpr == NULL);
9201  break;
9202  }
9203 
9204  if (subplan->testexpr != NULL)
9205  {
9206  deparse_namespace *dpns;
9207 
9208  /*
9209  * Push SubPlan into ancestors list while deparsing
9210  * testexpr, so that we can handle PARAM_EXEC references
9211  * to the SubPlan's paramIds. (This makes it look like
9212  * the SubPlan is an "ancestor" of the current plan node,
9213  * which is a little weird, but it does no harm.) In this
9214  * path, we don't need to mention the SubPlan explicitly,
9215  * because the referencing Params will show its existence.
9216  */
9217  dpns = (deparse_namespace *) linitial(context->namespaces);
9218  dpns->ancestors = lcons(subplan, dpns->ancestors);
9219 
9220  get_rule_expr(subplan->testexpr, context, showimplicit);
9221  appendStringInfoChar(buf, ')');
9222 
9223  dpns->ancestors = list_delete_first(dpns->ancestors);
9224  }
9225  else
9226  {
9227  /* No referencing Params, so show the SubPlan's name */
9228  if (subplan->useHashTable)
9229  appendStringInfo(buf, "hashed %s)", subplan->plan_name);
9230  else
9231  appendStringInfo(buf, "%s)", subplan->plan_name);
9232  }
9233  }
9234  break;
9235 
9236  case T_AlternativeSubPlan:
9237  {
9238  AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
9239  ListCell *lc;
9240 
9241  /*
9242  * This case cannot be reached in normal usage, since no
9243  * AlternativeSubPlan can appear either in parsetrees or
9244  * finished plan trees. We keep it just in case somebody
9245  * wants to use this code to print planner data structures.
9246  */
9247  appendStringInfoString(buf, "(alternatives: ");
9248  foreach(lc, asplan->subplans)
9249  {
9250  SubPlan *splan = lfirst_node(SubPlan, lc);
9251 
9252  if (splan->useHashTable)
9253  appendStringInfo(buf, "hashed %s", splan->plan_name);
9254  else
9255  appendStringInfoString(buf, splan->plan_name);
9256  if (lnext(asplan->subplans, lc))
9257  appendStringInfoString(buf, " or ");
9258  }
9259  appendStringInfoChar(buf, ')');
9260  }
9261  break;
9262 
9263  case T_FieldSelect:
9264  {
9265  FieldSelect *fselect = (FieldSelect *) node;
9266  Node *arg = (Node *) fselect->arg;
9267  int fno = fselect->fieldnum;
9268  const char *fieldname;
9269  bool need_parens;
9270 
9271  /*
9272  * Parenthesize the argument unless it's an SubscriptingRef or
9273  * another FieldSelect. Note in particular that it would be
9274  * WRONG to not parenthesize a Var argument; simplicity is not
9275  * the issue here, having the right number of names is.
9276  */
9277  need_parens = !IsA(arg, SubscriptingRef) &&
9278  !IsA(arg, FieldSelect);
9279  if (need_parens)
9280  appendStringInfoChar(buf, '(');
9281  get_rule_expr(arg, context, true);
9282  if (need_parens)
9283  appendStringInfoChar(buf, ')');
9284 
9285  /*
9286  * Get and print the field name.
9287  */
9288  fieldname = get_name_for_var_field((Var *) arg, fno,
9289  0, context);
9290  appendStringInfo(buf, ".%s", quote_identifier(fieldname));
9291  }
9292  break;
9293 
9294  case T_FieldStore:
9295  {
9296  FieldStore *fstore = (FieldStore *) node;
9297  bool need_parens;
9298 
9299  /*
9300  * There is no good way to represent a FieldStore as real SQL,
9301  * so decompilation of INSERT or UPDATE statements should
9302  * always use processIndirection as part of the
9303  * statement-level syntax. We should only get here when
9304  * EXPLAIN tries to print the targetlist of a plan resulting
9305  * from such a statement. The plan case is even harder than
9306  * ordinary rules would be, because the planner tries to
9307  * collapse multiple assignments to the same field or subfield
9308  * into one FieldStore; so we can see a list of target fields
9309  * not just one, and the arguments could be FieldStores
9310  * themselves. We don't bother to try to print the target
9311  * field names; we just print the source arguments, with a
9312  * ROW() around them if there's more than one. This isn't
9313  * terribly complete, but it's probably good enough for
9314  * EXPLAIN's purposes; especially since anything more would be
9315  * either hopelessly confusing or an even poorer
9316  * representation of what the plan is actually doing.
9317  */
9318  need_parens = (list_length(fstore->newvals) != 1);
9319  if (need_parens)
9320  appendStringInfoString(buf, "ROW(");
9321  get_rule_expr((Node *) fstore->newvals, context, showimplicit);
9322  if (need_parens)
9323  appendStringInfoChar(buf, ')');
9324  }
9325  break;
9326 
9327  case T_RelabelType:
9328  {
9329  RelabelType *relabel = (RelabelType *) node;
9330  Node *arg = (Node *) relabel->arg;
9331 
9332  if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
9333  !showimplicit)
9334  {
9335  /* don't show the implicit cast */
9336  get_rule_expr_paren(arg, context, false, node);
9337  }
9338  else
9339  {
9341  relabel->resulttype,
9342  relabel->resulttypmod,
9343  node);
9344  }
9345  }
9346  break;
9347 
9348  case T_CoerceViaIO:
9349  {
9350  CoerceViaIO *iocoerce = (CoerceViaIO *) node;
9351  Node *arg = (Node *) iocoerce->arg;
9352 
9353  if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9354  !showimplicit)
9355  {
9356  /* don't show the implicit cast */
9357  get_rule_expr_paren(arg, context, false, node);
9358  }
9359  else
9360  {
9362  iocoerce->resulttype,
9363  -1,
9364  node);
9365  }
9366  }
9367  break;
9368 
9369  case T_ArrayCoerceExpr:
9370  {
9371  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
9372  Node *arg = (Node *) acoerce->arg;
9373 
9374  if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9375  !showimplicit)
9376  {
9377  /* don't show the implicit cast */
9378  get_rule_expr_paren(arg, context, false, node);
9379  }
9380  else
9381  {
9383  acoerce->resulttype,
9384  acoerce->resulttypmod,
9385  node);
9386  }
9387  }
9388  break;
9389 
9390  case T_ConvertRowtypeExpr:
9391  {
9393  Node *arg = (Node *) convert->arg;
9394 
9395  if (convert->convertformat == COERCE_IMPLICIT_CAST &&
9396  !showimplicit)
9397  {
9398  /* don't show the implicit cast */
9399  get_rule_expr_paren(arg, context, false, node);
9400  }
9401  else
9402  {
9404  convert->resulttype, -1,
9405  node);
9406  }
9407  }
9408  break;
9409 
9410  case T_CollateExpr:
9411  {
9412  CollateExpr *collate = (CollateExpr *) node;
9413  Node *arg = (Node *) collate->arg;
9414 
9415  if (!PRETTY_PAREN(context))
9416  appendStringInfoChar(buf, '(');
9417  get_rule_expr_paren(arg, context, showimplicit, node);
9418  appendStringInfo(buf, " COLLATE %s",
9419  generate_collation_name(collate->collOid));
9420  if (!PRETTY_PAREN(context))
9421  appendStringInfoChar(buf, ')');
9422  }
9423  break;
9424 
9425  case T_CaseExpr:
9426  {
9427  CaseExpr *caseexpr = (CaseExpr *) node;
9428  ListCell *temp;
9429 
9430  appendContextKeyword(context, "CASE",
9431  0, PRETTYINDENT_VAR, 0);
9432  if (caseexpr->arg)
9433  {
9434  appendStringInfoChar(buf, ' ');
9435  get_rule_expr((Node *) caseexpr->arg, context, true);
9436  }
9437  foreach(temp, caseexpr->args)
9438  {
9439  CaseWhen *when = (CaseWhen *) lfirst(temp);
9440  Node *w = (Node *) when->expr;
9441 
9442  if (caseexpr->arg)
9443  {
9444  /*
9445  * The parser should have produced WHEN clauses of the
9446  * form "CaseTestExpr = RHS", possibly with an
9447  * implicit coercion inserted above the CaseTestExpr.
9448  * For accurate decompilation of rules it's essential
9449  * that we show just the RHS. However in an
9450  * expression that's been through the optimizer, the
9451  * WHEN clause could be almost anything (since the
9452  * equality operator could have been expanded into an
9453  * inline function). If we don't recognize the form
9454  * of the WHEN clause, just punt and display it as-is.
9455  */
9456  if (IsA(w, OpExpr))
9457  {
9458  List *args = ((OpExpr *) w)->args;
9459 
9460  if (list_length(args) == 2 &&
9462  CaseTestExpr))
9463  w = (Node *) lsecond(args);
9464  }
9465  }
9466 
9467  if (!PRETTY_INDENT(context))
9468  appendStringInfoChar(buf, ' ');
9469  appendContextKeyword(context, "WHEN ",
9470  0, 0, 0);
9471  get_rule_expr(w, context, false);
9472  appendStringInfoString(buf, " THEN ");
9473  get_rule_expr((Node *) when->result, context, true);
9474  }
9475  if (!PRETTY_INDENT(context))
9476  appendStringInfoChar(buf, ' ');
9477  appendContextKeyword(context, "ELSE ",
9478  0, 0, 0);
9479  get_rule_expr((Node *) caseexpr->defresult, context, true);
9480  if (!PRETTY_INDENT(context))
9481  appendStringInfoChar(buf, ' ');
9483  -PRETTYINDENT_VAR, 0, 0);
9484  }
9485  break;
9486 
9487  case T_CaseTestExpr:
9488  {
9489  /*
9490  * Normally we should never get here, since for expressions
9491  * that can contain this node type we attempt to avoid
9492  * recursing to it. But in an optimized expression we might
9493  * be unable to avoid that (see comments for CaseExpr). If we
9494  * do see one, print it as CASE_TEST_EXPR.
9495  */
9496  appendStringInfoString(buf, "CASE_TEST_EXPR");
9497  }
9498  break;
9499 
9500  case T_ArrayExpr:
9501  {
9502  ArrayExpr *arrayexpr = (ArrayExpr *) node;
9503 
9504  appendStringInfoString(buf, "ARRAY[");
9505  get_rule_expr((Node *) arrayexpr->elements, context, true);
9506  appendStringInfoChar(buf, ']');
9507 
9508  /*
9509  * If the array isn't empty, we assume its elements are
9510  * coerced to the desired type. If it's empty, though, we
9511  * need an explicit coercion to the array type.
9512  */
9513  if (arrayexpr->elements == NIL)
9514  appendStringInfo(buf, "::%s",
9515  format_type_with_typemod(arrayexpr->array_typeid, -1));
9516  }
9517  break;
9518 
9519  case T_RowExpr:
9520  {
9521  RowExpr *rowexpr = (RowExpr *) node;
9522  TupleDesc tupdesc = NULL;
9523  ListCell *arg;
9524  int i;
9525  char *sep;
9526 
9527  /*
9528  * If it's a named type and not RECORD, we may have to skip
9529  * dropped columns and/or claim there are NULLs for added
9530  * columns.
9531  */
9532  if (rowexpr->row_typeid != RECORDOID)
9533  {
9534  tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
9535  Assert(list_length(rowexpr->args) <= tupdesc->natts);
9536  }
9537 
9538  /*
9539  * SQL99 allows "ROW" to be omitted when there is more than
9540  * one column, but for simplicity we always print it.
9541  */
9542  appendStringInfoString(buf, "ROW(");
9543  sep = "";
9544  i = 0;
9545  foreach(arg, rowexpr->args)
9546  {
9547  Node *e = (Node *) lfirst(arg);
9548 
9549  if (tupdesc == NULL ||
9550  !TupleDescAttr(tupdesc, i)->attisdropped)
9551  {
9553  /* Whole-row Vars need special treatment here */
9555  sep = ", ";
9556  }
9557  i++;
9558  }
9559  if (tupdesc != NULL)
9560  {
9561  while (i < tupdesc->natts)
9562  {
9563  if (!TupleDescAttr(tupdesc, i)->attisdropped)
9564  {
9566  appendStringInfoString(buf, "NULL");
9567  sep = ", ";
9568  }
9569  i++;
9570  }
9571 
9572  ReleaseTupleDesc(tupdesc);
9573  }
9574  appendStringInfoChar(buf, ')');
9575  if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
9576  appendStringInfo(buf, "::%s",
9577  format_type_with_typemod(rowexpr->row_typeid, -1));
9578  }
9579  break;
9580 
9581  case T_RowCompareExpr:
9582  {
9583  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
9584 
9585  /*
9586  * SQL99 allows "ROW" to be omitted when there is more than
9587  * one column, but for simplicity we always print it. Within
9588  * a ROW expression, whole-row Vars need special treatment, so
9589  * use get_rule_list_toplevel.
9590  */
9591  appendStringInfoString(buf, "(ROW(");
9592  get_rule_list_toplevel(rcexpr->largs, context, true);
9593 
9594  /*
9595  * We assume that the name of the first-column operator will
9596  * do for all the rest too. This is definitely open to
9597  * failure, eg if some but not all operators were renamed
9598  * since the construct was parsed, but there seems no way to
9599  * be perfect.
9600  */
9601  appendStringInfo(buf, ") %s ROW(",
9602  generate_operator_name(linitial_oid(rcexpr->opnos),
9603  exprType(linitial(rcexpr->largs)),
9604  exprType(linitial(rcexpr->rargs))));
9605  get_rule_list_toplevel(rcexpr->rargs, context, true);
9606  appendStringInfoString(buf, "))");
9607  }
9608  break;
9609 
9610  case T_CoalesceExpr:
9611  {
9612  CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
9613 
9614  appendStringInfoString(buf, "COALESCE(");
9615  get_rule_expr((Node *) coalesceexpr->args, context, true);
9616  appendStringInfoChar(buf, ')');
9617  }
9618  break;
9619 
9620  case T_MinMaxExpr:
9621  {
9622  MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
9623 
9624  switch (minmaxexpr->op)
9625  {
9626  case IS_GREATEST:
9627  appendStringInfoString(buf, "GREATEST(");
9628  break;
9629  case IS_LEAST:
9630  appendStringInfoString(buf, "LEAST(");
9631  break;
9632  }
9633  get_rule_expr((Node *) minmaxexpr->args, context, true);
9634  appendStringInfoChar(buf, ')');
9635  }
9636  break;
9637 
9638  case T_SQLValueFunction:
9639  {
9640  SQLValueFunction *svf = (SQLValueFunction *) node;
9641 
9642  /*
9643  * Note: this code knows that typmod for time, timestamp, and
9644  * timestamptz just prints as integer.
9645  */
9646  switch (svf->op)
9647  {
9648  case SVFOP_CURRENT_DATE:
9649  appendStringInfoString(buf, "CURRENT_DATE");
9650  break;
9651  case SVFOP_CURRENT_TIME:
9652  appendStringInfoString(buf, "CURRENT_TIME");
9653  break;
9654  case SVFOP_CURRENT_TIME_N:
9655  appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
9656  break;
9658  appendStringInfoString(buf, "CURRENT_TIMESTAMP");
9659  break;
9661  appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
9662  svf->typmod);
9663  break;
9664  case SVFOP_LOCALTIME:
9665  appendStringInfoString(buf, "LOCALTIME");
9666  break;
9667  case SVFOP_LOCALTIME_N:
9668  appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
9669  break;
9670  case SVFOP_LOCALTIMESTAMP:
9671  appendStringInfoString(buf, "LOCALTIMESTAMP");
9672  break;
9674  appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
9675  svf->typmod);
9676  break;
9677  case SVFOP_CURRENT_ROLE:
9678  appendStringInfoString(buf, "CURRENT_ROLE");
9679  break;
9680  case SVFOP_CURRENT_USER:
9681  appendStringInfoString(buf, "CURRENT_USER");
9682  break;
9683  case SVFOP_USER:
9684  appendStringInfoString(buf, "USER");
9685  break;
9686  case SVFOP_SESSION_USER:
9687  appendStringInfoString(buf, "SESSION_USER");
9688  break;
9689  case SVFOP_CURRENT_CATALOG:
9690  appendStringInfoString(buf, "CURRENT_CATALOG");
9691  break;
9692  case SVFOP_CURRENT_SCHEMA:
9693  appendStringInfoString(buf, "CURRENT_SCHEMA");
9694  break;
9695  }
9696  }
9697  break;
9698 
9699  case T_XmlExpr:
9700  {
9701  XmlExpr *xexpr = (XmlExpr *) node;
9702  bool needcomma = false;
9703  ListCell *arg;
9704  ListCell *narg;
9705  Const *con;
9706 
9707  switch (xexpr->op)
9708  {
9709  case IS_XMLCONCAT:
9710  appendStringInfoString(buf, "XMLCONCAT(");
9711  break;
9712  case IS_XMLELEMENT:
9713  appendStringInfoString(buf, "XMLELEMENT(");
9714  break;
9715  case IS_XMLFOREST:
9716  appendStringInfoString(buf, "XMLFOREST(");
9717  break;
9718  case IS_XMLPARSE:
9719  appendStringInfoString(buf, "XMLPARSE(");
9720  break;
9721  case IS_XMLPI:
9722  appendStringInfoString(buf, "XMLPI(");
9723  break;
9724  case IS_XMLROOT:
9725  appendStringInfoString(buf, "XMLROOT(");
9726  break;
9727  case IS_XMLSERIALIZE:
9728  appendStringInfoString(buf, "XMLSERIALIZE(");
9729  break;
9730  case IS_DOCUMENT:
9731  break;
9732  }
9733  if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
9734  {
9735  if (xexpr->xmloption == XMLOPTION_DOCUMENT)
9736  appendStringInfoString(buf, "DOCUMENT ");
9737  else
9738  appendStringInfoString(buf, "CONTENT ");
9739  }
9740  if (xexpr->name)
9741  {
9742  appendStringInfo(buf, "NAME %s",
9744  needcomma = true;
9745  }
9746  if (xexpr->named_args)
9747  {
9748  if (xexpr->op != IS_XMLFOREST)
9749  {
9750  if (needcomma)
9751  appendStringInfoString(buf, ", ");
9752  appendStringInfoString(buf, "XMLATTRIBUTES(");
9753  needcomma = false;
9754  }
9755  forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
9756  {
9757  Node *e = (Node *) lfirst(arg);
9758  char *argname = strVal(lfirst(narg));
9759 
9760  if (needcomma)
9761  appendStringInfoString(buf, ", ");
9762  get_rule_expr((Node *) e, context, true);
9763  appendStringInfo(buf, " AS %s",
9765  needcomma = true;
9766  }
9767  if (xexpr->op != IS_XMLFOREST)
9768  appendStringInfoChar(buf, ')');
9769  }
9770  if (xexpr->args)
9771  {
9772  if (needcomma)
9773  appendStringInfoString(buf, ", ");
9774  switch (xexpr->op)
9775  {
9776  case IS_XMLCONCAT:
9777  case IS_XMLELEMENT:
9778  case IS_XMLFOREST:
9779  case IS_XMLPI:
9780  case IS_XMLSERIALIZE:
9781  /* no extra decoration needed */
9782  get_rule_expr((Node *) xexpr->args, context, true);
9783  break;
9784  case IS_XMLPARSE:
9785  Assert(list_length(xexpr->args) == 2);
9786 
9787  get_rule_expr((Node *) linitial(xexpr->args),
9788  context, true);
9789 
9790  con = lsecond_node(Const, xexpr->args);
9791  Assert(!con->constisnull);
9792  if (DatumGetBool(con->constvalue))
9794  " PRESERVE WHITESPACE");
9795  else
9797  " STRIP WHITESPACE");
9798  break;
9799  case IS_XMLROOT:
9800  Assert(list_length(xexpr->args) == 3);
9801 
9802  get_rule_expr((Node *) linitial(xexpr->args),
9803  context, true);
9804 
9805  appendStringInfoString(buf, ", VERSION ");
9806  con = (Const *) lsecond(xexpr->args);
9807  if (IsA(con, Const) &&
9808  con->constisnull)
9809  appendStringInfoString(buf, "NO VALUE");
9810  else
9811  get_rule_expr((Node *) con, context, false);
9812 
9813  con = lthird_node(Const, xexpr->args);
9814  if (con->constisnull)
9815  /* suppress STANDALONE NO VALUE */ ;
9816  else
9817  {
9818  switch (DatumGetInt32(con->constvalue))
9819  {
9820  case XML_STANDALONE_YES:
9822  ", STANDALONE YES");
9823  break;
9824  case XML_STANDALONE_NO:
9826  ", STANDALONE NO");
9827  break;
9830  ", STANDALONE NO VALUE");
9831  break;
9832  default:
9833  break;
9834  }
9835  }
9836  break;
9837  case IS_DOCUMENT:
9838  get_rule_expr_paren((Node *) xexpr->args, context, false, node);
9839  break;
9840  }
9841  }
9842  if (xexpr->op == IS_XMLSERIALIZE)
9843  appendStringInfo(buf, " AS %s",
9844  format_type_with_typemod(xexpr->type,
9845  xexpr->typmod));
9846  if (xexpr->op == IS_DOCUMENT)
9847  appendStringInfoString(buf, " IS DOCUMENT");
9848  else
9849  appendStringInfoChar(buf, ')');
9850  }
9851  break;
9852 
9853  case T_NullTest:
9854  {
9855  NullTest *ntest = (NullTest *) node;
9856 
9857  if (!PRETTY_PAREN(context))
9858  appendStringInfoChar(buf, '(');
9859  get_rule_expr_paren((Node *) ntest->arg, context, true, node);
9860 
9861  /*
9862  * For scalar inputs, we prefer to print as IS [NOT] NULL,
9863  * which is shorter and traditional. If it's a rowtype input
9864  * but we're applying a scalar test, must print IS [NOT]
9865  * DISTINCT FROM NULL to be semantically correct.
9866  */
9867  if (ntest->argisrow ||
9868  !type_is_rowtype(exprType((Node *) ntest->arg)))
9869  {
9870  switch (ntest->nulltesttype)
9871  {
9872  case IS_NULL:
9873  appendStringInfoString(buf, " IS NULL");
9874  break;
9875  case IS_NOT_NULL:
9876  appendStringInfoString(buf, " IS NOT NULL");
9877  break;
9878  default:
9879  elog(ERROR, "unrecognized nulltesttype: %d",
9880  (int) ntest->nulltesttype);
9881  }
9882  }
9883  else
9884  {
9885  switch (ntest->nulltesttype)
9886  {
9887  case IS_NULL:
9888  appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
9889  break;
9890  case IS_NOT_NULL:
9891  appendStringInfoString(buf, " IS DISTINCT FROM NULL");
9892  break;
9893  default:
9894  elog(ERROR, "unrecognized nulltesttype: %d",
9895  (int) ntest->nulltesttype);
9896  }
9897  }
9898  if (!PRETTY_PAREN(context))
9899  appendStringInfoChar(buf, ')');
9900  }
9901  break;
9902 
9903  case T_BooleanTest:
9904  {
9905  BooleanTest *btest = (BooleanTest *) node;
9906 
9907  if (!PRETTY_PAREN(context))
9908  appendStringInfoChar(buf, '(');
9909  get_rule_expr_paren((Node *) btest->arg, context, false, node);
9910  switch (btest->booltesttype)
9911  {
9912  case IS_TRUE:
9913  appendStringInfoString(buf, " IS TRUE");
9914  break;
9915  case IS_NOT_TRUE:
9916  appendStringInfoString(buf, " IS NOT TRUE");
9917  break;
9918  case IS_FALSE:
9919  appendStringInfoString(buf, " IS FALSE");
9920  break;
9921  case IS_NOT_FALSE:
9922  appendStringInfoString(buf, " IS NOT FALSE");
9923  break;
9924  case IS_UNKNOWN:
9925  appendStringInfoString(buf, " IS UNKNOWN");
9926  break;
9927  case IS_NOT_UNKNOWN:
9928  appendStringInfoString(buf, " IS NOT UNKNOWN");
9929  break;
9930  default:
9931  elog(ERROR, "unrecognized booltesttype: %d",
9932  (int) btest->booltesttype);
9933  }
9934  if (!PRETTY_PAREN(context))
9935  appendStringInfoChar(buf, ')');
9936  }
9937  break;
9938 
9939  case T_CoerceToDomain:
9940  {
9941  CoerceToDomain *ctest = (CoerceToDomain *) node;
9942  Node *arg = (Node *) ctest->arg;
9943 
9944  if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
9945  !showimplicit)
9946  {
9947  /* don't show the implicit cast */
9948  get_rule_expr(arg, context, false);
9949  }
9950  else
9951  {
9953  ctest->resulttype,
9954  ctest->resulttypmod,
9955  node);
9956  }
9957  }
9958  break;
9959 
9960  case T_CoerceToDomainValue:
9961  appendStringInfoString(buf, "VALUE");
9962  break;
9963 
9964  case T_SetToDefault:
9965  appendStringInfoString(buf, "DEFAULT");
9966  break;
9967 
9968  case T_CurrentOfExpr:
9969  {
9970  CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
9971 
9972  if (cexpr->cursor_name)
9973  appendStringInfo(buf, "CURRENT OF %s",
9974  quote_identifier(cexpr->cursor_name));
9975  else
9976  appendStringInfo(buf, "CURRENT OF $%d",
9977  cexpr->cursor_param);
9978  }
9979  break;
9980 
9981  case T_NextValueExpr:
9982  {
9983  NextValueExpr *nvexpr = (NextValueExpr *) node;
9984 
9985  /*
9986  * This isn't exactly nextval(), but that seems close enough
9987  * for EXPLAIN's purposes.
9988  */
9989  appendStringInfoString(buf, "nextval(");
9991  generate_relation_name(nvexpr->seqid,
9992  NIL));
9993  appendStringInfoChar(buf, ')');
9994  }
9995  break;
9996 
9997  case T_InferenceElem:
9998  {
9999  InferenceElem *iexpr = (InferenceElem *) node;
10000  bool save_varprefix;
10001  bool need_parens;
10002 
10003  /*
10004  * InferenceElem can only refer to target relation, so a
10005  * prefix is not useful, and indeed would cause parse errors.
10006  */
10007  save_varprefix = context->varprefix;
10008  context->varprefix = false;
10009 
10010  /*
10011  * Parenthesize the element unless it's a simple Var or a bare
10012  * function call. Follows pg_get_indexdef_worker().
10013  */
10014  need_parens = !IsA(iexpr->expr, Var);
10015  if (IsA(iexpr->expr, FuncExpr) &&
10016  ((FuncExpr *) iexpr->expr)->funcformat ==
10018  need_parens = false;
10019 
10020  if (need_parens)
10021  appendStringInfoChar(buf, '(');
10022  get_rule_expr((Node *) iexpr->expr,
10023  context, false);
10024  if (need_parens)
10025  appendStringInfoChar(buf, ')');
10026 
10027  context->varprefix = save_varprefix;
10028 
10029  if (iexpr->infercollid)
10030  appendStringInfo(buf, " COLLATE %s",
10032 
10033  /* Add the operator class name, if not default */
10034  if (iexpr->inferopclass)
10035  {
10036  Oid inferopclass = iexpr->inferopclass;
10037  Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
10038 
10039  get_opclass_name(inferopclass, inferopcinputtype, buf);
10040  }
10041  }
10042  break;
10043 
10044  case T_PartitionBoundSpec:
10045  {
10046  PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
10047  ListCell *cell;
10048  char *sep;
10049 
10050  if (spec->is_default)
10051  {
10052  appendStringInfoString(buf, "DEFAULT");
10053  break;
10054  }
10055 
10056  switch (spec->strategy)
10057  {
10059  Assert(spec->modulus > 0 && spec->remainder >= 0);
10060  Assert(spec->modulus > spec->remainder);
10061 
10062  appendStringInfoString(buf, "FOR VALUES");
10063  appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
10064  spec->modulus, spec->remainder);
10065  break;
10066 
10068  Assert(spec->listdatums != NIL);
10069 
10070  appendStringInfoString(buf, "FOR VALUES IN (");
10071  sep = "";
10072  foreach(cell, spec->listdatums)
10073  {
10074  Const *val = lfirst_node(Const, cell);
10075 
10077  get_const_expr(val, context, -1);
10078  sep = ", ";
10079  }
10080 
10081  appendStringInfoChar(buf, ')');
10082  break;
10083 
10085  Assert(spec->lowerdatums != NIL &&
10086  spec->upperdatums != NIL &&
10087  list_length(spec->lowerdatums) ==
10088  list_length(spec->upperdatums));
10089 
10090  appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
10093  break;
10094 
10095  default:
10096  elog(ERROR, "unrecognized partition strategy: %d",
10097  (int) spec->strategy);
10098  break;
10099  }
10100  }
10101  break;
10102 
10103  case T_JsonValueExpr:
10104  {
10105  JsonValueExpr *jve = (JsonValueExpr *) node;
10106 
10107  get_rule_expr((Node *) jve->raw_expr, context, false);
10108  get_json_format(jve->format, context->buf);
10109  }
10110  break;
10111 
10112  case T_JsonConstructorExpr:
10114  break;
10115 
10116  case T_JsonIsPredicate:
10117  {
10118  JsonIsPredicate *pred = (JsonIsPredicate *) node;
10119 
10120  if (!PRETTY_PAREN(context))
10121  appendStringInfoChar(context->buf, '(');
10122 
10123  get_rule_expr_paren(pred->expr, context, true, node);
10124 
10125  appendStringInfoString(context->buf, " IS JSON");
10126 
10127  /* TODO: handle FORMAT clause */
10128 
10129  switch (pred->item_type)
10130  {
10131  case JS_TYPE_SCALAR:
10132  appendStringInfoString(context->buf, " SCALAR");
10133  break;
10134  case JS_TYPE_ARRAY:
10135  appendStringInfoString(context->buf, " ARRAY");
10136  break;
10137  case JS_TYPE_OBJECT:
10138  appendStringInfoString(context->buf, " OBJECT");
10139  break;
10140  default:
10141  break;
10142  }
10143 
10144  if (pred->unique_keys)
10145  appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
10146 
10147  if (!PRETTY_PAREN(context))
10148  appendStringInfoChar(context->buf, ')');
10149  }
10150  break;
10151 
10152  case T_JsonExpr:
10153  {
10154  JsonExpr *jexpr = (JsonExpr *) node;
10155 
10156  switch (jexpr->op)
10157  {
10158  case JSON_EXISTS_OP:
10159  appendStringInfoString(buf, "JSON_EXISTS(");
10160  break;
10161  case JSON_QUERY_OP:
10162  appendStringInfoString(buf, "JSON_QUERY(");
10163  break;
10164  case JSON_VALUE_OP:
10165  appendStringInfoString(buf, "JSON_VALUE(");
10166  break;
10167  default:
10168  elog(ERROR, "unrecognized JsonExpr op: %d",
10169  (int) jexpr->op);
10170  }
10171 
10172  get_rule_expr(jexpr->formatted_expr, context, showimplicit);
10173 
10174  appendStringInfoString(buf, ", ");
10175 
10176  get_json_path_spec(jexpr->path_spec, context, showimplicit);
10177 
10178  if (jexpr->passing_values)
10179  {
10180  ListCell *lc1,
10181  *lc2;
10182  bool needcomma = false;
10183 
10184  appendStringInfoString(buf, " PASSING ");
10185 
10186  forboth(lc1, jexpr->passing_names,
10187  lc2, jexpr->passing_values)
10188  {
10189  if (needcomma)
10190  appendStringInfoString(buf, ", ");
10191  needcomma = true;
10192 
10193  get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
10194  appendStringInfo(buf, " AS %s",
10195  ((String *) lfirst_node(String, lc1))->sval);
10196  }
10197  }
10198 
10199  if (jexpr->op != JSON_EXISTS_OP ||
10200  jexpr->returning->typid != BOOLOID)
10201  get_json_returning(jexpr->returning, context->buf,
10202  jexpr->op == JSON_QUERY_OP);
10203 
10205  jexpr->op != JSON_EXISTS_OP ?
10208 
10209  appendStringInfoChar(buf, ')');
10210  }
10211  break;
10212 
10213  case T_List:
10214  {
10215  char *sep;
10216  ListCell *l;
10217 
10218  sep = "";
10219  foreach(l, (List *) node)
10220  {
10222  get_rule_expr((Node *) lfirst(l), context, showimplicit);
10223  sep = ", ";
10224  }
10225  }
10226  break;
10227 
10228  case T_TableFunc:
10229  get_tablefunc((TableFunc *) node, context, showimplicit);
10230  break;
10231 
10232  default:
10233  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
10234  break;
10235  }
10236 }
List * list_delete_first(List *list)
Definition: list.c:943
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1212
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2655
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2832
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
Node * strip_implicit_coercions(Node *node)
Definition: nodeFuncs.c:700
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:874
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:872
@ PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:873
#define lsecond_node(type, l)
Definition: pg_list.h:186
#define for_each_from(cell, lst, N)
Definition: pg_list.h:414
#define linitial_oid(l)
Definition: pg_list.h:180
#define lthird_node(type, l)
Definition: pg_list.h:191
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
e
Definition: preproc-init.c:82
@ IS_NOT_TRUE
Definition: primnodes.h:1948
@ IS_NOT_FALSE
Definition: primnodes.h:1948
@ IS_NOT_UNKNOWN
Definition: primnodes.h:1948
@ IS_TRUE
Definition: primnodes.h:1948
@ IS_UNKNOWN
Definition: primnodes.h:1948
@ IS_FALSE
Definition: primnodes.h:1948
@ ARRAY_SUBLINK
Definition: primnodes.h:973
@ ANY_SUBLINK
Definition: primnodes.h:969
@ CTE_SUBLINK
Definition: primnodes.h:974
@ EXPR_SUBLINK
Definition: primnodes.h:971
@ ROWCOMPARE_SUBLINK
Definition: primnodes.h:970
@ ALL_SUBLINK
Definition: primnodes.h:968
@ EXISTS_SUBLINK
Definition: primnodes.h:967
@ IS_LEAST
Definition: primnodes.h:1473
@ IS_GREATEST
Definition: primnodes.h:1472
@ AND_EXPR
Definition: primnodes.h:901
@ OR_EXPR
Definition: primnodes.h:901
@ NOT_EXPR
Definition: primnodes.h:901
@ XMLOPTION_DOCUMENT
Definition: primnodes.h:1562
@ SVFOP_CURRENT_CATALOG
Definition: primnodes.h:1519
@ SVFOP_LOCALTIME_N
Definition: primnodes.h:1512
@ SVFOP_CURRENT_TIMESTAMP
Definition: primnodes.h:1509
@ SVFOP_LOCALTIME
Definition: primnodes.h:1511
@ SVFOP_CURRENT_TIMESTAMP_N
Definition: primnodes.h:1510
@ SVFOP_CURRENT_ROLE
Definition: primnodes.h:1515
@ SVFOP_USER
Definition: primnodes.h:1517
@ SVFOP_CURRENT_SCHEMA
Definition: primnodes.h:1520
@ SVFOP_LOCALTIMESTAMP_N
Definition: primnodes.h:1514
@ SVFOP_CURRENT_DATE
Definition: primnodes.h:1506
@ SVFOP_CURRENT_TIME_N
Definition: primnodes.h:1508
@ SVFOP_CURRENT_TIME
Definition: primnodes.h:1507
@ SVFOP_LOCALTIMESTAMP
Definition: primnodes.h:1513
@ SVFOP_CURRENT_USER
Definition: primnodes.h:1516
@ SVFOP_SESSION_USER
Definition: primnodes.h:1518
@ IS_DOCUMENT
Definition: primnodes.h:1557
@ IS_XMLFOREST
Definition: primnodes.h:1552
@ IS_XMLCONCAT
Definition: primnodes.h:1550
@ IS_XMLPI
Definition: primnodes.h:1554
@ IS_XMLPARSE
Definition: primnodes.h:1553
@ IS_XMLSERIALIZE
Definition: primnodes.h:1556
@ IS_XMLROOT
Definition: primnodes.h:1555
@ IS_XMLELEMENT
Definition: primnodes.h:1551
@ JSON_VALUE_OP
Definition: primnodes.h:1770
@ COERCE_EXPLICIT_CALL
Definition: primnodes.h:704
@ IS_NULL
Definition: primnodes.h:1924
@ IS_NOT_NULL
Definition: primnodes.h:1924
@ JS_TYPE_ARRAY
Definition: primnodes.h:1690
@ JS_TYPE_OBJECT
Definition: primnodes.h:1689
@ JS_TYPE_SCALAR
Definition: primnodes.h:1691
static SPIPlanPtr splan
Definition: regress.c:269
static void get_sublink_expr(SubLink *sublink, deparse_context *context)
Definition: ruleutils.c:11415
static void get_parameter(Param *param, deparse_context *context)
Definition: ruleutils.c:8326
static void get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11267
static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
Definition: ruleutils.c:12593
static void get_oper_expr(OpExpr *expr, deparse_context *context)
Definition: ruleutils.c:10350
static void get_func_expr(FuncExpr *expr, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10390
static void get_rule_expr_toplevel(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10250
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:13268
static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
Definition: ruleutils.c:10640
static char * get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
Definition: ruleutils.c:7325
List * elements
Definition: primnodes.h:1350
BoolExprType boolop
Definition: primnodes.h:909
List * args
Definition: primnodes.h:910
BoolTestType booltesttype
Definition: primnodes.h:1955
Expr * arg
Definition: primnodes.h:1954
Expr * arg
Definition: primnodes.h:1283
Expr * defresult
Definition: primnodes.h:1285
List * args
Definition: primnodes.h:1284
List * args
Definition: primnodes.h:1462
Expr * arg
Definition: primnodes.h:1177
Oid resulttype
Definition: primnodes.h:1178
Expr * arg
Definition: primnodes.h:1249
char * cursor_name
Definition: primnodes.h:2068
AttrNumber fieldnum
Definition: primnodes.h:1099
Expr * arg
Definition: primnodes.h:1098
List * newvals
Definition: primnodes.h:1130
JsonReturning * returning
Definition: primnodes.h:1798
JsonValueType item_type
Definition: primnodes.h:1703
JsonFormat * format
Definition: primnodes.h:1651
Expr * raw_expr
Definition: primnodes.h:1649
List * args
Definition: primnodes.h:1488
MinMaxOp op
Definition: primnodes.h:1486
Expr * arg
Definition: primnodes.h:761
NullTestType nulltesttype
Definition: primnodes.h:1931
Expr * arg
Definition: primnodes.h:1930
Oid resulttype
Definition: primnodes.h:1155
Expr * arg
Definition: primnodes.h:1154
List * args
Definition: primnodes.h:1381
SQLValueFunctionOp op
Definition: primnodes.h:1526
Node * testexpr
Definition: primnodes.h:1037
Expr * refassgnexpr
Definition: primnodes.h:673
Expr * refexpr
Definition: primnodes.h:671
List * args
Definition: primnodes.h:1578
List * named_args
Definition: primnodes.h:1574
XmlExprOp op
Definition: primnodes.h:1570
Definition: type.h:88
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1833
char * map_xml_name_to_sql_identifier(const char *name)
Definition: xml.c:2371
@ XML_STANDALONE_NO_VALUE
Definition: xml.h:29
@ XML_STANDALONE_YES
Definition: xml.h:27
@ XML_STANDALONE_NO
Definition: xml.h:28
static void convert(const int32 val, char *const buf)
Definition: zic.c:1992

References ALL_SUBLINK, deparse_namespace::ancestors, AND_EXPR, ANY_SUBLINK, appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, NamedArgExpr::arg, FieldSelect::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, CollateExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, CoerceToDomain::arg, generate_unaccent_rules::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, CaseExpr::args, RowExpr::args, CoalesceExpr::args, MinMaxExpr::args, XmlExpr::args, ARRAY_SUBLINK, Assert, BoolExpr::boolop, BooleanTest::booltesttype, buf, CHECK_FOR_INTERRUPTS, check_stack_depth(), COERCE_EXPLICIT_CALL, COERCE_EXPLICIT_CAST, COERCE_IMPLICIT_CAST, CollateExpr::collOid, context, convert(), CTE_SUBLINK, CurrentOfExpr::cursor_name, CurrentOfExpr::cursor_param, DatumGetBool(), DatumGetInt32(), CaseExpr::defresult, ArrayExpr::elements, elog, ERROR, EXISTS_SUBLINK, JsonIsPredicate::expr, InferenceElem::expr, EXPR_SUBLINK, exprType(), exprTypmod(), FieldSelect::fieldnum, for_each_from, forboth, JsonValueExpr::format, format_type_with_typemod(), JsonExpr::formatted_expr, generate_collation_name(), generate_operator_name(), generate_relation_name(), get_agg_expr(), get_base_element_type(), get_coercion_expr(), get_const_expr(), get_func_expr(), get_json_constructor(), get_json_expr_options(), get_json_format(), get_json_path_spec(), get_json_returning(), get_name_for_var_field(), get_opclass_input_type(), get_opclass_name(), get_oper_expr(), get_parameter(), get_range_partbound_string(), get_rule_expr_paren(), get_rule_expr_toplevel(), get_rule_list_toplevel(), get_sublink_expr(), get_tablefunc(), get_variable(), get_windowfunc_expr(), i, if(), InferenceElem::infercollid, InferenceElem::inferopclass, PartitionBoundSpec::is_default, IS_DOCUMENT, IS_FALSE, IS_GREATEST, IS_LEAST, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, IS_XMLCONCAT, IS_XMLELEMENT, IS_XMLFOREST, IS_XMLPARSE, IS_XMLPI, IS_XMLROOT, IS_XMLSERIALIZE, IsA, JsonIsPredicate::item_type, JS_TYPE_ARRAY, JS_TYPE_OBJECT, JS_TYPE_SCALAR, JSON_BEHAVIOR_FALSE, JSON_BEHAVIOR_NULL, JSON_EXISTS_OP, JSON_QUERY_OP, JSON_VALUE_OP, RowCompareExpr::largs, lcons(), lfirst, lfirst_node, linitial, linitial_oid, list_delete_first(), list_length(), PartitionBoundSpec::listdatums, lnext(), lookup_rowtype_tupdesc(), PartitionBoundSpec::lowerdatums, lsecond, lsecond_node, lthird_node, map_xml_name_to_sql_identifier(), PartitionBoundSpec::modulus, MULTIEXPR_SUBLINK, XmlExpr::named_args, TupleDescData::natts, FieldStore::newvals, NIL, nodeTag, NOT_EXPR, NullTest::nulltesttype, MinMaxExpr::op, SQLValueFunction::op, XmlExpr::op, JsonExpr::op, ScalarArrayOpExpr::opno, OR_EXPR, PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, JsonExpr::passing_names, JsonExpr::passing_values, JsonExpr::path_spec, SubPlan::plan_name, PRETTY_INDENT, PRETTY_PAREN, PRETTYINDENT_VAR, printSubscripts(), processIndirection(), quote_identifier(), RowCompareExpr::rargs, JsonValueExpr::raw_expr, SubscriptingRef::refassgnexpr, SubscriptingRef::refexpr, ReleaseTupleDesc, PartitionBoundSpec::remainder, RelabelType::resulttype, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, CoerceToDomain::resulttype, JsonExpr::returning, ROWCOMPARE_SUBLINK, NextValueExpr::seqid, simple_quote_literal(), splan, PartitionBoundSpec::strategy, strip_implicit_coercions(), strVal, SubPlan::subLinkType, AlternativeSubPlan::subplans, SVFOP_CURRENT_CATALOG, SVFOP_CURRENT_DATE, SVFOP_CURRENT_ROLE, SVFOP_CURRENT_SCHEMA, SVFOP_CURRENT_TIME, SVFOP_CURRENT_TIME_N, SVFOP_CURRENT_TIMESTAMP, SVFOP_CURRENT_TIMESTAMP_N, SVFOP_CURRENT_USER, SVFOP_LOCALTIME, SVFOP_LOCALTIME_N, SVFOP_LOCALTIMESTAMP, SVFOP_LOCALTIMESTAMP_N, SVFOP_SESSION_USER, SVFOP_USER, SubPlan::testexpr, TupleDescAttr, type_is_rowtype(), JsonReturning::typid, SQLValueFunction::typmod, JsonIsPredicate::unique_keys, PartitionBoundSpec::upperdatums, SubPlan::useHashTable, ScalarArrayOpExpr::useOr, val, XML_STANDALONE_NO, XML_STANDALONE_NO_VALUE, XML_STANDALONE_YES, and XMLOPTION_DOCUMENT.

Referenced by deparse_expression_pretty(), get_agg_expr_helper(), get_basic_select_query(), get_delete_query_def(), get_from_clause_item(), get_func_expr(), get_func_sql_syntax(), get_insert_query_def(), get_json_behavior(), get_json_constructor(), get_json_path_spec(), get_json_table(), get_merge_query_def(), get_parameter(), get_rule_expr_funccall(), get_rule_expr_paren(), get_rule_expr_toplevel(), get_rule_sortgroupclause(), get_rule_windowspec(), get_select_query_def(), get_special_variable(), get_sublink_expr(), get_tablesample_def(), get_target_list(), get_update_query_def(), get_update_query_targetlist_def(), get_variable(), get_windowfunc_expr_helper(), get_with_clause(), get_xmltable(), make_ruledef(), pg_get_triggerdef_worker(), and printSubscripts().

◆ get_rule_expr_funccall()

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

Definition at line 10298 of file ruleutils.c.

10300 {
10301  if (looks_like_function(node))
10302  get_rule_expr(node, context, showimplicit);
10303  else
10304  {
10305  StringInfo buf = context->buf;
10306 
10307  appendStringInfoString(buf, "CAST(");
10308  /* no point in showing any top-level implicit cast */
10309  get_rule_expr(node, context, false);
10310  appendStringInfo(buf, " AS %s)",
10312  exprTypmod(node)));
10313  }
10314 }
static bool looks_like_function(Node *node)
Definition: ruleutils.c:10321

References appendStringInfo(), appendStringInfoString(), buf, context, exprType(), exprTypmod(), format_type_with_typemod(), get_rule_expr(), and looks_like_function().

Referenced by get_from_clause_item().

◆ get_rule_expr_paren()

static void get_rule_expr_paren ( Node node,
deparse_context context,
bool  showimplicit,
Node parentNode 
)
static

Definition at line 8791 of file ruleutils.c.

8793 {
8794  bool need_paren;
8795 
8796  need_paren = PRETTY_PAREN(context) &&
8797  !isSimpleNode(node, parentNode, context->prettyFlags);
8798 
8799  if (need_paren)
8800  appendStringInfoChar(context->buf, '(');
8801 
8802  get_rule_expr(node, context, showimplicit);
8803 
8804  if (need_paren)
8805  appendStringInfoChar(context->buf, ')');
8806 }
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
Definition: ruleutils.c:8489

References appendStringInfoChar(), context, get_rule_expr(), isSimpleNode(), and PRETTY_PAREN.

Referenced by get_coercion_expr(), get_func_expr(), get_func_sql_syntax(), get_oper_expr(), and get_rule_expr().

◆ get_rule_expr_toplevel()

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

Definition at line 10250 of file ruleutils.c.

10252 {
10253  if (node && IsA(node, Var))
10254  (void) get_variable((Var *) node, 0, true, context);
10255  else
10256  get_rule_expr(node, context, showimplicit);
10257 }

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

Referenced by get_rule_expr(), get_rule_list_toplevel(), and get_values_def().

◆ get_rule_groupingset()

static void get_rule_groupingset ( GroupingSet gset,
List targetlist,
bool  omit_parens,
deparse_context context 
)
static

Definition at line 6379 of file ruleutils.c.

6381 {
6382  ListCell *l;
6383  StringInfo buf = context->buf;
6384  bool omit_child_parens = true;
6385  char *sep = "";
6386 
6387  switch (gset->kind)
6388  {
6389  case GROUPING_SET_EMPTY:
6390  appendStringInfoString(buf, "()");
6391  return;
6392 
6393  case GROUPING_SET_SIMPLE:
6394  {
6395  if (!omit_parens || list_length(gset->content) != 1)
6396  appendStringInfoChar(buf, '(');
6397 
6398  foreach(l, gset->content)
6399  {
6400  Index ref = lfirst_int(l);
6401 
6403  get_rule_sortgroupclause(ref, targetlist,
6404  false, context);
6405  sep = ", ";
6406  }
6407 
6408  if (!omit_parens || list_length(gset->content) != 1)
6409  appendStringInfoChar(buf, ')');
6410  }
6411  return;
6412 
6413  case GROUPING_SET_ROLLUP:
6414  appendStringInfoString(buf, "ROLLUP(");
6415  break;
6416  case GROUPING_SET_CUBE:
6417  appendStringInfoString(buf, "CUBE(");
6418  break;
6419  case GROUPING_SET_SETS:
6420  appendStringInfoString(buf, "GROUPING SETS (");
6421  omit_child_parens = false;
6422  break;
6423  }
6424 
6425  foreach(l, gset->content)
6426  {
6428  get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6429  sep = ", ";
6430  }
6431 
6432  appendStringInfoChar(buf, ')');
6433 }
@ GROUPING_SET_CUBE
Definition: parsenodes.h:1505
@ GROUPING_SET_SIMPLE
Definition: parsenodes.h:1503
@ GROUPING_SET_ROLLUP
Definition: parsenodes.h:1504
@ GROUPING_SET_SETS
Definition: parsenodes.h:1506
@ GROUPING_SET_EMPTY
Definition: parsenodes.h:1502
List * content
Definition: parsenodes.h:1513

References appendStringInfoChar(), appendStringInfoString(), buf, GroupingSet::content, context, get_rule_sortgroupclause(), GROUPING_SET_CUBE, GROUPING_SET_EMPTY, GROUPING_SET_ROLLUP, GROUPING_SET_SETS, GROUPING_SET_SIMPLE, lfirst, lfirst_int, and list_length().

Referenced by get_basic_select_query().

◆ get_rule_list_toplevel()

static void get_rule_list_toplevel ( List lst,
deparse_context context,
bool  showimplicit 
)
static

Definition at line 10268 of file ruleutils.c.

10270 {
10271  const char *sep;
10272  ListCell *lc;
10273 
10274  sep = "";
10275  foreach(lc, lst)
10276  {
10277  Node *e = (Node *) lfirst(lc);
10278 
10279  appendStringInfoString(context->buf, sep);
10280  get_rule_expr_toplevel(e, context, showimplicit);
10281  sep = ", ";
10282  }
10283 }

References appendStringInfoString(), context, get_rule_expr_toplevel(), and lfirst.

Referenced by get_insert_query_def(), get_merge_query_def(), and get_rule_expr().

◆ get_rule_orderby()

static void get_rule_orderby ( List orderList,
List targetList,
bool  force_colno,
deparse_context context 
)
static

Definition at line 6439 of file ruleutils.c.

6441 {
6442  StringInfo buf = context->buf;
6443  const char *sep;
6444  ListCell *l;
6445 
6446  sep = "";
6447  foreach(l, orderList)
6448  {
6449  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6450  Node *sortexpr;
6451  Oid sortcoltype;
6452  TypeCacheEntry *typentry;
6453 
6455  sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6456  force_colno, context);
6457  sortcoltype = exprType(sortexpr);
6458  /* See whether operator is default < or > for datatype */
6459  typentry = lookup_type_cache(sortcoltype,
6461  if (srt->sortop == typentry->lt_opr)
6462  {
6463  /* ASC is default, so emit nothing for it */
6464  if (srt->nulls_first)
6465  appendStringInfoString(buf, " NULLS FIRST");
6466  }
6467  else if (srt->sortop == typentry->gt_opr)
6468  {
6469  appendStringInfoString(buf, " DESC");
6470  /* DESC defaults to NULLS FIRST */
6471  if (!srt->nulls_first)
6472  appendStringInfoString(buf, " NULLS LAST");
6473  }
6474  else
6475  {
6476  appendStringInfo(buf, " USING %s",
6478  sortcoltype,
6479  sortcoltype));
6480  /* be specific to eliminate ambiguity */
6481  if (srt->nulls_first)
6482  appendStringInfoString(buf, " NULLS FIRST");
6483  else
6484  appendStringInfoString(buf, " NULLS LAST");
6485  }
6486  sep = ", ";
6487  }
6488 }
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:346
#define TYPECACHE_GT_OPR
Definition: typcache.h:139
#define TYPECACHE_LT_OPR
Definition: typcache.h:138

References appendStringInfo(), appendStringInfoString(), buf, context, exprType(), generate_operator_name(), get_rule_sortgroupclause(), TypeCacheEntry::gt_opr, lfirst, lookup_type_cache(), TypeCacheEntry::lt_opr, SortGroupClause::nulls_first, SortGroupClause::sortop, SortGroupClause::tleSortGroupRef, TYPECACHE_GT_OPR, and TYPECACHE_LT_OPR.

Referenced by get_agg_expr_helper(), get_rule_windowspec(), and get_select_query_def().

◆ get_rule_sortgroupclause()

static Node * get_rule_sortgroupclause ( Index  ref,
List tlist,
bool  force_colno,
deparse_context context 
)
static

Definition at line 6322 of file ruleutils.c.

6324 {
6325  StringInfo buf = context->buf;
6326  TargetEntry *tle;
6327  Node *expr;
6328 
6329  tle = get_sortgroupref_tle(ref, tlist);
6330  expr = (Node *) tle->expr;
6331 
6332  /*
6333  * Use column-number form if requested by caller. Otherwise, if
6334  * expression is a constant, force it to be dumped with an explicit cast
6335  * as decoration --- this is because a simple integer constant is
6336  * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
6337  * dump it without any decoration. If it's anything more complex than a
6338  * simple Var, then force extra parens around it, to ensure it can't be
6339  * misinterpreted as a cube() or rollup() construct.
6340  */
6341  if (force_colno)
6342  {
6343  Assert(!tle->resjunk);
6344  appendStringInfo(buf, "%d", tle->resno);
6345  }
6346  else if (expr && IsA(expr, Const))
6347  get_const_expr((Const *) expr, context, 1);
6348  else if (!expr || IsA(expr, Var))
6349  get_rule_expr(expr, context, true);
6350  else
6351  {
6352  /*
6353  * We must force parens for function-like expressions even if
6354  * PRETTY_PAREN is off, since those are the ones in danger of
6355  * misparsing. For other expressions we need to force them only if
6356  * PRETTY_PAREN is on, since otherwise the expression will output them
6357  * itself. (We can't skip the parens.)
6358  */
6359  bool need_paren = (PRETTY_PAREN(context)
6360  || IsA(expr, FuncExpr)
6361  || IsA(expr, Aggref)
6362  || IsA(expr, WindowFunc)
6363  || IsA(expr, JsonConstructorExpr));
6364 
6365  if (need_paren)
6366  appendStringInfoChar(context->buf, '(');
6367  get_rule_expr(expr, context, true);
6368  if (need_paren)
6369  appendStringInfoChar(context->buf, ')');
6370  }
6371 
6372  return expr;
6373 }
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition: tlist.c:345

References appendStringInfo(), appendStringInfoChar(), Assert, buf, context, TargetEntry::expr, get_const_expr(), get_rule_expr(), get_sortgroupref_tle(), if(), IsA, PRETTY_PAREN, and TargetEntry::resno.

Referenced by get_basic_select_query(), get_rule_groupingset(), get_rule_orderby(), and get_rule_windowspec().

◆ get_rule_windowclause()

static void get_rule_windowclause ( Query query,
deparse_context context 
)
static

Definition at line 6497 of file ruleutils.c.

6498 {
6499  StringInfo buf = context->buf;
6500  const char *sep;
6501  ListCell *l;
6502 
6503  sep = NULL;
6504  foreach(l, query->windowClause)
6505  {
6506  WindowClause *wc = (WindowClause *) lfirst(l);
6507 
6508  if (wc->name == NULL)
6509  continue; /* ignore anonymous windows */
6510 
6511  if (sep == NULL)
6512  appendContextKeyword(context, " WINDOW ",
6514  else
6516 
6517  appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6518 
6519  get_rule_windowspec(wc, query->targetList, context);
6520 
6521  sep = ", ";
6522  }
6523 }
static void get_rule_windowspec(WindowClause *wc, List *targetList, deparse_context *context)
Definition: ruleutils.c:6529

References appendContextKeyword(), appendStringInfo(), appendStringInfoString(), buf, context, get_rule_windowspec(), lfirst, PRETTYINDENT_STD, quote_identifier(), Query::targetList, and Query::windowClause.

Referenced by get_basic_select_query().

◆ get_rule_windowspec()

static void get_rule_windowspec ( WindowClause wc,
List targetList,
deparse_context context 
)
static

Definition at line 6529 of file ruleutils.c.

6531 {
6532  StringInfo buf = context->buf;
6533  bool needspace = false;
6534  const char *sep;
6535  ListCell *l;
6536 
6537  appendStringInfoChar(buf, '(');
6538  if (wc->refname)
6539  {
6541  needspace = true;
6542  }
6543  /* partition clauses are always inherited, so only print if no refname */
6544  if (wc->partitionClause && !wc->refname)
6545  {
6546  if (needspace)
6547  appendStringInfoChar(buf, ' ');
6548  appendStringInfoString(buf, "PARTITION BY ");
6549  sep = "";
6550  foreach(l, wc->partitionClause)
6551  {
6552  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6553 
6555  get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
6556  false, context);
6557  sep = ", ";
6558  }
6559  needspace = true;
6560  }
6561  /* print ordering clause only if not inherited */
6562  if (wc->orderClause && !wc->copiedOrder)
6563  {
6564  if (needspace)
6565  appendStringInfoChar(buf, ' ');
6566  appendStringInfoString(buf, "ORDER BY ");
6567  get_rule_orderby(wc->orderClause, targetList, false, context);
6568  needspace = true;
6569  }
6570  /* framing clause is never inherited, so print unless it's default */
6572  {
6573  if (needspace)
6574  appendStringInfoChar(buf, ' ');
6575  if (wc->frameOptions & FRAMEOPTION_RANGE)
6576  appendStringInfoString(buf, "RANGE ");
6577  else if (wc->frameOptions & FRAMEOPTION_ROWS)
6578  appendStringInfoString(buf, "ROWS ");
6579  else if (wc->frameOptions & FRAMEOPTION_GROUPS)
6580  appendStringInfoString(buf, "GROUPS ");
6581  else
6582  Assert(false);
6584  appendStringInfoString(buf, "BETWEEN ");
6586  appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
6588  appendStringInfoString(buf, "CURRENT ROW ");
6589  else if (wc->frameOptions & FRAMEOPTION_START_OFFSET)
6590  {
6591  get_rule_expr(wc->startOffset, context, false);
6593  appendStringInfoString(buf, " PRECEDING ");
6595  appendStringInfoString(buf, " FOLLOWING ");
6596  else
6597  Assert(false);
6598  }
6599  else
6600  Assert(false);
6602  {
6603  appendStringInfoString(buf, "AND ");
6605  appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
6607  appendStringInfoString(buf, "CURRENT ROW ");
6608  else if (wc->frameOptions & FRAMEOPTION_END_OFFSET)
6609  {
6610  get_rule_expr(wc->endOffset, context, false);
6612  appendStringInfoString(buf, " PRECEDING ");
6614  appendStringInfoString(buf, " FOLLOWING ");
6615  else
6616  Assert(false);
6617  }
6618  else
6619  Assert(false);
6620  }
6622  appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6623  else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6624  appendStringInfoString(buf, "EXCLUDE GROUP ");
6625  else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
6626  appendStringInfoString(buf, "EXCLUDE TIES ");
6627  /* we will now have a trailing space; remove it */
6628  buf->len--;
6629  }
6630  appendStringInfoChar(buf, ')');
6631 }
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:591
#define FRAMEOPTION_END_OFFSET
Definition: parsenodes.h:602
#define FRAMEOPTION_EXCLUDE_CURRENT_ROW
Definition: parsenodes.h:596
#define FRAMEOPTION_END_OFFSET_PRECEDING
Definition: parsenodes.h:593
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:586
#define FRAMEOPTION_START_CURRENT_ROW
Definition: parsenodes.h:590
#define FRAMEOPTION_START_OFFSET
Definition: parsenodes.h:600
#define FRAMEOPTION_END_OFFSET_FOLLOWING
Definition: parsenodes.h:595
#define FRAMEOPTION_EXCLUDE_TIES
Definition: parsenodes.h:598
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:582
#define FRAMEOPTION_EXCLUDE_GROUP
Definition: parsenodes.h:597
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:584
#define FRAMEOPTION_BETWEEN
Definition: parsenodes.h:585
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING
Definition: parsenodes.h:589
#define FRAMEOPTION_START_OFFSET_PRECEDING
Definition: parsenodes.h:592
#define FRAMEOPTION_START_OFFSET_FOLLOWING
Definition: parsenodes.h:594
#define FRAMEOPTION_NONDEFAULT
Definition: parsenodes.h:581
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:583
Node * startOffset
Definition: parsenodes.h:1550
List * partitionClause
Definition: parsenodes.h:1546
Node * endOffset
Definition: parsenodes.h:1551
List * orderClause
Definition: parsenodes.h:1548

References appendStringInfoChar(), appendStringInfoString(), Assert, buf, context, WindowClause::endOffset, FRAMEOPTION_BETWEEN, FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_END_OFFSET, FRAMEOPTION_END_OFFSET_FOLLOWING, FRAMEOPTION_END_OFFSET_PRECEDING, FRAMEOPTION_END_UNBOUNDED_FOLLOWING, FRAMEOPTION_EXCLUDE_CURRENT_ROW, FRAMEOPTION_EXCLUDE_GROUP, FRAMEOPTION_EXCLUDE_TIES, FRAMEOPTION_GROUPS, FRAMEOPTION_NONDEFAULT, FRAMEOPTION_RANGE, FRAMEOPTION_ROWS, FRAMEOPTION_START_CURRENT_ROW, FRAMEOPTION_START_OFFSET, FRAMEOPTION_START_OFFSET_FOLLOWING, FRAMEOPTION_START_OFFSET_PRECEDING, FRAMEOPTION_START_UNBOUNDED_PRECEDING, WindowClause::frameOptions, get_rule_expr(), get_rule_orderby(), get_rule_sortgroupclause(), lfirst, WindowClause::orderClause, WindowClause::partitionClause, quote_identifier(), WindowClause::startOffset, and SortGroupClause::tleSortGroupRef.

Referenced by get_rule_windowclause(), and get_windowfunc_expr_helper().

◆ get_select_query_def()

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

Definition at line 5717 of file ruleutils.c.

5719 {
5720  StringInfo buf = context->buf;
5721  List *save_windowclause;
5722  List *save_windowtlist;
5723  bool force_colno;
5724  ListCell *l;
5725 
5726  /* Insert the WITH clause if given */
5727  get_with_clause(query, context);
5728 
5729  /* Set up context for possible window functions */
5730  save_windowclause = context->windowClause;
5731  context->windowClause = query->windowClause;
5732  save_windowtlist = context->windowTList;
5733  context->windowTList = query->targetList;
5734 
5735  /*
5736  * If the Query node has a setOperations tree, then it's the top level of
5737  * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5738  * fields are interesting in the top query itself.
5739  */
5740  if (query->setOperations)
5741  {
5742  get_setop_query(query->setOperations, query, context, resultDesc,
5743  colNamesVisible);
5744  /* ORDER BY clauses must be simple in this case */
5745  force_colno = true;
5746  }
5747  else
5748  {
5749  get_basic_select_query(query, context, resultDesc, colNamesVisible);
5750  force_colno = false;
5751  }
5752 
5753  /* Add the ORDER BY clause if given */
5754  if (query->sortClause != NIL)
5755  {
5756  appendContextKeyword(context, " ORDER BY ",
5758  get_rule_orderby(query->sortClause, query->targetList,
5759  force_colno, context);
5760  }
5761 
5762  /*
5763  * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5764  * standard spelling of LIMIT.
5765  */
5766  if (query->limitOffset != NULL)
5767  {
5768  appendContextKeyword(context, " OFFSET ",
5770  get_rule_expr(query->limitOffset, context, false);
5771  }
5772  if (query->limitCount != NULL)
5773  {
5774  if (query->limitOption == LIMIT_OPTION_WITH_TIES)
5775  {
5776  appendContextKeyword(context, " FETCH FIRST ",
5778  get_rule_expr(query->limitCount, context, false);
5779  appendStringInfoString(buf, " ROWS WITH TIES");
5780  }
5781  else
5782  {
5783  appendContextKeyword(context, " LIMIT ",
5785  if (IsA(query->limitCount, Const) &&
5786  ((Const *) query->limitCount)->constisnull)
5787  appendStringInfoString(buf, "ALL");
5788  else
5789  get_rule_expr(query->limitCount, context, false);
5790  }
5791  }
5792 
5793  /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5794  if (query->hasForUpdate)
5795  {
5796  foreach(l, query->rowMarks)
5797  {
5798  RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5799 
5800  /* don't print implicit clauses */
5801  if (rc->pushedDown)
5802  continue;
5803 
5804  switch (rc->strength)
5805  {
5806  case LCS_NONE:
5807  /* we intentionally throw an error for LCS_NONE */
5808  elog(ERROR, "unrecognized LockClauseStrength %d",
5809  (int) rc->strength);
5810  break;
5811  case LCS_FORKEYSHARE:
5812  appendContextKeyword(context, " FOR KEY SHARE",
5814  break;
5815  case LCS_FORSHARE:
5816  appendContextKeyword(context, " FOR SHARE",
5818  break;
5819  case LCS_FORNOKEYUPDATE:
5820  appendContextKeyword(context, " FOR NO KEY UPDATE",
5822  break;
5823  case LCS_FORUPDATE:
5824  appendContextKeyword(context, " FOR UPDATE",
5826  break;
5827  }
5828 
5829  appendStringInfo(buf, " OF %s",
5831  context)));
5832  if (rc->waitPolicy == LockWaitError)
5833  appendStringInfoString(buf, " NOWAIT");
5834  else if (rc->waitPolicy == LockWaitSkip)
5835  appendStringInfoString(buf, " SKIP LOCKED");
5836  }
5837  }
5838 
5839  context->windowClause = save_windowclause;
5840  context->windowTList = save_windowtlist;
5841 }
@ LockWaitSkip
Definition: lockoptions.h:41
@ LockWaitError
Definition: lockoptions.h:43
@ LCS_FORUPDATE
Definition: lockoptions.h:27
@ LCS_NONE
Definition: lockoptions.h:23
@ LCS_FORSHARE
Definition: lockoptions.h:25
@ LCS_FORKEYSHARE
Definition: lockoptions.h:24
@ LCS_FORNOKEYUPDATE
Definition: lockoptions.h:26
@ LIMIT_OPTION_WITH_TIES
Definition: nodes.h:431
static void get_basic_select_query(Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:5918
static void get_setop_query(Node *setOp, Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6188
List * rowMarks
Definition: parsenodes.h:217
Node * limitCount
Definition: parsenodes.h:214
Node * setOperations
Definition: parsenodes.h:219
Node * limitOffset
Definition: parsenodes.h:213
LimitOption limitOption
Definition: parsenodes.h:215
List * sortClause
Definition: parsenodes.h:211
LockClauseStrength strength
Definition: parsenodes.h:1585
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1586

References appendContextKeyword(), appendStringInfo(), appendStringInfoString(), buf, context, elog, ERROR, get_basic_select_query(), get_rtable_name(), get_rule_expr(), get_rule_orderby(), get_setop_query(), get_with_clause(), IsA, LCS_FORKEYSHARE, LCS_FORNOKEYUPDATE, LCS_FORSHARE, LCS_FORUPDATE, LCS_NONE, lfirst, LIMIT_OPTION_WITH_TIES, Query::limitCount, Query::limitOffset, Query::limitOption, LockWaitError, LockWaitSkip, NIL, PRETTYINDENT_STD, RowMarkClause::pushedDown, quote_identifier(), Query::rowMarks, RowMarkClause::rti, Query::setOperations, Query::sortClause, RowMarkClause::strength, Query::targetList, RowMarkClause::waitPolicy, and Query::windowClause.

Referenced by get_query_def().

◆ get_setop_query()

static void get_setop_query ( Node setOp,
Query query,
deparse_context context,
TupleDesc  resultDesc,
bool  colNamesVisible 
)
static

Definition at line 6188 of file ruleutils.c.

6190 {
6191  StringInfo buf = context->buf;
6192  bool need_paren;
6193 
6194  /* Guard against excessively long or deeply-nested queries */
6197 
6198  if (IsA(setOp, RangeTblRef))
6199  {
6200  RangeTblRef *rtr = (RangeTblRef *) setOp;
6201  RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6202  Query *subquery = rte->subquery;
6203 
6204  Assert(subquery != NULL);
6205  Assert(subquery->setOperations == NULL);
6206  /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
6207  need_paren = (subquery->cteList ||
6208  subquery->sortClause ||
6209  subquery->rowMarks ||
6210  subquery->limitOffset ||
6211  subquery->limitCount);
6212  if (need_paren)
6213  appendStringInfoChar(buf, '(');
6214  get_query_def(subquery, buf, context->namespaces, resultDesc,
6215  colNamesVisible,
6216  context->prettyFlags, context->wrapColumn,
6217  context->indentLevel);
6218  if (need_paren)
6219  appendStringInfoChar(buf, ')');
6220  }
6221  else if (IsA(setOp, SetOperationStmt))
6222  {
6223  SetOperationStmt *op = (SetOperationStmt *) setOp;
6224  int subindent;
6225 
6226  /*
6227  * We force parens when nesting two SetOperationStmts, except when the
6228  * lefthand input is another setop of the same kind. Syntactically,
6229  * we could omit parens in rather more cases, but it seems best to use
6230  * parens to flag cases where the setop operator changes. If we use
6231  * parens, we also increase the indentation level for the child query.
6232  *
6233  * There are some cases in which parens are needed around a leaf query
6234  * too, but those are more easily handled at the next level down (see
6235  * code above).
6236  */
6237  if (IsA(op->larg, SetOperationStmt))
6238  {
6239  SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6240 
6241  if (op->op == lop->op && op->all == lop->all)
6242  need_paren = false;
6243  else
6244  need_paren = true;
6245  }
6246  else
6247  need_paren = false;
6248 
6249  if (need_paren)
6250  {
6251  appendStringInfoChar(buf, '(');
6252  subindent = PRETTYINDENT_STD;
6253  appendContextKeyword(context, "", subindent, 0, 0);
6254  }
6255  else
6256  subindent = 0;
6257 
6258  get_setop_query(op->larg, query, context, resultDesc, colNamesVisible);
6259 
6260  if (need_paren)
6261  appendContextKeyword(context, ") ", -subindent, 0, 0);
6262  else if (PRETTY_INDENT(context))
6263  appendContextKeyword(context, "", -subindent, 0, 0);
6264  else
6265  appendStringInfoChar(buf, ' ');
6266 
6267  switch (op->op)
6268  {
6269  case SETOP_UNION:
6270  appendStringInfoString(buf, "UNION ");
6271  break;
6272  case SETOP_INTERSECT:
6273  appendStringInfoString(buf, "INTERSECT ");
6274  break;
6275  case SETOP_EXCEPT:
6276  appendStringInfoString(buf, "EXCEPT ");
6277  break;
6278  default:
6279  elog(ERROR, "unrecognized set op: %d",
6280  (int) op->op);
6281  }
6282  if (op->all)
6283  appendStringInfoString(buf, "ALL ");
6284 
6285  /* Always parenthesize if RHS is another setop */
6286  need_paren = IsA(op->rarg, SetOperationStmt);
6287 
6288  /*
6289  * The indentation code here is deliberately a bit different from that
6290  * for the lefthand input, because we want the line breaks in
6291  * different places.
6292  */
6293  if (need_paren)
6294  {
6295  appendStringInfoChar(buf, '(');
6296  subindent = PRETTYINDENT_STD;
6297  }
6298  else
6299  subindent = 0;
6300  appendContextKeyword(context, "", subindent, 0, 0);
6301 
6302  get_setop_query(op->rarg, query, context, resultDesc, false);
6303 
6304  if (PRETTY_INDENT(context))
6305  context->indentLevel -= subindent;
6306  if (need_paren)
6307  appendContextKeyword(context, ")", 0, 0, 0);
6308  }
6309  else
6310  {
6311  elog(ERROR, "unrecognized node type: %d",
6312  (int) nodeTag(setOp));
6313  }
6314 }
@ SETOP_INTERSECT
Definition: parsenodes.h:2117
@ SETOP_UNION
Definition: parsenodes.h:2116
@ SETOP_EXCEPT
Definition: parsenodes.h:2118
List * cteList
Definition: parsenodes.h:166
SetOperation op
Definition: parsenodes.h:2193

References SetOperationStmt::all, appendContextKeyword(), appendStringInfoChar(), appendStringInfoString(), Assert, buf, CHECK_FOR_INTERRUPTS, check_stack_depth(), context, Query::cteList, elog, ERROR, get_query_def(), if(), IsA, SetOperationStmt::larg, Query::limitCount, Query::limitOffset, nodeTag, SetOperationStmt::op, PRETTY_INDENT, PRETTYINDENT_STD, SetOperationStmt::rarg, Query::rowMarks, rt_fetch, Query::rtable, RangeTblRef::rtindex, SETOP_EXCEPT, SETOP_INTERSECT, SETOP_UNION, Query::setOperations, Query::sortClause, and RangeTblEntry::subquery.

Referenced by get_select_query_def().

◆ get_simple_binary_op_name()

static const char * get_simple_binary_op_name ( OpExpr expr)
static

Definition at line 8463 of file ruleutils.c.

8464 {
8465  List *args = expr->args;
8466 
8467  if (list_length(args) == 2)
8468  {
8469  /* binary operator */
8470  Node *arg1 = (Node *) linitial(args);
8471  Node *arg2 = (Node *) lsecond(args);
8472  const char *op;
8473 
8474  op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
8475  if (strlen(op) == 1)
8476  return op;
8477  }
8478  return NULL;
8479 }

References generate_unaccent_rules::args, OpExpr::args, exprType(), generate_operator_name(), linitial, list_length(), lsecond, and OpExpr::opno.

Referenced by isSimpleNode().

◆ get_simple_values_rte()

static RangeTblEntry* get_simple_values_rte ( Query query,
TupleDesc  resultDesc 
)
static

Definition at line 5849 of file ruleutils.c.

5850 {
5851  RangeTblEntry *result = NULL;
5852  ListCell *lc;
5853 
5854  /*
5855  * We want to detect a match even if the Query also contains OLD or NEW
5856  * rule RTEs. So the idea is to scan the rtable and see if there is only
5857  * one inFromCl RTE that is a VALUES RTE.
5858  */
5859  foreach(lc, query->rtable)
5860  {
5861  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
5862 
5863  if (rte->rtekind == RTE_VALUES && rte->inFromCl)
5864  {
5865  if (result)
5866  return NULL; /* multiple VALUES (probably not possible) */
5867  result = rte;
5868  }
5869  else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
5870  continue; /* ignore rule entries */
5871  else
5872  return NULL; /* something else -> not simple VALUES */
5873  }
5874 
5875  /*
5876  * We don't need to check the targetlist in any great detail, because
5877  * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
5878  * appear inside auto-generated sub-queries with very restricted
5879  * structure. However, DefineView might have modified the tlist by
5880  * injecting new column aliases, or we might have some other column
5881  * aliases forced by a resultDesc. We can only simplify if the RTE's
5882  * column names match the names that get_target_list() would select.
5883  */
5884  if (result)
5885  {
5886  ListCell *lcn;
5887  int colno;
5888 
5889  if (list_length(query->targetList) != list_length(result->eref->colnames))
5890  return NULL; /* this probably cannot happen */
5891  colno = 0;
5892  forboth(lc, query->targetList, lcn, result->eref->colnames)
5893  {
5894  TargetEntry *tle = (TargetEntry *) lfirst(lc);
5895  char *cname = strVal(lfirst(lcn));
5896  char *colname;
5897 
5898  if (tle->resjunk)
5899  return NULL; /* this probably cannot happen */
5900 
5901  /* compute name that get_target_list would use for column */
5902  colno++;
5903  if (resultDesc && colno <= resultDesc->natts)
5904  colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
5905  else
5906  colname = tle->resname;
5907 
5908  /* does it match the VALUES RTE? */
5909  if (colname == NULL || strcmp(colname, cname) != 0)
5910  return NULL; /* column name has been changed */
5911  }
5912  }
5913 
5914  return result;
5915 }

References attname, forboth, lfirst, list_length(), NameStr, Query::rtable, RTE_RELATION, RTE_VALUES, RangeTblEntry::rtekind, strVal, Query::targetList, and TupleDescAttr.

Referenced by get_basic_select_query().

◆ get_special_variable()

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

Definition at line 7559 of file ruleutils.c.

7560 {
7561  StringInfo buf = context->buf;
7562 
7563  /*
7564  * For a non-Var referent, force parentheses because our caller probably
7565  * assumed a Var is a simple expression.
7566  */
7567  if (!IsA(node, Var))
7568  appendStringInfoChar(buf, '(');
7569  get_rule_expr(node, context, true);
7570  if (!IsA(node, Var))
7571  appendStringInfoChar(buf, ')');
7572 }

References appendStringInfoChar(), buf, context, get_rule_expr(), and IsA.

Referenced by get_variable().

◆ get_sublink_expr()

static void get_sublink_expr ( SubLink sublink,
deparse_context context 
)
static

Definition at line 11415 of file ruleutils.c.

11416 {
11417  StringInfo buf = context->buf;
11418  Query *query = (Query *) (sublink->subselect);
11419  char *opname = NULL;
11420  bool need_paren;
11421 
11422  if (sublink->subLinkType == ARRAY_SUBLINK)
11423  appendStringInfoString(buf, "ARRAY(");
11424  else
11425  appendStringInfoChar(buf, '(');
11426 
11427  /*
11428  * Note that we print the name of only the first operator, when there are
11429  * multiple combining operators. This is an approximation that could go
11430  * wrong in various scenarios (operators in different schemas, renamed
11431  * operators, etc) but there is not a whole lot we can do about it, since
11432  * the syntax allows only one operator to be shown.
11433  */
11434  if (sublink->testexpr)
11435  {
11436  if (IsA(sublink->testexpr, OpExpr))
11437  {
11438  /* single combining operator */
11439  OpExpr *opexpr = (OpExpr *) sublink->testexpr;
11440 
11441  get_rule_expr(linitial(opexpr->args), context, true);
11442  opname = generate_operator_name(opexpr->opno,
11443  exprType(linitial(opexpr->args)),
11444  exprType(lsecond(opexpr->args)));
11445  }
11446  else if (IsA(sublink->testexpr, BoolExpr))
11447  {
11448  /* multiple combining operators, = or <> cases */
11449  char *sep;
11450  ListCell *l;
11451 
11452  appendStringInfoChar(buf, '(');
11453  sep = "";
11454  foreach(l, ((BoolExpr *) sublink->testexpr)->args)
11455  {
11456  OpExpr *opexpr = lfirst_node(OpExpr, l);
11457 
11459  get_rule_expr(linitial(opexpr->args), context, true);
11460  if (!opname)
11461  opname = generate_operator_name(opexpr->opno,
11462  exprType(linitial(opexpr->args)),
11463  exprType(lsecond(opexpr->args)));
11464  sep = ", ";
11465  }
11466  appendStringInfoChar(buf, ')');
11467  }
11468  else if (IsA(sublink->testexpr, RowCompareExpr))
11469  {
11470  /* multiple combining operators, < <= > >= cases */
11471  RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
11472 
11473  appendStringInfoChar(buf, '(');
11474  get_rule_expr((Node *) rcexpr->largs, context, true);
11475  opname = generate_operator_name(linitial_oid(rcexpr->opnos),
11476  exprType(linitial(rcexpr->largs)),
11477  exprType(linitial(rcexpr->rargs)));
11478  appendStringInfoChar(buf, ')');
11479  }
11480  else
11481  elog(ERROR, "unrecognized testexpr type: %d",
11482  (int) nodeTag(sublink->testexpr));
11483  }
11484 
11485  need_paren = true;
11486 
11487  switch (sublink->subLinkType)
11488  {
11489  case EXISTS_SUBLINK:
11490  appendStringInfoString(buf, "EXISTS ");
11491  break;
11492 
11493  case ANY_SUBLINK:
11494  if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
11495  appendStringInfoString(buf, " IN ");
11496  else
11497  appendStringInfo(buf, " %s ANY ", opname);
11498  break;
11499 
11500  case ALL_SUBLINK:
11501  appendStringInfo(buf, " %s ALL ", opname);
11502  break;
11503 
11504  case ROWCOMPARE_SUBLINK:
11505  appendStringInfo(buf, " %s ", opname);
11506  break;
11507 
11508  case EXPR_SUBLINK:
11509  case MULTIEXPR_SUBLINK:
11510  case ARRAY_SUBLINK:
11511  need_paren = false;
11512  break;
11513 
11514  case CTE_SUBLINK: /* shouldn't occur in a SubLink */
11515  default:
11516  elog(ERROR, "unrecognized sublink type: %d",
11517  (int) sublink->subLinkType);
11518  break;
11519  }
11520 
11521  if (need_paren)
11522  appendStringInfoChar(buf, '(');
11523 
11524  get_query_def(query, buf, context->namespaces, NULL, false,
11525  context->prettyFlags, context->wrapColumn,
11526  context->indentLevel);
11527 
11528  if (need_paren)
11529  appendStringInfoString(buf, "))");
11530  else
11531  appendStringInfoChar(buf, ')');
11532 }

References ALL_SUBLINK, ANY_SUBLINK, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), OpExpr::args, ARRAY_SUBLINK, buf, context, CTE_SUBLINK, elog, ERROR, EXISTS_SUBLINK, EXPR_SUBLINK, exprType(), generate_operator_name(), get_query_def(), get_rule_expr(), IsA, RowCompareExpr::largs, lfirst_node, linitial, linitial_oid, lsecond, MULTIEXPR_SUBLINK, nodeTag, OpExpr::opno, RowCompareExpr::rargs, ROWCOMPARE_SUBLINK, SubLink::subLinkType, SubLink::subselect, and SubLink::testexpr.

Referenced by get_rule_expr().

◆ get_tablefunc()

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

Definition at line 11845 of file ruleutils.c.

11846 {
11847  /* XMLTABLE and JSON_TABLE are the only existing implementations. */
11848 
11849  if (tf->functype == TFT_XMLTABLE)
11850  get_xmltable(tf, context, showimplicit);
11851  else if (tf->functype == TFT_JSON_TABLE)
11852  get_json_table(tf, context, showimplicit);
11853 }
@ TFT_XMLTABLE
Definition: primnodes.h:99
@ TFT_JSON_TABLE
Definition: primnodes.h:100
static void get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11540
static void get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11776
TableFuncType functype
Definition: primnodes.h:113

References context, TableFunc::functype, get_json_table(), get_xmltable(), TFT_JSON_TABLE, and TFT_XMLTABLE.

Referenced by get_from_clause_item(), and get_rule_expr().

◆ get_tablesample_def()

static void get_tablesample_def ( TableSampleClause tablesample,
deparse_context context 
)
static

Definition at line 12411 of file ruleutils.c.

12412 {
12413  StringInfo buf = context->buf;
12414  Oid argtypes[1];
12415  int nargs;
12416  ListCell *l;
12417 
12418  /*
12419  * We should qualify the handler's function name if it wouldn't be
12420  * resolved by lookup in the current search path.
12421  */
12422  argtypes[0] = INTERNALOID;
12423  appendStringInfo(buf, " TABLESAMPLE %s (",
12424  generate_function_name(tablesample->tsmhandler, 1,
12425  NIL, argtypes,
12426  false, NULL, EXPR_KIND_NONE));
12427 
12428  nargs = 0;
12429  foreach(l, tablesample->args)
12430  {
12431  if (nargs++ > 0)
12432  appendStringInfoString(buf, ", ");
12433  get_rule_expr((Node *) lfirst(l), context, false);
12434  }
12435  appendStringInfoChar(buf, ')');
12436 
12437  if (tablesample->repeatable != NULL)
12438  {
12439  appendStringInfoString(buf, " REPEATABLE (");
12440  get_rule_expr((Node *) tablesample->repeatable, context, false);
12441  appendStringInfoChar(buf, ')');
12442  }
12443 }

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), TableSampleClause::args, buf, context, EXPR_KIND_NONE, generate_function_name(), get_rule_expr(), lfirst, NIL, TableSampleClause::repeatable, and TableSampleClause::tsmhandler.

Referenced by get_from_clause_item().

◆ get_target_list()

static void get_target_list ( List targetList,
deparse_context context,
TupleDesc  resultDesc,
bool  colNamesVisible 
)
static

Definition at line 6052 of file ruleutils.c.

6054 {
6055  StringInfo buf = context->buf;
6056  StringInfoData targetbuf;
6057  bool last_was_multiline = false;
6058  char *sep;
6059  int colno;
6060  ListCell *l;
6061 
6062  /* we use targetbuf to hold each TLE's text temporarily */
6063  initStringInfo(&targetbuf);
6064 
6065  sep = " ";
6066  colno = 0;
6067  foreach(l, targetList)
6068  {
6069  TargetEntry *tle = (TargetEntry *) lfirst(l);
6070  char *colname;
6071  char *attname;
6072 
6073  if (tle->resjunk)
6074  continue; /* ignore junk entries */
6075 
6077  sep = ", ";
6078  colno++;
6079 
6080  /*
6081  * Put the new field text into targetbuf so we can decide after we've
6082  * got it whether or not it needs to go on a new line.
6083  */
6084  resetStringInfo(&targetbuf);
6085  context->buf = &targetbuf;
6086 
6087  /*
6088  * We special-case Var nodes rather than using get_rule_expr. This is
6089  * needed because get_rule_expr will display a whole-row Var as
6090  * "foo.*", which is the preferred notation in most contexts, but at
6091  * the top level of a SELECT list it's not right (the parser will
6092  * expand that notation into multiple columns, yielding behavior
6093  * different from a whole-row Var). We need to call get_variable
6094  * directly so that we can tell it to do the right thing, and so that
6095  * we can get the attribute name which is the default AS label.
6096  */
6097  if (tle->expr && (IsA(tle->expr, Var)))
6098  {
6099  attname = get_variable((Var *) tle->expr, 0, true, context);
6100  }
6101  else
6102  {
6103  get_rule_expr((Node *) tle->expr, context, true);
6104 
6105  /*
6106  * When colNamesVisible is true, we should always show the
6107  * assigned column name explicitly. Otherwise, show it only if
6108  * it's not FigureColname's fallback.
6109  */
6110  attname = colNamesVisible ? NULL : "?column?";
6111  }
6112 
6113  /*
6114  * Figure out what the result column should be called. In the context
6115  * of a view, use the view's tuple descriptor (so as to pick up the
6116  * effects of any column RENAME that's been done on the view).
6117  * Otherwise, just use what we can find in the TLE.
6118  */
6119  if (resultDesc && colno <= resultDesc->natts)
6120  colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6121  else
6122  colname = tle->resname;
6123 
6124  /* Show AS unless the column's name is correct as-is */
6125  if (colname) /* resname could be NULL */
6126  {
6127  if (attname == NULL || strcmp(attname, colname) != 0)
6128  appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6129  }
6130 
6131  /* Restore context's output buffer */
6132  context->buf = buf;
6133 
6134  /* Consider line-wrapping if enabled */
6135  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6136  {
6137  int leading_nl_pos;
6138 
6139  /* Does the new field start with a new line? */
6140  if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
6141  leading_nl_pos = 0;
6142  else
6143  leading_nl_pos = -1;
6144 
6145  /* If so, we shouldn't add anything */
6146  if (leading_nl_pos >= 0)
6147  {
6148  /* instead, remove any trailing spaces currently in buf */
6150  }
6151  else
6152  {
6153  char *trailing_nl;
6154 
6155  /* Locate the start of the current line in the output buffer */
6156  trailing_nl = strrchr(buf->data, '\n');
6157  if (trailing_nl == NULL)
6158  trailing_nl = buf->data;
6159  else
6160  trailing_nl++;
6161 
6162  /*
6163  * Add a newline, plus some indentation, if the new field is
6164  * not the first and either the new field would cause an
6165  * overflow or the last field used more than one line.
6166  */
6167  if (colno > 1 &&
6168  ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
6169  last_was_multiline))
6172  }
6173 
6174  /* Remember this field's multiline status for next iteration */
6175  last_was_multiline =
6176  (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6177  }
6178 
6179  /* Add the new field */
6180  appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
6181  }
6182 
6183  /* clean up */
6184  pfree(targetbuf.data);
6185 }
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:78

References appendBinaryStringInfo(), appendContextKeyword(), appendStringInfo(), appendStringInfoString(), attname, buf, context, StringInfoData::data, TargetEntry::expr, get_rule_expr(), get_variable(), initStringInfo(), IsA, StringInfoData::len, lfirst, NameStr, pfree(), PRETTY_INDENT, PRETTYINDENT_STD, PRETTYINDENT_VAR, quote_identifier(), removeStringInfoSpaces(), resetStringInfo(), and TupleDescAttr.

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

◆ get_update_query_def()

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

Definition at line 6855 of file ruleutils.c.

6857 {
6858  StringInfo buf = context->buf;
6859  RangeTblEntry *rte;
6860 
6861  /* Insert the WITH clause if given */
6862  get_with_clause(query, context);
6863 
6864  /*
6865  * Start the query with UPDATE relname SET
6866  */
6867  rte = rt_fetch(query->resultRelation, query->rtable);
6868  Assert(rte->rtekind == RTE_RELATION);
6869  if (PRETTY_INDENT(context))
6870  {
6871  appendStringInfoChar(buf, ' ');
6872  context->indentLevel += PRETTYINDENT_STD;
6873  }
6874  appendStringInfo(buf, "UPDATE %s%s",
6875  only_marker(rte),
6877 
6878  /* Print the relation alias, if needed */
6879  get_rte_alias(rte, query->resultRelation, false, context);
6880 
6881  appendStringInfoString(buf, " SET ");
6882 
6883  /* Deparse targetlist */
6884  get_update_query_targetlist_def(query, query->targetList, context, rte);
6885 
6886  /* Add the FROM clause if needed */
6887  get_from_clause(query, " FROM ", context);
6888 
6889  /* Add a WHERE clause if given */
6890  if (query->jointree->quals != NULL)
6891  {
6892  appendContextKeyword(context, " WHERE ",
6894  get_rule_expr(query->jointree->quals, context, false);
6895  }
6896 
6897  /* Add RETURNING if present */
6898  if (query->returningList)
6899  {
6900  appendContextKeyword(context, " RETURNING",
6902  get_target_list(query->returningList, context, NULL, colNamesVisible);
6903  }
6904 }

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

Referenced by get_query_def().

◆ get_update_query_targetlist_def()

static void get_update_query_targetlist_def ( Query query,
List targetList,
deparse_context context,
RangeTblEntry rte 
)
static

Definition at line 6912 of file ruleutils.c.

6914 {
6915  StringInfo buf = context->buf;
6916  ListCell *l;
6917  ListCell *next_ma_cell;
6918  int remaining_ma_columns;
6919  const char *sep;
6920  SubLink *cur_ma_sublink;
6921  List *ma_sublinks;
6922 
6923  /*
6924  * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
6925  * into a list. We expect them to appear, in ID order, in resjunk tlist
6926  * entries.
6927  */
6928  ma_sublinks = NIL;
6929  if (query->hasSubLinks) /* else there can't be any */
6930  {
6931  foreach(l, targetList)
6932  {
6933  TargetEntry *tle = (TargetEntry *) lfirst(l);
6934 
6935  if (tle->resjunk && IsA(tle->expr, SubLink))
6936  {
6937  SubLink *sl = (SubLink *) tle->expr;
6938 
6940  {
6941  ma_sublinks = lappend(ma_sublinks, sl);
6942  Assert(sl->subLinkId == list_length(ma_sublinks));
6943  }
6944  }
6945  }
6946  }
6947  next_ma_cell = list_head(ma_sublinks);
6948  cur_ma_sublink = NULL;
6949  remaining_ma_columns = 0;
6950 
6951  /* Add the comma separated list of 'attname = value' */
6952  sep = "";
6953  foreach(l, targetList)
6954  {
6955  TargetEntry *tle = (TargetEntry *) lfirst(l);
6956  Node *expr;
6957 
6958  if (tle->resjunk)
6959  continue; /* ignore junk entries */
6960 
6961  /* Emit separator (OK whether we're in multiassignment or not) */
6963  sep = ", ";
6964 
6965  /*
6966  * Check to see if we're starting a multiassignment group: if so,
6967  * output a left paren.
6968  */
6969  if (next_ma_cell != NULL && cur_ma_sublink == NULL)
6970  {
6971  /*
6972  * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
6973  * Param. That could be buried under FieldStores and
6974  * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
6975  * and underneath those there could be an implicit type coercion.
6976  * Because we would ignore implicit type coercions anyway, we
6977  * don't need to be as careful as processIndirection() is about
6978  * descending past implicit CoerceToDomains.
6979  */
6980  expr = (Node *) tle->expr;
6981  while (expr)
6982  {
6983  if (IsA(expr, FieldStore))
6984  {
6985  FieldStore *fstore = (FieldStore *) expr;
6986 
6987  expr = (Node *) linitial(fstore->newvals);
6988  }
6989  else if (IsA(expr, SubscriptingRef))
6990  {
6991  SubscriptingRef *sbsref = (SubscriptingRef *) expr;
6992 
6993  if (sbsref->refassgnexpr == NULL)
6994  break;
6995 
6996  expr = (Node *) sbsref->refassgnexpr;
6997  }
6998  else if (IsA(expr, CoerceToDomain))
6999  {
7000  CoerceToDomain *cdomain = (CoerceToDomain *) expr;
7001 
7002  if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
7003  break;
7004  expr = (Node *) cdomain->arg;
7005  }
7006  else
7007  break;
7008  }
7009  expr = strip_implicit_coercions(expr);
7010 
7011  if (expr && IsA(expr, Param) &&
7012  ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
7013  {
7014  cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
7015  next_ma_cell = lnext(ma_sublinks, next_ma_cell);
7016  remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
7017  Assert(((Param *) expr)->paramid ==
7018  ((cur_ma_sublink->subLinkId << 16) | 1));
7019  appendStringInfoChar(buf, '(');
7020  }
7021  }
7022 
7023  /*
7024  * Put out name of target column; look in the catalogs, not at
7025  * tle->resname, since resname will fail to track RENAME.
7026  */
7029  tle->resno,
7030  false)));
7031 
7032  /*
7033  * Print any indirection needed (subfields or subscripts), and strip
7034  * off the top-level nodes representing the indirection assignments.
7035  */
7036  expr = processIndirection((Node *) tle->expr, context);
7037 
7038  /*
7039  * If we're in a multiassignment, skip printing anything more, unless
7040  * this is the last column; in which case, what we print should be the
7041  * sublink, not the Param.
7042  */
7043  if (cur_ma_sublink != NULL)
7044  {
7045  if (--remaining_ma_columns > 0)
7046  continue; /* not the last column of multiassignment */
7047  appendStringInfoChar(buf, ')');
7048  expr = (Node *) cur_ma_sublink;
7049  cur_ma_sublink = NULL;
7050  }
7051 
7052  appendStringInfoString(buf, " = ");
7053 
7054  get_rule_expr(expr, context, false);
7055  }
7056 }
while(p+4<=pend)
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
@ PARAM_MULTIEXPR
Definition: primnodes.h:370
int count_nonjunk_tlist_entries(List *tlist)
Definition: tlist.c:186

References appendStringInfoChar(), appendStringInfoString(), CoerceToDomain::arg, Assert, buf, COERCE_IMPLICIT_CAST, context, count_nonjunk_tlist_entries(), TargetEntry::expr, get_attname(), get_rule_expr(), if(), IsA, lappend(), lfirst, linitial, list_head(), list_length(), lnext(), MULTIEXPR_SUBLINK, FieldStore::newvals, NIL, PARAM_MULTIEXPR, processIndirection(), quote_identifier(), SubscriptingRef::refassgnexpr, RangeTblEntry::relid, TargetEntry::resno, strip_implicit_coercions(), SubLink::subLinkId, SubLink::subLinkType, SubLink::subselect, and while().

Referenced by get_insert_query_def(), get_merge_query_def(), and get_update_query_def().

◆ get_utility_query_def()

static void get_utility_query_def ( Query query,
deparse_context context 
)
static

Definition at line 7280 of file ruleutils.c.

7281 {
7282  StringInfo buf = context->buf;
7283 
7284  if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7285  {
7286  NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7287 
7289  0, PRETTYINDENT_STD, 1);
7290  appendStringInfo(buf, "NOTIFY %s",
7291  quote_identifier(stmt->conditionname));
7292  if (stmt->payload)
7293  {
7294  appendStringInfoString(buf, ", ");
7295  simple_quote_literal(buf, stmt->payload);
7296  }
7297  }
7298  else
7299  {
7300  /* Currently only NOTIFY utility commands can appear in rules */
7301  elog(ERROR, "unexpected utility statement type");
7302  }
7303 }
#define stmt
Definition: indent_codes.h:59
Node * utilityStmt
Definition: parsenodes.h:136

References appendContextKeyword(), appendStringInfo(), appendStringInfoString(), buf, context, elog, ERROR, IsA, PRETTYINDENT_STD, quote_identifier(), simple_quote_literal(), stmt, and Query::utilityStmt.

Referenced by get_query_def().

◆ get_values_def()

static void get_values_def ( List values_lists,
deparse_context context 
)
static

Definition at line 5535 of file ruleutils.c.

5536 {
5537  StringInfo buf = context->buf;
5538  bool first_list = true;
5539  ListCell *vtl;
5540 
5541  appendStringInfoString(buf, "VALUES ");
5542 
5543  foreach(vtl, values_lists)
5544  {
5545  List *sublist = (List *) lfirst(vtl);
5546  bool first_col = true;
5547  ListCell *lc;
5548 
5549  if (first_list)
5550  first_list = false;
5551  else
5552  appendStringInfoString(buf, ", ");
5553 
5554  appendStringInfoChar(buf, '(');
5555  foreach(lc, sublist)
5556  {
5557  Node *col = (Node *) lfirst(lc);
5558 
5559  if (first_col)
5560  first_col = false;
5561  else
5562  appendStringInfoChar(buf, ',');
5563 
5564  /*
5565  * Print the value. Whole-row Vars need special treatment.
5566  */
5567  get_rule_expr_toplevel(col, context, false);
5568  }
5569  appendStringInfoChar(buf, ')');
5570  }
5571 }

References appendStringInfoChar(), appendStringInfoString(), buf, context, get_rule_expr_toplevel(), and lfirst.

Referenced by get_basic_select_query(), get_from_clause_item(), and get_insert_query_def().

◆ get_variable()

static char * get_variable ( Var var,
int  levelsup,
bool  istoplevel,
deparse_context context 
)
static

Definition at line 7325 of file ruleutils.c.

7326 {
7327  StringInfo buf = context->buf;
7328  RangeTblEntry *rte;
7330  int netlevelsup;
7331  deparse_namespace *dpns;
7332  int varno;
7333  AttrNumber varattno;
7334  deparse_columns *colinfo;
7335  char *refname;
7336  char *attname;
7337 
7338  /* Find appropriate nesting depth */
7339  netlevelsup = var->varlevelsup + levelsup;
7340  if (netlevelsup >= list_length(context->namespaces))
7341  elog(ERROR, "bogus varlevelsup: %d offset %d",
7342  var->varlevelsup, levelsup);
7343  dpns = (deparse_namespace *) list_nth(context->namespaces,
7344  netlevelsup);
7345 
7346  /*
7347  * If we have a syntactic referent for the Var, and we're working from a
7348  * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7349  * on the semantic referent. (Forcing use of the semantic referent when
7350  * printing plan trees is a design choice that's perhaps more motivated by
7351  * backwards compatibility than anything else. But it does have the
7352  * advantage of making plans more explicit.)
7353  */
7354  if (var->varnosyn > 0 && dpns->plan == NULL)
7355  {
7356  varno = var->varnosyn;
7357  varattno = var->varattnosyn;
7358  }
7359  else
7360  {
7361  varno = var->varno;
7362  varattno = var->varattno;
7363  }
7364 
7365  /*
7366  * Try to find the relevant RTE in this rtable. In a plan tree, it's
7367  * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7368  * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7369  * find the aliases previously assigned for this RTE.
7370  */
7371  if (varno >= 1 && varno <= list_length(dpns->rtable))
7372  {
7373  /*
7374  * We might have been asked to map child Vars to some parent relation.
7375  */
7376  if (context->appendparents && dpns->appendrels)
7377  {
7378  int pvarno = varno;
7379  AttrNumber pvarattno = varattno;
7380  AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7381  bool found = false;
7382 
7383  /* Only map up to inheritance parents, not UNION ALL appendrels */
7384  while (appinfo &&
7385  rt_fetch(appinfo->parent_relid,
7386  dpns->rtable)->rtekind == RTE_RELATION)
7387  {
7388  found = false;
7389  if (pvarattno > 0) /* system columns stay as-is */
7390  {
7391  if (pvarattno > appinfo->num_child_cols)
7392  break; /* safety check */
7393  pvarattno = appinfo->parent_colnos[pvarattno - 1];
7394  if (pvarattno == 0)
7395  break; /* Var is local to child */
7396  }
7397 
7398  pvarno = appinfo->parent_relid;
7399  found = true;
7400 
7401  /* If the parent is itself a child, continue up. */
7402  Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7403  appinfo = dpns->appendrels[pvarno];
7404  }
7405 
7406  /*
7407  * If we found an ancestral rel, and that rel is included in
7408  * appendparents, print that column not the original one.
7409  */
7410  if (found && bms_is_member(pvarno, context->appendparents))
7411  {
7412  varno = pvarno;
7413  varattno = pvarattno;
7414  }
7415  }
7416 
7417  rte = rt_fetch(varno, dpns->rtable);
7418  refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7419  colinfo = deparse_columns_fetch(varno, dpns);
7420  attnum = varattno;
7421  }
7422  else
7423  {
7425  get_special_variable, NULL);
7426  return NULL;
7427  }
7428 
7429  /*
7430  * The planner will sometimes emit Vars referencing resjunk elements of a
7431  * subquery's target list (this is currently only possible if it chooses
7432  * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7433  * Although we prefer to print subquery-referencing Vars using the
7434  * subquery's alias, that's not possible for resjunk items since they have
7435  * no alias. So in that case, drill down to the subplan and print the
7436  * contents of the referenced tlist item. This works because in a plan
7437  * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
7438  * we'll have set dpns->inner_plan to reference the child plan node.
7439  */
7440  if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7441  attnum > list_length(rte->eref->colnames) &&
7442  dpns->inner_plan)
7443  {
7444  TargetEntry *tle;
7445  deparse_namespace save_dpns;
7446 
7447  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7448  if (!tle)
7449  elog(ERROR, "invalid attnum %d for relation \"%s\"",
7450  attnum, rte->eref->aliasname);
7451 
7452  Assert(netlevelsup == 0);
7453  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7454 
7455  /*
7456  * Force parentheses because our caller probably assumed a Var is a
7457  * simple expression.
7458  */
7459  if (!IsA(tle->expr, Var))
7460  appendStringInfoChar(buf, '(');
7461  get_rule_expr((Node *) tle->expr, context, true);
7462  if (!IsA(tle->expr, Var))
7463  appendStringInfoChar(buf, ')');
7464 
7465  pop_child_plan(dpns, &save_dpns);
7466  return NULL;
7467  }
7468 
7469  /*
7470  * If it's an unnamed join, look at the expansion of the alias variable.
7471  * If it's a simple reference to one of the input vars, then recursively
7472  * print the name of that var instead. When it's not a simple reference,
7473  * we have to just print the unqualified join column name. (This can only
7474  * happen with "dangerous" merged columns in a JOIN USING; we took pains
7475  * previously to make the unqualified column name unique in such cases.)
7476  *
7477  * This wouldn't work in decompiling plan trees, because we don't store
7478  * joinaliasvars lists after planning; but a plan tree should never
7479  * contain a join alias variable.
7480  */
7481  if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7482  {
7483  if (rte->joinaliasvars == NIL)
7484  elog(ERROR, "cannot decompile join alias var in plan tree");
7485  if (attnum > 0)
7486  {
7487  Var *aliasvar;
7488 
7489  aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7490  /* we intentionally don't strip implicit coercions here */
7491  if (aliasvar && IsA(aliasvar, Var))
7492  {
7493  return get_variable(aliasvar, var->varlevelsup + levelsup,
7494  istoplevel, context);
7495  }
7496  }
7497 
7498  /*
7499  * Unnamed join has no refname. (Note: since it's unnamed, there is
7500  * no way the user could have referenced it to create a whole-row Var
7501  * for it. So we don't have to cover that case below.)
7502  */
7503  Assert(refname == NULL);
7504  }
7505 
7506  if (attnum == InvalidAttrNumber)
7507  attname = NULL;
7508  else if (attnum > 0)
7509  {
7510  /* Get column name to use from the colinfo struct */
7511  if (attnum > colinfo->num_cols)
7512  elog(ERROR, "invalid attnum %d for relation \"%s\"",
7513  attnum, rte->eref->aliasname);
7514  attname = colinfo->colnames[attnum - 1];
7515 
7516  /*
7517  * If we find a Var referencing a dropped column, it seems better to
7518  * print something (anything) than to fail. In general this should
7519  * not happen, but it used to be possible for some cases involving
7520  * functions returning named composite types, and perhaps there are
7521  * still bugs out there.
7522  */
7523  if (attname == NULL)
7524  attname = "?dropped?column?";
7525  }
7526  else
7527  {
7528  /* System column - name is fixed, get it from the catalog */
7530  }
7531 
7532  if (refname && (context->varprefix || attname == NULL))
7533  {
7535  appendStringInfoChar(buf, '.');
7536  }
7537  if (attname)
7539  else
7540  {
7541  appendStringInfoChar(buf, '*');
7542  if (istoplevel)
7543  appendStringInfo(buf, "::%s",
7544  format_type_with_typemod(var->vartype,
7545  var->vartypmod));
7546  }
7547 
7548  return attname;
7549 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
static void get_special_variable(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:7559
Index parent_relid
Definition: pathnodes.h:2957
int num_child_cols
Definition: pathnodes.h:2993

References deparse_namespace::appendrels, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, attname, attnum, bms_is_member(), buf, deparse_columns::colnames, context, deparse_columns_fetch, elog, ERROR, TargetEntry::expr, format_type_with_typemod(), get_rte_attribute_name(), get_rule_expr(), get_special_variable(), get_tle_by_resno(), deparse_namespace::inner_plan, deparse_namespace::inner_tlist, InvalidAttrNumber, IsA, list_length(), list_nth(), NIL, AppendRelInfo::num_child_cols, deparse_columns::num_cols, AppendRelInfo::parent_relid, deparse_namespace::plan, pop_child_plan(), push_child_plan(), quote_identifier(), resolve_special_varno(), rt_fetch, deparse_namespace::rtable, deparse_namespace::rtable_names, RTE_CTE, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by get_rule_expr(), get_rule_expr_toplevel(), and get_target_list().

◆ get_windowfunc_expr()

static void get_windowfunc_expr ( WindowFunc wfunc,
deparse_context context 
)
static

Definition at line 10640 of file ruleutils.c.

10641 {
10642  get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
10643 }

References context, and get_windowfunc_expr_helper().

Referenced by get_rule_expr().

◆ get_windowfunc_expr_helper()

static void get_windowfunc_expr_helper ( WindowFunc wfunc,
deparse_context context,
const char *  funcname,
const char *  options,
bool  is_json_objectagg 
)
static

Definition at line 10651 of file ruleutils.c.

10654 {
10655  StringInfo buf = context->buf;
10656  Oid argtypes[FUNC_MAX_ARGS];
10657  int nargs;
10658  List *argnames;
10659  ListCell *l;
10660 
10661  if (list_length(wfunc->args) > FUNC_MAX_ARGS)
10662  ereport(ERROR,
10663  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10664  errmsg("too many arguments")));
10665  nargs = 0;
10666  argnames = NIL;
10667  foreach(l, wfunc->args)
10668  {
10669  Node *arg = (Node *) lfirst(l);
10670 
10671  if (IsA(arg, NamedArgExpr))
10672  argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10673  argtypes[nargs] = exprType(arg);
10674  nargs++;
10675  }
10676 
10677  if (!funcname)
10678  funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
10679  argtypes, false, NULL,
10680  context->special_exprkind);
10681 
10682  appendStringInfo(buf, "%s(", funcname);
10683 
10684  /* winstar can be set only in zero-argument aggregates */
10685  if (wfunc->winstar)
10686  appendStringInfoChar(buf, '*');
10687  else
10688  {
10689  if (is_json_objectagg)
10690  {
10691  get_rule_expr((Node *) linitial(wfunc->args), context, false);
10692  appendStringInfoString(buf, " : ");
10693  get_rule_expr((Node *) lsecond(wfunc->args), context, false);
10694  }
10695  else
10696  get_rule_expr((Node *) wfunc->args, context, true);
10697  }
10698 
10699  if (options)
10701 
10702  if (wfunc->aggfilter != NULL)
10703  {
10704  appendStringInfoString(buf, ") FILTER (WHERE ");
10705  get_rule_expr((Node *) wfunc->aggfilter, context, false);
10706  }
10707 
10708  appendStringInfoString(buf, ") OVER ");
10709 
10710  foreach(l, context->windowClause)
10711  {
10712  WindowClause *wc = (WindowClause *) lfirst(l);
10713 
10714  if (wc->winref == wfunc->winref)
10715  {
10716  if (wc->name)
10718  else
10719  get_rule_windowspec(wc, context->windowTList, context);
10720  break;
10721  }
10722  }
10723  if (l == NULL)
10724  {
10725  if (context->windowClause)
10726  elog(ERROR, "could not find window clause for winref %u",
10727  wfunc->winref);
10728 
10729  /*
10730  * In EXPLAIN, we don't have window context information available, so
10731  * we have to settle for this:
10732  */
10733  appendStringInfoString(buf, "(?)");
10734  }
10735 }
List * args
Definition: primnodes.h:575
Index winref
Definition: primnodes.h:579
Expr * aggfilter
Definition: primnodes.h:577
Oid winfnoid
Definition: primnodes.h:567

References WindowFunc::aggfilter, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, WindowFunc::args, buf, context, elog, ereport, errcode(), errmsg(), ERROR, exprType(), FUNC_MAX_ARGS, funcname, generate_function_name(), get_rule_expr(), get_rule_windowspec(), IsA, lappend(), lfirst, linitial, list_length(), lsecond, NIL, quote_identifier(), WindowFunc::winfnoid, WindowClause::winref, and WindowFunc::winref.

Referenced by get_json_agg_constructor(), and get_windowfunc_expr().

◆ get_with_clause()

static void get_with_clause ( Query query,
deparse_context context 
)
static

Definition at line 5578 of file ruleutils.c.

5579 {
5580  StringInfo buf = context->buf;
5581  const char *sep;
5582  ListCell *l;
5583 
5584  if (query->cteList == NIL)
5585  return;
5586 
5587  if (PRETTY_INDENT(context))
5588  {
5589  context->indentLevel += PRETTYINDENT_STD;
5590  appendStringInfoChar(buf, ' ');
5591  }
5592 
5593  if (query->hasRecursive)
5594  sep = "WITH RECURSIVE ";
5595  else
5596  sep = "WITH ";
5597  foreach(l, query->cteList)
5598  {
5599  CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5600 
5603  if (cte->aliascolnames)
5604  {
5605  bool first = true;
5606  ListCell *col;
5607 
5608  appendStringInfoChar(buf, '(');
5609  foreach(col, cte->aliascolnames)
5610  {
5611  if (first)
5612  first = false;
5613  else
5614  appendStringInfoString(buf, ", ");
5616  quote_identifier(strVal(lfirst(col))));
5617  }
5618  appendStringInfoChar(buf, ')');
5619  }
5620  appendStringInfoString(buf, " AS ");
5621  switch (cte->ctematerialized)
5622  {
5623  case CTEMaterializeDefault:
5624  break;
5625  case CTEMaterializeAlways:
5626  appendStringInfoString(buf, "MATERIALIZED ");
5627  break;
5628  case CTEMaterializeNever:
5629  appendStringInfoString(buf, "NOT MATERIALIZED ");
5630  break;
5631  }
5632  appendStringInfoChar(buf, '(');
5633  if (PRETTY_INDENT(context))
5634  appendContextKeyword(context, "", 0, 0, 0);
5635  get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5636  true,
5637  context->prettyFlags, context->wrapColumn,
5638  context->indentLevel);
5639  if (PRETTY_INDENT(context))
5640  appendContextKeyword(context, "", 0, 0, 0);
5641  appendStringInfoChar(buf, ')');
5642 
5643  if (cte->search_clause)
5644  {
5645  bool first = true;
5646  ListCell *lc;
5647 
5648  appendStringInfo(buf, " SEARCH %s FIRST BY ",
5649  cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
5650 
5651  foreach(lc, cte->search_clause->search_col_list)
5652  {
5653  if (first)
5654  first = false;
5655  else
5656  appendStringInfoString(buf, ", ");
5659  }
5660 
5661  appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
5662  }
5663 
5664  if (cte->cycle_clause)
5665  {
5666  bool first = true;
5667  ListCell *lc;
5668 
5669  appendStringInfoString(buf, " CYCLE ");
5670 
5671  foreach(lc, cte->cycle_clause->cycle_col_list)
5672  {
5673  if (first)
5674  first = false;
5675  else
5676  appendStringInfoString(buf, ", ");
5679  }
5680 
5681  appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5682 
5683  {
5684  Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5685  Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5686 
5687  if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5688  cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5689  {
5690  appendStringInfoString(buf, " TO ");
5691  get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
5692  appendStringInfoString(buf, " DEFAULT ");
5693  get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
5694  }
5695  }
5696 
5697  appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5698  }
5699 
5700  sep = ", ";
5701  }
5702 
5703  if (PRETTY_INDENT(context))
5704  {
5705  context->indentLevel -= PRETTYINDENT_STD;
5706  appendContextKeyword(context, "", 0, 0, 0);
5707  }
5708  else
5709  appendStringInfoChar(buf, ' ');
5710 }
@ CTEMaterializeNever
Definition: parsenodes.h:1645
@ CTEMaterializeAlways
Definition: parsenodes.h:1644
@ CTEMaterializeDefault
Definition: parsenodes.h:1643
CTEMaterialize ctematerialized
Definition: parsenodes.h:1684

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), buf, castNode, Const::consttype, context, Query::cteList, CTEMaterializeAlways, CommonTableExpr::ctematerialized, CTEMaterializeDefault, CTEMaterializeNever, CommonTableExpr::ctename, CommonTableExpr::ctequery, DatumGetBool(), get_query_def(), get_rule_expr(), lfirst, NIL, PRETTY_INDENT, PRETTYINDENT_STD, quote_identifier(), and strVal.

Referenced by get_delete_query_def(), get_insert_query_def(), get_merge_query_def(), get_select_query_def(), and get_update_query_def().

◆ get_xmltable()

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

Definition at line 11540 of file ruleutils.c.

11541 {
11542  StringInfo buf = context->buf;
11543 
11544  appendStringInfoString(buf, "XMLTABLE(");
11545 
11546  if (tf->ns_uris != NIL)
11547  {
11548  ListCell *lc1,
11549  *lc2;
11550  bool first = true;
11551 
11552  appendStringInfoString(buf, "XMLNAMESPACES (");
11553  forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
11554  {
11555  Node *expr = (Node *) lfirst(lc1);
11556  String *ns_node = lfirst_node(String, lc2);
11557 
11558  if (!first)
11559  appendStringInfoString(buf, ", ");
11560  else
11561  first = false;
11562 
11563  if (ns_node != NULL)
11564  {
11565  get_rule_expr(expr, context, showimplicit);
11566  appendStringInfo(buf, " AS %s", strVal(ns_node));
11567  }
11568  else
11569  {
11570  appendStringInfoString(buf, "DEFAULT ");
11571  get_rule_expr(expr, context, showimplicit);
11572  }
11573  }
11574  appendStringInfoString(buf, "), ");
11575  }
11576 
11577  appendStringInfoChar(buf, '(');
11578  get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
11579  appendStringInfoString(buf, ") PASSING (");
11580  get_rule_expr((Node *) tf->docexpr, context, showimplicit);
11581  appendStringInfoChar(buf, ')');
11582 
11583  if (tf->colexprs != NIL)
11584  {
11585  ListCell *l1;
11586  ListCell *l2;
11587  ListCell *l3;
11588  ListCell *l4;
11589  ListCell *l5;
11590  int colnum = 0;
11591 
11592  appendStringInfoString(buf, " COLUMNS ");
11593  forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
11594  l4, tf->colexprs, l5, tf->coldefexprs)
11595  {
11596  char *colname = strVal(lfirst(l1));
11597  Oid typid = lfirst_oid(l2);
11598  int32 typmod = lfirst_int(l3);
11599  Node *colexpr = (Node *) lfirst(l4);
11600  Node *coldefexpr = (Node *) lfirst(l5);
11601  bool ordinality = (tf->ordinalitycol == colnum);
11602  bool notnull = bms_is_member(colnum, tf->notnulls);
11603 
11604  if (colnum > 0)
11605  appendStringInfoString(buf, ", ");
11606  colnum++;
11607 
11608  appendStringInfo(buf, "%s %s", quote_identifier(colname),
11609  ordinality ? "FOR ORDINALITY" :
11610  format_type_with_typemod(typid, typmod));
11611  if (ordinality)
11612  continue;
11613 
11614  if (coldefexpr != NULL)
11615  {
11616  appendStringInfoString(buf, " DEFAULT (");
11617  get_rule_expr((Node *) coldefexpr, context, showimplicit);
11618  appendStringInfoChar(buf, ')');
11619  }
11620  if (colexpr != NULL)
11621  {
11622  appendStringInfoString(buf, " PATH (");
11623  get_rule_expr((Node *) colexpr, context, showimplicit);
11624  appendStringInfoChar(buf, ')');
11625  }
11626  if (notnull)
11627  appendStringInfoString(buf, " NOT NULL");
11628  }
11629  }
11630 
11631  appendStringInfoChar(buf, ')');
11632 }
#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5)
Definition: pg_list.h:588
Node * rowexpr
Definition: primnodes.h:121
List * colexprs
Definition: primnodes.h:131

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), bms_is_member(), buf, TableFunc::colexprs, context, TableFunc::docexpr, forboth, forfive, format_type_with_typemod(), get_rule_expr(), lfirst, lfirst_int, lfirst_node, lfirst_oid, NIL, quote_identifier(), TableFunc::rowexpr, and strVal.

Referenced by get_tablefunc().

◆ has_dangerous_join_using()

static bool has_dangerous_join_using ( deparse_namespace dpns,
Node jtnode 
)
static

Definition at line 4102 of file ruleutils.c.

4103 {
4104  if (IsA(jtnode, RangeTblRef))
4105  {
4106  /* nothing to do here */
4107  }
4108  else if (IsA(jtnode, FromExpr))
4109  {
4110  FromExpr *f = (FromExpr *) jtnode;
4111  ListCell *lc;
4112 
4113  foreach(lc, f->fromlist)
4114  {
4115  if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
4116  return true;
4117  }
4118  }
4119  else if (IsA(jtnode, JoinExpr))
4120  {
4121  JoinExpr *j = (JoinExpr *) jtnode;
4122 
4123  /* Is it an unnamed JOIN with USING? */
4124  if (j->alias == NULL && j->usingClause)
4125  {
4126  /*
4127  * Yes, so check each join alias var to see if any of them are not
4128  * simple references to underlying columns. If so, we have a
4129  * dangerous situation and must pick unique aliases.
4130  */
4131  RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4132 
4133  /* We need only examine the merged columns */
4134  for (int i = 0; i < jrte->joinmergedcols; i++)
4135  {
4136  Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4137 
4138  if (!IsA(aliasvar, Var))
4139  return true;
4140  }
4141  }
4142 
4143  /* Nope, but inspect children */
4144  if (has_dangerous_join_using(dpns, j->larg))
4145  return true;
4146  if (has_dangerous_join_using(dpns, j->rarg))
4147  return true;
4148  }
4149  else
4150  elog(ERROR, "unrecognized node type: %d",
4151  (int) nodeTag(jtnode));
4152  return false;
4153 }
static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
Definition: ruleutils.c:4102

References elog, ERROR, FromExpr::fromlist, i, IsA, j, lfirst, list_nth(), nodeTag, rt_fetch, and deparse_namespace::rtable.

Referenced by set_deparse_for_query().

◆ identify_join_columns()

static void identify_join_columns ( JoinExpr j,
RangeTblEntry jrte,
deparse_columns colinfo 
)
static

Definition at line 4901 of file ruleutils.c.

4903 {
4904  int numjoincols;
4905  int jcolno;
4906  int rcolno;
4907  ListCell *lc;
4908 
4909  /* Extract left/right child RT indexes */
4910  if (IsA(j->larg, RangeTblRef))
4911  colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
4912  else if (IsA(j->larg, JoinExpr))
4913  colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
4914  else
4915  elog(ERROR, "unrecognized node type in jointree: %d",
4916  (int) nodeTag(j->larg));
4917  if (IsA(j->rarg, RangeTblRef))
4918  colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
4919  else if (IsA(j->rarg, JoinExpr))
4920  colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
4921  else
4922  elog(ERROR, "unrecognized node type in jointree: %d",
4923  (int) nodeTag(j->rarg));
4924 
4925  /* Assert children will be processed earlier than join in second pass */
4926  Assert(colinfo->leftrti < j->rtindex);
4927  Assert(colinfo->rightrti < j->rtindex);
4928 
4929  /* Initialize result arrays with zeroes */
4930  numjoincols = list_length(jrte->joinaliasvars);
4931  Assert(numjoincols == list_length(jrte->eref->colnames));
4932  colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
4933  colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
4934 
4935  /*
4936  * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
4937  * Recall that the column(s) merged due to USING are the first column(s)
4938  * of the join output. We need not do anything special while scanning
4939  * joinleftcols, but while scanning joinrightcols we must distinguish
4940  * merged from unmerged columns.
4941  */
4942  jcolno = 0;
4943  foreach(lc, jrte->joinleftcols)
4944  {
4945  int leftattno = lfirst_int(lc);
4946 
4947  colinfo->leftattnos[jcolno++] = leftattno;
4948  }
4949  rcolno = 0;
4950  foreach(lc, jrte->joinrightcols)
4951  {
4952  int rightattno = lfirst_int(lc);
4953 
4954  if (rcolno < jrte->joinmergedcols) /* merged column? */
4955  colinfo->rightattnos[rcolno] = rightattno;
4956  else
4957  colinfo->rightattnos[jcolno++] = rightattno;
4958  rcolno++;
4959  }
4960  Assert(jcolno == numjoincols);
4961 }
int * rightattnos
Definition: ruleutils.c:291
int * leftattnos
Definition: ruleutils.c:290

References Assert, elog, ERROR, IsA, j, deparse_columns::leftattnos, deparse_columns::leftrti, lfirst_int, list_length(), nodeTag, palloc0(), deparse_columns::rightattnos, and deparse_columns::rightrti.

Referenced by set_using_names().

◆ is_input_argument()

static bool is_input_argument ( int  nth,
const char *  argmodes 
)
static

Definition at line 3426 of file ruleutils.c.

3427 {
3428  return (!argmodes
3429  || argmodes[nth] == PROARGMODE_IN
3430  || argmodes[nth] == PROARGMODE_INOUT
3431  || argmodes[nth] == PROARGMODE_VARIADIC);
3432 }

Referenced by pg_get_function_arg_default().

◆ isSimpleNode()

static bool isSimpleNode ( Node node,
Node parentNode,
int  prettyFlags 
)
static

Definition at line 8489 of file ruleutils.c.

8490 {
8491  if (!node)
8492  return false;
8493 
8494  switch (nodeTag(node))
8495  {
8496  case T_Var:
8497  case T_Const:
8498  case T_Param:
8499  case T_CoerceToDomainValue:
8500  case T_SetToDefault:
8501  case T_CurrentOfExpr:
8502  /* single words: always simple */
8503  return true;
8504 
8505  case T_SubscriptingRef:
8506  case T_ArrayExpr:
8507  case T_RowExpr:
8508  case T_CoalesceExpr:
8509  case T_MinMaxExpr:
8510  case T_SQLValueFunction:
8511  case T_XmlExpr:
8512  case T_NextValueExpr:
8513  case T_NullIfExpr:
8514  case T_Aggref:
8515  case T_GroupingFunc:
8516  case T_WindowFunc:
8517  case T_MergeSupportFunc:
8518  case T_FuncExpr:
8519  case T_JsonConstructorExpr:
8520  case T_JsonExpr:
8521  /* function-like: name(..) or name[..] */
8522  return true;
8523 
8524  /* CASE keywords act as parentheses */
8525  case T_CaseExpr:
8526  return true;
8527 
8528  case T_FieldSelect:
8529 
8530  /*
8531  * appears simple since . has top precedence, unless parent is
8532  * T_FieldSelect itself!
8533  */
8534  return !IsA(parentNode, FieldSelect);
8535 
8536  case T_FieldStore:
8537 
8538  /*
8539  * treat like FieldSelect (probably doesn't matter)
8540  */
8541  return !IsA(parentNode, FieldStore);
8542 
8543  case T_CoerceToDomain:
8544  /* maybe simple, check args */
8545  return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8546  node, prettyFlags);
8547  case T_RelabelType:
8548  return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8549  node, prettyFlags);
8550  case T_CoerceViaIO:
8551  return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
8552  node, prettyFlags);
8553  case T_ArrayCoerceExpr:
8554  return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8555  node, prettyFlags);
8556  case T_ConvertRowtypeExpr:
8557  return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8558  node, prettyFlags);
8559 
8560  case T_OpExpr:
8561  {
8562  /* depends on parent node type; needs further checking */
8563  if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8564  {
8565  const char *op;
8566  const char *parentOp;
8567  bool is_lopriop;
8568  bool is_hipriop;
8569  bool is_lopriparent;
8570  bool is_hipriparent;
8571 
8572  op = get_simple_binary_op_name((OpExpr *) node);
8573  if (!op)
8574  return false;
8575 
8576  /* We know only the basic operators + - and * / % */
8577  is_lopriop = (strchr("+-", *op) != NULL);
8578  is_hipriop = (strchr("*/%", *op) != NULL);
8579  if (!(is_lopriop || is_hipriop))
8580  return false;
8581 
8582  parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8583  if (!parentOp)
8584  return false;
8585 
8586  is_lopriparent = (strchr("+-", *parentOp) != NULL);
8587  is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8588  if (!(is_lopriparent || is_hipriparent))
8589  return false;
8590 
8591  if (is_hipriop && is_lopriparent)
8592  return true; /* op binds tighter than parent */
8593 
8594  if (is_lopriop && is_hipriparent)
8595  return false;
8596 
8597  /*
8598  * Operators are same priority --- can skip parens only if
8599  * we have (a - b) - c, not a - (b - c).
8600  */
8601  if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
8602  return true;
8603 
8604  return false;
8605  }
8606  /* else do the same stuff as for T_SubLink et al. */
8607  }
8608  /* FALLTHROUGH */
8609 
8610  case T_SubLink:
8611  case T_NullTest:
8612  case T_BooleanTest:
8613  case T_DistinctExpr:
8614  case T_JsonIsPredicate:
8615  switch (nodeTag(parentNode))
8616  {
8617  case T_FuncExpr:
8618  {
8619  /* special handling for casts and COERCE_SQL_SYNTAX */
8620  CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8621 
8622  if (type == COERCE_EXPLICIT_CAST ||
8625  return false;
8626  return true; /* own parentheses */
8627  }
8628  case T_BoolExpr: /* lower precedence */
8629  case T_SubscriptingRef: /* other separators */
8630  case T_ArrayExpr: /* other separators */
8631  case T_RowExpr: /* other separators */
8632  case T_CoalesceExpr: /* own parentheses */
8633  case T_MinMaxExpr: /* own parentheses */
8634  case T_XmlExpr: /* own parentheses */
8635  case T_NullIfExpr: /* other separators */
8636  case T_Aggref: /* own parentheses */
8637  case T_GroupingFunc: /* own parentheses */
8638  case T_WindowFunc: /* own parentheses */
8639  case T_CaseExpr: /* other separators */
8640  return true;
8641  default:
8642  return false;
8643  }
8644 
8645  case T_BoolExpr:
8646  switch (nodeTag(parentNode))
8647  {
8648  case T_BoolExpr:
8649  if (prettyFlags & PRETTYFLAG_PAREN)
8650  {
8652  BoolExprType parentType;
8653 
8654  type = ((BoolExpr *) node)->boolop;
8655  parentType = ((BoolExpr *) parentNode)->boolop;
8656  switch (type)
8657  {
8658  case NOT_EXPR:
8659  case AND_EXPR:
8660  if (parentType == AND_EXPR || parentType == OR_EXPR)
8661  return true;
8662  break;
8663  case OR_EXPR:
8664  if (parentType == OR_EXPR)
8665  return true;
8666  break;
8667  }
8668  }
8669  return false;
8670  case T_FuncExpr:
8671  {
8672  /* special handling for casts and COERCE_SQL_SYNTAX */
8673  CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8674 
8675  if (type == COERCE_EXPLICIT_CAST ||
8678  return false;
8679  return true; /* own parentheses */
8680  }
8681  case T_SubscriptingRef: /* other separators */
8682  case T_ArrayExpr: /* other separators */
8683  case T_RowExpr: /* other separators */
8684  case T_CoalesceExpr: /* own parentheses */
8685  case T_MinMaxExpr: /* own parentheses */
8686  case T_XmlExpr: /* own parentheses */
8687  case T_NullIfExpr: /* other separators */
8688  case T_Aggref: /* own parentheses */
8689  case T_GroupingFunc: /* own parentheses */
8690  case T_WindowFunc: /* own parentheses */
8691  case T_CaseExpr: /* other separators */
8692  case T_JsonExpr: /* own parentheses */
8693  return true;
8694  default:
8695  return false;
8696  }
8697 
8698  case T_JsonValueExpr:
8699  /* maybe simple, check args */
8700  return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
8701  node, prettyFlags);
8702 
8703  default:
8704  break;
8705  }
8706  /* those we don't know: in dubio complexo */
8707  return false;
8708 }
BoolExprType
Definition: primnodes.h:900
CoercionForm
Definition: primnodes.h:703
static const char * get_simple_binary_op_name(OpExpr *expr)
Definition: ruleutils.c:8463
const char * type

References AND_EXPR, arg, generate_unaccent_rules::args, COERCE_EXPLICIT_CAST, COERCE_IMPLICIT_CAST, COERCE_SQL_SYNTAX, get_simple_binary_op_name(), IsA, linitial, nodeTag, NOT_EXPR, OR_EXPR, PRETTYFLAG_PAREN, and type.

Referenced by get_rule_expr_paren().

◆ looks_like_function()

static bool looks_like_function ( Node node)
static

Definition at line 10321 of file ruleutils.c.

10322 {
10323  if (node == NULL)
10324  return false; /* probably shouldn't happen */
10325  switch (nodeTag(node))
10326  {
10327  case T_FuncExpr:
10328  /* OK, unless it's going to deparse as a cast */
10329  return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
10330  ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
10331  case T_NullIfExpr:
10332  case T_CoalesceExpr:
10333  case T_MinMaxExpr:
10334  case T_SQLValueFunction:
10335  case T_XmlExpr:
10336  case T_JsonExpr:
10337  /* these are all accepted by func_expr_common_subexpr */
10338  return true;
10339  default:
10340  break;
10341  }
10342  return false;
10343 }

References COERCE_EXPLICIT_CALL, COERCE_SQL_SYNTAX, and nodeTag.

Referenced by get_rule_expr_funccall(), pg_get_indexdef_worker(), pg_get_partkeydef_worker(), and pg_get_statisticsobj_worker().

◆ make_colname_unique()

static char * make_colname_unique ( char *  colname,
deparse_namespace dpns,
deparse_columns colinfo 
)
static

Definition at line 4843 of file ruleutils.c.

4845 {
4846  /*
4847  * If the selected name isn't unique, append digits to make it so. For a
4848  * very long input name, we might have to truncate to stay within
4849  * NAMEDATALEN.
4850  */
4851  if (!colname_is_unique(colname, dpns, colinfo))
4852  {
4853  int colnamelen = strlen(colname);
4854  char *modname = (char *) palloc(colnamelen + 16);
4855  int i = 0;
4856 
4857  do
4858  {
4859  i++;
4860  for (;;)
4861  {
4862  memcpy(modname, colname, colnamelen);
4863  sprintf(modname + colnamelen, "_%d", i);
4864  if (strlen(modname) < NAMEDATALEN)
4865  break;
4866  /* drop chars from colname to keep all the digits */
4867  colnamelen = pg_mbcliplen(colname, colnamelen,
4868  colnamelen - 1);
4869  }
4870  } while (!colname_is_unique(modname, dpns, colinfo));
4871  colname = modname;
4872  }
4873  return colname;
4874 }
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1083
void * palloc(Size size)
Definition: mcxt.c:1316
#define NAMEDATALEN
#define sprintf
Definition: port.h:240
static bool colname_is_unique(const char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
Definition: ruleutils.c:4789

References colname_is_unique(), i, NAMEDATALEN, palloc(), pg_mbcliplen(), and sprintf.

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

◆ make_ruledef()

static void make_ruledef ( StringInfo  buf,
HeapTuple  ruletup,
TupleDesc  rulettc,
int  prettyFlags 
)
static

Definition at line 5183 of file ruleutils.c.

5185 {
5186  char *rulename;
5187  char ev_type;
5188  Oid ev_class;
5189  bool is_instead;
5190  char *ev_qual;
5191  char *ev_action;
5192  List *actions;
5193  Relation ev_relation;
5194  TupleDesc viewResultDesc = NULL;
5195  int fno;
5196  Datum dat;
5197  bool isnull;
5198 
5199  /*
5200  * Get the attribute values from the rules tuple
5201  */
5202  fno = SPI_fnumber(rulettc, "rulename");
5203  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5204  Assert(!isnull);
5205  rulename = NameStr(*(DatumGetName(dat)));
5206 
5207  fno = SPI_fnumber(rulettc, "ev_type");
5208  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5209  Assert(!isnull);
5210  ev_type = DatumGetChar(dat);
5211 
5212  fno = SPI_fnumber(rulettc, "ev_class");
5213  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5214  Assert(!isnull);
5215  ev_class = DatumGetObjectId(dat);
5216 
5217  fno = SPI_fnumber(rulettc, "is_instead");
5218  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5219  Assert(!isnull);
5220  is_instead = DatumGetBool(dat);
5221 
5222  fno = SPI_fnumber(rulettc, "ev_qual");
5223  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5224  Assert(ev_qual != NULL);
5225 
5226  fno = SPI_fnumber(rulettc, "ev_action");
5227  ev_action = SPI_getvalue(ruletup, rulettc, fno);
5228  Assert(ev_action != NULL);
5229  actions = (List *) stringToNode(ev_action);
5230  if (actions == NIL)
5231  elog(ERROR, "invalid empty ev_action list");
5232 
5233  ev_relation = table_open(ev_class, AccessShareLock);
5234 
5235  /*
5236  * Build the rules definition text
5237  */
5238  appendStringInfo(buf, "CREATE RULE %s AS",
5239  quote_identifier(rulename));
5240 
5241  if (prettyFlags & PRETTYFLAG_INDENT)
5242  appendStringInfoString(buf, "\n ON ");
5243  else
5244  appendStringInfoString(buf, " ON ");
5245 
5246  /* The event the rule is fired for */
5247  switch (ev_type)
5248  {
5249  case '1':
5250  appendStringInfoString(buf, "SELECT");
5251  viewResultDesc = RelationGetDescr(ev_relation);
5252  break;
5253 
5254  case '2':
5255  appendStringInfoString(buf, "UPDATE");
5256  break;
5257 
5258  case '3':
5259  appendStringInfoString(buf, "INSERT");
5260  break;
5261 
5262  case '4':
5263  appendStringInfoString(buf, "DELETE");
5264  break;
5265 
5266  default:
5267  ereport(ERROR,
5268  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5269  errmsg("rule \"%s\" has unsupported event type %d",
5270  rulename, ev_type)));
5271  break;
5272  }
5273 
5274  /* The relation the rule is fired on */
5275  appendStringInfo(buf, " TO %s",
5276  (prettyFlags & PRETTYFLAG_SCHEMA) ?
5277  generate_relation_name(ev_class, NIL) :
5279 
5280  /* If the rule has an event qualification, add it */
5281  if (strcmp(ev_qual, "<>") != 0)
5282  {
5283  Node *qual;
5284  Query *query;
5286  deparse_namespace dpns;
5287 
5288  if (prettyFlags & PRETTYFLAG_INDENT)
5289  appendStringInfoString(buf, "\n ");
5290  appendStringInfoString(buf, " WHERE ");
5291 
5292  qual = stringToNode(ev_qual);
5293 
5294  /*
5295  * We need to make a context for recognizing any Vars in the qual
5296  * (which can only be references to OLD and NEW). Use the rtable of
5297  * the first query in the action list for this purpose.
5298  */
5299  query = (Query *) linitial(actions);
5300 
5301  /*
5302  * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5303  * into the SELECT, and that's what we need to look at. (Ugly kluge
5304  * ... try to fix this when we redesign querytrees.)
5305  */
5306  query = getInsertSelectQuery(query, NULL);
5307 
5308  /* Must acquire locks right away; see notes in get_query_def() */
5309  AcquireRewriteLocks(query, false, false);
5310 
5311  context.buf = buf;
5312  context.namespaces = list_make1(&dpns);
5313  context.windowClause = NIL;
5314  context.windowTList = NIL;
5315  context.varprefix = (list_length(query->rtable) != 1);
5316  context.prettyFlags = prettyFlags;
5317  context.wrapColumn = WRAP_COLUMN_DEFAULT;
5318  context.indentLevel = PRETTYINDENT_STD;
5319  context.special_exprkind = EXPR_KIND_NONE;
5320  context.appendparents = NULL;
5321 
5322  set_deparse_for_query(&dpns, query, NIL);
5323 
5324  get_rule_expr(qual, &context, false);
5325  }
5326 
5327  appendStringInfoString(buf, " DO ");
5328 
5329  /* The INSTEAD keyword (if so) */
5330  if (is_instead)
5331  appendStringInfoString(buf, "INSTEAD ");
5332 
5333  /* Finally the rules actions */
5334  if (list_length(actions) > 1)
5335  {
5336  ListCell *action;
5337  Query *query;
5338 
5339  appendStringInfoChar(buf, '(');
5340  foreach(action, actions)
5341  {
5342  query = (Query *) lfirst(action);
5343  get_query_def(query, buf, NIL, viewResultDesc, true,
5344  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5345  if (prettyFlags)
5346  appendStringInfoString(buf, ";\n");
5347  else
5348  appendStringInfoString(buf, "; ");
5349  }
5350  appendStringInfoString(buf, ");");
5351  }
5352  else
5353  {
5354  Query *query;
5355 
5356  query = (Query *) linitial(actions);
5357  get_query_def(query, buf, NIL, viewResultDesc, true,
5358  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5359  appendStringInfoChar(buf, ';');
5360  }
5361 
5362  table_close(ev_relation, AccessShareLock);
5363 }
static Name DatumGetName(Datum X)
Definition: postgres.h:360
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
static char DatumGetChar(Datum X)
Definition: postgres.h:112
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetDescr(relation)
Definition: rel.h:531
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
Definition: rewriteManip.c:998
static char * generate_qualified_relation_name(Oid relid)
Definition: ruleutils.c:12807
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Definition: spi.c:1172
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition: spi.c:1217
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1249
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References AccessShareLock, AcquireRewriteLocks(), generate_unaccent_rules::action, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, buf, context, DatumGetBool(), DatumGetChar(), DatumGetName(), DatumGetObjectId(), elog, ereport, errcode(), errmsg(), ERROR, EXPR_KIND_NONE, generate_qualified_relation_name(), generate_relation_name(), get_query_def(), get_rule_expr(), getInsertSelectQuery(), lfirst, linitial, list_length(), list_make1, NameStr, NIL, PRETTYFLAG_INDENT, PRETTYFLAG_SCHEMA, PRETTYINDENT_STD, quote_identifier(), RelationGetDescr, Query::rtable, set_deparse_for_query(), SPI_fnumber(), SPI_getbinval(), SPI_getvalue(), stringToNode(), table_close(), table_open(), and WRAP_COLUMN_DEFAULT.

Referenced by pg_get_ruledef_worker().

◆ make_viewdef()

static void make_viewdef ( StringInfo  buf,
HeapTuple  ruletup,
TupleDesc  rulettc,
int  prettyFlags,
int  wrapColumn 
)
static

Definition at line 5372 of file ruleutils.c.

5374 {
5375  Query *query;
5376  char ev_type;
5377  Oid ev_class;
5378  bool is_instead;
5379  char *ev_qual;
5380  char *ev_action;
5381  List *actions;
5382  Relation ev_relation;
5383  int fno;
5384  Datum dat;
5385  bool isnull;
5386 
5387  /*
5388  * Get the attribute values from the rules tuple
5389  */
5390  fno = SPI_fnumber(rulettc, "ev_type");
5391  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5392  Assert(!isnull);
5393  ev_type = DatumGetChar(dat);
5394 
5395  fno = SPI_fnumber(rulettc, "ev_class");
5396  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5397  Assert(!isnull);
5398  ev_class = DatumGetObjectId(dat);
5399 
5400  fno = SPI_fnumber(rulettc, "is_instead");
5401  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5402  Assert(!isnull);
5403  is_instead = DatumGetBool(dat);
5404 
5405  fno = SPI_fnumber(rulettc, "ev_qual");
5406  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5407  Assert(ev_qual != NULL);
5408 
5409  fno = SPI_fnumber(rulettc, "ev_action");
5410  ev_action = SPI_getvalue(ruletup, rulettc, fno);
5411  Assert(ev_action != NULL);
5412  actions = (List *) stringToNode(ev_action);
5413 
5414  if (list_length(actions) != 1)
5415  {
5416  /* keep output buffer empty and leave */
5417  return;
5418  }
5419 
5420  query = (Query *) linitial(actions);
5421 
5422  if (ev_type != '1' || !is_instead ||
5423  strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5424  {
5425  /* keep output buffer empty and leave */
5426  return;
5427  }
5428 
5429  ev_relation = table_open(ev_class, AccessShareLock);
5430 
5431  get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
5432  prettyFlags, wrapColumn, 0);
5433  appendStringInfoChar(buf, ';');
5434 
5435  table_close(ev_relation, AccessShareLock);
5436 }

References AccessShareLock, appendStringInfoChar(), Assert, buf, CMD_SELECT, Query::commandType, DatumGetBool(), DatumGetChar(), DatumGetObjectId(), get_query_def(), linitial, list_length(), NIL, RelationGetDescr, SPI_fnumber(), SPI_getbinval(), SPI_getvalue(), stringToNode(), table_close(), and table_open().

Referenced by pg_get_viewdef_worker().

◆ pg_get_constraintdef()

Datum pg_get_constraintdef ( PG_FUNCTION_ARGS  )

Definition at line 2130 of file ruleutils.c.

2131 {
2132  Oid constraintId = PG_GETARG_OID(0);
2133  int prettyFlags;
2134  char *res;
2135 
2136  prettyFlags = PRETTYFLAG_INDENT;
2137 
2138  res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2139 
2140  if (res == NULL)
2141  PG_RETURN_NULL();
2142 
2144 }
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
static text * string_to_text(char *str)
Definition: ruleutils.c:13167
static char * pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, int prettyFlags, bool missing_ok)
Definition: ruleutils.c:2177

References pg_get_constraintdef_worker(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, PRETTYFLAG_INDENT, res, and string_to_text().

◆ pg_get_constraintdef_command()

char* pg_get_constraintdef_command ( Oid  constraintId)

Definition at line 2168 of file ruleutils.c.

2169 {
2170  return pg_get_constraintdef_worker(constraintId, true, 0, false);
2171 }

References pg_get_constraintdef_worker().

Referenced by RememberConstraintForRebuilding().

◆ pg_get_constraintdef_ext()

Datum pg_get_constraintdef_ext ( PG_FUNCTION_ARGS  )

Definition at line 2147 of file ruleutils.c.

2148 {
2149  Oid constraintId = PG_GETARG_OID(0);
2150  bool pretty = PG_GETARG_BOOL(1);
2151  int prettyFlags;
2152  char *res;
2153 
2154  prettyFlags = GET_PRETTY_FLAGS(pretty);
2155 
2156  res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2157 
2158  if (res == NULL)
2159  PG_RETURN_NULL();
2160 
2162 }
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define GET_PRETTY_FLAGS(pretty)
Definition: ruleutils.c:94

References GET_PRETTY_FLAGS, pg_get_constraintdef_worker(), PG_GETARG_BOOL, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, and string_to_text().

◆ pg_get_constraintdef_worker()

static char * pg_get_constraintdef_worker ( Oid  constraintId,
bool  fullCommand,
int  prettyFlags,
bool  missing_ok 
)
static

Definition at line 2177 of file ruleutils.c.

2179 {
2180  HeapTuple tup;
2181  Form_pg_constraint conForm;
2183  SysScanDesc scandesc;
2184  ScanKeyData scankey[1];
2186  Relation relation = table_open(ConstraintRelationId, AccessShareLock);
2187 
2188  ScanKeyInit(&scankey[0],
2189  Anum_pg_constraint_oid,
2190  BTEqualStrategyNumber, F_OIDEQ,
2191  ObjectIdGetDatum(constraintId));
2192 
2193  scandesc = systable_beginscan(relation,
2194  ConstraintOidIndexId,
2195  true,
2196  snapshot,
2197  1,
2198  scankey);
2199 
2200  /*
2201  * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2202  * via SearchSysCache, which works fine.
2203  */
2204  tup = systable_getnext(scandesc);
2205 
2206  UnregisterSnapshot(snapshot);
2207 
2208  if (!HeapTupleIsValid(tup))
2209  {
2210  if (missing_ok)
2211  {
2212  systable_endscan(scandesc);
2213  table_close(relation, AccessShareLock);
2214  return NULL;
2215  }
2216  elog(ERROR, "could not find tuple for constraint %u", constraintId);
2217  }
2218 
2219  conForm = (Form_pg_constraint) GETSTRUCT(tup);
2220 
2221  initStringInfo(&buf);
2222 
2223  if (fullCommand)
2224  {
2225  if (OidIsValid(conForm->conrelid))
2226  {
2227  /*
2228  * Currently, callers want ALTER TABLE (without ONLY) for CHECK
2229  * constraints, and other types of constraints don't inherit
2230  * anyway so it doesn't matter whether we say ONLY or not. Someday
2231  * we might need to let callers specify whether to put ONLY in the
2232  * command.
2233  */
2234  appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2235  generate_qualified_relation_name(conForm->conrelid),
2236  quote_identifier(NameStr(conForm->conname)));
2237  }
2238  else
2239  {
2240  /* Must be a domain constraint */
2241  Assert(OidIsValid(conForm->contypid));
2242  appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
2243  generate_qualified_type_name(conForm->contypid),
2244  quote_identifier(NameStr(conForm->conname)));
2245  }
2246  }
2247 
2248  switch (conForm->contype)
2249  {
2250  case CONSTRAINT_FOREIGN:
2251  {
2252  Datum val;
2253  bool isnull;
2254  const char *string;
2255 
2256  /* Start off the constraint definition */
2257  appendStringInfoString(&buf, "FOREIGN KEY (");
2258 
2259  /* Fetch and build referencing-column list */
2260  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2261  Anum_pg_constraint_conkey);
2262 
2263  /* If it is a temporal foreign key then it uses PERIOD. */
2264  decompile_column_index_array(val, conForm->conrelid, conForm->conperiod, &buf);
2265 
2266  /* add foreign relation name */
2267  appendStringInfo(&buf, ") REFERENCES %s(",
2268  generate_relation_name(conForm->confrelid,
2269  NIL));
2270 
2271  /* Fetch and build referenced-column list */
2272  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2273  Anum_pg_constraint_confkey);
2274 
2275  decompile_column_index_array(val, conForm->confrelid, conForm->conperiod, &buf);
2276 
2277  appendStringInfoChar(&buf, ')');
2278 
2279  /* Add match type */
2280  switch (conForm->confmatchtype)
2281  {
2282  case FKCONSTR_MATCH_FULL:
2283  string = " MATCH FULL";
2284  break;
2286  string = " MATCH PARTIAL";
2287  break;
2288  case FKCONSTR_MATCH_SIMPLE:
2289  string = "";
2290  break;
2291  default:
2292  elog(ERROR, "unrecognized confmatchtype: %d",
2293  conForm->confmatchtype);
2294  string = ""; /* keep compiler quiet */
2295  break;
2296  }
2297  appendStringInfoString(&buf, string);
2298 
2299  /* Add ON UPDATE and ON DELETE clauses, if needed */
2300  switch (conForm->confupdtype)
2301  {
2303  string = NULL; /* suppress default */
2304  break;
2306  string = "RESTRICT";
2307  break;
2309  string = "CASCADE";
2310  break;
2312  string = "SET NULL";
2313  break;
2315  string = "SET DEFAULT";
2316  break;
2317  default:
2318  elog(ERROR, "unrecognized confupdtype: %d",
2319  conForm->confupdtype);
2320  string = NULL; /* keep compiler quiet */
2321  break;
2322  }
2323  if (string)
2324  appendStringInfo(&buf, " ON UPDATE %s", string);
2325 
2326  switch (conForm->confdeltype)
2327  {
2329  string = NULL; /* suppress default */
2330  break;
2332  string = "RESTRICT";
2333  break;
2335  string = "CASCADE";
2336  break;
2338  string = "SET NULL";
2339  break;
2341  string = "SET DEFAULT";
2342  break;
2343  default:
2344  elog(ERROR, "unrecognized confdeltype: %d",
2345  conForm->confdeltype);
2346  string = NULL; /* keep compiler quiet */
2347  break;
2348  }
2349  if (string)
2350  appendStringInfo(&buf, " ON DELETE %s", string);
2351 
2352  /*
2353  * Add columns specified to SET NULL or SET DEFAULT if
2354  * provided.
2355  */
2356  val = SysCacheGetAttr(CONSTROID, tup,
2357  Anum_pg_constraint_confdelsetcols, &isnull);
2358  if (!isnull)
2359  {
2360  appendStringInfoString(&buf, " (");
2361  decompile_column_index_array(val, conForm->conrelid, false, &buf);
2362  appendStringInfoChar(&buf, ')');
2363  }
2364 
2365  break;
2366  }
2367  case CONSTRAINT_PRIMARY:
2368  case CONSTRAINT_UNIQUE:
2369  {
2370  Datum val;
2371  Oid indexId;
2372  int keyatts;
2373  HeapTuple indtup;
2374 
2375  /* Start off the constraint definition */
2376  if (conForm->contype == CONSTRAINT_PRIMARY)
2377  appendStringInfoString(&buf, "PRIMARY KEY ");
2378  else
2379  appendStringInfoString(&buf, "UNIQUE ");
2380 
2381  indexId = conForm->conindid;
2382 
2383  indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2384  if (!HeapTupleIsValid(indtup))
2385  elog(ERROR, "cache lookup failed for index %u", indexId);
2386  if (conForm->contype == CONSTRAINT_UNIQUE &&
2387  ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
2388  appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
2389 
2390  appendStringInfoChar(&buf, '(');
2391 
2392  /* Fetch and build target column list */
2393  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2394  Anum_pg_constraint_conkey);
2395 
2396  keyatts = decompile_column_index_array(val, conForm->conrelid, false, &buf);
2397  if (conForm->conperiod)
2398  appendStringInfoString(&buf, " WITHOUT OVERLAPS");
2399 
2400  appendStringInfoChar(&buf, ')');
2401 
2402  /* Build including column list (from pg_index.indkeys) */
2403  val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2404  Anum_pg_index_indnatts);
2405  if (DatumGetInt32(val) > keyatts)
2406  {
2407  Datum cols;
2408  Datum *keys;
2409  int nKeys;
2410  int j;
2411 
2412  appendStringInfoString(&buf, " INCLUDE (");
2413 
2414  cols = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2415  Anum_pg_index_indkey);
2416 
2418  &keys, NULL, &nKeys);
2419 
2420  for (j = keyatts; j < nKeys; j++)
2421  {
2422  char *colName;
2423 
2424  colName = get_attname(conForm->conrelid,
2425  DatumGetInt16(keys[j]), false);
2426  if (j > keyatts)
2427  appendStringInfoString(&buf, ", ");
2429  }
2430 
2431  appendStringInfoChar(&buf, ')');
2432  }
2433  ReleaseSysCache(indtup);
2434 
2435  /* XXX why do we only print these bits if fullCommand? */
2436  if (fullCommand && OidIsValid(indexId))
2437  {
2438  char *options = flatten_reloptions(indexId);
2439  Oid tblspc;
2440 
2441  if (options)
2442  {
2443  appendStringInfo(&buf, " WITH (%s)", options);
2444  pfree(options);
2445  }
2446 
2447  /*
2448  * Print the tablespace, unless it's the database default.
2449  * This is to help ALTER TABLE usage of this facility,
2450  * which needs this behavior to recreate exact catalog
2451  * state.
2452  */
2453  tblspc = get_rel_tablespace(indexId);
2454  if (OidIsValid(tblspc))
2455  appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2457  }
2458 
2459  break;
2460  }
2461  case CONSTRAINT_CHECK:
2462  {
2463  Datum val;
2464  char *conbin;
2465  char *consrc;
2466  Node *expr;
2467  List *context;
2468 
2469  /* Fetch constraint expression in parsetree form */
2470  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2471  Anum_pg_constraint_conbin);
2472 
2473  conbin = TextDatumGetCString(val);
2474  expr = stringToNode(conbin);
2475 
2476  /* Set up deparsing context for Var nodes in constraint */
2477  if (conForm->conrelid != InvalidOid)
2478  {
2479  /* relation constraint */
2480  context = deparse_context_for(get_relation_name(conForm->conrelid),
2481  conForm->conrelid);
2482  }
2483  else
2484  {
2485  /* domain constraint --- can't have Vars */
2486  context = NIL;
2487  }
2488 
2489  consrc = deparse_expression_pretty(expr, context, false, false,
2490  prettyFlags, 0);
2491 
2492  /*
2493  * Now emit the constraint definition, adding NO INHERIT if
2494  * necessary.
2495  *
2496  * There are cases where the constraint expression will be
2497  * fully parenthesized and we don't need the outer parens ...
2498  * but there are other cases where we do need 'em. Be
2499  * conservative for now.
2500  *
2501  * Note that simply checking for leading '(' and trailing ')'
2502  * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2503  */
2504  appendStringInfo(&buf, "CHECK (%s)%s",
2505  consrc,
2506  conForm->connoinherit ? " NO INHERIT" : "");
2507  break;
2508  }
2509  case CONSTRAINT_NOTNULL:
2510  {
2511  if (conForm->conrelid)
2512  {
2514 
2516 
2517  appendStringInfo(&buf, "NOT NULL %s",
2518  quote_identifier(get_attname(conForm->conrelid,
2519  attnum, false)));
2520  if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
2521  appendStringInfoString(&buf, " NO INHERIT");
2522  }
2523  else if (conForm->contypid)
2524  {
2525  /* conkey is null for domain not-null constraints */
2526  appendStringInfoString(&buf, "NOT NULL");
2527  }
2528  break;
2529  }
2530 
2531  case CONSTRAINT_TRIGGER:
2532 
2533  /*
2534  * There isn't an ALTER TABLE syntax for creating a user-defined
2535  * constraint trigger, but it seems better to print something than
2536  * throw an error; if we throw error then this function couldn't
2537  * safely be applied to all rows of pg_constraint.
2538  */
2539  appendStringInfoString(&buf, "TRIGGER");
2540  break;
2541  case CONSTRAINT_EXCLUSION:
2542  {
2543  Oid indexOid = conForm->conindid;
2544  Datum val;
2545  Datum *elems;
2546  int nElems;
2547  int i;
2548  Oid *operators;
2549 
2550  /* Extract operator OIDs from the pg_constraint tuple */
2551  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2552  Anum_pg_constraint_conexclop);
2553 
2555  &elems, NULL, &nElems);
2556 
2557  operators = (Oid *) palloc(nElems * sizeof(Oid));
2558  for (i = 0; i < nElems; i++)
2559  operators[i] = DatumGetObjectId(elems[i]);
2560 
2561  /* pg_get_indexdef_worker does the rest */
2562  /* suppress tablespace because pg_dump wants it that way */
2564  pg_get_indexdef_worker(indexOid,
2565  0,
2566  operators,
2567  false,
2568  false,
2569  false,
2570  false,
2571  prettyFlags,
2572  false));
2573  break;
2574  }
2575  default:
2576  elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2577  break;
2578  }
2579 
2580  if (conForm->condeferrable)
2581  appendStringInfoString(&buf, " DEFERRABLE");
2582  if (conForm->condeferred)
2583  appendStringInfoString(&buf, " INITIALLY DEFERRED");
2584  if (!conForm->convalidated)
2585  appendStringInfoString(&buf, " NOT VALID");
2586 
2587  /* Cleanup */
2588  systable_endscan(scandesc);
2589  table_close(relation, AccessShareLock);
2590 
2591  return buf.data;
2592 }
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
Oid get_rel_tablespace(Oid relid)
Definition: lsyscache.c:2054
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:2726
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2729
#define FKCONSTR_MATCH_SIMPLE
Definition: parsenodes.h:2734
#define FKCONSTR_MATCH_PARTIAL
Definition: parsenodes.h:2733
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2727
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2728
#define FKCONSTR_MATCH_FULL
Definition: parsenodes.h:2732
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2725
AttrNumber extractNotNullColumn(HeapTuple constrTup)
FormData_pg_constraint * Form_pg_constraint
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
char string[11]
Definition: preproc-type.c:52
static int decompile_column_index_array(Datum column_index_array, Oid relId, bool withPeriod, StringInfo buf)
Definition: ruleutils.c:2601
List * deparse_context_for(const char *aliasname, Oid relid)
Definition: ruleutils.c:3685
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)
Definition: ruleutils.c:1254
static char * flatten_reloptions(Oid relid)
Definition: ruleutils.c:13235
static char * generate_qualified_type_name(Oid typid)
Definition: ruleutils.c:13102
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:836
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:510

References AccessShareLock, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, attnum, BTEqualStrategyNumber, buf, context, DatumGetArrayTypeP, DatumGetInt16(), DatumGetInt32(), DatumGetObjectId(), decompile_column_index_array(), deconstruct_array_builtin(), deparse_context_for(), deparse_expression_pretty(), elog, ERROR, extractNotNullColumn(), FKCONSTR_ACTION_CASCADE, FKCONSTR_ACTION_NOACTION, FKCONSTR_ACTION_RESTRICT, FKCONSTR_ACTION_SETDEFAULT, FKCONSTR_ACTION_SETNULL, FKCONSTR_MATCH_FULL, FKCONSTR_MATCH_PARTIAL, FKCONSTR_MATCH_SIMPLE, flatten_reloptions(), generate_qualified_relation_name(), generate_qualified_type_name(), generate_relation_name(), get_attname(), get_rel_tablespace(), get_relation_name(), get_tablespace_name(), GETSTRUCT, GetTransactionSnapshot(), HeapTupleIsValid, i, initStringInfo(), InvalidOid, j, NameStr, NIL, ObjectIdGetDatum(), OidIsValid, palloc(), pfree(), pg_get_indexdef_worker(), quote_identifier(), RegisterSnapshot(), ReleaseSysCache(), ScanKeyInit(), SearchSysCache1(), stringToNode(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, UnregisterSnapshot(), and val.

Referenced by pg_get_constraintdef(), pg_get_constraintdef_command(), and pg_get_constraintdef_ext().

◆ pg_get_expr()

Datum pg_get_expr ( PG_FUNCTION_ARGS  )

Definition at line 2655 of file ruleutils.c.

2656 {
2657  text *expr = PG_GETARG_TEXT_PP(0);
2658  Oid relid = PG_GETARG_OID(1);
2659  text *result;
2660  int prettyFlags;
2661 
2662  prettyFlags = PRETTYFLAG_INDENT;
2663 
2664  result = pg_get_expr_worker(expr, relid, prettyFlags);
2665  if (result)
2666  PG_RETURN_TEXT_P(result);
2667  else
2668  PG_RETURN_NULL();
2669 }
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
static text * pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
Definition: ruleutils.c:2690
Definition: c.h:687

References pg_get_expr_worker(), PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, and PRETTYFLAG_INDENT.

Referenced by decompile_conbin().

◆ pg_get_expr_ext()

Datum pg_get_expr_ext ( PG_FUNCTION_ARGS  )

Definition at line 2672 of file ruleutils.c.

2673 {
2674  text *expr = PG_GETARG_TEXT_PP(0);
2675  Oid relid = PG_GETARG_OID(1);
2676  bool pretty = PG_GETARG_BOOL(2);
2677  text *result;
2678  int prettyFlags;
2679 
2680  prettyFlags = GET_PRETTY_FLAGS(pretty);
2681 
2682  result = pg_get_expr_worker(expr, relid, prettyFlags);
2683  if (result)
2684  PG_RETURN_TEXT_P(result);
2685  else
2686  PG_RETURN_NULL();
2687 }

References GET_PRETTY_FLAGS, pg_get_expr_worker(), PG_GETARG_BOOL, PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_NULL, and PG_RETURN_TEXT_P.

◆ pg_get_expr_worker()

static text * pg_get_expr_worker ( text expr,
Oid  relid,
int  prettyFlags 
)
static

Definition at line 2690 of file ruleutils.c.

2691 {
2692  Node *node;
2693  Node *tst;
2694  Relids relids;
2695  List *context;
2696  char *exprstr;
2697  Relation rel = NULL;
2698  char *str;
2699 
2700  /* Convert input pg_node_tree (really TEXT) object to C string */
2701  exprstr = text_to_cstring(expr);
2702 
2703  /* Convert expression to node tree */
2704  node = (Node *) stringToNode(exprstr);
2705 
2706  pfree(exprstr);
2707 
2708  /*
2709  * Throw error if the input is a querytree rather than an expression tree.
2710  * While we could support queries here, there seems no very good reason
2711  * to. In most such catalog columns, we'll see a List of Query nodes, or
2712  * even nested Lists, so drill down to a non-List node before checking.
2713  */
2714  tst = node;
2715  while (tst && IsA(tst, List))
2716  tst = linitial((List *) tst);
2717  if (tst && IsA(tst, Query))
2718  ereport(ERROR,
2719  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2720  errmsg("input is a query, not an expression")));
2721 
2722  /*
2723  * Throw error if the expression contains Vars we won't be able to
2724  * deparse.
2725  */
2726  relids = pull_varnos(NULL, node);
2727  if (OidIsValid(relid))
2728  {
2729  if (!bms_is_subset(relids, bms_make_singleton(1)))
2730  ereport(ERROR,
2731  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2732  errmsg("expression contains variables of more than one relation")));
2733  }
2734  else
2735  {
2736  if (!bms_is_empty(relids))
2737  ereport(ERROR,
2738  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2739  errmsg("expression contains variables")));
2740  }
2741 
2742  /*
2743  * Prepare deparse context if needed. If we are deparsing with a relid,
2744  * we need to transiently open and lock the rel, to make sure it won't go
2745  * away underneath us. (set_relation_column_names would lock it anyway,
2746  * so this isn't really introducing any new behavior.)
2747  */
2748  if (OidIsValid(relid))
2749  {
2750  rel = try_relation_open(relid, AccessShareLock);
2751  if (rel == NULL)
2752  return NULL;
2754  }
2755  else
2756  context = NIL;
2757 
2758  /* Deparse */
2759  str = deparse_expression_pretty(node, context, false, false,
2760  prettyFlags, 0);
2761 
2762  if (rel != NULL)
2764 
2765  return string_to_text(str);
2766 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
#define bms_is_empty(a)
Definition: bitmapset.h:118
#define RelationGetRelationName(relation)
Definition: rel.h:539
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:88
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:108
char * text_to_cstring(const text *t)
Definition: varlena.c:217

References AccessShareLock, bms_is_empty, bms_is_subset(), bms_make_singleton(), context, deparse_context_for(), deparse_expression_pretty(), ereport, errcode(), errmsg(), ERROR, IsA, linitial, NIL, OidIsValid, pfree(), pull_varnos(), relation_close(), RelationGetRelationName, str, string_to_text(), stringToNode(), text_to_cstring(), and try_relation_open().

Referenced by pg_get_expr(), and pg_get_expr_ext().

◆ pg_get_function_arg_default()

Datum pg_get_function_arg_default ( PG_FUNCTION_ARGS  )

Definition at line 3466 of file ruleutils.c.

3467 {
3468  Oid funcid = PG_GETARG_OID(0);
3469  int32 nth_arg = PG_GETARG_INT32(1);
3470  HeapTuple proctup;
3471  Form_pg_proc proc;
3472  int numargs;
3473  Oid *argtypes;
3474  char **argnames;
3475  char *argmodes;
3476  int i;
3477  List *argdefaults;
3478  Node *node;
3479  char *str;
3480  int nth_inputarg;
3481  Datum proargdefaults;
3482  bool isnull;
3483  int nth_default;
3484 
3485  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3486  if (!HeapTupleIsValid(proctup))
3487  PG_RETURN_NULL();
3488 
3489  numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3490  if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3491  {
3492  ReleaseSysCache(proctup);
3493  PG_RETURN_NULL();
3494  }
3495 
3496  nth_inputarg = 0;
3497  for (i = 0; i < nth_arg; i++)
3498  if (is_input_argument(i, argmodes))
3499  nth_inputarg++;
3500 
3501  proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3502  Anum_pg_proc_proargdefaults,
3503  &isnull);
3504  if (isnull)
3505  {
3506  ReleaseSysCache(proctup);
3507  PG_RETURN_NULL();
3508  }
3509 
3510  str = TextDatumGetCString(proargdefaults);
3511  argdefaults = castNode(List, stringToNode(str));
3512  pfree(str);
3513 
3514  proc = (Form_pg_proc) GETSTRUCT(proctup);
3515 
3516  /*
3517  * Calculate index into proargdefaults: proargdefaults corresponds to the
3518  * last N input arguments, where N = pronargdefaults.
3519  */
3520  nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3521 
3522  if (nth_default < 0 || nth_default >= list_length(argdefaults))
3523  {
3524  ReleaseSysCache(proctup);
3525  PG_RETURN_NULL();
3526  }
3527  node = list_nth(argdefaults, nth_default);
3528  str = deparse_expression(node, NIL, false, false);
3529 
3530  ReleaseSysCache(proctup);
3531 
3533 }
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1379
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3625
static bool is_input_argument(int nth, const char *argmodes)
Definition: ruleutils.c:3426

References castNode, deparse_expression(), get_func_arg_info(), GETSTRUCT, HeapTupleIsValid, i, is_input_argument(), list_length(), list_nth(), NIL, ObjectIdGetDatum(), pfree(), PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, ReleaseSysCache(), SearchSysCache1(), str, string_to_text(), stringToNode(), SysCacheGetAttr(), and TextDatumGetCString.

◆ pg_get_function_arguments()

Datum pg_get_function_arguments ( PG_FUNCTION_ARGS  )

Definition at line 3159 of file ruleutils.c.

3160 {
3161  Oid funcid = PG_GETARG_OID(0);
3163  HeapTuple proctup;
3164 
3165  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3166  if (!HeapTupleIsValid(proctup))
3167  PG_RETURN_NULL();
3168 
3169  initStringInfo(&buf);
3170 
3171  (void) print_function_arguments(&buf, proctup, false, true);
3172 
3173  ReleaseSysCache(proctup);
3174 
3176 }
static int print_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults)
Definition: ruleutils.c:3278

References buf, HeapTupleIsValid, initStringInfo(), ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, print_function_arguments(), ReleaseSysCache(), SearchSysCache1(), and string_to_text().

◆ pg_get_function_identity_arguments()

Datum pg_get_function_identity_arguments ( PG_FUNCTION_ARGS  )

Definition at line 3185 of file ruleutils.c.

3186 {
3187  Oid funcid = PG_GETARG_OID(0);
3189  HeapTuple proctup;
3190 
3191  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3192  if (!HeapTupleIsValid(proctup))
3193  PG_RETURN_NULL();
3194 
3195  initStringInfo(&buf);
3196 
3197  (void) print_function_arguments(&buf, proctup, false, false);
3198 
3199  ReleaseSysCache(proctup);
3200 
3202 }

References buf, HeapTupleIsValid, initStringInfo(), ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, print_function_arguments(), ReleaseSysCache(), SearchSysCache1(), and string_to_text().

◆ pg_get_function_result()

Datum pg_get_function_result ( PG_FUNCTION_ARGS  )

Definition at line 3210 of file ruleutils.c.

3211 {
3212  Oid funcid = PG_GETARG_OID(0);
3214  HeapTuple proctup;
3215 
3216  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3217  if (!HeapTupleIsValid(proctup))
3218  PG_RETURN_NULL();
3219 
3220  if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3221  {
3222  ReleaseSysCache(proctup);
3223  PG_RETURN_NULL();
3224  }
3225 
3226  initStringInfo(&buf);
3227 
3228  print_function_rettype(&buf, proctup);
3229 
3230  ReleaseSysCache(proctup);
3231 
3233 }
static void print_function_rettype(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3240

References buf, GETSTRUCT, HeapTupleIsValid, initStringInfo(), ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, print_function_rettype(), ReleaseSysCache(), SearchSysCache1(), and string_to_text().

◆ pg_get_function_sqlbody()

Datum pg_get_function_sqlbody ( PG_FUNCTION_ARGS  )

Definition at line 3590 of file ruleutils.c.

3591 {
3592  Oid funcid = PG_GETARG_OID(0);
3594  HeapTuple proctup;
3595  bool isnull;
3596 
3597  initStringInfo(&buf);
3598 
3599  /* Look up the function */
3600  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3601  if (!HeapTupleIsValid(proctup))
3602  PG_RETURN_NULL();
3603 
3604  (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3605  if (isnull)
3606  {
3607  ReleaseSysCache(proctup);
3608  PG_RETURN_NULL();
3609  }
3610 
3611  print_function_sqlbody(&buf, proctup);
3612 
3613  ReleaseSysCache(proctup);
3614 
3616 }
static void print_function_sqlbody(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3536
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:196

References buf, cstring_to_text_with_len(), HeapTupleIsValid, initStringInfo(), ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, print_function_sqlbody(), ReleaseSysCache(), SearchSysCache1(), and SysCacheGetAttr().

◆ pg_get_functiondef()

Datum pg_get_functiondef ( PG_FUNCTION_ARGS  )

Definition at line 2907 of file ruleutils.c.

2908 {
2909  Oid funcid = PG_GETARG_OID(0);
2911  StringInfoData dq;
2912  HeapTuple proctup;
2913  Form_pg_proc proc;
2914  bool isfunction;
2915  Datum tmp;
2916  bool isnull;
2917  const char *prosrc;
2918  const char *name;
2919  const char *nsp;
2920  float4 procost;
2921  int oldlen;
2922 
2923  initStringInfo(&buf);
2924 
2925  /* Look up the function */
2926  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2927  if (!HeapTupleIsValid(proctup))
2928  PG_RETURN_NULL();
2929 
2930  proc = (Form_pg_proc) GETSTRUCT(proctup);
2931  name = NameStr(proc->proname);
2932 
2933  if (proc->prokind == PROKIND_AGGREGATE)
2934  ereport(ERROR,
2935  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2936  errmsg("\"%s\" is an aggregate function", name)));
2937 
2938  isfunction = (proc->prokind != PROKIND_PROCEDURE);
2939 
2940  /*
2941  * We always qualify the function name, to ensure the right function gets
2942  * replaced.
2943  */
2944  nsp = get_namespace_name_or_temp(proc->pronamespace);
2945  appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
2946  isfunction ? "FUNCTION" : "PROCEDURE",
2948  (void) print_function_arguments(&buf, proctup, false, true);
2949  appendStringInfoString(&buf, ")\n");
2950  if (isfunction)
2951  {
2952  appendStringInfoString(&buf, " RETURNS ");
2953  print_function_rettype(&buf, proctup);
2954  appendStringInfoChar(&buf, '\n');
2955  }
2956 
2957  print_function_trftypes(&buf, proctup);
2958 
2959  appendStringInfo(&buf, " LANGUAGE %s\n",
2960  quote_identifier(get_language_name(proc->prolang, false)));
2961 
2962  /* Emit some miscellaneous options on one line */
2963  oldlen = buf.len;
2964 
2965  if (proc->prokind == PROKIND_WINDOW)
2966  appendStringInfoString(&buf, " WINDOW");
2967  switch (proc->provolatile)
2968  {
2969  case PROVOLATILE_IMMUTABLE:
2970  appendStringInfoString(&buf, " IMMUTABLE");
2971  break;
2972  case PROVOLATILE_STABLE:
2973  appendStringInfoString(&buf, " STABLE");
2974  break;
2975  case PROVOLATILE_VOLATILE:
2976  break;
2977  }
2978 
2979  switch (proc->proparallel)
2980  {
2981  case PROPARALLEL_SAFE:
2982  appendStringInfoString(&buf, " PARALLEL SAFE");
2983  break;
2984  case PROPARALLEL_RESTRICTED:
2985  appendStringInfoString(&buf, " PARALLEL RESTRICTED");
2986  break;
2987  case PROPARALLEL_UNSAFE:
2988  break;
2989  }
2990 
2991  if (proc->proisstrict)
2992  appendStringInfoString(&buf, " STRICT");
2993  if (proc->prosecdef)
2994  appendStringInfoString(&buf, " SECURITY DEFINER");
2995  if (proc->proleakproof)
2996  appendStringInfoString(&buf, " LEAKPROOF");
2997 
2998  /* This code for the default cost and rows should match functioncmds.c */
2999  if (proc->prolang == INTERNALlanguageId ||
3000  proc->prolang == ClanguageId)
3001  procost = 1;
3002  else
3003  procost = 100;
3004  if (proc->procost != procost)
3005  appendStringInfo(&buf, " COST %g", proc->procost);
3006 
3007  if (proc->prorows > 0 && proc->prorows != 1000)
3008  appendStringInfo(&buf, " ROWS %g", proc->prorows);
3009 
3010  if (proc->prosupport)
3011  {
3012  Oid argtypes[1];
3013 
3014  /*
3015  * We should qualify the support function's name if it wouldn't be
3016  * resolved by lookup in the current search path.
3017  */
3018  argtypes[0] = INTERNALOID;
3019  appendStringInfo(&buf, " SUPPORT %s",
3020  generate_function_name(proc->prosupport, 1,
3021  NIL, argtypes,
3022  false, NULL, EXPR_KIND_NONE));
3023  }
3024 
3025  if (oldlen != buf.len)
3026  appendStringInfoChar(&buf, '\n');
3027 
3028  /* Emit any proconfig options, one per line */
3029  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
3030  if (!isnull)
3031  {
3032  ArrayType *a = DatumGetArrayTypeP(tmp);
3033  int i;
3034 
3035  Assert(ARR_ELEMTYPE(a) == TEXTOID);
3036  Assert(ARR_NDIM(a) == 1);
3037  Assert(ARR_LBOUND(a)[0] == 1);
3038 
3039  for (i = 1; i <= ARR_DIMS(a)[0]; i++)
3040  {
3041  Datum d;
3042 
3043  d = array_ref(a, 1, &i,
3044  -1 /* varlenarray */ ,
3045  -1 /* TEXT's typlen */ ,
3046  false /* TEXT's typbyval */ ,
3047  TYPALIGN_INT /* TEXT's typalign */ ,
3048  &isnull);
3049  if (!isnull)
3050  {
3051  char *configitem = TextDatumGetCString(d);
3052  char *pos;
3053 
3054  pos = strchr(configitem, '=');
3055  if (pos == NULL)
3056  continue;
3057  *pos++ = '\0';
3058 
3059  appendStringInfo(&buf, " SET %s TO ",
3060  quote_identifier(configitem));
3061 
3062  /*
3063  * Variables that are marked GUC_LIST_QUOTE were already fully
3064  * quoted by flatten_set_variable_args() before they were put
3065  * into the proconfig array. However, because the quoting
3066  * rules used there aren't exactly like SQL's, we have to
3067  * break the list value apart and then quote the elements as
3068  * string literals. (The elements may be double-quoted as-is,
3069  * but we can't just feed them to the SQL parser; it would do
3070  * the wrong thing with elements that are zero-length or
3071  * longer than NAMEDATALEN.)
3072  *
3073  * Variables that are not so marked should just be emitted as
3074  * simple string literals. If the variable is not known to
3075  * guc.c, we'll do that; this makes it unsafe to use
3076  * GUC_LIST_QUOTE for extension variables.
3077  */
3078  if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
3079  {
3080  List *namelist;
3081  ListCell *lc;
3082 
3083  /* Parse string into list of identifiers */
3084  if (!SplitGUCList(pos, ',', &namelist))
3085  {
3086  /* this shouldn't fail really */
3087  elog(ERROR, "invalid list syntax in proconfig item");
3088  }
3089  foreach(lc, namelist)
3090  {
3091  char *curname = (char *) lfirst(lc);
3092 
3093  simple_quote_literal(&buf, curname);
3094  if (lnext(namelist, lc))
3095  appendStringInfoString(&buf, ", ");
3096  }
3097  }
3098  else
3099  simple_quote_literal(&buf, pos);
3100  appendStringInfoChar(&buf, '\n');
3101  }
3102  }
3103  }
3104 
3105  /* And finally the function definition ... */
3106  (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3107  if (proc->prolang == SQLlanguageId && !isnull)
3108  {
3109  print_function_sqlbody(&buf, proctup);
3110  }
3111  else
3112  {
3113  appendStringInfoString(&buf, "AS ");
3114 
3115  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
3116  if (!isnull)
3117  {
3119  appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
3120  }
3121 
3122  tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosrc);
3123  prosrc = TextDatumGetCString(tmp);
3124 
3125  /*
3126  * We always use dollar quoting. Figure out a suitable delimiter.
3127  *
3128  * Since the user is likely to be editing the function body string, we
3129  * shouldn't use a short delimiter that he might easily create a
3130  * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3131  * if needed.
3132  */
3133  initStringInfo(&dq);
3134  appendStringInfoChar(&dq, '$');
3135  appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3136  while (strstr(prosrc, dq.data) != NULL)
3137  appendStringInfoChar(&dq, 'x');
3138  appendStringInfoChar(&dq, '$');
3139 
3140  appendBinaryStringInfo(&buf, dq.data, dq.len);
3141  appendStringInfoString(&buf, prosrc);
3142  appendBinaryStringInfo(&buf, dq.data, dq.len);
3143  }
3144 
3145  appendStringInfoChar(&buf, '\n');
3146 
3147  ReleaseSysCache(proctup);
3148 
3150 }
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_LBOUND(a)
Definition: array.h:296
Datum array_ref(ArrayType *array, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:3139
float float4
Definition: c.h:629
int GetConfigOptionFlags(const char *name, bool missing_ok)
Definition: guc.c:4395
#define GUC_LIST_QUOTE
Definition: guc.h:211
int a
Definition: isn.c:69
char * get_language_name(Oid langoid, bool missing_ok)
Definition: lsyscache.c:1161
static void print_function_trftypes(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3438
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3705

References a, appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_ref(), Assert, buf, StringInfoData::data, DatumGetArrayTypeP, elog, ereport, errcode(), errmsg(), ERROR, EXPR_KIND_NONE, generate_function_name(), get_language_name(), get_namespace_name_or_temp(), GetConfigOptionFlags(), GETSTRUCT, GUC_LIST_QUOTE, HeapTupleIsValid, i, initStringInfo(), StringInfoData::len, lfirst, lnext(), name, NameStr, NIL, ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, print_function_arguments(), print_function_rettype(), print_function_sqlbody(), print_function_trftypes(), quote_identifier(), quote_qualified_identifier(), ReleaseSysCache(), SearchSysCache1(), simple_quote_literal(), SplitGUCList(), string_to_text(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), and TextDatumGetCString.

◆ pg_get_indexdef()

Datum pg_get_indexdef ( PG_FUNCTION_ARGS  )

Definition at line 1162 of file ruleutils.c.

1163 {
1164  Oid indexrelid = PG_GETARG_OID(0);
1165  int prettyFlags;
1166  char *res;
1167 
1168  prettyFlags = PRETTYFLAG_INDENT;
1169 
1170  res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1171  false, false,
1172  false, false,
1173  prettyFlags, true);
1174 
1175  if (res == NULL)
1176  PG_RETURN_NULL();
1177 
1179 }

References pg_get_indexdef_worker(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, PRETTYFLAG_INDENT, res, and string_to_text().

◆ pg_get_indexdef_columns()

char* pg_get_indexdef_columns ( Oid  indexrelid,
bool  pretty 
)

Definition at line 1219 of file ruleutils.c.

1220 {
1221  int prettyFlags;
1222 
1223  prettyFlags = GET_PRETTY_FLAGS(pretty);
1224 
1225  return pg_get_indexdef_worker(indexrelid, 0, NULL,
1226  true, true,
1227  false, false,
1228  prettyFlags, false);
1229 }

References GET_PRETTY_FLAGS, and pg_get_indexdef_worker().

Referenced by BuildIndexValueDescription().

◆ pg_get_indexdef_columns_extended()

char* pg_get_indexdef_columns_extended ( Oid  indexrelid,
bits16  flags 
)

Definition at line 1233 of file ruleutils.c.

1234 {
1235  bool pretty = ((flags & RULE_INDEXDEF_PRETTY) != 0);
1236  bool keys_only = ((flags & RULE_INDEXDEF_KEYS_ONLY) != 0);
1237  int prettyFlags;
1238 
1239  prettyFlags = GET_PRETTY_FLAGS(pretty);
1240 
1241  return pg_get_indexdef_worker(indexrelid, 0, NULL,
1242  true, keys_only,
1243  false, false,
1244  prettyFlags, false);
1245 }
#define RULE_INDEXDEF_PRETTY
Definition: ruleutils.h:24
#define RULE_INDEXDEF_KEYS_ONLY
Definition: ruleutils.h:25

References GET_PRETTY_FLAGS, pg_get_indexdef_worker(), RULE_INDEXDEF_KEYS_ONLY, and RULE_INDEXDEF_PRETTY.

Referenced by gist_page_items().

◆ pg_get_indexdef_ext()

Datum pg_get_indexdef_ext ( PG_FUNCTION_ARGS  )

Definition at line 1182 of file ruleutils.c.

1183 {
1184  Oid indexrelid = PG_GETARG_OID(0);
1185  int32 colno = PG_GETARG_INT32(1);
1186  bool pretty = PG_GETARG_BOOL(2);
1187  int prettyFlags;
1188  char *res;
1189 
1190  prettyFlags = GET_PRETTY_FLAGS(pretty);
1191 
1192  res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1193  colno != 0, false,
1194  false, false,
1195  prettyFlags, true);
1196 
1197  if (res == NULL)
1198  PG_RETURN_NULL();
1199 
1201 }

References GET_PRETTY_FLAGS, pg_get_indexdef_worker(), PG_GETARG_BOOL, PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, and string_to_text().

◆ pg_get_indexdef_string()

char* pg_get_indexdef_string ( Oid  indexrelid)

Definition at line 1209 of file ruleutils.c.

1210 {
1211  return pg_get_indexdef_worker(indexrelid, 0, NULL,
1212  false, false,
1213  true, true,
1214  0, false);
1215 }

References pg_get_indexdef_worker().

Referenced by RememberIndexForRebuilding().

◆ pg_get_indexdef_worker()

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

Definition at line 1254 of file ruleutils.c.

1259 {
1260  /* might want a separate isConstraint parameter later */
1261  bool isConstraint = (excludeOps != NULL);
1262  HeapTuple ht_idx;
1263  HeapTuple ht_idxrel;
1264  HeapTuple ht_am;
1265  Form_pg_index idxrec;
1266  Form_pg_class idxrelrec;
1267  Form_pg_am amrec;
1268  IndexAmRoutine *amroutine;
1269  List *indexprs;
1270  ListCell *indexpr_item;
1271  List *context;
1272  Oid indrelid;
1273  int keyno;
1274  Datum indcollDatum;
1275  Datum indclassDatum;
1276  Datum indoptionDatum;
1277  oidvector *indcollation;
1278  oidvector *indclass;
1279  int2vector *indoption;
1281  char *str;
1282  char *sep;
1283 
1284  /*
1285  * Fetch the pg_index tuple by the Oid of the index
1286  */
1287  ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
1288  if (!HeapTupleIsValid(ht_idx))
1289  {
1290  if (missing_ok)
1291  return NULL;
1292  elog(ERROR, "cache lookup failed for index %u", indexrelid);
1293  }
1294  idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1295 
1296  indrelid = idxrec->indrelid;
1297  Assert(indexrelid == idxrec->indexrelid);
1298 
1299  /* Must get indcollation, indclass, and indoption the hard way */
1300  indcollDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1301  Anum_pg_index_indcollation);
1302  indcollation = (oidvector *) DatumGetPointer(indcollDatum);
1303 
1304  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1305  Anum_pg_index_indclass);
1306  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1307 
1308  indoptionDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1309  Anum_pg_index_indoption);
1310  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1311 
1312  /*
1313  * Fetch the pg_class tuple of the index relation
1314  */
1315  ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
1316  if (!HeapTupleIsValid(ht_idxrel))
1317  elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1318  idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1319 
1320  /*
1321  * Fetch the pg_am tuple of the index' access method
1322  */
1323  ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1324  if (!HeapTupleIsValid(ht_am))
1325  elog(ERROR, "cache lookup failed for access method %u",
1326  idxrelrec->relam);
1327  amrec = (Form_pg_am) GETSTRUCT(ht_am);
1328 
1329  /* Fetch the index AM's API struct */
1330  amroutine = GetIndexAmRoutine(amrec->amhandler);
1331 
1332  /*
1333  * Get the index expressions, if any. (NOTE: we do not use the relcache
1334  * versions of the expressions and predicate, because we want to display
1335  * non-const-folded expressions.)
1336  */
1337  if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
1338  {
1339  Datum exprsDatum;
1340  char *exprsString;
1341 
1342  exprsDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1343  Anum_pg_index_indexprs);
1344  exprsString = TextDatumGetCString(exprsDatum);
1345  indexprs = (List *) stringToNode(exprsString);
1346  pfree(exprsString);
1347  }
1348  else
1349  indexprs = NIL;
1350 
1351  indexpr_item = list_head(indexprs);
1352 
1353  context = deparse_context_for(get_relation_name(indrelid), indrelid);
1354 
1355  /*
1356  * Start the index definition. Note that the index's name should never be
1357  * schema-qualified, but the indexed rel's name may be.
1358  */
1359  initStringInfo(&buf);
1360 
1361  if (!attrsOnly)
1362  {
1363  if (!isConstraint)
1364  appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
1365  idxrec->indisunique ? "UNIQUE " : "",
1366  quote_identifier(NameStr(idxrelrec->relname)),
1367  idxrelrec->relkind == RELKIND_PARTITIONED_INDEX
1368  && !inherits ? "ONLY " : "",
1369  (prettyFlags & PRETTYFLAG_SCHEMA) ?
1370  generate_relation_name(indrelid, NIL) :
1372  quote_identifier(NameStr(amrec->amname)));
1373  else /* currently, must be EXCLUDE constraint */
1374  appendStringInfo(&buf, "EXCLUDE USING %s (",
1375  quote_identifier(NameStr(amrec->amname)));
1376  }
1377 
1378  /*
1379  * Report the indexed attributes
1380  */
1381  sep = "";
1382  for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1383  {
1384  AttrNumber attnum = idxrec->indkey.values[keyno];
1385  Oid keycoltype;
1386  Oid keycolcollation;
1387 
1388  /*
1389  * Ignore non-key attributes if told to.
1390  */
1391  if (keysOnly && keyno >= idxrec->indnkeyatts)
1392  break;
1393 
1394  /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1395  if (!colno && keyno == idxrec->indnkeyatts)
1396  {
1397  appendStringInfoString(&buf, ") INCLUDE (");
1398  sep = "";
1399  }
1400 
1401  if (!colno)
1402  appendStringInfoString(&buf, sep);
1403  sep = ", ";
1404 
1405  if (attnum != 0)
1406  {
1407  /* Simple index column */
1408  char *attname;
1409  int32 keycoltypmod;
1410 
1411  attname = get_attname(indrelid, attnum, false);
1412  if (!colno || colno == keyno + 1)
1414  get_atttypetypmodcoll(indrelid, attnum,
1415  &keycoltype, &keycoltypmod,
1416  &keycolcollation);
1417  }
1418  else
1419  {
1420  /* expressional index */
1421  Node *indexkey;
1422 
1423  if (indexpr_item == NULL)
1424  elog(ERROR, "too few entries in indexprs list");
1425  indexkey = (Node *) lfirst(indexpr_item);
1426  indexpr_item = lnext(indexprs, indexpr_item);
1427  /* Deparse */
1428  str = deparse_expression_pretty(indexkey, context, false, false,
1429  prettyFlags, 0);
1430  if (!colno || colno == keyno + 1)
1431  {
1432  /* Need parens if it's not a bare function call */
1433  if (looks_like_function(indexkey))
1435  else
1436  appendStringInfo(&buf, "(%s)", str);
1437  }
1438  keycoltype = exprType(indexkey);
1439  keycolcollation = exprCollation(indexkey);
1440  }
1441 
1442  /* Print additional decoration for (selected) key columns */
1443  if (!attrsOnly && keyno < idxrec->indnkeyatts &&
1444  (!colno || colno == keyno + 1))
1445  {
1446  int16 opt = indoption->values[keyno];
1447  Oid indcoll = indcollation->values[keyno];
1448  Datum attoptions = get_attoptions(indexrelid, keyno + 1);
1449  bool has_options = attoptions != (Datum) 0;
1450 
1451  /* Add collation, if not default for column */
1452  if (OidIsValid(indcoll) && indcoll != keycolcollation)
1453  appendStringInfo(&buf, " COLLATE %s",
1454  generate_collation_name((indcoll)));
1455 
1456  /* Add the operator class name, if not default */
1457  get_opclass_name(indclass->values[keyno],
1458  has_options ? InvalidOid : keycoltype, &buf);
1459 
1460  if (has_options)
1461  {
1462  appendStringInfoString(&buf, " (");
1463  get_reloptions(&buf, attoptions);
1464  appendStringInfoChar(&buf, ')');
1465  }
1466 
1467  /* Add options if relevant */
1468  if (amroutine->amcanorder)
1469  {
1470  /* if it supports sort ordering, report DESC and NULLS opts */
1471  if (opt & INDOPTION_DESC)
1472  {
1473  appendStringInfoString(&buf, " DESC");
1474  /* NULLS FIRST is the default in this case */
1475  if (!(opt & INDOPTION_NULLS_FIRST))
1476  appendStringInfoString(&buf, " NULLS LAST");
1477  }
1478  else
1479  {
1480  if (opt & INDOPTION_NULLS_FIRST)
1481  appendStringInfoString(&buf, " NULLS FIRST");
1482  }
1483  }
1484 
1485  /* Add the exclusion operator if relevant */
1486  if (excludeOps != NULL)
1487  appendStringInfo(&buf, " WITH %s",
1488  generate_operator_name(excludeOps[keyno],
1489  keycoltype,
1490  keycoltype));
1491  }
1492  }
1493 
1494  if (!attrsOnly)
1495  {
1496  appendStringInfoChar(&buf, ')');
1497 
1498  if (idxrec->indnullsnotdistinct)
1499  appendStringInfoString(&buf, " NULLS NOT DISTINCT");
1500 
1501  /*
1502  * If it has options, append "WITH (options)"
1503  */
1504  str = flatten_reloptions(indexrelid);
1505  if (str)
1506  {
1507  appendStringInfo(&buf, " WITH (%s)", str);
1508  pfree(str);
1509  }
1510 
1511  /*
1512  * Print tablespace, but only if requested
1513  */
1514  if (showTblSpc)
1515  {
1516  Oid tblspc;
1517 
1518  tblspc = get_rel_tablespace(indexrelid);
1519  if (OidIsValid(tblspc))
1520  {
1521  if (isConstraint)
1522  appendStringInfoString(&buf, " USING INDEX");
1523  appendStringInfo(&buf, " TABLESPACE %s",
1525  }
1526  }
1527 
1528  /*
1529  * If it's a partial index, decompile and append the predicate
1530  */
1531  if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
1532  {
1533  Node *node;
1534  Datum predDatum;
1535  char *predString;
1536 
1537  /* Convert text string to node tree */
1538  predDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1539  Anum_pg_index_indpred);
1540  predString = TextDatumGetCString(predDatum);
1541  node = (Node *) stringToNode(predString);
1542  pfree(predString);
1543 
1544  /* Deparse */
1545  str = deparse_expression_pretty(node, context, false, false,
1546  prettyFlags, 0);
1547  if (isConstraint)
1548  appendStringInfo(&buf, " WHERE (%s)", str);
1549  else
1550  appendStringInfo(&buf, " WHERE %s", str);
1551  }
1552  }
1553 
1554  /* Clean up */
1555  ReleaseSysCache(ht_idx);
1556  ReleaseSysCache(ht_idxrel);
1557  ReleaseSysCache(ht_am);
1558 
1559  return buf.data;
1560 }
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
signed short int16
Definition: c.h:493
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod, Oid *collid)
Definition: lsyscache.c:943
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
bool amcanorder
Definition: amapi.h:223
Definition: c.h:715
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:722
Definition: c.h:726
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:733

References IndexAmRoutine::amcanorder, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, attname, attnum, buf, context, DatumGetPointer(), deparse_context_for(), deparse_expression_pretty(), elog, ERROR, exprCollation(), exprType(), flatten_reloptions(), generate_collation_name(), generate_operator_name(), generate_qualified_relation_name(), generate_relation_name(), get_attname(), get_attoptions(), get_atttypetypmodcoll(), get_opclass_name(), get_rel_tablespace(), get_relation_name(), get_reloptions(), get_tablespace_name(), GetIndexAmRoutine(), GETSTRUCT, heap_attisnull(), HeapTupleIsValid, initStringInfo(), InvalidOid, lfirst, list_head(), lnext(), looks_like_function(), NameStr, NIL, ObjectIdGetDatum(), OidIsValid, pfree(), PRETTYFLAG_SCHEMA, quote_identifier(), ReleaseSysCache(), SearchSysCache1(), str, stringToNode(), SysCacheGetAttrNotNull(), TextDatumGetCString, int2vector::values, and oidvector::values.

Referenced by pg_get_constraintdef_worker(), pg_get_indexdef(), pg_get_indexdef_columns(), pg_get_indexdef_columns_extended(), pg_get_indexdef_ext(), and pg_get_indexdef_string().

◆ pg_get_partconstrdef_string()

char* pg_get_partconstrdef_string ( Oid  partitionId,
char *  aliasname 
)

Definition at line 2112 of file ruleutils.c.

2113 {
2114  Expr *constr_expr;
2115  List *context;
2116 
2117  constr_expr = get_partition_qual_relid(partitionId);
2118  context = deparse_context_for(aliasname, partitionId);
2119 
2120  return deparse_expression((Node *) constr_expr, context, true, false);
2121 }
Expr * get_partition_qual_relid(Oid relid)
Definition: partcache.c:299

References context, deparse_context_for(), deparse_expression(), and get_partition_qual_relid().

Referenced by RI_PartitionRemove_Check().

◆ pg_get_partition_constraintdef()

Datum pg_get_partition_constraintdef ( PG_FUNCTION_ARGS  )

Definition at line 2080 of file ruleutils.c.

2081 {
2082  Oid relationId = PG_GETARG_OID(0);
2083  Expr *constr_expr;
2084  int prettyFlags;
2085  List *context;
2086  char *consrc;
2087 
2088  constr_expr = get_partition_qual_relid(relationId);
2089 
2090  /* Quick exit if no partition constraint */
2091  if (constr_expr == NULL)
2092  PG_RETURN_NULL();
2093 
2094  /*
2095  * Deparse and return the constraint expression.
2096  */
2097  prettyFlags = PRETTYFLAG_INDENT;
2098  context = deparse_context_for(get_relation_name(relationId), relationId);
2099  consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2100  false, prettyFlags, 0);
2101 
2103 }

References context, deparse_context_for(), deparse_expression_pretty(), get_partition_qual_relid(), get_relation_name(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, PRETTYFLAG_INDENT, and string_to_text().

◆ pg_get_partkeydef()

Datum pg_get_partkeydef ( PG_FUNCTION_ARGS  )

Definition at line 1893 of file ruleutils.c.

1894 {
1895  Oid relid = PG_GETARG_OID(0);
1896  char *res;
1897 
1898  res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1899 
1900  if (res == NULL)
1901  PG_RETURN_NULL();
1902 
1904 }
static char * pg_get_partkeydef_worker(Oid relid, int prettyFlags, bool attrsOnly, bool missing_ok)
Definition: ruleutils.c:1921

References pg_get_partkeydef_worker(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, PRETTYFLAG_INDENT, res, and string_to_text().

◆ pg_get_partkeydef_columns()

char* pg_get_partkeydef_columns ( Oid  relid,
bool  pretty 
)

Definition at line 1908 of file ruleutils.c.

1909 {
1910  int prettyFlags;
1911 
1912  prettyFlags = GET_PRETTY_FLAGS(pretty);
1913 
1914  return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1915 }

References GET_PRETTY_FLAGS, and pg_get_partkeydef_worker().

Referenced by ExecBuildSlotPartitionKeyDescription().

◆ pg_get_partkeydef_worker()

static char * pg_get_partkeydef_worker ( Oid  relid,
int  prettyFlags,
bool  attrsOnly,
bool  missing_ok 
)
static

Definition at line 1921 of file ruleutils.c.

1923 {
1925  HeapTuple tuple;
1926  oidvector *partclass;
1927  oidvector *partcollation;
1928  List *partexprs;
1929  ListCell *partexpr_item;
1930  List *context;
1931  Datum datum;
1933  int keyno;
1934  char *str;
1935  char *sep;
1936 
1937  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
1938  if (!HeapTupleIsValid(tuple))
1939  {
1940  if (missing_ok)
1941  return NULL;
1942  elog(ERROR, "cache lookup failed for partition key of %u", relid);
1943  }
1944 
1945  form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
1946 
1947  Assert(form->partrelid == relid);
1948 
1949  /* Must get partclass and partcollation the hard way */
1950  datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1951  Anum_pg_partitioned_table_partclass);
1952  partclass = (oidvector *) DatumGetPointer(datum);
1953 
1954  datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1955  Anum_pg_partitioned_table_partcollation);
1956  partcollation = (oidvector *) DatumGetPointer(datum);
1957 
1958 
1959  /*
1960  * Get the expressions, if any. (NOTE: we do not use the relcache
1961  * versions of the expressions, because we want to display
1962  * non-const-folded expressions.)
1963  */
1964  if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
1965  {
1966  Datum exprsDatum;
1967  char *exprsString;
1968 
1969  exprsDatum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1970  Anum_pg_partitioned_table_partexprs);
1971  exprsString = TextDatumGetCString(exprsDatum);
1972  partexprs = (List *) stringToNode(exprsString);
1973 
1974  if (!IsA(partexprs, List))
1975  elog(ERROR, "unexpected node type found in partexprs: %d",
1976  (int) nodeTag(partexprs));
1977 
1978  pfree(exprsString);
1979  }
1980  else
1981  partexprs = NIL;
1982 
1983  partexpr_item = list_head(partexprs);
1985 
1986  initStringInfo(&buf);
1987 
1988  switch (form->partstrat)
1989  {
1991  if (!attrsOnly)
1992  appendStringInfoString(&buf, "HASH");
1993  break;
1995  if (!attrsOnly)
1996  appendStringInfoString(&buf, "LIST");
1997  break;
1999  if (!attrsOnly)
2000  appendStringInfoString(&buf, "RANGE");
2001  break;
2002  default:
2003  elog(ERROR, "unexpected partition strategy: %d",
2004  (int) form->partstrat);
2005  }
2006 
2007  if (!attrsOnly)
2008  appendStringInfoString(&buf, " (");
2009  sep = "";
2010  for (keyno = 0; keyno < form->partnatts; keyno++)
2011  {
2012  AttrNumber attnum = form->partattrs.values[keyno];
2013  Oid keycoltype;
2014  Oid keycolcollation;
2015  Oid partcoll;
2016 
2017  appendStringInfoString(&buf, sep);
2018  sep = ", ";
2019  if (attnum != 0)
2020  {
2021  /* Simple attribute reference */
2022  char *attname;
2023  int32 keycoltypmod;
2024 
2025  attname = get_attname(relid, attnum, false);
2028  &keycoltype, &keycoltypmod,
2029  &keycolcollation);
2030  }
2031  else
2032  {
2033  /* Expression */
2034  Node *partkey;
2035 
2036  if (partexpr_item == NULL)
2037  elog(ERROR, "too few entries in partexprs list");
2038  partkey = (Node *) lfirst(partexpr_item);
2039  partexpr_item = lnext(partexprs, partexpr_item);
2040 
2041  /* Deparse */
2042  str = deparse_expression_pretty(partkey, context, false, false,
2043  prettyFlags, 0);
2044  /* Need parens if it's not a bare function call */
2045  if (looks_like_function(partkey))
2047  else
2048  appendStringInfo(&buf, "(%s)", str);
2049 
2050  keycoltype = exprType(partkey);
2051  keycolcollation = exprCollation(partkey);
2052  }
2053 
2054  /* Add collation, if not default for column */
2055  partcoll = partcollation->values[keyno];
2056  if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
2057  appendStringInfo(&buf, " COLLATE %s",
2058  generate_collation_name((partcoll)));
2059 
2060  /* Add the operator class name, if not default */
2061  if (!attrsOnly)
2062  get_opclass_name(partclass->values[keyno], keycoltype, &buf);
2063  }
2064 
2065  if (!attrsOnly)
2066  appendStringInfoChar(&buf, ')');
2067 
2068  /* Clean up */
2069  ReleaseSysCache(tuple);
2070 
2071  return buf.data;
2072 }
FormData_pg_partitioned_table * Form_pg_partitioned_table

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, attname, attnum, buf, context, DatumGetPointer(), deparse_context_for(), deparse_expression_pretty(), elog, ERROR, exprCollation(), exprType(), generate_collation_name(), get_attname(), get_atttypetypmodcoll(), get_opclass_name(), get_relation_name(), GETSTRUCT, heap_attisnull(), HeapTupleIsValid, initStringInfo(), IsA, lfirst, list_head(), lnext(), looks_like_function(), NIL, nodeTag, ObjectIdGetDatum(), OidIsValid, PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, pfree(), quote_identifier(), ReleaseSysCache(), SearchSysCache1(), str, stringToNode(), SysCacheGetAttrNotNull(), TextDatumGetCString, and oidvector::values.

Referenced by pg_get_partkeydef(), and pg_get_partkeydef_columns().

◆ pg_get_querydef()

char* pg_get_querydef ( Query query,
bool  pretty 
)

Definition at line 1572 of file ruleutils.c.

1573 {
1575  int prettyFlags;
1576 
1577  prettyFlags = GET_PRETTY_FLAGS(pretty);
1578 
1579  initStringInfo(&buf);
1580 
1581  get_query_def(query, &buf, NIL, NULL, true,
1582  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1583 
1584  return buf.data;
1585 }

References buf, GET_PRETTY_FLAGS, get_query_def(), initStringInfo(), NIL, and WRAP_COLUMN_DEFAULT.

◆ pg_get_ruledef()

Datum pg_get_ruledef ( PG_FUNCTION_ARGS  )

Definition at line 545 of file ruleutils.c.

546 {
547  Oid ruleoid = PG_GETARG_OID(0);
548  int prettyFlags;
549  char *res;
550 
551  prettyFlags = PRETTYFLAG_INDENT;
552 
553  res = pg_get_ruledef_worker(ruleoid, prettyFlags);
554 
555  if (res == NULL)
556  PG_RETURN_NULL();
557 
559 }
static char * pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
Definition: ruleutils.c:582

References pg_get_ruledef_worker(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, PRETTYFLAG_INDENT, res, and string_to_text().

◆ pg_get_ruledef_ext()

Datum pg_get_ruledef_ext ( PG_FUNCTION_ARGS  )

Definition at line 563 of file ruleutils.c.

564 {
565  Oid ruleoid = PG_GETARG_OID(0);
566  bool pretty = PG_GETARG_BOOL(1);
567  int prettyFlags;
568  char *res;
569 
570  prettyFlags = GET_PRETTY_FLAGS(pretty);
571 
572  res = pg_get_ruledef_worker(ruleoid, prettyFlags);
573 
574  if (res == NULL)
575  PG_RETURN_NULL();
576 
578 }

References GET_PRETTY_FLAGS, pg_get_ruledef_worker(), PG_GETARG_BOOL, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, and string_to_text().

◆ pg_get_ruledef_worker()

static char * pg_get_ruledef_worker ( Oid  ruleoid,
int  prettyFlags 
)
static

Definition at line 582 of file ruleutils.c.

583 {
584  Datum args[1];
585  char nulls[1];
586  int spirc;
587  HeapTuple ruletup;
588  TupleDesc rulettc;
590 
591  /*
592  * Do this first so that string is alloc'd in outer context not SPI's.
593  */
595 
596  /*
597  * Connect to SPI manager
598  */
599  if (SPI_connect() != SPI_OK_CONNECT)
600  elog(ERROR, "SPI_connect failed");
601 
602  /*
603  * On the first call prepare the plan to lookup pg_rewrite. We read
604  * pg_rewrite over the SPI manager instead of using the syscache to be
605  * checked for read access on pg_rewrite.
606  */
607  if (plan_getrulebyoid == NULL)
608  {
609  Oid argtypes[1];
611 
612  argtypes[0] = OIDOID;
613  plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
614  if (plan == NULL)
615  elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
618  }
619 
620  /*
621  * Get the pg_rewrite tuple for this rule
622  */
623  args[0] = ObjectIdGetDatum(ruleoid);
624  nulls[0] = ' ';
625  spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
626  if (spirc != SPI_OK_SELECT)
627  elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
628  if (SPI_processed != 1)
629  {
630  /*
631  * There is no tuple data available here, just keep the output buffer
632  * empty.
633  */
634  }
635  else
636  {
637  /*
638  * Get the rule's definition and put it into executor's memory
639  */
640  ruletup = SPI_tuptable->vals[0];
641  rulettc = SPI_tuptable->tupdesc;
642  make_ruledef(&buf, ruletup, rulettc, prettyFlags);
643  }
644 
645  /*
646  * Disconnect from SPI manager
647  */
648  if (SPI_finish() != SPI_OK_FINISH)
649  elog(ERROR, "SPI_finish failed");
650 
651  if (buf.len == 0)
652  return NULL;
653 
654  return buf.data;
655 }
static const char *const query_getrulebyoid
Definition: ruleutils.c:318
static SPIPlanPtr plan_getrulebyoid
Definition: ruleutils.c:317
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
Definition: ruleutils.c:5183
uint64 SPI_processed
Definition: spi.c:44
SPITupleTable * SPI_tuptable
Definition: spi.c:45
int SPI_connect(void)
Definition: spi.c:94
int SPI_finish(void)
Definition: spi.c:182
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:669
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:857
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:973
#define SPI_OK_CONNECT
Definition: spi.h:82
#define SPI_OK_FINISH
Definition: spi.h:83
#define SPI_OK_SELECT
Definition: spi.h:86
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26

References generate_unaccent_rules::args, buf, elog, ERROR, initStringInfo(), make_ruledef(), ObjectIdGetDatum(), plan, plan_getrulebyoid, query_getrulebyoid, SPI_connect(), SPI_execute_plan(), SPI_finish(), SPI_keepplan(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_OK_SELECT, SPI_prepare(), SPI_processed, SPI_tuptable, SPITupleTable::tupdesc, and SPITupleTable::vals.

Referenced by pg_get_ruledef(), and pg_get_ruledef_ext().

◆ pg_get_serial_sequence()

Datum pg_get_serial_sequence ( PG_FUNCTION_ARGS  )

Definition at line 2813 of file ruleutils.c.

2814 {
2815  text *tablename = PG_GETARG_TEXT_PP(0);
2816  text *columnname = PG_GETARG_TEXT_PP(1);
2817  RangeVar *tablerv;
2818  Oid tableOid;
2819  char *column;
2821  Oid sequenceId = InvalidOid;
2822  Relation depRel;
2823  ScanKeyData key[3];
2824  SysScanDesc scan;
2825  HeapTuple tup;
2826 
2827  /* Look up table name. Can't lock it - we might not have privileges. */
2828  tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2829  tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2830 
2831  /* Get the number of the column */
2832  column = text_to_cstring(columnname);
2833 
2834  attnum = get_attnum(tableOid, column);
2835  if (attnum == InvalidAttrNumber)
2836  ereport(ERROR,
2837  (errcode(ERRCODE_UNDEFINED_COLUMN),
2838  errmsg("column \"%s\" of relation \"%s\" does not exist",
2839  column, tablerv->relname)));
2840 
2841  /* Search the dependency table for the dependent sequence */
2842  depRel = table_open(DependRelationId, AccessShareLock);
2843 
2844  ScanKeyInit(&key[0],
2845  Anum_pg_depend_refclassid,
2846  BTEqualStrategyNumber, F_OIDEQ,
2847  ObjectIdGetDatum(RelationRelationId));
2848  ScanKeyInit(&key[1],
2849  Anum_pg_depend_refobjid,
2850  BTEqualStrategyNumber, F_OIDEQ,
2851  ObjectIdGetDatum(tableOid));
2852  ScanKeyInit(&key[2],
2853  Anum_pg_depend_refobjsubid,
2854  BTEqualStrategyNumber, F_INT4EQ,
2856 
2857  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2858  NULL, 3, key);
2859 
2860  while (HeapTupleIsValid(tup = systable_getnext(scan)))
2861  {
2862  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2863 
2864  /*
2865  * Look for an auto dependency (serial column) or internal dependency
2866  * (identity column) of a sequence on a column. (We need the relkind
2867  * test because indexes can also have auto dependencies on columns.)
2868  */
2869  if (deprec->classid == RelationRelationId &&
2870  deprec->objsubid == 0 &&
2871  (deprec->deptype == DEPENDENCY_AUTO ||
2872  deprec->deptype == DEPENDENCY_INTERNAL) &&
2873  get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2874  {
2875  sequenceId = deprec->objid;
2876  break;
2877  }
2878  }
2879 
2880  systable_endscan(scan);
2881  table_close(depRel, AccessShareLock);
2882 
2883  if (OidIsValid(sequenceId))
2884  {
2885  char *result;
2886 
2887  result = generate_qualified_relation_name(sequenceId);
2888 
2890  }
2891 
2892  PG_RETURN_NULL();
2893 }
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
#define NoLock
Definition: lockdefs.h:34
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3539
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
char * relname
Definition: primnodes.h:82
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3399

References AccessShareLock, attnum, BTEqualStrategyNumber, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, ereport, errcode(), errmsg(), ERROR, generate_qualified_relation_name(), get_attnum(), get_rel_relkind(), GETSTRUCT, HeapTupleIsValid, Int32GetDatum(), InvalidAttrNumber, InvalidOid, sort-test::key, makeRangeVarFromNameList(), NoLock, ObjectIdGetDatum(), OidIsValid, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, RangeVarGetRelid, RangeVar::relname, ScanKeyInit(), string_to_text(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), text_to_cstring(), and textToQualifiedNameList().

◆ pg_get_statisticsobj_worker()

static char * pg_get_statisticsobj_worker ( Oid  statextid,
bool  columns_only,
bool  missing_ok 
)
static

Definition at line 1638 of file ruleutils.c.

1639 {
1640  Form_pg_statistic_ext statextrec;
1641  HeapTuple statexttup;
1643  int colno;
1644  char *nsp;
1645  ArrayType *arr;
1646  char *enabled;
1647  Datum datum;
1648  bool ndistinct_enabled;
1649  bool dependencies_enabled;
1650  bool mcv_enabled;
1651  int i;
1652  List *context;
1653  ListCell *lc;
1654  List *exprs = NIL;
1655  bool has_exprs;
1656  int ncolumns;
1657 
1658  statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1659 
1660  if (!HeapTupleIsValid(statexttup))
1661  {
1662  if (missing_ok)
1663  return NULL;
1664  elog(ERROR, "cache lookup failed for statistics object %u", statextid);
1665  }
1666 
1667  /* has the statistics expressions? */
1668  has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1669 
1670  statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1671 
1672  /*
1673  * Get the statistics expressions, if any. (NOTE: we do not use the
1674  * relcache versions of the expressions, because we want to display
1675  * non-const-folded expressions.)
1676  */
1677  if (has_exprs)
1678  {
1679  Datum exprsDatum;
1680  char *exprsString;
1681 
1682  exprsDatum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1683  Anum_pg_statistic_ext_stxexprs);
1684  exprsString = TextDatumGetCString(exprsDatum);
1685  exprs = (List *) stringToNode(exprsString);
1686  pfree(exprsString);
1687  }
1688  else
1689  exprs = NIL;
1690 
1691  /* count the number of columns (attributes and expressions) */
1692  ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
1693 
1694  initStringInfo(&buf);
1695 
1696  if (!columns_only)
1697  {
1698  nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
1699  appendStringInfo(&buf, "CREATE STATISTICS %s",
1701  NameStr(statextrec->stxname)));
1702 
1703  /*
1704  * Decode the stxkind column so that we know which stats types to
1705  * print.
1706  */
1707  datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1708  Anum_pg_statistic_ext_stxkind);
1709  arr = DatumGetArrayTypeP(datum);
1710  if (ARR_NDIM(arr) != 1 ||
1711  ARR_HASNULL(arr) ||
1712  ARR_ELEMTYPE(arr) != CHAROID)
1713  elog(ERROR, "stxkind is not a 1-D char array");
1714  enabled = (char *) ARR_DATA_PTR(arr);
1715 
1716  ndistinct_enabled = false;
1717  dependencies_enabled = false;
1718  mcv_enabled = false;
1719 
1720  for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1721  {
1722  if (enabled[i] == STATS_EXT_NDISTINCT)
1723  ndistinct_enabled = true;
1724  else if (enabled[i] == STATS_EXT_DEPENDENCIES)
1725  dependencies_enabled = true;
1726  else if (enabled[i] == STATS_EXT_MCV)
1727  mcv_enabled = true;
1728 
1729  /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
1730  }
1731 
1732  /*
1733  * If any option is disabled, then we'll need to append the types
1734  * clause to show which options are enabled. We omit the types clause
1735  * on purpose when all options are enabled, so a pg_dump/pg_restore
1736  * will create all statistics types on a newer postgres version, if
1737  * the statistics had all options enabled on the original version.
1738  *
1739  * But if the statistics is defined on just a single column, it has to
1740  * be an expression statistics. In that case we don't need to specify
1741  * kinds.
1742  */
1743  if ((!ndistinct_enabled || !dependencies_enabled || !mcv_enabled) &&
1744  (ncolumns > 1))
1745  {
1746  bool gotone = false;
1747 
1748  appendStringInfoString(&buf, " (");
1749 
1750  if (ndistinct_enabled)
1751  {
1752  appendStringInfoString(&buf, "ndistinct");
1753  gotone = true;
1754  }
1755 
1756  if (dependencies_enabled)
1757  {
1758  appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
1759  gotone = true;
1760  }
1761 
1762  if (mcv_enabled)
1763  appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
1764 
1765  appendStringInfoChar(&buf, ')');
1766  }
1767 
1768  appendStringInfoString(&buf, " ON ");
1769  }
1770 
1771  /* decode simple column references */
1772  for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
1773  {
1774  AttrNumber attnum = statextrec->stxkeys.values[colno];
1775  char *attname;
1776 
1777  if (colno > 0)
1778  appendStringInfoString(&buf, ", ");
1779 
1780  attname = get_attname(statextrec->stxrelid, attnum, false);
1781 
1783  }
1784 
1785  context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1786  statextrec->stxrelid);
1787 
1788  foreach(lc, exprs)
1789  {
1790  Node *expr = (Node *) lfirst(lc);
1791  char *str;
1792  int prettyFlags = PRETTYFLAG_PAREN;
1793 
1794  str = deparse_expression_pretty(expr, context, false, false,
1795  prettyFlags, 0);
1796 
1797  if (colno > 0)
1798  appendStringInfoString(&buf, ", ");
1799 
1800  /* Need parens if it's not a bare function call */
1801  if (looks_like_function(expr))
1803  else
1804  appendStringInfo(&buf, "(%s)", str);
1805 
1806  colno++;
1807  }
1808 
1809  if (!columns_only)
1810  appendStringInfo(&buf, " FROM %s",
1811  generate_relation_name(statextrec->stxrelid, NIL));
1812 
1813  ReleaseSysCache(statexttup);
1814 
1815  return buf.data;
1816 }
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define ARR_HASNULL(a)
Definition: array.h:291
FormData_pg_statistic_ext * Form_pg_statistic_ext

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, attname, attnum, buf, context, DatumGetArrayTypeP, deparse_context_for(), deparse_expression_pretty(), elog, ERROR, generate_relation_name(), get_attname(), get_namespace_name_or_temp(), get_relation_name(), GETSTRUCT, heap_attisnull(), HeapTupleIsValid, i, initStringInfo(), lfirst, list_length(), looks_like_function(), NameStr, NIL, ObjectIdGetDatum(), pfree(), PRETTYFLAG_PAREN, quote_identifier(), quote_qualified_identifier(), ReleaseSysCache(), SearchSysCache1(), str, stringToNode(), SysCacheGetAttrNotNull(), and TextDatumGetCString.

Referenced by pg_get_statisticsobjdef(), pg_get_statisticsobjdef_columns(), and pg_get_statisticsobjdef_string().

◆ pg_get_statisticsobjdef()

Datum pg_get_statisticsobjdef ( PG_FUNCTION_ARGS  )

Definition at line 1592 of file ruleutils.c.

1593 {
1594  Oid statextid = PG_GETARG_OID(0);
1595  char *res;
1596 
1597  res = pg_get_statisticsobj_worker(statextid, false, true);
1598 
1599  if (res == NULL)
1600  PG_RETURN_NULL();
1601 
1603 }
static char * pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
Definition: ruleutils.c:1638

References pg_get_statisticsobj_worker(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, and string_to_text().

◆ pg_get_statisticsobjdef_columns()

Datum pg_get_statisticsobjdef_columns ( PG_FUNCTION_ARGS  )

Definition at line 1621 of file ruleutils.c.

1622 {
1623  Oid statextid = PG_GETARG_OID(0);
1624  char *res;
1625 
1626  res = pg_get_statisticsobj_worker(statextid, true, true);
1627 
1628  if (res == NULL)
1629  PG_RETURN_NULL();
1630 
1632 }

References pg_get_statisticsobj_worker(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, and string_to_text().

◆ pg_get_statisticsobjdef_expressions()

Datum pg_get_statisticsobjdef_expressions ( PG_FUNCTION_ARGS  )

Definition at line 1822 of file ruleutils.c.

1823 {
1824  Oid statextid = PG_GETARG_OID(0);
1825  Form_pg_statistic_ext statextrec;
1826  HeapTuple statexttup;
1827  Datum datum;
1828  List *context;
1829  ListCell *lc;
1830  List *exprs = NIL;
1831  bool has_exprs;
1832  char *tmp;
1833  ArrayBuildState *astate = NULL;
1834 
1835  statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1836 
1837  if (!HeapTupleIsValid(statexttup))
1838  PG_RETURN_NULL();
1839 
1840  /* Does the stats object have expressions? */
1841  has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1842 
1843  /* no expressions? we're done */
1844  if (!has_exprs)
1845  {
1846  ReleaseSysCache(statexttup);
1847  PG_RETURN_NULL();
1848  }
1849 
1850  statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1851 
1852  /*
1853  * Get the statistics expressions, and deparse them into text values.
1854  */
1855  datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1856  Anum_pg_statistic_ext_stxexprs);
1857  tmp = TextDatumGetCString(datum);
1858  exprs = (List *) stringToNode(tmp);
1859  pfree(tmp);
1860 
1861  context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1862  statextrec->stxrelid);
1863 
1864  foreach(lc, exprs)
1865  {
1866  Node *expr = (Node *) lfirst(lc);
1867  char *str;
1868  int prettyFlags = PRETTYFLAG_INDENT;
1869 
1870  str = deparse_expression_pretty(expr, context, false, false,
1871  prettyFlags, 0);
1872 
1873  astate = accumArrayResult(astate,
1875  false,
1876  TEXTOID,
1878  }
1879 
1880  ReleaseSysCache(statexttup);
1881 
1883 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5331
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5401
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
text * cstring_to_text(const char *s)
Definition: varlena.c:184

References accumArrayResult(), context, cstring_to_text(), CurrentMemoryContext, deparse_context_for(), deparse_expression_pretty(), get_relation_name(), GETSTRUCT, heap_attisnull(), HeapTupleIsValid, lfirst, makeArrayResult(), NIL, ObjectIdGetDatum(), pfree(), PG_GETARG_OID, PG_RETURN_DATUM, PG_RETURN_NULL, PointerGetDatum(), PRETTYFLAG_INDENT, ReleaseSysCache(), SearchSysCache1(), str, stringToNode(), SysCacheGetAttrNotNull(), and TextDatumGetCString.

◆ pg_get_statisticsobjdef_string()

char* pg_get_statisticsobjdef_string ( Oid  statextid)

Definition at line 1611 of file ruleutils.c.

1612 {
1613  return pg_get_statisticsobj_worker(statextid, false, false);
1614 }

References pg_get_statisticsobj_worker().

Referenced by RememberStatisticsForRebuilding().

◆ pg_get_triggerdef()

Datum pg_get_triggerdef ( PG_FUNCTION_ARGS  )

Definition at line 858 of file ruleutils.c.

859 {
860  Oid trigid = PG_GETARG_OID(0);
861  char *res;
862 
863  res = pg_get_triggerdef_worker(trigid, false);
864 
865  if (res == NULL)
866  PG_RETURN_NULL();
867 
869 }
static char * pg_get_triggerdef_worker(Oid trigid, bool pretty)
Definition: ruleutils.c:887

References pg_get_triggerdef_worker(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, and string_to_text().

◆ pg_get_triggerdef_ext()

Datum pg_get_triggerdef_ext ( PG_FUNCTION_ARGS  )

Definition at line 872 of file ruleutils.c.

873 {
874  Oid trigid = PG_GETARG_OID(0);
875  bool pretty = PG_GETARG_BOOL(1);
876  char *res;
877 
878  res = pg_get_triggerdef_worker(trigid, pretty);
879 
880  if (res == NULL)
881  PG_RETURN_NULL();
882 
884 }

References pg_get_triggerdef_worker(), PG_GETARG_BOOL, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, and string_to_text().

◆ pg_get_triggerdef_worker()

static char * pg_get_triggerdef_worker ( Oid  trigid,
bool  pretty 
)
static

Definition at line 887 of file ruleutils.c.

888 {
889  HeapTuple ht_trig;
890  Form_pg_trigger trigrec;
892  Relation tgrel;
893  ScanKeyData skey[1];
894  SysScanDesc tgscan;
895  int findx = 0;
896  char *tgname;
897  char *tgoldtable;
898  char *tgnewtable;
899  Datum value;
900  bool isnull;
901 
902  /*
903  * Fetch the pg_trigger tuple by the Oid of the trigger
904  */
905  tgrel = table_open(TriggerRelationId, AccessShareLock);
906 
907  ScanKeyInit(&skey[0],
908  Anum_pg_trigger_oid,
909  BTEqualStrategyNumber, F_OIDEQ,
910  ObjectIdGetDatum(trigid));
911 
912  tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
913  NULL, 1, skey);
914 
915  ht_trig = systable_getnext(tgscan);
916 
917  if (!HeapTupleIsValid(ht_trig))
918  {
919  systable_endscan(tgscan);
921  return NULL;
922  }
923 
924  trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
925 
926  /*
927  * Start the trigger definition. Note that the trigger's name should never
928  * be schema-qualified, but the trigger rel's name may be.
929  */
931 
932  tgname = NameStr(trigrec->tgname);
933  appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
934  OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
935  quote_identifier(tgname));
936 
937  if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
938  appendStringInfoString(&buf, "BEFORE");
939  else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
940  appendStringInfoString(&buf, "AFTER");
941  else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
942  appendStringInfoString(&buf, "INSTEAD OF");
943  else
944  elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
945 
946  if (TRIGGER_FOR_INSERT(trigrec->tgtype))
947  {
948  appendStringInfoString(&buf, " INSERT");
949  findx++;
950  }
951  if (TRIGGER_FOR_DELETE(trigrec->tgtype))
952  {
953  if (findx > 0)
954  appendStringInfoString(&buf, " OR DELETE");
955  else
956  appendStringInfoString(&buf, " DELETE");
957  findx++;
958  }
959  if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
960  {
961  if (findx > 0)
962  appendStringInfoString(&buf, " OR UPDATE");
963  else
964  appendStringInfoString(&buf, " UPDATE");
965  findx++;
966  /* tgattr is first var-width field, so OK to access directly */
967  if (trigrec->tgattr.dim1 > 0)
968  {
969  int i;
970 
971  appendStringInfoString(&buf, " OF ");
972  for (i = 0; i < trigrec->tgattr.dim1; i++)
973  {
974  char *attname;
975 
976  if (i > 0)
977  appendStringInfoString(&buf, ", ");
978  attname = get_attname(trigrec->tgrelid,
979  trigrec->tgattr.values[i], false);
981  }
982  }
983  }
984  if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
985  {
986  if (findx > 0)
987  appendStringInfoString(&buf, " OR TRUNCATE");
988  else
989  appendStringInfoString(&buf, " TRUNCATE");
990  findx++;
991  }
992 
993  /*
994  * In non-pretty mode, always schema-qualify the target table name for
995  * safety. In pretty mode, schema-qualify only if not visible.
996  */
997  appendStringInfo(&buf, " ON %s ",
998  pretty ?
999  generate_relation_name(trigrec->tgrelid, NIL) :
1000  generate_qualified_relation_name(trigrec->tgrelid));
1001 
1002  if (OidIsValid(trigrec->tgconstraint))
1003  {
1004  if (OidIsValid(trigrec->tgconstrrelid))
1005  appendStringInfo(&buf, "FROM %s ",
1006  generate_relation_name(trigrec->tgconstrrelid, NIL));
1007  if (!trigrec->tgdeferrable)
1008  appendStringInfoString(&buf, "NOT ");
1009  appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
1010  if (trigrec->tginitdeferred)
1011  appendStringInfoString(&buf, "DEFERRED ");
1012  else
1013  appendStringInfoString(&buf, "IMMEDIATE ");
1014  }
1015 
1016  value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
1017  tgrel->rd_att, &isnull);
1018  if (!isnull)
1019  tgoldtable = NameStr(*DatumGetName(value));
1020  else
1021  tgoldtable = NULL;
1022  value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
1023  tgrel->rd_att, &isnull);
1024  if (!isnull)
1025  tgnewtable = NameStr(*DatumGetName(value));
1026  else
1027  tgnewtable = NULL;
1028  if (tgoldtable != NULL || tgnewtable != NULL)
1029  {
1030  appendStringInfoString(&buf, "REFERENCING ");
1031  if (tgoldtable != NULL)
1032  appendStringInfo(&buf, "OLD TABLE AS %s ",
1033  quote_identifier(tgoldtable));
1034  if (tgnewtable != NULL)
1035  appendStringInfo(&buf, "NEW TABLE AS %s ",
1036  quote_identifier(tgnewtable));
1037  }
1038 
1039  if (TRIGGER_FOR_ROW(trigrec->tgtype))
1040  appendStringInfoString(&buf, "FOR EACH ROW ");
1041  else
1042  appendStringInfoString(&buf, "FOR EACH STATEMENT ");
1043 
1044  /* If the trigger has a WHEN qualification, add that */
1045  value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
1046  tgrel->rd_att, &isnull);
1047  if (!isnull)
1048  {
1049  Node *qual;
1050  char relkind;
1052  deparse_namespace dpns;
1053  RangeTblEntry *oldrte;
1054  RangeTblEntry *newrte;
1055 
1056  appendStringInfoString(&buf, "WHEN (");
1057 
1059 
1060  relkind = get_rel_relkind(trigrec->tgrelid);
1061 
1062  /* Build minimal OLD and NEW RTEs for the rel */
1063  oldrte = makeNode(RangeTblEntry);
1064  oldrte->rtekind = RTE_RELATION;
1065  oldrte->relid = trigrec->tgrelid;
1066  oldrte->relkind = relkind;
1067  oldrte->rellockmode = AccessShareLock;
1068  oldrte->alias = makeAlias("old", NIL);
1069  oldrte->eref = oldrte->alias;
1070  oldrte->lateral = false;
1071  oldrte->inh = false;
1072  oldrte->inFromCl = true;
1073 
1074  newrte = makeNode(RangeTblEntry);
1075  newrte->rtekind = RTE_RELATION;
1076  newrte->relid = trigrec->tgrelid;
1077  newrte->relkind = relkind;
1078  newrte->rellockmode = AccessShareLock;
1079  newrte->alias = makeAlias("new", NIL);
1080  newrte->eref = newrte->alias;
1081  newrte->lateral = false;
1082  newrte->inh = false;
1083  newrte->inFromCl = true;
1084 
1085  /* Build two-element rtable */
1086  memset(&dpns, 0, sizeof(dpns));
1087  dpns.rtable = list_make2(oldrte, newrte);
1088  dpns.subplans = NIL;
1089  dpns.ctes = NIL;
1090  dpns.appendrels = NULL;
1091  set_rtable_names(&dpns, NIL, NULL);
1092  set_simple_column_names(&dpns);
1093 
1094  /* Set up context with one-deep namespace stack */
1095  context.buf = &buf;
1096  context.namespaces = list_make1(&dpns);
1097  context.windowClause = NIL;
1098  context.windowTList = NIL;
1099  context.varprefix = true;
1100  context.prettyFlags = GET_PRETTY_FLAGS(pretty);
1101  context.wrapColumn = WRAP_COLUMN_DEFAULT;
1102  context.indentLevel = PRETTYINDENT_STD;
1103  context.special_exprkind = EXPR_KIND_NONE;
1104  context.appendparents = NULL;
1105 
1106  get_rule_expr(qual, &context, false);
1107 
1108  appendStringInfoString(&buf, ") ");
1109  }
1110 
1111  appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
1112  generate_function_name(trigrec->tgfoid, 0,
1113  NIL, NULL,
1114  false, NULL, EXPR_KIND_NONE));
1115 
1116  if (trigrec->tgnargs > 0)
1117  {
1118  char *p;
1119  int i;
1120 
1121  value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
1122  tgrel->rd_att, &isnull);
1123  if (isnull)
1124  elog(ERROR, "tgargs is null for trigger %u", trigid);
1125  p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1126  for (i = 0; i < trigrec->tgnargs; i++)
1127  {
1128  if (i > 0)
1129  appendStringInfoString(&buf, ", ");
1131  /* advance p to next string embedded in tgargs */
1132  while (*p)
1133  p++;
1134  p++;
1135  }
1136  }
1137 
1138  /* We deliberately do not put semi-colon at end */
1139  appendStringInfoChar(&buf, ')');
1140 
1141  /* Clean up */
1142  systable_endscan(tgscan);
1143 
1144  table_close(tgrel, AccessShareLock);
1145 
1146  return buf.data;
1147 }
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
#define list_make2(x1, x2)
Definition: pg_list.h:214
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
TupleDesc rd_att
Definition: rel.h:112
#define VARDATA_ANY(PTR)
Definition: varatt.h:324

References AccessShareLock, deparse_namespace::appendrels, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), attname, BTEqualStrategyNumber, buf, context, deparse_namespace::ctes, DatumGetByteaPP, DatumGetName(), elog, ERROR, EXPR_KIND_NONE, fastgetattr(), generate_function_name(), generate_qualified_relation_name(), generate_relation_name(), get_attname(), GET_PRETTY_FLAGS, get_rel_relkind(), get_rule_expr(), GETSTRUCT, HeapTupleIsValid, i, RangeTblEntry::inh, initStringInfo(), list_make1, list_make2, makeAlias(), makeNode, NameStr, NIL, ObjectIdGetDatum(), OidIsValid, PRETTYINDENT_STD, quote_identifier(), RelationData::rd_att, RangeTblEntry::relid, deparse_namespace::rtable, RTE_RELATION, RangeTblEntry::rtekind, ScanKeyInit(), set_rtable_names(), set_simple_column_names(), simple_quote_literal(), stringToNode(), deparse_namespace::subplans, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, value, VARDATA_ANY, and WRAP_COLUMN_DEFAULT.

Referenced by pg_get_triggerdef(), and pg_get_triggerdef_ext().

◆ pg_get_userbyid()

Datum pg_get_userbyid ( PG_FUNCTION_ARGS  )

Definition at line 2775 of file ruleutils.c.

2776 {
2777  Oid roleid = PG_GETARG_OID(0);
2778  Name result;
2779  HeapTuple roletup;
2780  Form_pg_authid role_rec;
2781 
2782  /*
2783  * Allocate space for the result
2784  */
2785  result = (Name) palloc(NAMEDATALEN);
2786  memset(NameStr(*result), 0, NAMEDATALEN);
2787 
2788  /*
2789  * Get the pg_authid entry and print the result
2790  */
2791  roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2792  if (HeapTupleIsValid(roletup))
2793  {
2794  role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2795  *result = role_rec->rolname;
2796  ReleaseSysCache(roletup);
2797  }
2798  else
2799  sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2800 
2801  PG_RETURN_NAME(result);
2802 }
NameData * Name
Definition: c.h:744
#define PG_RETURN_NAME(x)
Definition: fmgr.h:363
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:56
Definition: c.h:741

References GETSTRUCT, HeapTupleIsValid, NAMEDATALEN, NameStr, ObjectIdGetDatum(), palloc(), PG_GETARG_OID, PG_RETURN_NAME, ReleaseSysCache(), SearchSysCache1(), and sprintf.

◆ pg_get_viewdef()

Datum pg_get_viewdef ( PG_FUNCTION_ARGS  )

Definition at line 664 of file ruleutils.c.

665 {
666  /* By OID */
667  Oid viewoid = PG_GETARG_OID(0);
668  int prettyFlags;
669  char *res;
670 
671  prettyFlags = PRETTYFLAG_INDENT;
672 
673  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
674 
675  if (res == NULL)
676  PG_RETURN_NULL();
677 
679 }
static char * pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
Definition: ruleutils.c:775

References pg_get_viewdef_worker(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, PRETTYFLAG_INDENT, res, string_to_text(), and WRAP_COLUMN_DEFAULT.

◆ pg_get_viewdef_ext()

Datum pg_get_viewdef_ext ( PG_FUNCTION_ARGS  )

Definition at line 683 of file ruleutils.c.

684 {
685  /* By OID */
686  Oid viewoid = PG_GETARG_OID(0);
687  bool pretty = PG_GETARG_BOOL(1);
688  int prettyFlags;
689  char *res;
690 
691  prettyFlags = GET_PRETTY_FLAGS(pretty);
692 
693  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
694 
695  if (res == NULL)
696  PG_RETURN_NULL();
697 
699 }

References GET_PRETTY_FLAGS, pg_get_viewdef_worker(), PG_GETARG_BOOL, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, string_to_text(), and WRAP_COLUMN_DEFAULT.

◆ pg_get_viewdef_name()

Datum pg_get_viewdef_name ( PG_FUNCTION_ARGS  )

Definition at line 722 of file ruleutils.c.

723 {
724  /* By qualified name */
725  text *viewname = PG_GETARG_TEXT_PP(0);
726  int prettyFlags;
727  RangeVar *viewrel;
728  Oid viewoid;
729  char *res;
730 
731  prettyFlags = PRETTYFLAG_INDENT;
732 
733  /* Look up view name. Can't lock it - we might not have privileges. */
735  viewoid = RangeVarGetRelid(viewrel, NoLock, false);
736 
737  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
738 
739  if (res == NULL)
740  PG_RETURN_NULL();
741 
743 }

References makeRangeVarFromNameList(), NoLock, pg_get_viewdef_worker(), PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, PRETTYFLAG_INDENT, RangeVarGetRelid, res, string_to_text(), textToQualifiedNameList(), and WRAP_COLUMN_DEFAULT.

◆ pg_get_viewdef_name_ext()

Datum pg_get_viewdef_name_ext ( PG_FUNCTION_ARGS  )

Definition at line 747 of file ruleutils.c.

748 {
749  /* By qualified name */
750  text *viewname = PG_GETARG_TEXT_PP(0);
751  bool pretty = PG_GETARG_BOOL(1);
752  int prettyFlags;
753  RangeVar *viewrel;
754  Oid viewoid;
755  char *res;
756 
757  prettyFlags = GET_PRETTY_FLAGS(pretty);
758 
759  /* Look up view name. Can't lock it - we might not have privileges. */
761  viewoid = RangeVarGetRelid(viewrel, NoLock, false);
762 
763  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
764 
765  if (res == NULL)
766  PG_RETURN_NULL();
767 
769 }

References GET_PRETTY_FLAGS, makeRangeVarFromNameList(), NoLock, pg_get_viewdef_worker(), PG_GETARG_BOOL, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, RangeVarGetRelid, res, string_to_text(), textToQualifiedNameList(), and WRAP_COLUMN_DEFAULT.

◆ pg_get_viewdef_worker()

static char * pg_get_viewdef_worker ( Oid  viewoid,
int  prettyFlags,
int  wrapColumn 
)
static

Definition at line 775 of file ruleutils.c.

776 {
777  Datum args[2];
778  char nulls[2];
779  int spirc;
780  HeapTuple ruletup;
781  TupleDesc rulettc;
783 
784  /*
785  * Do this first so that string is alloc'd in outer context not SPI's.
786  */
788 
789  /*
790  * Connect to SPI manager
791  */
792  if (SPI_connect() != SPI_OK_CONNECT)
793  elog(ERROR, "SPI_connect failed");
794 
795  /*
796  * On the first call prepare the plan to lookup pg_rewrite. We read
797  * pg_rewrite over the SPI manager instead of using the syscache to be
798  * checked for read access on pg_rewrite.
799  */
800  if (plan_getviewrule == NULL)
801  {
802  Oid argtypes[2];
804 
805  argtypes[0] = OIDOID;
806  argtypes[1] = NAMEOID;
807  plan = SPI_prepare(query_getviewrule, 2, argtypes);
808  if (plan == NULL)
809  elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
812  }
813 
814  /*
815  * Get the pg_rewrite tuple for the view's SELECT rule
816  */
817  args[0] = ObjectIdGetDatum(viewoid);
819  nulls[0] = ' ';
820  nulls[1] = ' ';
821  spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
822  if (spirc != SPI_OK_SELECT)
823  elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
824  if (SPI_processed != 1)
825  {
826  /*
827  * There is no tuple data available here, just keep the output buffer
828  * empty.
829  */
830  }
831  else
832  {
833  /*
834  * Get the rule's definition and put it into executor's memory
835  */
836  ruletup = SPI_tuptable->vals[0];
837  rulettc = SPI_tuptable->tupdesc;
838  make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
839  }
840 
841  /*
842  * Disconnect from SPI manager
843  */
844  if (SPI_finish() != SPI_OK_FINISH)
845  elog(ERROR, "SPI_finish failed");
846 
847  if (buf.len == 0)
848  return NULL;
849 
850  return buf.data;
851 }
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
#define ViewSelectRuleName
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags, int wrapColumn)
Definition: ruleutils.c:5372
static SPIPlanPtr plan_getviewrule
Definition: ruleutils.c:319
static const char *const query_getviewrule
Definition: ruleutils.c:320

References generate_unaccent_rules::args, buf, CStringGetDatum(), DirectFunctionCall1, elog, ERROR, initStringInfo(), make_viewdef(), namein(), ObjectIdGetDatum(), plan, plan_getviewrule, query_getviewrule, SPI_connect(), SPI_execute_plan(), SPI_finish(), SPI_keepplan(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_OK_SELECT, SPI_prepare(), SPI_processed, SPI_tuptable, SPITupleTable::tupdesc, SPITupleTable::vals, and ViewSelectRuleName.

Referenced by pg_get_viewdef(), pg_get_viewdef_ext(), pg_get_viewdef_name(), pg_get_viewdef_name_ext(), and pg_get_viewdef_wrap().

◆ pg_get_viewdef_wrap()

Datum pg_get_viewdef_wrap ( PG_FUNCTION_ARGS  )

Definition at line 702 of file ruleutils.c.

703 {
704  /* By OID */
705  Oid viewoid = PG_GETARG_OID(0);
706  int wrap = PG_GETARG_INT32(1);
707  int prettyFlags;
708  char *res;
709 
710  /* calling this implies we want pretty printing */
711  prettyFlags = GET_PRETTY_FLAGS(true);
712 
713  res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
714 
715  if (res == NULL)
716  PG_RETURN_NULL();
717 
719 }

References GET_PRETTY_FLAGS, pg_get_viewdef_worker(), PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, and string_to_text().

◆ pop_ancestor_plan()

static void pop_ancestor_plan ( deparse_namespace dpns,
deparse_namespace save_dpns 
)
static

Definition at line 5167 of file ruleutils.c.

5168 {
5169  /* Free the ancestor list made in push_ancestor_plan */
5170  list_free(dpns->ancestors);
5171 
5172  /* Restore fields changed by push_ancestor_plan */
5173  *dpns = *save_dpns;
5174 }
void list_free(List *list)
Definition: list.c:1546

References deparse_namespace::ancestors, and list_free().

Referenced by get_name_for_var_field(), and get_parameter().

◆ pop_child_plan()

static void pop_child_plan ( deparse_namespace dpns,
deparse_namespace save_dpns 
)
static

Definition at line 5116 of file ruleutils.c.

5117 {
5118  List *ancestors;
5119 
5120  /* Get rid of ancestors list cell added by push_child_plan */
5121  ancestors = list_delete_first(dpns->ancestors);
5122 
5123  /* Restore fields changed by push_child_plan */
5124  *dpns = *save_dpns;
5125 
5126  /* Make sure dpns->ancestors is right (may be unnecessary) */
5127  dpns->ancestors = ancestors;
5128 }

References deparse_namespace::ancestors, and list_delete_first().

Referenced by get_name_for_var_field(), get_variable(), and resolve_special_varno().

◆ print_function_arguments()

static int print_function_arguments ( StringInfo  buf,
HeapTuple  proctup,
bool  print_table_args,
bool  print_defaults 
)
static

Definition at line 3278 of file ruleutils.c.

3280 {
3281  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3282  int numargs;
3283  Oid *argtypes;
3284  char **argnames;
3285  char *argmodes;
3286  int insertorderbyat = -1;
3287  int argsprinted;
3288  int inputargno;
3289  int nlackdefaults;
3290  List *argdefaults = NIL;
3291  ListCell *nextargdefault = NULL;
3292  int i;
3293 
3294  numargs = get_func_arg_info(proctup,
3295  &argtypes, &argnames, &argmodes);
3296 
3297  nlackdefaults = numargs;
3298  if (print_defaults && proc->pronargdefaults > 0)
3299  {
3300  Datum proargdefaults;
3301  bool isnull;
3302 
3303  proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3304  Anum_pg_proc_proargdefaults,
3305  &isnull);
3306  if (!isnull)
3307  {
3308  char *str;
3309 
3310  str = TextDatumGetCString(proargdefaults);
3311  argdefaults = castNode(List, stringToNode(str));
3312  pfree(str);
3313  nextargdefault = list_head(argdefaults);
3314  /* nlackdefaults counts only *input* arguments lacking defaults */
3315  nlackdefaults = proc->pronargs - list_length(argdefaults);
3316  }
3317  }
3318 
3319  /* Check for special treatment of ordered-set aggregates */
3320  if (proc->prokind == PROKIND_AGGREGATE)
3321  {
3322  HeapTuple aggtup;
3323  Form_pg_aggregate agg;
3324 
3325  aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(proc->oid));
3326  if (!HeapTupleIsValid(aggtup))
3327  elog(ERROR, "cache lookup failed for aggregate %u",
3328  proc->oid);
3329  agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
3330  if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3331  insertorderbyat = agg->aggnumdirectargs;
3332  ReleaseSysCache(aggtup);
3333  }
3334 
3335  argsprinted = 0;
3336  inputargno = 0;
3337  for (i = 0; i < numargs; i++)
3338  {
3339  Oid argtype = argtypes[i];
3340  char *argname = argnames ? argnames[i] : NULL;
3341  char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
3342  const char *modename;
3343  bool isinput;
3344 
3345  switch (argmode)
3346  {
3347  case PROARGMODE_IN:
3348 
3349  /*
3350  * For procedures, explicitly mark all argument modes, so as
3351  * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3352  */
3353  if (proc->prokind == PROKIND_PROCEDURE)
3354  modename = "IN ";
3355  else
3356  modename = "";
3357  isinput = true;
3358  break;
3359  case PROARGMODE_INOUT:
3360  modename = "INOUT ";
3361  isinput = true;
3362  break;
3363  case PROARGMODE_OUT:
3364  modename = "OUT ";
3365  isinput = false;
3366  break;
3367  case PROARGMODE_VARIADIC:
3368  modename = "VARIADIC ";
3369  isinput = true;
3370  break;
3371  case PROARGMODE_TABLE:
3372  modename = "";
3373  isinput = false;
3374  break;
3375  default:
3376  elog(ERROR, "invalid parameter mode '%c'", argmode);
3377  modename = NULL; /* keep compiler quiet */
3378  isinput = false;
3379  break;
3380  }
3381  if (isinput)
3382  inputargno++; /* this is a 1-based counter */
3383 
3384  if (print_table_args != (argmode == PROARGMODE_TABLE))
3385  continue;
3386 
3387  if (argsprinted == insertorderbyat)
3388  {
3389  if (argsprinted)
3390  appendStringInfoChar(buf, ' ');
3391  appendStringInfoString(buf, "ORDER BY ");
3392  }
3393  else if (argsprinted)
3394  appendStringInfoString(buf, ", ");
3395 
3396  appendStringInfoString(buf, modename);
3397  if (argname && argname[0])
3398  appendStringInfo(buf, "%s ", quote_identifier(argname));
3400  if (print_defaults && isinput && inputargno > nlackdefaults)
3401  {
3402  Node *expr;
3403 
3404  Assert(nextargdefault != NULL);
3405  expr = (Node *) lfirst(nextargdefault);
3406  nextargdefault = lnext(argdefaults, nextargdefault);
3407 
3408  appendStringInfo(buf, " DEFAULT %s",
3409  deparse_expression(expr, NIL, false, false));
3410  }
3411  argsprinted++;
3412 
3413  /* nasty hack: print the last arg twice for variadic ordered-set agg */
3414  if (argsprinted == insertorderbyat && i == numargs - 1)
3415  {
3416  i--;
3417  /* aggs shouldn't have defaults anyway, but just to be sure ... */
3418  print_defaults = false;
3419  }
3420  }
3421 
3422  return argsprinted;
3423 }
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, buf, castNode, deparse_expression(), elog, ERROR, format_type_be(), get_func_arg_info(), GETSTRUCT, HeapTupleIsValid, i, lfirst, list_head(), list_length(), lnext(), NIL, ObjectIdGetDatum(), pfree(), quote_identifier(), ReleaseSysCache(), SearchSysCache1(), str, stringToNode(), SysCacheGetAttr(), and TextDatumGetCString.

Referenced by pg_get_function_arguments(), pg_get_function_identity_arguments(), pg_get_functiondef(), and print_function_rettype().

◆ print_function_rettype()

static void print_function_rettype ( StringInfo  buf,
HeapTuple  proctup 
)
static

Definition at line 3240 of file ruleutils.c.

3241 {
3242  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3243  int ntabargs = 0;
3244  StringInfoData rbuf;
3245 
3246  initStringInfo(&rbuf);
3247 
3248  if (proc->proretset)
3249  {
3250  /* It might be a table function; try to print the arguments */
3251  appendStringInfoString(&rbuf, "TABLE(");
3252  ntabargs = print_function_arguments(&rbuf, proctup, true, false);
3253  if (ntabargs > 0)
3254  appendStringInfoChar(&rbuf, ')');
3255  else
3256  resetStringInfo(&rbuf);
3257  }
3258 
3259  if (ntabargs == 0)
3260  {
3261  /* Not a table function, so do the normal thing */
3262  if (proc->proretset)
3263  appendStringInfoString(&rbuf, "SETOF ");
3264  appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3265  }
3266 
3267  appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3268 }

References appendBinaryStringInfo(), appendStringInfoChar(), appendStringInfoString(), buf, StringInfoData::data, format_type_be(), GETSTRUCT, initStringInfo(), StringInfoData::len, print_function_arguments(), and resetStringInfo().

Referenced by pg_get_function_result(), and pg_get_functiondef().

◆ print_function_sqlbody()

static void print_function_sqlbody ( StringInfo  buf,
HeapTuple  proctup 
)
static

Definition at line 3536 of file ruleutils.c.

3537 {
3538  int numargs;
3539  Oid *argtypes;
3540  char **argnames;
3541  char *argmodes;
3542  deparse_namespace dpns = {0};
3543  Datum tmp;
3544  Node *n;
3545 
3546  dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
3547  numargs = get_func_arg_info(proctup,
3548  &argtypes, &argnames, &argmodes);
3549  dpns.numargs = numargs;
3550  dpns.argnames = argnames;
3551 
3552  tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
3554 
3555  if (IsA(n, List))
3556  {
3557  List *stmts;
3558  ListCell *lc;
3559 
3560  stmts = linitial(castNode(List, n));
3561 
3562  appendStringInfoString(buf, "BEGIN ATOMIC\n");
3563 
3564  foreach(lc, stmts)
3565  {
3566  Query *query = lfirst_node(Query, lc);
3567 
3568  /* It seems advisable to get at least AccessShareLock on rels */
3569  AcquireRewriteLocks(query, false, false);
3570  get_query_def(query, buf, list_make1(&dpns), NULL, false,
3572  appendStringInfoChar(buf, ';');
3573  appendStringInfoChar(buf, '\n');
3574  }
3575 
3576  appendStringInfoString(buf, "END");
3577  }
3578  else
3579  {
3580  Query *query = castNode(Query, n);
3581 
3582  /* It seems advisable to get at least AccessShareLock on rels */
3583  AcquireRewriteLocks(query, false, false);
3584  get_query_def(query, buf, list_make1(&dpns), NULL, false,
3585  0, WRAP_COLUMN_DEFAULT, 0);
3586  }
3587 }
char * pstrdup(const char *in)
Definition: mcxt.c:1695

References AcquireRewriteLocks(), appendStringInfoChar(), appendStringInfoString(), deparse_namespace::argnames, buf, castNode, deparse_namespace::funcname, get_func_arg_info(), get_query_def(), GETSTRUCT, IsA, lfirst_node, linitial, list_make1, NameStr, deparse_namespace::numargs, PRETTYFLAG_INDENT, proname, pstrdup(), stringToNode(), SysCacheGetAttrNotNull(), TextDatumGetCString, and WRAP_COLUMN_DEFAULT.

Referenced by pg_get_function_sqlbody(), and pg_get_functiondef().

◆ print_function_trftypes()

static void print_function_trftypes ( StringInfo  buf,
HeapTuple  proctup 
)
static

Definition at line 3438 of file ruleutils.c.

3439 {
3440  Oid *trftypes;
3441  int ntypes;
3442 
3443  ntypes = get_func_trftypes(proctup, &trftypes);
3444  if (ntypes > 0)
3445  {
3446  int i;
3447 
3448  appendStringInfoString(buf, " TRANSFORM ");
3449  for (i = 0; i < ntypes; i++)
3450  {
3451  if (i != 0)
3452  appendStringInfoString(buf, ", ");
3453  appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3454  }
3455  appendStringInfoChar(buf, '\n');
3456  }
3457 }
int get_func_trftypes(HeapTuple procTup, Oid **p_trftypes)
Definition: funcapi.c:1475

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), buf, format_type_be(), get_func_trftypes(), and i.

Referenced by pg_get_functiondef().

◆ printSubscripts()

static void printSubscripts ( SubscriptingRef sbsref,
deparse_context context 
)
static

Definition at line 12593 of file ruleutils.c.

12594 {
12595  StringInfo buf = context->buf;
12596  ListCell *lowlist_item;
12597  ListCell *uplist_item;
12598 
12599  lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
12600  foreach(uplist_item, sbsref->refupperindexpr)
12601  {
12602  appendStringInfoChar(buf, '[');
12603  if (lowlist_item)
12604  {
12605  /* If subexpression is NULL, get_rule_expr prints nothing */
12606  get_rule_expr((Node *) lfirst(lowlist_item), context, false);
12607  appendStringInfoChar(buf, ':');
12608  lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
12609  }
12610  /* If subexpression is NULL, get_rule_expr prints nothing */
12611  get_rule_expr((Node *) lfirst(uplist_item), context, false);
12612  appendStringInfoChar(buf, ']');
12613  }
12614 }
List * refupperindexpr
Definition: primnodes.h:663
List * reflowerindexpr
Definition: primnodes.h:669

References appendStringInfoChar(), buf, context, get_rule_expr(), lfirst, list_head(), lnext(), SubscriptingRef::reflowerindexpr, and SubscriptingRef::refupperindexpr.

Referenced by get_rule_expr(), and processIndirection().

◆ processIndirection()

static Node * processIndirection ( Node node,
deparse_context context 
)
static

Definition at line 12515 of file ruleutils.c.

12516 {
12517  StringInfo buf = context->buf;
12518  CoerceToDomain *cdomain = NULL;
12519 
12520  for (;;)
12521  {
12522  if (node == NULL)
12523  break;
12524  if (IsA(node, FieldStore))
12525  {
12526  FieldStore *fstore = (FieldStore *) node;
12527  Oid typrelid;
12528  char *fieldname;
12529 
12530  /* lookup tuple type */
12531  typrelid = get_typ_typrelid(fstore->resulttype);
12532  if (!OidIsValid(typrelid))
12533  elog(ERROR, "argument type %s of FieldStore is not a tuple type",
12534  format_type_be(fstore->resulttype));
12535 
12536  /*
12537  * Print the field name. There should only be one target field in
12538  * stored rules. There could be more than that in executable
12539  * target lists, but this function cannot be used for that case.
12540  */
12541  Assert(list_length(fstore->fieldnums) == 1);
12542  fieldname = get_attname(typrelid,
12543  linitial_int(fstore->fieldnums), false);
12544  appendStringInfo(buf, ".%s", quote_identifier(fieldname));
12545 
12546  /*
12547  * We ignore arg since it should be an uninteresting reference to
12548  * the target column or subcolumn.
12549  */
12550  node = (Node *) linitial(fstore->newvals);
12551  }
12552  else if (IsA(node, SubscriptingRef))
12553  {
12554  SubscriptingRef *sbsref = (SubscriptingRef *) node;
12555 
12556  if (sbsref->refassgnexpr == NULL)
12557  break;
12558 
12559  printSubscripts(sbsref, context);
12560 
12561  /*
12562  * We ignore refexpr since it should be an uninteresting reference
12563  * to the target column or subcolumn.
12564  */
12565  node = (Node *) sbsref->refassgnexpr;
12566  }
12567  else if (IsA(node, CoerceToDomain))
12568  {
12569  cdomain = (CoerceToDomain *) node;
12570  /* If it's an explicit domain coercion, we're done */
12571  if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
12572  break;
12573  /* Tentatively descend past the CoerceToDomain */
12574  node = (Node *) cdomain->arg;
12575  }
12576  else
12577  break;
12578  }
12579 
12580  /*
12581  * If we descended past a CoerceToDomain whose argument turned out not to
12582  * be a FieldStore or array assignment, back up to the CoerceToDomain.
12583  * (This is not enough to be fully correct if there are nested implicit
12584  * CoerceToDomains, but such cases shouldn't ever occur.)
12585  */
12586  if (cdomain && node == (Node *) cdomain->arg)
12587  node = (Node *) cdomain;
12588 
12589  return node;
12590 }
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2731
#define linitial_int(l)
Definition: pg_list.h:179

References appendStringInfo(), CoerceToDomain::arg, Assert, buf, COERCE_IMPLICIT_CAST, context, elog, ERROR, format_type_be(), get_attname(), get_typ_typrelid(), IsA, linitial, linitial_int, list_length(), FieldStore::newvals, OidIsValid, printSubscripts(), quote_identifier(), and SubscriptingRef::refassgnexpr.

Referenced by get_insert_query_def(), get_merge_query_def(), get_rule_expr(), and get_update_query_targetlist_def().

◆ push_ancestor_plan()

static void push_ancestor_plan ( deparse_namespace dpns,
ListCell ancestor_cell,
deparse_namespace save_dpns 
)
static

Definition at line 5146 of file ruleutils.c.

5148 {
5149  Plan *plan = (Plan *) lfirst(ancestor_cell);
5150 
5151  /* Save state for restoration later */
5152  *save_dpns = *dpns;
5153 
5154  /* Build a new ancestor list with just this node's ancestors */
5155  dpns->ancestors =
5156  list_copy_tail(dpns->ancestors,
5157  list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5158 
5159  /* Set attention on selected ancestor */
5160  set_deparse_plan(dpns, plan);
5161 }
static int list_cell_number(const List *l, const ListCell *c)
Definition: pg_list.h:333
static void set_deparse_plan(deparse_namespace *dpns, Plan *plan)
Definition: ruleutils.c:4988

References deparse_namespace::ancestors, lfirst, list_cell_number(), list_copy_tail(), plan, and set_deparse_plan().

Referenced by get_name_for_var_field(), and get_parameter().

◆ push_child_plan()

static void push_child_plan ( deparse_namespace dpns,
Plan plan,
deparse_namespace save_dpns 
)
static

Definition at line 5099 of file ruleutils.c.

5101 {
5102  /* Save state for restoration later */
5103  *save_dpns = *dpns;
5104 
5105  /* Link current plan node into ancestors list */
5106  dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5107 
5108  /* Set attention on selected child */
5109  set_deparse_plan(dpns, plan);
5110 }

References deparse_namespace::ancestors, lcons(), deparse_namespace::plan, plan, and set_deparse_plan().

Referenced by get_name_for_var_field(), get_variable(), and resolve_special_varno().

◆ quote_identifier()

const char* quote_identifier ( const char *  ident)

Definition at line 12623 of file ruleutils.c.

12624 {
12625  /*
12626  * Can avoid quoting if ident starts with a lowercase letter or underscore
12627  * and contains only lowercase letters, digits, and underscores, *and* is
12628  * not any SQL keyword. Otherwise, supply quotes.
12629  */
12630  int nquotes = 0;
12631  bool safe;
12632  const char *ptr;
12633  char *result;
12634  char *optr;
12635 
12636  /*
12637  * would like to use <ctype.h> macros here, but they might yield unwanted
12638  * locale-specific results...
12639  */
12640  safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
12641 
12642  for (ptr = ident; *ptr; ptr++)
12643  {
12644  char ch = *ptr;
12645 
12646  if ((ch >= 'a' && ch <= 'z') ||
12647  (ch >= '0' && ch <= '9') ||
12648  (ch == '_'))
12649  {
12650  /* okay */
12651  }
12652  else
12653  {
12654  safe = false;
12655  if (ch == '"')
12656  nquotes++;
12657  }
12658  }
12659 
12661  safe = false;
12662 
12663  if (safe)
12664  {
12665  /*
12666  * Check for keyword. We quote keywords except for unreserved ones.
12667  * (In some cases we could avoid quoting a col_name or type_func_name
12668  * keyword, but it seems much harder than it's worth to tell that.)
12669  *
12670  * Note: ScanKeywordLookup() does case-insensitive comparison, but
12671  * that's fine, since we already know we have all-lower-case.
12672  */
12673  int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
12674 
12675  if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
12676  safe = false;
12677  }
12678 
12679  if (safe)
12680  return ident; /* no change needed */
12681 
12682  result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
12683 
12684  optr = result;
12685  *optr++ = '"';
12686  for (ptr = ident; *ptr; ptr++)
12687  {
12688  char ch = *ptr;
12689 
12690  if (ch == '"')
12691  *optr++ = '"';
12692  *optr++ = ch;
12693  }
12694  *optr++ = '"';
12695  *optr = '\0';
12696 
12697  return result;
12698 }
const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS]
Definition: keywords.c:29
#define ident
Definition: indent_codes.h:47
PGDLLIMPORT const ScanKeywordList ScanKeywords
#define UNRESERVED_KEYWORD
Definition: keywords.h:20
int ScanKeywordLookup(const char *str, const ScanKeywordList *keywords)
Definition: kwlookup.c:38
bool quote_all_identifiers
Definition: ruleutils.c:323

References ident, palloc(), quote_all_identifiers, ScanKeywordCategories, ScanKeywordLookup(), ScanKeywords, and UNRESERVED_KEYWORD.

Referenced by add_cast_to(), appendFunctionName(), ATPrepAlterColumnType(), CheckMyDatabase(), copy_table(), createdb(), CreateSchemaCommand(), decompile_column_index_array(), deparseAnalyzeSql(), deparseColumnRef(), deparseOperatorName(), deparseRelation(), execute_extension_script(), ExplainIndexScanDetails(), ExplainNode(), ExplainTargetRel(), flatten_set_variable_args(), format_operator_extended(), generate_operator_clause(), generate_operator_name(), get_column_alias_list(), get_from_clause_coldeflist(), get_from_clause_item(), get_insert_query_def(), get_json_table(), get_json_table_columns(), get_json_table_nested_columns(), get_merge_query_def(), get_opclass_name(), get_parameter(), get_reloptions(), get_rte_alias(), get_rule_expr(), get_rule_windowclause(), get_rule_windowspec(), get_select_query_def(), get_target_list(), get_update_query_targetlist_def(), get_utility_query_def(), get_variable(), get_windowfunc_expr_helper(), get_with_clause(), get_xmltable(), getObjectIdentityParts(), libpqrcv_alter_slot(), make_ruledef(), NameListToQuotedString(), old_9_6_invalidate_hash_indexes(), pg_get_constraintdef_worker(), pg_get_functiondef(), pg_get_indexdef_worker(), pg_get_partkeydef_worker(), pg_get_statisticsobj_worker(), pg_get_triggerdef_worker(), pg_identify_object(), PLy_quote_ident(), postgresExplainForeignScan(), postgresImportForeignSchema(), print_function_arguments(), processIndirection(), quote_ident(), quote_object_name(), quote_qualified_identifier(), regnamespaceout(), regoperout(), regroleout(), ReplicationSlotDropAtPubNode(), report_extension_updates(), sepgsql_attribute_post_create(), sepgsql_database_post_create(), sepgsql_relation_post_create(), sepgsql_schema_post_create(), serialize_deflist(), set_frozenxids(), show_sortorder_options(), text_format_string_conversion(), tuple_to_stringinfo(), and worker_spi_main().

◆ quote_qualified_identifier()

◆ removeStringInfoSpaces()

static void removeStringInfoSpaces ( StringInfo  str)
static

Definition at line 8772 of file ruleutils.c.

8773 {
8774  while (str->len > 0 && str->data[str->len - 1] == ' ')
8775  str->data[--(str->len)] = '\0';
8776 }

References str.

Referenced by appendContextKeyword(), get_from_clause(), and get_target_list().

◆ resolve_special_varno()

static void resolve_special_varno ( Node node,
deparse_context context,
rsv_callback  callback,
void *  callback_arg 
)
static

Definition at line 7580 of file ruleutils.c.

7582 {
7583  Var *var;
7584  deparse_namespace *dpns;
7585 
7586  /* This function is recursive, so let's be paranoid. */
7588 
7589  /* If it's not a Var, invoke the callback. */
7590  if (!IsA(node, Var))
7591  {
7592  (*callback) (node, context, callback_arg);
7593  return;
7594  }
7595 
7596  /* Find appropriate nesting depth */
7597  var = (Var *) node;
7598  dpns = (deparse_namespace *) list_nth(context->namespaces,
7599  var->varlevelsup);
7600 
7601  /*
7602  * If varno is special, recurse. (Don't worry about varnosyn; if we're
7603  * here, we already decided not to use that.)
7604  */
7605  if (var->varno == OUTER_VAR && dpns->outer_tlist)
7606  {
7607  TargetEntry *tle;
7608  deparse_namespace save_dpns;
7609  Bitmapset *save_appendparents;
7610 
7611  tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
7612  if (!tle)
7613  elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7614 
7615  /*
7616  * If we're descending to the first child of an Append or MergeAppend,
7617  * update appendparents. This will affect deparsing of all Vars
7618  * appearing within the eventually-resolved subexpression.
7619  */
7620  save_appendparents = context->appendparents;
7621 
7622  if (IsA(dpns->plan, Append))
7623  context->appendparents = bms_union(context->appendparents,
7624  ((Append *) dpns->plan)->apprelids);
7625  else if (IsA(dpns->plan, MergeAppend))
7626  context->appendparents = bms_union(context->appendparents,
7627  ((MergeAppend *) dpns->plan)->apprelids);
7628 
7629  push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7631  callback, callback_arg);
7632  pop_child_plan(dpns, &save_dpns);
7633  context->appendparents = save_appendparents;
7634  return;
7635  }
7636  else if (var->varno == INNER_VAR && dpns->inner_tlist)
7637  {
7638  TargetEntry *tle;
7639  deparse_namespace save_dpns;
7640 
7641  tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
7642  if (!tle)
7643  elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7644 
7645  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7647  callback, callback_arg);
7648  pop_child_plan(dpns, &save_dpns);
7649  return;
7650  }
7651  else if (var->varno == INDEX_VAR && dpns->index_tlist)
7652  {
7653  TargetEntry *tle;
7654 
7655  tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
7656  if (!tle)
7657  elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
7658 
7660  callback, callback_arg);
7661  return;
7662  }
7663  else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
7664  elog(ERROR, "bogus varno: %d", var->varno);
7665 
7666  /* Not special. Just invoke the callback. */
7667  (*callback) (node, context, callback_arg);
7668 }
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46

References bms_union(), callback(), check_stack_depth(), context, elog, ERROR, TargetEntry::expr, get_tle_by_resno(), deparse_namespace::index_tlist, INDEX_VAR, deparse_namespace::inner_plan, deparse_namespace::inner_tlist, INNER_VAR, IsA, list_length(), list_nth(), deparse_namespace::outer_plan, deparse_namespace::outer_tlist, OUTER_VAR, deparse_namespace::plan, pop_child_plan(), push_child_plan(), deparse_namespace::rtable, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by get_agg_expr_helper(), and get_variable().

◆ select_rtable_names_for_explain()

List* select_rtable_names_for_explain ( List rtable,
Bitmapset rels_used 
)

Definition at line 3822 of file ruleutils.c.

3823 {
3824  deparse_namespace dpns;
3825 
3826  memset(&dpns, 0, sizeof(dpns));
3827  dpns.rtable = rtable;
3828  dpns.subplans = NIL;
3829  dpns.ctes = NIL;
3830  dpns.appendrels = NULL;
3831  set_rtable_names(&dpns, NIL, rels_used);
3832  /* We needn't bother computing column aliases yet */
3833 
3834  return dpns.rtable_names;
3835 }

References deparse_namespace::appendrels, deparse_namespace::ctes, NIL, deparse_namespace::rtable, deparse_namespace::rtable_names, set_rtable_names(), and deparse_namespace::subplans.

Referenced by ExplainPrintPlan().

◆ set_deparse_context_plan()

List* set_deparse_context_plan ( List dpcontext,
Plan plan,
List ancestors 
)

Definition at line 3799 of file ruleutils.c.

3800 {
3801  deparse_namespace *dpns;
3802 
3803  /* Should always have one-entry namespace list for Plan deparsing */
3804  Assert(list_length(dpcontext) == 1);
3805  dpns = (deparse_namespace *) linitial(dpcontext);
3806 
3807  /* Set our attention on the specific plan node passed in */
3808  dpns->ancestors = ancestors;
3809  set_deparse_plan(dpns, plan);
3810 
3811  return dpcontext;
3812 }

References deparse_namespace::ancestors, Assert, linitial, list_length(), plan, and set_deparse_plan().

Referenced by show_expression(), show_grouping_sets(), show_memoize_info(), show_plan_tlist(), show_sort_group_keys(), and show_tablesample().

◆ set_deparse_for_query()

static void set_deparse_for_query ( deparse_namespace dpns,
Query query,
List parent_namespaces 
)
static

Definition at line 3996 of file ruleutils.c.

3998 {
3999  ListCell *lc;
4000  ListCell *lc2;
4001 
4002  /* Initialize *dpns and fill rtable/ctes links */
4003  memset(dpns, 0, sizeof(deparse_namespace));
4004  dpns->rtable = query->rtable;
4005  dpns->subplans = NIL;
4006  dpns->ctes = query->cteList;
4007  dpns->appendrels = NULL;
4008 
4009  /* Assign a unique relation alias to each RTE */
4010  set_rtable_names(dpns, parent_namespaces, NULL);
4011 
4012  /* Initialize dpns->rtable_columns to contain zeroed structs */
4013  dpns->rtable_columns = NIL;
4014  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4015  dpns->rtable_columns = lappend(dpns->rtable_columns,
4016  palloc0(sizeof(deparse_columns)));
4017 
4018  /* If it's a utility query, it won't have a jointree */
4019  if (query->jointree)
4020  {
4021  /* Detect whether global uniqueness of USING names is needed */
4022  dpns->unique_using =
4023  has_dangerous_join_using(dpns, (Node *) query->jointree);
4024 
4025  /*
4026  * Select names for columns merged by USING, via a recursive pass over
4027  * the query jointree.
4028  */
4029  set_using_names(dpns, (Node *) query->jointree, NIL);
4030  }
4031 
4032  /*
4033  * Now assign remaining column aliases for each RTE. We do this in a
4034  * linear scan of the rtable, so as to process RTEs whether or not they
4035  * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
4036  * etc). JOIN RTEs must be processed after their children, but this is
4037  * okay because they appear later in the rtable list than their children
4038  * (cf Asserts in identify_join_columns()).
4039  */
4040  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4041  {
4042  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4043  deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4044 
4045  if (rte->rtekind == RTE_JOIN)
4046  set_join_column_names(dpns, rte, colinfo);
4047  else
4048  set_relation_column_names(dpns, rte, colinfo);
4049  }
4050 }
static void set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition: ruleutils.c:4333
static void set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
Definition: ruleutils.c:4168
static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition: ruleutils.c:4529
List * rtable_columns
Definition: ruleutils.c:165

References deparse_namespace::appendrels, Query::cteList, deparse_namespace::ctes, forboth, has_dangerous_join_using(), Query::jointree, lappend(), lfirst, list_length(), NIL, palloc0(), deparse_namespace::rtable, Query::rtable, deparse_namespace::rtable_columns, RTE_JOIN, RangeTblEntry::rtekind, set_join_column_names(), set_relation_column_names(), set_rtable_names(), set_using_names(), deparse_namespace::subplans, and deparse_namespace::unique_using.

Referenced by get_name_for_var_field(), get_query_def(), and make_ruledef().

◆ set_deparse_plan()

static void set_deparse_plan ( deparse_namespace dpns,
Plan plan 
)
static

Definition at line 4988 of file ruleutils.c.

4989 {
4990  dpns->plan = plan;
4991 
4992  /*
4993  * We special-case Append and MergeAppend to pretend that the first child
4994  * plan is the OUTER referent; we have to interpret OUTER Vars in their
4995  * tlists according to one of the children, and the first one is the most
4996  * natural choice.
4997  */
4998  if (IsA(plan, Append))
4999  dpns->outer_plan = linitial(((Append *) plan)->appendplans);
5000  else if (IsA(plan, MergeAppend))
5001  dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
5002  else
5003  dpns->outer_plan = outerPlan(plan);
5004 
5005  if (dpns->outer_plan)
5006  dpns->outer_tlist = dpns->outer_plan->targetlist;
5007  else
5008  dpns->outer_tlist = NIL;
5009 
5010  /*
5011  * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
5012  * use OUTER because that could someday conflict with the normal meaning.)
5013  * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
5014  * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
5015  * that as INNER referent.
5016  *
5017  * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
5018  * INNER referent. This is the join from the target relation to the data
5019  * source, and all INNER_VAR Vars in other parts of the query refer to its
5020  * targetlist.
5021  *
5022  * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
5023  * excluded expression's tlist. (Similar to the SubqueryScan we don't want
5024  * to reuse OUTER, it's used for RETURNING in some modify table cases,
5025  * although not INSERT .. CONFLICT).
5026  */
5027  if (IsA(plan, SubqueryScan))
5028  dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
5029  else if (IsA(plan, CteScan))
5030  dpns->inner_plan = list_nth(dpns->subplans,
5031  ((CteScan *) plan)->ctePlanId - 1);
5032  else if (IsA(plan, WorkTableScan))
5033  dpns->inner_plan = find_recursive_union(dpns,
5034  (WorkTableScan *) plan);
5035  else if (IsA(plan, ModifyTable))
5036  {
5037  if (((ModifyTable *) plan)->operation == CMD_MERGE)
5038  dpns->inner_plan = outerPlan(plan);
5039  else
5040  dpns->inner_plan = plan;
5041  }
5042  else
5043  dpns->inner_plan = innerPlan(plan);
5044 
5045  if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
5046  dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5047  else if (dpns->inner_plan)
5048  dpns->inner_tlist = dpns->inner_plan->targetlist;
5049  else
5050  dpns->inner_tlist = NIL;
5051 
5052  /* Set up referent for INDEX_VAR Vars, if needed */
5053  if (IsA(plan, IndexOnlyScan))
5054  dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5055  else if (IsA(plan, ForeignScan))
5056  dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5057  else if (IsA(plan, CustomScan))
5058  dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5059  else
5060  dpns->index_tlist = NIL;
5061 }
#define outerPlan(node)
Definition: plannodes.h:182
static Plan * find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
Definition: ruleutils.c:5069

References CMD_INSERT, CMD_MERGE, find_recursive_union(), deparse_namespace::index_tlist, deparse_namespace::inner_plan, deparse_namespace::inner_tlist, innerPlan, IsA, linitial, list_nth(), NIL, deparse_namespace::outer_plan, deparse_namespace::outer_tlist, outerPlan, deparse_namespace::plan, plan, deparse_namespace::subplans, and Plan::targetlist.

Referenced by push_ancestor_plan(), push_child_plan(), and set_deparse_context_plan().

◆ set_join_column_names()

static void set_join_column_names ( deparse_namespace dpns,
RangeTblEntry rte,
deparse_columns colinfo 
)
static

Definition at line 4529 of file ruleutils.c.

4531 {
4532  deparse_columns *leftcolinfo;
4533  deparse_columns *rightcolinfo;
4534  bool changed_any;
4535  int noldcolumns;
4536  int nnewcolumns;
4537  Bitmapset *leftmerged = NULL;
4538  Bitmapset *rightmerged = NULL;
4539  int i;
4540  int j;
4541  int ic;
4542  int jc;
4543 
4544  /* Look up the previously-filled-in child deparse_columns structs */
4545  leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4546  rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4547 
4548  /*
4549  * Ensure colinfo->colnames has a slot for each column. (It could be long
4550  * enough already, if we pushed down a name for the last column.) Note:
4551  * it's possible that one or both inputs now have more columns than there
4552  * were when the query was parsed, but we'll deal with that below. We
4553  * only need entries in colnames for pre-existing columns.
4554  */
4555  noldcolumns = list_length(rte->eref->colnames);
4556  expand_colnames_array_to(colinfo, noldcolumns);
4557  Assert(colinfo->num_cols == noldcolumns);
4558 
4559  /*
4560  * Scan the join output columns, select an alias for each one, and store
4561  * it in colinfo->colnames. If there are USING columns, set_using_names()
4562  * already selected their names, so we can start the loop at the first
4563  * non-merged column.
4564  */
4565  changed_any = false;
4566  for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4567  {
4568  char *colname = colinfo->colnames[i];
4569  char *real_colname;
4570 
4571  /* Join column must refer to at least one input column */
4572  Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4573 
4574  /* Get the child column name */
4575  if (colinfo->leftattnos[i] > 0)
4576  real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4577  else if (colinfo->rightattnos[i] > 0)
4578  real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4579  else
4580  {
4581  /* We're joining system columns --- use eref name */
4582  real_colname = strVal(list_nth(rte->eref->colnames, i));
4583  }
4584 
4585  /* If child col has been dropped, no need to assign a join colname */
4586  if (real_colname == NULL)
4587  {
4588  colinfo->colnames[i] = NULL;
4589  continue;
4590  }
4591 
4592  /* In an unnamed join, just report child column names as-is */
4593  if (rte->alias == NULL)
4594  {
4595  colinfo->colnames[i] = real_colname;
4596  continue;
4597  }
4598 
4599  /* If alias already assigned, that's what to use */
4600  if (colname == NULL)
4601  {
4602  /* If user wrote an alias, prefer that over real column name */
4603  if (rte->alias && i < list_length(rte->alias->colnames))
4604  colname = strVal(list_nth(rte->alias->colnames, i));
4605  else
4606  colname = real_colname;
4607 
4608  /* Unique-ify and insert into colinfo */
4609  colname = make_colname_unique(colname, dpns, colinfo);
4610 
4611  colinfo->colnames[i] = colname;
4612  }
4613 
4614  /* Remember if any assigned aliases differ from "real" name */
4615  if (!changed_any && strcmp(colname, real_colname) != 0)
4616  changed_any = true;
4617  }
4618 
4619  /*
4620  * Calculate number of columns the join would have if it were re-parsed
4621  * now, and create storage for the new_colnames and is_new_col arrays.
4622  *
4623  * Note: colname_is_unique will be consulting new_colnames[] during the
4624  * loops below, so its not-yet-filled entries must be zeroes.
4625  */
4626  nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4627  list_length(colinfo->usingNames);
4628  colinfo->num_new_cols = nnewcolumns;
4629  colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
4630  colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
4631 
4632  /*
4633  * Generating the new_colnames array is a bit tricky since any new columns
4634  * added since parse time must be inserted in the right places. This code
4635  * must match the parser, which will order a join's columns as merged
4636  * columns first (in USING-clause order), then non-merged columns from the
4637  * left input (in attnum order), then non-merged columns from the right
4638  * input (ditto). If one of the inputs is itself a join, its columns will
4639  * be ordered according to the same rule, which means newly-added columns
4640  * might not be at the end. We can figure out what's what by consulting
4641  * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4642  *
4643  * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4644  * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4645  * meanings for the current child RTE.
4646  */
4647 
4648  /* Handle merged columns; they are first and can't be new */
4649  i = j = 0;
4650  while (i < noldcolumns &&
4651  colinfo->leftattnos[i] != 0 &&
4652  colinfo->rightattnos[i] != 0)
4653  {
4654  /* column name is already determined and known unique */
4655  colinfo->new_colnames[j] = colinfo->colnames[i];
4656  colinfo->is_new_col[j] = false;
4657 
4658  /* build bitmapsets of child attnums of merged columns */
4659  if (colinfo->leftattnos[i] > 0)
4660  leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
4661  if (colinfo->rightattnos[i] > 0)
4662  rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4663 
4664  i++, j++;
4665  }
4666 
4667  /* Handle non-merged left-child columns */
4668  ic = 0;
4669  for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4670  {
4671  char *child_colname = leftcolinfo->new_colnames[jc];
4672 
4673  if (!leftcolinfo->is_new_col[jc])
4674  {
4675  /* Advance ic to next non-dropped old column of left child */
4676  while (ic < leftcolinfo->num_cols &&
4677  leftcolinfo->colnames[ic] == NULL)
4678  ic++;
4679  Assert(ic < leftcolinfo->num_cols);
4680  ic++;
4681  /* If it is a merged column, we already processed it */
4682  if (bms_is_member(ic, leftmerged))
4683  continue;
4684  /* Else, advance i to the corresponding existing join column */
4685  while (i < colinfo->num_cols &&
4686  colinfo->colnames[i] == NULL)
4687  i++;
4688  Assert(i < colinfo->num_cols);
4689  Assert(ic == colinfo->leftattnos[i]);
4690  /* Use the already-assigned name of this column */
4691  colinfo->new_colnames[j] = colinfo->colnames[i];
4692  i++;
4693  }
4694  else
4695  {
4696  /*
4697  * Unique-ify the new child column name and assign, unless we're
4698  * in an unnamed join, in which case just copy
4699  */
4700  if (rte->alias != NULL)
4701  {
4702  colinfo->new_colnames[j] =
4703  make_colname_unique(child_colname, dpns, colinfo);
4704  if (!changed_any &&
4705  strcmp(colinfo->new_colnames[j], child_colname) != 0)
4706  changed_any = true;
4707  }
4708  else
4709  colinfo->new_colnames[j] = child_colname;
4710  }
4711 
4712  colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4713  j++;
4714  }
4715 
4716  /* Handle non-merged right-child columns in exactly the same way */
4717  ic = 0;
4718  for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4719  {
4720  char *child_colname = rightcolinfo->new_colnames[jc];
4721 
4722  if (!rightcolinfo->is_new_col[jc])
4723  {
4724  /* Advance ic to next non-dropped old column of right child */
4725  while (ic < rightcolinfo->num_cols &&
4726  rightcolinfo->colnames[ic] == NULL)
4727  ic++;
4728  Assert(ic < rightcolinfo->num_cols);
4729  ic++;
4730  /* If it is a merged column, we already processed it */
4731  if (bms_is_member(ic, rightmerged))
4732  continue;
4733  /* Else, advance i to the corresponding existing join column */
4734  while (i < colinfo->num_cols &&
4735  colinfo->colnames[i] == NULL)
4736  i++;
4737  Assert(i < colinfo->num_cols);
4738  Assert(ic == colinfo->rightattnos[i]);
4739  /* Use the already-assigned name of this column */
4740  colinfo->new_colnames[j] = colinfo->colnames[i];
4741  i++;
4742  }
4743  else
4744  {
4745  /*
4746  * Unique-ify the new child column name and assign, unless we're
4747  * in an unnamed join, in which case just copy
4748  */
4749  if (rte->alias != NULL)
4750  {
4751  colinfo->new_colnames[j] =
4752  make_colname_unique(child_colname, dpns, colinfo);
4753  if (!changed_any &&
4754  strcmp(colinfo->new_colnames[j], child_colname) != 0)
4755  changed_any = true;
4756  }
4757  else
4758  colinfo->new_colnames[j] = child_colname;
4759  }
4760 
4761  colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4762  j++;
4763  }
4764 
4765  /* Assert we processed the right number of columns */
4766 #ifdef USE_ASSERT_CHECKING
4767  while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4768  i++;
4769  Assert(i == colinfo->num_cols);
4770  Assert(j == nnewcolumns);
4771 #endif
4772 
4773  /*
4774  * For a named join, print column aliases if we changed any from the child
4775  * names. Unnamed joins cannot print aliases.
4776  */
4777  if (rte->alias != NULL)
4778  colinfo->printaliases = changed_any;
4779  else
4780  colinfo->printaliases = false;
4781 }
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
static char * make_colname_unique(char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
Definition: ruleutils.c:4843
static void expand_colnames_array_to(deparse_columns *colinfo, int n)
Definition: ruleutils.c:4882
bool * is_new_col
Definition: ruleutils.c:263

References Assert, bms_add_member(), bms_is_member(), deparse_columns::colnames, deparse_columns_fetch, expand_colnames_array_to(), i, deparse_columns::is_new_col, j, deparse_columns::leftattnos, deparse_columns::leftrti, list_length(), list_nth(), make_colname_unique(), deparse_columns::new_colnames, deparse_columns::num_cols, deparse_columns::num_new_cols, palloc0(), deparse_columns::printaliases, deparse_columns::rightattnos, deparse_columns::rightrti, strVal, and deparse_columns::usingNames.

Referenced by set_deparse_for_query().

◆ set_relation_column_names()

static void set_relation_column_names ( deparse_namespace dpns,
RangeTblEntry rte,
deparse_columns colinfo 
)
static

Definition at line 4333 of file ruleutils.c.

4335 {
4336  int ncolumns;
4337  char **real_colnames;
4338  bool changed_any;
4339  int noldcolumns;
4340  int i;
4341  int j;
4342 
4343  /*
4344  * Construct an array of the current "real" column names of the RTE.
4345  * real_colnames[] will be indexed by physical column number, with NULL
4346  * entries for dropped columns.
4347  */
4348  if (rte->rtekind == RTE_RELATION)
4349  {
4350  /* Relation --- look to the system catalogs for up-to-date info */
4351  Relation rel;
4352  TupleDesc tupdesc;
4353 
4354  rel = relation_open(rte->relid, AccessShareLock);
4355  tupdesc = RelationGetDescr(rel);
4356 
4357  ncolumns = tupdesc->natts;
4358  real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4359 
4360  for (i = 0; i < ncolumns; i++)
4361  {
4362  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4363 
4364  if (attr->attisdropped)
4365  real_colnames[i] = NULL;
4366  else
4367  real_colnames[i] = pstrdup(NameStr(attr->attname));
4368  }
4370  }
4371  else
4372  {
4373  /* Otherwise get the column names from eref or expandRTE() */
4374  List *colnames;
4375  ListCell *lc;
4376 
4377  /*
4378  * Functions returning composites have the annoying property that some
4379  * of the composite type's columns might have been dropped since the
4380  * query was parsed. If possible, use expandRTE() to handle that
4381  * case, since it has the tedious logic needed to find out about
4382  * dropped columns. However, if we're explaining a plan, then we
4383  * don't have rte->functions because the planner thinks that won't be
4384  * needed later, and that breaks expandRTE(). So in that case we have
4385  * to rely on rte->eref, which may lead us to report a dropped
4386  * column's old name; that seems close enough for EXPLAIN's purposes.
4387  *
4388  * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4389  * which should be sufficiently up-to-date: no other RTE types can
4390  * have columns get dropped from under them after parsing.
4391  */
4392  if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
4393  {
4394  /* Since we're not creating Vars, rtindex etc. don't matter */
4395  expandRTE(rte, 1, 0, -1, true /* include dropped */ ,
4396  &colnames, NULL);
4397  }
4398  else
4399  colnames = rte->eref->colnames;
4400 
4401  ncolumns = list_length(colnames);
4402  real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4403 
4404  i = 0;
4405  foreach(lc, colnames)
4406  {
4407  /*
4408  * If the column name we find here is an empty string, then it's a
4409  * dropped column, so change to NULL.
4410  */
4411  char *cname = strVal(lfirst(lc));
4412 
4413  if (cname[0] == '\0')
4414  cname = NULL;
4415  real_colnames[i] = cname;
4416  i++;
4417  }
4418  }
4419 
4420  /*
4421  * Ensure colinfo->colnames has a slot for each column. (It could be long
4422  * enough already, if we pushed down a name for the last column.) Note:
4423  * it's possible that there are now more columns than there were when the
4424  * query was parsed, ie colnames could be longer than rte->eref->colnames.
4425  * We must assign unique aliases to the new columns too, else there could
4426  * be unresolved conflicts when the view/rule is reloaded.
4427  */
4428  expand_colnames_array_to(colinfo, ncolumns);
4429  Assert(colinfo->num_cols == ncolumns);
4430 
4431  /*
4432  * Make sufficiently large new_colnames and is_new_col arrays, too.
4433  *
4434  * Note: because we leave colinfo->num_new_cols zero until after the loop,
4435  * colname_is_unique will not consult that array, which is fine because it
4436  * would only be duplicate effort.
4437  */
4438  colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4439  colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4440 
4441  /*
4442  * Scan the columns, select a unique alias for each one, and store it in
4443  * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4444  * entries for dropped columns, the latter omits them. Also mark
4445  * new_colnames entries as to whether they are new since parse time; this
4446  * is the case for entries beyond the length of rte->eref->colnames.
4447  */
4448  noldcolumns = list_length(rte->eref->colnames);
4449  changed_any = false;
4450  j = 0;
4451  for (i = 0; i < ncolumns; i++)
4452  {
4453  char *real_colname = real_colnames[i];
4454  char *colname = colinfo->colnames[i];
4455 
4456  /* Skip dropped columns */
4457  if (real_colname == NULL)
4458  {
4459  Assert(colname == NULL); /* colnames[i] is already NULL */
4460  continue;
4461  }
4462 
4463  /* If alias already assigned, that's what to use */
4464  if (colname == NULL)
4465  {
4466  /* If user wrote an alias, prefer that over real column name */
4467  if (rte->alias && i < list_length(rte->alias->colnames))
4468  colname = strVal(list_nth(rte->alias->colnames, i));
4469  else
4470  colname = real_colname;
4471 
4472  /* Unique-ify and insert into colinfo */
4473  colname = make_colname_unique(colname, dpns, colinfo);
4474 
4475  colinfo->colnames[i] = colname;
4476  }
4477 
4478  /* Put names of non-dropped columns in new_colnames[] too */
4479  colinfo->new_colnames[j] = colname;
4480  /* And mark them as new or not */
4481  colinfo->is_new_col[j] = (i >= noldcolumns);
4482  j++;
4483 
4484  /* Remember if any assigned aliases differ from "real" name */
4485  if (!changed_any && strcmp(colname, real_colname) != 0)
4486  changed_any = true;
4487  }
4488 
4489  /*
4490  * Set correct length for new_colnames[] array. (Note: if columns have
4491  * been added, colinfo->num_cols includes them, which is not really quite
4492  * right but is harmless, since any new columns must be at the end where
4493  * they won't affect varattnos of pre-existing columns.)
4494  */
4495  colinfo->num_new_cols = j;
4496 
4497  /*
4498  * For a relation RTE, we need only print the alias column names if any
4499  * are different from the underlying "real" names. For a function RTE,
4500  * always emit a complete column alias list; this is to protect against
4501  * possible instability of the default column names (eg, from altering
4502  * parameter names). For tablefunc RTEs, we never print aliases, because
4503  * the column names are part of the clause itself. For other RTE types,
4504  * print if we changed anything OR if there were user-written column
4505  * aliases (since the latter would be part of the underlying "reality").
4506  */
4507  if (rte->rtekind == RTE_RELATION)
4508  colinfo->printaliases = changed_any;
4509  else if (rte->rtekind == RTE_FUNCTION)
4510  colinfo->printaliases = true;
4511  else if (rte->rtekind == RTE_TABLEFUNC)
4512  colinfo->printaliases = false;
4513  else if (rte->alias && rte->alias->colnames != NIL)
4514  colinfo->printaliases = true;
4515  else
4516  colinfo->printaliases = changed_any;
4517 }
void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars)
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47

References AccessShareLock, Assert, deparse_columns::colnames, expand_colnames_array_to(), expandRTE(), RangeTblEntry::functions, i, deparse_columns::is_new_col, j, lfirst, list_length(), list_nth(), make_colname_unique(), NameStr, TupleDescData::natts, deparse_columns::new_colnames, NIL, deparse_columns::num_cols, deparse_columns::num_new_cols, palloc(), deparse_columns::printaliases, pstrdup(), relation_close(), relation_open(), RelationGetDescr, RangeTblEntry::relid, RTE_FUNCTION, RTE_RELATION, RTE_TABLEFUNC, RangeTblEntry::rtekind, strVal, and TupleDescAttr.

Referenced by set_deparse_for_query(), and set_simple_column_names().

◆ set_rtable_names()

static void set_rtable_names ( deparse_namespace dpns,
List parent_namespaces,
Bitmapset rels_used 
)
static

Definition at line 3851 of file ruleutils.c.

3853 {
3854  HASHCTL hash_ctl;
3855  HTAB *names_hash;
3856  NameHashEntry *hentry;
3857  bool found;
3858  int rtindex;
3859  ListCell *lc;
3860 
3861  dpns->rtable_names = NIL;
3862  /* nothing more to do if empty rtable */
3863  if (dpns->rtable == NIL)
3864  return;
3865 
3866  /*
3867  * We use a hash table to hold known names, so that this process is O(N)
3868  * not O(N^2) for N names.
3869  */
3870  hash_ctl.keysize = NAMEDATALEN;
3871  hash_ctl.entrysize = sizeof(NameHashEntry);
3872  hash_ctl.hcxt = CurrentMemoryContext;
3873  names_hash = hash_create("set_rtable_names names",
3874  list_length(dpns->rtable),
3875  &hash_ctl,
3877 
3878  /* Preload the hash table with names appearing in parent_namespaces */
3879  foreach(lc, parent_namespaces)
3880  {
3881  deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3882  ListCell *lc2;
3883 
3884  foreach(lc2, olddpns->rtable_names)
3885  {
3886  char *oldname = (char *) lfirst(lc2);
3887 
3888  if (oldname == NULL)
3889  continue;
3890  hentry = (NameHashEntry *) hash_search(names_hash,
3891  oldname,
3892  HASH_ENTER,
3893  &found);
3894  /* we do not complain about duplicate names in parent namespaces */
3895  hentry->counter = 0;
3896  }
3897  }
3898 
3899  /* Now we can scan the rtable */
3900  rtindex = 1;
3901  foreach(lc, dpns->rtable)
3902  {
3903  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3904  char *refname;
3905 
3906  /* Just in case this takes an unreasonable amount of time ... */
3908 
3909  if (rels_used && !bms_is_member(rtindex, rels_used))
3910  {
3911  /* Ignore unreferenced RTE */
3912  refname = NULL;
3913  }
3914  else if (rte->alias)
3915  {
3916  /* If RTE has a user-defined alias, prefer that */
3917  refname = rte->alias->aliasname;
3918  }
3919  else if (rte->rtekind == RTE_RELATION)
3920  {
3921  /* Use the current actual name of the relation */
3922  refname = get_rel_name(rte->relid);
3923  }
3924  else if (rte->rtekind == RTE_JOIN)
3925  {
3926  /* Unnamed join has no refname */
3927  refname = NULL;
3928  }
3929  else
3930  {
3931  /* Otherwise use whatever the parser assigned */
3932  refname = rte->eref->aliasname;
3933  }
3934 
3935  /*
3936  * If the selected name isn't unique, append digits to make it so, and
3937  * make a new hash entry for it once we've got a unique name. For a
3938  * very long input name, we might have to truncate to stay within
3939  * NAMEDATALEN.
3940  */
3941  if (refname)
3942  {
3943  hentry = (NameHashEntry *) hash_search(names_hash,
3944  refname,
3945  HASH_ENTER,
3946  &found);
3947  if (found)
3948  {
3949  /* Name already in use, must choose a new one */
3950  int refnamelen = strlen(refname);
3951  char *modname = (char *) palloc(refnamelen + 16);
3952  NameHashEntry *hentry2;
3953 
3954  do
3955  {
3956  hentry->counter++;
3957  for (;;)
3958  {
3959  memcpy(modname, refname, refnamelen);
3960  sprintf(modname + refnamelen, "_%d", hentry->counter);
3961  if (strlen(modname) < NAMEDATALEN)
3962  break;
3963  /* drop chars from refname to keep all the digits */
3964  refnamelen = pg_mbcliplen(refname, refnamelen,
3965  refnamelen - 1);
3966  }
3967  hentry2 = (NameHashEntry *) hash_search(names_hash,
3968  modname,
3969  HASH_ENTER,
3970  &found);
3971  } while (found);
3972  hentry2->counter = 0; /* init new hash entry */
3973  refname = modname;
3974  }
3975  else
3976  {
3977  /* Name not previously used, need only initialize hentry */
3978  hentry->counter = 0;
3979  }
3980  }
3981 
3982  dpns->rtable_names = lappend(dpns->rtable_names, refname);
3983  rtindex++;
3984  }
3985 
3986  hash_destroy(names_hash);
3987 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_STRINGS
Definition: hsearch.h:96
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:220

References bms_is_member(), CHECK_FOR_INTERRUPTS, NameHashEntry::counter, CurrentMemoryContext, HASHCTL::entrysize, get_rel_name(), HASH_CONTEXT, hash_create(), hash_destroy(), HASH_ELEM, HASH_ENTER, hash_search(), HASH_STRINGS, HASHCTL::hcxt, HASHCTL::keysize, lappend(), lfirst, list_length(), NAMEDATALEN, NIL, palloc(), pg_mbcliplen(), RangeTblEntry::relid, deparse_namespace::rtable, deparse_namespace::rtable_names, RTE_JOIN, RTE_RELATION, RangeTblEntry::rtekind, and sprintf.

Referenced by deparse_context_for(), pg_get_triggerdef_worker(), select_rtable_names_for_explain(), and set_deparse_for_query().

◆ set_simple_column_names()

static void set_simple_column_names ( deparse_namespace dpns)
static

Definition at line 4061 of file ruleutils.c.

4062 {
4063  ListCell *lc;
4064  ListCell *lc2;
4065 
4066  /* Initialize dpns->rtable_columns to contain zeroed structs */
4067  dpns->rtable_columns = NIL;
4068  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4069  dpns->rtable_columns = lappend(dpns->rtable_columns,
4070  palloc0(sizeof(deparse_columns)));
4071 
4072  /* Assign unique column aliases within each RTE */
4073  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4074  {
4075  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4076  deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4077 
4078  set_relation_column_names(dpns, rte, colinfo);
4079  }
4080 }

References forboth, lappend(), lfirst, list_length(), NIL, palloc0(), deparse_namespace::rtable, deparse_namespace::rtable_columns, and set_relation_column_names().

Referenced by deparse_context_for(), deparse_context_for_plan_tree(), and pg_get_triggerdef_worker().

◆ set_using_names()

static void set_using_names ( deparse_namespace dpns,
Node jtnode,
List parentUsing 
)
static

Definition at line 4168 of file ruleutils.c.

4169 {
4170  if (IsA(jtnode, RangeTblRef))
4171  {
4172  /* nothing to do now */
4173  }
4174  else if (IsA(jtnode, FromExpr))
4175  {
4176  FromExpr *f = (FromExpr *) jtnode;
4177  ListCell *lc;
4178 
4179  foreach(lc, f->fromlist)
4180  set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4181  }
4182  else if (IsA(jtnode, JoinExpr))
4183  {
4184  JoinExpr *j = (JoinExpr *) jtnode;
4185  RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4186  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
4187  int *leftattnos;
4188  int *rightattnos;
4189  deparse_columns *leftcolinfo;
4190  deparse_columns *rightcolinfo;
4191  int i;
4192  ListCell *lc;
4193 
4194  /* Get info about the shape of the join */
4195  identify_join_columns(j, rte, colinfo);
4196  leftattnos = colinfo->leftattnos;
4197  rightattnos = colinfo->rightattnos;
4198 
4199  /* Look up the not-yet-filled-in child deparse_columns structs */
4200  leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4201  rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4202 
4203  /*
4204  * If this join is unnamed, then we cannot substitute new aliases at
4205  * this level, so any name requirements pushed down to here must be
4206  * pushed down again to the children.
4207  */
4208  if (rte->alias == NULL)
4209  {
4210  for (i = 0; i < colinfo->num_cols; i++)
4211  {
4212  char *colname = colinfo->colnames[i];
4213 
4214  if (colname == NULL)
4215  continue;
4216 
4217  /* Push down to left column, unless it's a system column */
4218  if (leftattnos[i] > 0)
4219  {
4220  expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4221  leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4222  }
4223 
4224  /* Same on the righthand side */
4225  if (rightattnos[i] > 0)
4226  {
4227  expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4228  rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4229  }
4230  }
4231  }
4232 
4233  /*
4234  * If there's a USING clause, select the USING column names and push
4235  * those names down to the children. We have two strategies:
4236  *
4237  * If dpns->unique_using is true, we force all USING names to be
4238  * unique across the whole query level. In principle we'd only need
4239  * the names of dangerous USING columns to be globally unique, but to
4240  * safely assign all USING names in a single pass, we have to enforce
4241  * the same uniqueness rule for all of them. However, if a USING
4242  * column's name has been pushed down from the parent, we should use
4243  * it as-is rather than making a uniqueness adjustment. This is
4244  * necessary when we're at an unnamed join, and it creates no risk of
4245  * ambiguity. Also, if there's a user-written output alias for a
4246  * merged column, we prefer to use that rather than the input name;
4247  * this simplifies the logic and seems likely to lead to less aliasing
4248  * overall.
4249  *
4250  * If dpns->unique_using is false, we only need USING names to be
4251  * unique within their own join RTE. We still need to honor
4252  * pushed-down names, though.
4253  *
4254  * Though significantly different in results, these two strategies are
4255  * implemented by the same code, with only the difference of whether
4256  * to put assigned names into dpns->using_names.
4257  */
4258  if (j->usingClause)
4259  {
4260  /* Copy the input parentUsing list so we don't modify it */
4261  parentUsing = list_copy(parentUsing);
4262 
4263  /* USING names must correspond to the first join output columns */
4264  expand_colnames_array_to(colinfo, list_length(j->usingClause));
4265  i = 0;
4266  foreach(lc, j->usingClause)
4267  {
4268  char *colname = strVal(lfirst(lc));
4269 
4270  /* Assert it's a merged column */
4271  Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4272 
4273  /* Adopt passed-down name if any, else select unique name */
4274  if (colinfo->colnames[i] != NULL)
4275  colname = colinfo->colnames[i];
4276  else
4277  {
4278  /* Prefer user-written output alias if any */
4279  if (rte->alias && i < list_length(rte->alias->colnames))
4280  colname = strVal(list_nth(rte->alias->colnames, i));
4281  /* Make it appropriately unique */
4282  colname = make_colname_unique(colname, dpns, colinfo);
4283  if (dpns->unique_using)
4284  dpns->using_names = lappend(dpns->using_names,
4285  colname);
4286  /* Save it as output column name, too */
4287  colinfo->colnames[i] = colname;
4288  }
4289 
4290  /* Remember selected names for use later */
4291  colinfo->usingNames = lappend(colinfo->usingNames, colname);
4292  parentUsing = lappend(parentUsing, colname);
4293 
4294  /* Push down to left column, unless it's a system column */
4295  if (leftattnos[i] > 0)
4296  {
4297  expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4298  leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4299  }
4300 
4301  /* Same on the righthand side */
4302  if (rightattnos[i] > 0)
4303  {
4304  expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4305  rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4306  }
4307 
4308  i++;
4309  }
4310  }
4311 
4312  /* Mark child deparse_columns structs with correct parentUsing info */
4313  leftcolinfo->parentUsing = parentUsing;
4314  rightcolinfo->parentUsing = parentUsing;
4315 
4316  /* Now recursively assign USING column names in children */
4317  set_using_names(dpns, j->larg, parentUsing);
4318  set_using_names(dpns, j->rarg, parentUsing);
4319  }
4320  else
4321  elog(ERROR, "unrecognized node type: %d",
4322  (int) nodeTag(jtnode));
4323 }
static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte, deparse_columns *colinfo)
Definition: ruleutils.c:4901

References Assert, deparse_columns::colnames, deparse_columns_fetch, elog, ERROR, expand_colnames_array_to(), FromExpr::fromlist, i, identify_join_columns(), IsA, j, lappend(), deparse_columns::leftattnos, deparse_columns::leftrti, lfirst, list_copy(), list_length(), list_nth(), make_colname_unique(), nodeTag, deparse_columns::num_cols, deparse_columns::parentUsing, deparse_columns::rightattnos, deparse_columns::rightrti, rt_fetch, deparse_namespace::rtable, strVal, deparse_namespace::unique_using, deparse_namespace::using_names, and deparse_columns::usingNames.

Referenced by set_deparse_for_query().

◆ simple_quote_literal()

static void simple_quote_literal ( StringInfo  buf,
const char *  val 
)
static

Definition at line 11388 of file ruleutils.c.

11389 {
11390  const char *valptr;
11391 
11392  /*
11393  * We form the string literal according to the prevailing setting of
11394  * standard_conforming_strings; we never use E''. User is responsible for
11395  * making sure result is used correctly.
11396  */
11397  appendStringInfoChar(buf, '\'');
11398  for (valptr = val; *valptr; valptr++)
11399  {
11400  char ch = *valptr;
11401 
11405  }
11406  appendStringInfoChar(buf, '\'');
11407 }
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1163
PGDLLIMPORT bool standard_conforming_strings

References appendStringInfoChar(), buf, SQL_STR_DOUBLE, standard_conforming_strings, and val.

Referenced by get_const_expr(), get_reloptions(), get_rule_expr(), get_utility_query_def(), pg_get_functiondef(), and pg_get_triggerdef_worker().

◆ string_to_text()

Variable Documentation

◆ plan_getrulebyoid

SPIPlanPtr plan_getrulebyoid = NULL
static

Definition at line 317 of file ruleutils.c.

Referenced by pg_get_ruledef_worker().

◆ plan_getviewrule

SPIPlanPtr plan_getviewrule = NULL
static

Definition at line 319 of file ruleutils.c.

Referenced by pg_get_viewdef_worker().

◆ query_getrulebyoid

const char* const query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1"
static

Definition at line 318 of file ruleutils.c.

Referenced by pg_get_ruledef_worker().

◆ query_getviewrule

const char* const query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2"
static

Definition at line 320 of file ruleutils.c.

Referenced by pg_get_viewdef_worker().

◆ quote_all_identifiers

bool quote_all_identifiers = false

Definition at line 323 of file ruleutils.c.

Referenced by main(), quote_identifier(), and setup_connection().