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_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 build_colinfo_names_hash (deparse_columns *colinfo)
 
static void add_to_names_hash (deparse_columns *colinfo, const char *name)
 
static void destroy_colinfo_names_hash (deparse_columns *colinfo)
 
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)
 
static void get_insert_query_def (Query *query, deparse_context *context)
 
static void get_update_query_def (Query *query, deparse_context *context)
 
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)
 
static void get_merge_query_def (Query *query, deparse_context *context)
 
static void get_utility_query_def (Query *query, deparse_context *context)
 
static void get_basic_select_query (Query *query, deparse_context *context)
 
static void get_target_list (List *targetList, deparse_context *context)
 
static void get_returning_clause (Query *query, deparse_context *context)
 
static void get_setop_query (Node *setOp, Query *query, deparse_context *context)
 
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 void get_window_frame_options (int frameOptions, Node *startOffset, Node *endOffset, 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, bool inGroupBy)
 
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)
 
char * get_window_frame_options_for_explain (int frameOptions, Node *startOffset, Node *endOffset, List *dpcontext, bool forceprefix)
 
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)
 

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

◆ GET_PRETTY_FLAGS

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

Definition at line 93 of file ruleutils.c.

◆ only_marker

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

Definition at line 550 of file ruleutils.c.

◆ PRETTY_INDENT

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

Definition at line 102 of file ruleutils.c.

◆ PRETTY_PAREN

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

Definition at line 101 of file ruleutils.c.

◆ PRETTY_SCHEMA

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

Definition at line 103 of file ruleutils.c.

◆ PRETTYFLAG_INDENT

#define PRETTYFLAG_INDENT   0x0002

Definition at line 89 of file ruleutils.c.

◆ PRETTYFLAG_PAREN

#define PRETTYFLAG_PAREN   0x0001

Definition at line 88 of file ruleutils.c.

◆ PRETTYFLAG_SCHEMA

#define PRETTYFLAG_SCHEMA   0x0004

Definition at line 90 of file ruleutils.c.

◆ PRETTYINDENT_JOIN

#define PRETTYINDENT_JOIN   4

Definition at line 82 of file ruleutils.c.

◆ PRETTYINDENT_LIMIT

#define PRETTYINDENT_LIMIT   40 /* wrap limit */

Definition at line 85 of file ruleutils.c.

◆ PRETTYINDENT_STD

#define PRETTYINDENT_STD   8

Definition at line 81 of file ruleutils.c.

◆ PRETTYINDENT_VAR

#define PRETTYINDENT_VAR   4

Definition at line 83 of file ruleutils.c.

◆ WRAP_COLUMN_DEFAULT

#define WRAP_COLUMN_DEFAULT   0

Definition at line 98 of file ruleutils.c.

Typedef Documentation

◆ rsv_callback

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

Definition at line 325 of file ruleutils.c.

Function Documentation

◆ add_cast_to()

static void add_cast_to ( StringInfo  buf,
Oid  typid 
)
static

Definition at line 13479 of file ruleutils.c.

13480{
13481 HeapTuple typetup;
13482 Form_pg_type typform;
13483 char *typname;
13484 char *nspname;
13485
13486 typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13487 if (!HeapTupleIsValid(typetup))
13488 elog(ERROR, "cache lookup failed for type %u", typid);
13489 typform = (Form_pg_type) GETSTRUCT(typetup);
13490
13491 typname = NameStr(typform->typname);
13492 nspname = get_namespace_name_or_temp(typform->typnamespace);
13493
13494 appendStringInfo(buf, "::%s.%s",
13496
13497 ReleaseSysCache(typetup);
13498}
#define NameStr(name)
Definition: c.h:717
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3530
static char * buf
Definition: pg_test_fsync.c:72
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:257
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:13029
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

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

◆ add_to_names_hash()

static void add_to_names_hash ( deparse_columns colinfo,
const char *  name 
)
static

Definition at line 5036 of file ruleutils.c.

5037{
5038 if (colinfo->names_hash)
5039 (void) hash_search(colinfo->names_hash,
5040 name,
5041 HASH_ENTER,
5042 NULL);
5043}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:956
@ HASH_ENTER
Definition: hsearch.h:114
HTAB * names_hash
Definition: ruleutils.c:308
const char * name

References HASH_ENTER, hash_search(), name, and deparse_columns::names_hash.

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

◆ appendContextKeyword()

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

Definition at line 9082 of file ruleutils.c.

9084{
9085 StringInfo buf = context->buf;
9086
9087 if (PRETTY_INDENT(context))
9088 {
9089 int indentAmount;
9090
9091 context->indentLevel += indentBefore;
9092
9093 /* remove any trailing spaces currently in the buffer ... */
9095 /* ... then add a newline and some spaces */
9097
9098 if (context->indentLevel < PRETTYINDENT_LIMIT)
9099 indentAmount = Max(context->indentLevel, 0) + indentPlus;
9100 else
9101 {
9102 /*
9103 * If we're indented more than PRETTYINDENT_LIMIT characters, try
9104 * to conserve horizontal space by reducing the per-level
9105 * indentation. For best results the scale factor here should
9106 * divide all the indent amounts that get added to indentLevel
9107 * (PRETTYINDENT_STD, etc). It's important that the indentation
9108 * not grow unboundedly, else deeply-nested trees use O(N^2)
9109 * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
9110 */
9111 indentAmount = PRETTYINDENT_LIMIT +
9112 (context->indentLevel - PRETTYINDENT_LIMIT) /
9113 (PRETTYINDENT_STD / 2);
9114 indentAmount %= PRETTYINDENT_LIMIT;
9115 /* scale/wrap logic affects indentLevel, but not indentPlus */
9116 indentAmount += indentPlus;
9117 }
9118 appendStringInfoSpaces(buf, indentAmount);
9119
9121
9122 context->indentLevel += indentAfter;
9123 if (context->indentLevel < 0)
9124 context->indentLevel = 0;
9125 }
9126 else
9128}
#define Max(x, y)
Definition: c.h:969
const char * str
static void removeStringInfoSpaces(StringInfo str)
Definition: ruleutils.c:9136
#define PRETTYINDENT_LIMIT
Definition: ruleutils.c:85
#define PRETTYINDENT_STD
Definition: ruleutils.c:81
#define PRETTY_INDENT(context)
Definition: ruleutils.c:102
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:260
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
StringInfo buf
Definition: ruleutils.c:114

References appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), deparse_context::buf, buf, deparse_context::indentLevel, 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_returning_clause(), 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().

◆ build_colinfo_names_hash()

static void build_colinfo_names_hash ( deparse_columns colinfo)
static

Definition at line 4978 of file ruleutils.c.

4979{
4980 HASHCTL hash_ctl;
4981 int i;
4982 ListCell *lc;
4983
4984 /*
4985 * Use a hash table only for RTEs with at least 32 columns. (The cutoff
4986 * is somewhat arbitrary, but let's choose it so that this code does get
4987 * exercised in the regression tests.)
4988 */
4989 if (colinfo->num_cols < 32)
4990 return;
4991
4992 /*
4993 * Set up the hash table. The entries are just strings with no other
4994 * payload.
4995 */
4996 hash_ctl.keysize = NAMEDATALEN;
4997 hash_ctl.entrysize = NAMEDATALEN;
4998 hash_ctl.hcxt = CurrentMemoryContext;
4999 colinfo->names_hash = hash_create("deparse_columns names",
5000 colinfo->num_cols + colinfo->num_new_cols,
5001 &hash_ctl,
5003
5004 /*
5005 * Preload the hash table with any names already present (these would have
5006 * come from set_using_names).
5007 */
5008 for (i = 0; i < colinfo->num_cols; i++)
5009 {
5010 char *oldname = colinfo->colnames[i];
5011
5012 if (oldname)
5013 add_to_names_hash(colinfo, oldname);
5014 }
5015
5016 for (i = 0; i < colinfo->num_new_cols; i++)
5017 {
5018 char *oldname = colinfo->new_colnames[i];
5019
5020 if (oldname)
5021 add_to_names_hash(colinfo, oldname);
5022 }
5023
5024 foreach(lc, colinfo->parentUsing)
5025 {
5026 char *oldname = (char *) lfirst(lc);
5027
5028 add_to_names_hash(colinfo, oldname);
5029 }
5030}
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_STRINGS
Definition: hsearch.h:96
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
int i
Definition: isn.c:77
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define NAMEDATALEN
#define lfirst(lc)
Definition: pg_list.h:172
static void add_to_names_hash(deparse_columns *colinfo, const char *name)
Definition: ruleutils.c:5036
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
List * parentUsing
Definition: ruleutils.c:276
char ** new_colnames
Definition: ruleutils.c:269
char ** colnames
Definition: ruleutils.c:252

References add_to_names_hash(), deparse_columns::colnames, CurrentMemoryContext, HASHCTL::entrysize, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_STRINGS, HASHCTL::hcxt, i, HASHCTL::keysize, lfirst, NAMEDATALEN, deparse_columns::names_hash, deparse_columns::new_colnames, deparse_columns::num_cols, deparse_columns::num_new_cols, and deparse_columns::parentUsing.

Referenced by set_join_column_names(), and set_relation_column_names().

◆ colname_is_unique()

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

Definition at line 4848 of file ruleutils.c.

4850{
4851 int i;
4852 ListCell *lc;
4853
4854 /*
4855 * If we have a hash table, consult that instead of linearly scanning the
4856 * colinfo's strings.
4857 */
4858 if (colinfo->names_hash)
4859 {
4860 if (hash_search(colinfo->names_hash,
4861 colname,
4862 HASH_FIND,
4863 NULL) != NULL)
4864 return false;
4865 }
4866 else
4867 {
4868 /* Check against already-assigned column aliases within RTE */
4869 for (i = 0; i < colinfo->num_cols; i++)
4870 {
4871 char *oldname = colinfo->colnames[i];
4872
4873 if (oldname && strcmp(oldname, colname) == 0)
4874 return false;
4875 }
4876
4877 /*
4878 * If we're building a new_colnames array, check that too (this will
4879 * be partially but not completely redundant with the previous checks)
4880 */
4881 for (i = 0; i < colinfo->num_new_cols; i++)
4882 {
4883 char *oldname = colinfo->new_colnames[i];
4884
4885 if (oldname && strcmp(oldname, colname) == 0)
4886 return false;
4887 }
4888
4889 /*
4890 * Also check against names already assigned for parent-join USING
4891 * cols
4892 */
4893 foreach(lc, colinfo->parentUsing)
4894 {
4895 char *oldname = (char *) lfirst(lc);
4896
4897 if (strcmp(oldname, colname) == 0)
4898 return false;
4899 }
4900 }
4901
4902 /*
4903 * Also check against USING-column names that must be globally unique.
4904 * These are not hashed, but there should be few of them.
4905 */
4906 foreach(lc, dpns->using_names)
4907 {
4908 char *oldname = (char *) lfirst(lc);
4909
4910 if (strcmp(oldname, colname) == 0)
4911 return false;
4912 }
4913
4914 return true;
4915}
@ HASH_FIND
Definition: hsearch.h:113
List * using_names
Definition: ruleutils.c:174

References deparse_columns::colnames, HASH_FIND, hash_search(), i, lfirst, deparse_columns::names_hash, 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 2621 of file ruleutils.c.

2623{
2624 Datum *keys;
2625 int nKeys;
2626 int j;
2627
2628 /* Extract data from array of int16 */
2629 deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2630 &keys, NULL, &nKeys);
2631
2632 for (j = 0; j < nKeys; j++)
2633 {
2634 char *colName;
2635
2636 colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2637
2638 if (j == 0)
2640 else
2641 appendStringInfo(buf, ", %s%s",
2642 (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
2643 quote_identifier(colName));
2644 }
2645
2646 return nKeys;
2647}
#define DatumGetArrayTypeP(X)
Definition: array.h:261
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3697
int j
Definition: isn.c:78
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:919
uintptr_t Datum
Definition: postgres.h:69
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:167

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

3709{
3710 deparse_namespace *dpns;
3711 RangeTblEntry *rte;
3712
3713 dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3714
3715 /* Build a minimal RTE for the rel */
3716 rte = makeNode(RangeTblEntry);
3717 rte->rtekind = RTE_RELATION;
3718 rte->relid = relid;
3719 rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3720 rte->rellockmode = AccessShareLock;
3721 rte->alias = makeAlias(aliasname, NIL);
3722 rte->eref = rte->alias;
3723 rte->lateral = false;
3724 rte->inh = false;
3725 rte->inFromCl = true;
3726
3727 /* Build one-element rtable */
3728 dpns->rtable = list_make1(rte);
3729 dpns->subplans = NIL;
3730 dpns->ctes = NIL;
3731 dpns->appendrels = NULL;
3732 set_rtable_names(dpns, NIL, NULL);
3734
3735 /* Return a one-deep namespace stack */
3736 return list_make1(dpns);
3737}
#define AccessShareLock
Definition: lockdefs.h:36
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:438
void * palloc0(Size size)
Definition: mcxt.c:1351
#define makeNode(_type_)
Definition: nodes.h:161
@ RTE_RELATION
Definition: parsenodes.h:1026
#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:4098
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
Definition: ruleutils.c:3884
RTEKind rtekind
Definition: parsenodes.h:1061
AppendRelInfo ** appendrels
Definition: ruleutils.c:169

References AccessShareLock, deparse_namespace::appendrels, deparse_namespace::ctes, RangeTblEntry::inh, list_make1, makeAlias(), makeNode, NIL, palloc0(), 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 3753 of file ruleutils.c.

3754{
3755 deparse_namespace *dpns;
3756
3757 dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3758
3759 /* Initialize fields that stay the same across the whole plan tree */
3760 dpns->rtable = pstmt->rtable;
3761 dpns->rtable_names = rtable_names;
3762 dpns->subplans = pstmt->subplans;
3763 dpns->ctes = NIL;
3764 if (pstmt->appendRelations)
3765 {
3766 /* Set up the array, indexed by child relid */
3767 int ntables = list_length(dpns->rtable);
3768 ListCell *lc;
3769
3770 dpns->appendrels = (AppendRelInfo **)
3771 palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3772 foreach(lc, pstmt->appendRelations)
3773 {
3774 AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3775 Index crelid = appinfo->child_relid;
3776
3777 Assert(crelid > 0 && crelid <= ntables);
3778 Assert(dpns->appendrels[crelid] == NULL);
3779 dpns->appendrels[crelid] = appinfo;
3780 }
3781 }
3782 else
3783 dpns->appendrels = NULL; /* don't need it */
3784
3785 /*
3786 * Set up column name aliases, ignoring any join RTEs; they don't matter
3787 * because plan trees don't contain any join alias Vars.
3788 */
3790
3791 /* Return a one-deep namespace stack */
3792 return list_make1(dpns);
3793}
unsigned int Index
Definition: c.h:585
Assert(PointerIsAligned(start, uint64))
#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:3111
List * appendRelations
Definition: plannodes.h:109
List * subplans
Definition: plannodes.h:114
List * rtable
Definition: plannodes.h:91
List * rtable_names
Definition: ruleutils.c:165

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

Referenced by ExplainPrintPlan().

◆ deparse_expression()

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

Definition at line 3645 of file ruleutils.c.

3647{
3648 return deparse_expression_pretty(expr, dpcontext, forceprefix,
3649 showimplicit, 0, 0);
3650}
static char * deparse_expression_pretty(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
Definition: ruleutils.c:3672

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

3675{
3677 deparse_context context;
3678
3680 context.buf = &buf;
3681 context.namespaces = dpcontext;
3682 context.resultDesc = NULL;
3683 context.targetList = NIL;
3684 context.windowClause = NIL;
3685 context.varprefix = forceprefix;
3686 context.prettyFlags = prettyFlags;
3688 context.indentLevel = startIndent;
3689 context.colNamesVisible = true;
3690 context.inGroupBy = false;
3691 context.varInOrderBy = false;
3692 context.appendparents = NULL;
3693
3694 get_rule_expr(expr, &context, showimplicit);
3695
3696 return buf.data;
3697}
#define WRAP_COLUMN_DEFAULT
Definition: ruleutils.c:98
static void get_rule_expr(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:9252
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
TupleDesc resultDesc
Definition: ruleutils.c:116
List * targetList
Definition: ruleutils.c:117
bool colNamesVisible
Definition: ruleutils.c:123
List * namespaces
Definition: ruleutils.c:115
List * windowClause
Definition: ruleutils.c:118
Bitmapset * appendparents
Definition: ruleutils.c:126

References deparse_context::appendparents, deparse_context::buf, buf, deparse_context::colNamesVisible, get_rule_expr(), deparse_context::indentLevel, deparse_context::inGroupBy, initStringInfo(), deparse_context::namespaces, NIL, deparse_context::prettyFlags, deparse_context::resultDesc, deparse_context::targetList, deparse_context::varInOrderBy, deparse_context::varprefix, deparse_context::windowClause, WRAP_COLUMN_DEFAULT, and deparse_context::wrapColumn.

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

◆ destroy_colinfo_names_hash()

static void destroy_colinfo_names_hash ( deparse_columns colinfo)
static

Definition at line 5049 of file ruleutils.c.

5050{
5051 if (colinfo->names_hash)
5052 {
5053 hash_destroy(colinfo->names_hash);
5054 colinfo->names_hash = NULL;
5055 }
5056}
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:866

References hash_destroy(), and deparse_columns::names_hash.

Referenced by set_join_column_names(), and set_relation_column_names().

◆ expand_colnames_array_to()

static void expand_colnames_array_to ( deparse_columns colinfo,
int  n 
)
static

Definition at line 4962 of file ruleutils.c.

4963{
4964 if (n > colinfo->num_cols)
4965 {
4966 if (colinfo->colnames == NULL)
4967 colinfo->colnames = palloc0_array(char *, n);
4968 else
4969 colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4970 colinfo->num_cols = n;
4971 }
4972}
#define palloc0_array(type, count)
Definition: fe_memutils.h:77
#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 8569 of file ruleutils.c.

8570{
8571 /* Initialize output parameter to prevent compiler warnings */
8572 *column_p = 0;
8573
8574 /*
8575 * If it's a PARAM_EXEC parameter, search the current plan node as well as
8576 * ancestor nodes looking for a subplan or initplan that emits the value
8577 * for the Param. It could appear in the setParams of an initplan or
8578 * MULTIEXPR_SUBLINK subplan, or in the paramIds of an ancestral SubPlan.
8579 */
8580 if (param->paramkind == PARAM_EXEC)
8581 {
8582 SubPlan *result;
8583 deparse_namespace *dpns;
8584 ListCell *lc;
8585
8586 dpns = (deparse_namespace *) linitial(context->namespaces);
8587
8588 /* First check the innermost plan node's initplans */
8589 result = find_param_generator_initplan(param, dpns->plan, column_p);
8590 if (result)
8591 return result;
8592
8593 /*
8594 * The plan's targetlist might contain MULTIEXPR_SUBLINK SubPlans,
8595 * which can be referenced by Params elsewhere in the targetlist.
8596 * (Such Params should always be in the same targetlist, so there's no
8597 * need to do this work at upper plan nodes.)
8598 */
8600 {
8601 if (tle->expr && IsA(tle->expr, SubPlan))
8602 {
8603 SubPlan *subplan = (SubPlan *) tle->expr;
8604
8605 if (subplan->subLinkType == MULTIEXPR_SUBLINK)
8606 {
8607 foreach_int(paramid, subplan->setParam)
8608 {
8609 if (paramid == param->paramid)
8610 {
8611 /* Found a match, so return it. */
8612 *column_p = foreach_current_index(paramid);
8613 return subplan;
8614 }
8615 }
8616 }
8617 }
8618 }
8619
8620 /* No luck, so check the ancestor nodes */
8621 foreach(lc, dpns->ancestors)
8622 {
8623 Node *ancestor = (Node *) lfirst(lc);
8624
8625 /*
8626 * If ancestor is a SubPlan, check the paramIds it provides.
8627 */
8628 if (IsA(ancestor, SubPlan))
8629 {
8630 SubPlan *subplan = (SubPlan *) ancestor;
8631
8632 foreach_int(paramid, subplan->paramIds)
8633 {
8634 if (paramid == param->paramid)
8635 {
8636 /* Found a match, so return it. */
8637 *column_p = foreach_current_index(paramid);
8638 return subplan;
8639 }
8640 }
8641
8642 /* SubPlan isn't a kind of Plan, so skip the rest */
8643 continue;
8644 }
8645
8646 /*
8647 * Otherwise, it's some kind of Plan node, so check its initplans.
8648 */
8649 result = find_param_generator_initplan(param, (Plan *) ancestor,
8650 column_p);
8651 if (result)
8652 return result;
8653
8654 /* No luck, crawl up to next ancestor */
8655 }
8656 }
8657
8658 /* No generator found */
8659 return NULL;
8660}
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#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:1019
@ PARAM_EXEC
Definition: primnodes.h:385
static SubPlan * find_param_generator_initplan(Param *param, Plan *plan, int *column_p)
Definition: ruleutils.c:8666
Definition: nodes.h:135
int paramid
Definition: primnodes.h:394
ParamKind paramkind
Definition: primnodes.h:393
List * targetlist
Definition: plannodes.h:202
List * paramIds
Definition: primnodes.h:1085
List * setParam
Definition: primnodes.h:1105
SubLinkType subLinkType
Definition: primnodes.h:1082

References deparse_namespace::ancestors, find_param_generator_initplan(), foreach_current_index, foreach_int, foreach_node, if(), IsA, lfirst, linitial, MULTIEXPR_SUBLINK, deparse_context::namespaces, 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 8666 of file ruleutils.c.

8667{
8668 foreach_node(SubPlan, subplan, plan->initPlan)
8669 {
8670 foreach_int(paramid, subplan->setParam)
8671 {
8672 if (paramid == param->paramid)
8673 {
8674 /* Found a match, so return it. */
8675 *column_p = foreach_current_index(paramid);
8676 return subplan;
8677 }
8678 }
8679 }
8680 return NULL;
8681}
#define plan(x)
Definition: pg_regress.c:161

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

8457{
8458 /* Initialize output parameters to prevent compiler warnings */
8459 *dpns_p = NULL;
8460 *ancestor_cell_p = NULL;
8461
8462 /*
8463 * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
8464 * SubPlan argument. This will necessarily be in some ancestor of the
8465 * current expression's Plan node.
8466 */
8467 if (param->paramkind == PARAM_EXEC)
8468 {
8469 deparse_namespace *dpns;
8470 Plan *child_plan;
8471 ListCell *lc;
8472
8473 dpns = (deparse_namespace *) linitial(context->namespaces);
8474 child_plan = dpns->plan;
8475
8476 foreach(lc, dpns->ancestors)
8477 {
8478 Node *ancestor = (Node *) lfirst(lc);
8479 ListCell *lc2;
8480
8481 /*
8482 * NestLoops transmit params to their inner child only.
8483 */
8484 if (IsA(ancestor, NestLoop) &&
8485 child_plan == innerPlan(ancestor))
8486 {
8487 NestLoop *nl = (NestLoop *) ancestor;
8488
8489 foreach(lc2, nl->nestParams)
8490 {
8491 NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
8492
8493 if (nlp->paramno == param->paramid)
8494 {
8495 /* Found a match, so return it */
8496 *dpns_p = dpns;
8497 *ancestor_cell_p = lc;
8498 return (Node *) nlp->paramval;
8499 }
8500 }
8501 }
8502
8503 /*
8504 * If ancestor is a SubPlan, check the arguments it provides.
8505 */
8506 if (IsA(ancestor, SubPlan))
8507 {
8508 SubPlan *subplan = (SubPlan *) ancestor;
8509 ListCell *lc3;
8510 ListCell *lc4;
8511
8512 forboth(lc3, subplan->parParam, lc4, subplan->args)
8513 {
8514 int paramid = lfirst_int(lc3);
8515 Node *arg = (Node *) lfirst(lc4);
8516
8517 if (paramid == param->paramid)
8518 {
8519 /*
8520 * Found a match, so return it. But, since Vars in
8521 * the arg are to be evaluated in the surrounding
8522 * context, we have to point to the next ancestor item
8523 * that is *not* a SubPlan.
8524 */
8525 ListCell *rest;
8526
8527 for_each_cell(rest, dpns->ancestors,
8528 lnext(dpns->ancestors, lc))
8529 {
8530 Node *ancestor2 = (Node *) lfirst(rest);
8531
8532 if (!IsA(ancestor2, SubPlan))
8533 {
8534 *dpns_p = dpns;
8535 *ancestor_cell_p = rest;
8536 return arg;
8537 }
8538 }
8539 elog(ERROR, "SubPlan cannot be outermost ancestor");
8540 }
8541 }
8542
8543 /* SubPlan isn't a kind of Plan, so skip the rest */
8544 continue;
8545 }
8546
8547 /*
8548 * We need not consider the ancestor's initPlan list, since
8549 * initplans never have any parParams.
8550 */
8551
8552 /* No luck, crawl up to next ancestor */
8553 child_plan = (Plan *) ancestor;
8554 }
8555 }
8556
8557 /* No referent found */
8558 return NULL;
8559}
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:233
Var * paramval
Definition: plannodes.h:953
List * nestParams
Definition: plannodes.h:942
List * args
Definition: primnodes.h:1108
List * parParam
Definition: primnodes.h:1107

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

Referenced by get_name_for_var_field(), and get_parameter().

◆ find_recursive_union()

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

Definition at line 5233 of file ruleutils.c.

5234{
5235 ListCell *lc;
5236
5237 foreach(lc, dpns->ancestors)
5238 {
5239 Plan *ancestor = (Plan *) lfirst(lc);
5240
5241 if (IsA(ancestor, RecursiveUnion) &&
5242 ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5243 return ancestor;
5244 }
5245 elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5246 wtscan->wtParam);
5247 return NULL;
5248}

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

13644{
13645 char *result = NULL;
13646 HeapTuple tuple;
13647 Datum reloptions;
13648 bool isnull;
13649
13650 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13651 if (!HeapTupleIsValid(tuple))
13652 elog(ERROR, "cache lookup failed for relation %u", relid);
13653
13654 reloptions = SysCacheGetAttr(RELOID, tuple,
13655 Anum_pg_class_reloptions, &isnull);
13656 if (!isnull)
13657 {
13659
13661 get_reloptions(&buf, reloptions);
13662
13663 result = buf.data;
13664 }
13665
13666 ReleaseSysCache(tuple);
13667
13668 return result;
13669}
static void get_reloptions(StringInfo buf, Datum reloptions)
Definition: ruleutils.c:13588
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600

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

13544{
13545 HeapTuple tp;
13546 Form_pg_collation colltup;
13547 char *collname;
13548 char *nspname;
13549 char *result;
13550
13551 tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
13552 if (!HeapTupleIsValid(tp))
13553 elog(ERROR, "cache lookup failed for collation %u", collid);
13554 colltup = (Form_pg_collation) GETSTRUCT(tp);
13555 collname = NameStr(colltup->collname);
13556
13558 nspname = get_namespace_name_or_temp(colltup->collnamespace);
13559 else
13560 nspname = NULL;
13561
13562 result = quote_qualified_identifier(nspname, collname);
13563
13564 ReleaseSysCache(tp);
13565
13566 return result;
13567}
Oid collid
bool CollationIsVisible(Oid collid)
Definition: namespace.c:2407
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:58
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:13113

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,
bool  inGroupBy 
)
static

Definition at line 13257 of file ruleutils.c.

13260{
13261 char *result;
13262 HeapTuple proctup;
13263 Form_pg_proc procform;
13264 char *proname;
13265 bool use_variadic;
13266 char *nspname;
13267 FuncDetailCode p_result;
13268 Oid p_funcid;
13269 Oid p_rettype;
13270 bool p_retset;
13271 int p_nvargs;
13272 Oid p_vatype;
13273 Oid *p_true_typeids;
13274 bool force_qualify = false;
13275
13276 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
13277 if (!HeapTupleIsValid(proctup))
13278 elog(ERROR, "cache lookup failed for function %u", funcid);
13279 procform = (Form_pg_proc) GETSTRUCT(proctup);
13280 proname = NameStr(procform->proname);
13281
13282 /*
13283 * Due to parser hacks to avoid needing to reserve CUBE, we need to force
13284 * qualification of some function names within GROUP BY.
13285 */
13286 if (inGroupBy)
13287 {
13288 if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
13289 force_qualify = true;
13290 }
13291
13292 /*
13293 * Determine whether VARIADIC should be printed. We must do this first
13294 * since it affects the lookup rules in func_get_detail().
13295 *
13296 * We always print VARIADIC if the function has a merged variadic-array
13297 * argument. Note that this is always the case for functions taking a
13298 * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
13299 * and printed the array elements as separate arguments, the call could
13300 * match a newer non-VARIADIC function.
13301 */
13302 if (use_variadic_p)
13303 {
13304 /* Parser should not have set funcvariadic unless fn is variadic */
13305 Assert(!has_variadic || OidIsValid(procform->provariadic));
13306 use_variadic = has_variadic;
13307 *use_variadic_p = use_variadic;
13308 }
13309 else
13310 {
13311 Assert(!has_variadic);
13312 use_variadic = false;
13313 }
13314
13315 /*
13316 * The idea here is to schema-qualify only if the parser would fail to
13317 * resolve the correct function given the unqualified func name with the
13318 * specified argtypes and VARIADIC flag. But if we already decided to
13319 * force qualification, then we can skip the lookup and pretend we didn't
13320 * find it.
13321 */
13322 if (!force_qualify)
13324 NIL, argnames, nargs, argtypes,
13325 !use_variadic, true, false,
13326 &p_funcid, &p_rettype,
13327 &p_retset, &p_nvargs, &p_vatype,
13328 &p_true_typeids, NULL);
13329 else
13330 {
13331 p_result = FUNCDETAIL_NOTFOUND;
13332 p_funcid = InvalidOid;
13333 }
13334
13335 if ((p_result == FUNCDETAIL_NORMAL ||
13336 p_result == FUNCDETAIL_AGGREGATE ||
13337 p_result == FUNCDETAIL_WINDOWFUNC) &&
13338 p_funcid == funcid)
13339 nspname = NULL;
13340 else
13341 nspname = get_namespace_name_or_temp(procform->pronamespace);
13342
13343 result = quote_qualified_identifier(nspname, proname);
13344
13345 ReleaseSysCache(proctup);
13346
13347 return result;
13348}
#define OidIsValid(objectId)
Definition: c.h:746
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:1395
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
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
NameData proname
Definition: pg_proc.h:35
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
String * makeString(char *str)
Definition: value.c:63

References Assert(), elog, ERROR, 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 12899 of file ruleutils.c.

12900{
12902
12904 get_opclass_name(opclass, InvalidOid, &buf);
12905
12906 return &buf.data[1]; /* get_opclass_name() prepends space */
12907}
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Definition: ruleutils.c:12861

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

13443{
13444 HeapTuple opertup;
13445 Form_pg_operator operform;
13446 char *oprname;
13447 char *nspname;
13448
13449 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
13450 if (!HeapTupleIsValid(opertup))
13451 elog(ERROR, "cache lookup failed for operator %u", opoid);
13452 operform = (Form_pg_operator) GETSTRUCT(opertup);
13453 Assert(operform->oprkind == 'b');
13454 oprname = NameStr(operform->oprname);
13455
13456 nspname = get_namespace_name(operform->oprnamespace);
13457
13458 appendStringInfoString(buf, leftop);
13459 if (leftoptype != operform->oprleft)
13460 add_cast_to(buf, operform->oprleft);
13461 appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
13462 appendStringInfoString(buf, oprname);
13463 appendStringInfo(buf, ") %s", rightop);
13464 if (rightoptype != operform->oprright)
13465 add_cast_to(buf, operform->oprright);
13466
13467 ReleaseSysCache(opertup);
13468}
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3506
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static void add_cast_to(StringInfo buf, Oid typid)
Definition: ruleutils.c:13479

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

13363{
13365 HeapTuple opertup;
13366 Form_pg_operator operform;
13367 char *oprname;
13368 char *nspname;
13369 Operator p_result;
13370
13372
13373 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
13374 if (!HeapTupleIsValid(opertup))
13375 elog(ERROR, "cache lookup failed for operator %u", operid);
13376 operform = (Form_pg_operator) GETSTRUCT(opertup);
13377 oprname = NameStr(operform->oprname);
13378
13379 /*
13380 * The idea here is to schema-qualify only if the parser would fail to
13381 * resolve the correct operator given the unqualified op name with the
13382 * specified argtypes.
13383 */
13384 switch (operform->oprkind)
13385 {
13386 case 'b':
13387 p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
13388 true, -1);
13389 break;
13390 case 'l':
13391 p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
13392 true, -1);
13393 break;
13394 default:
13395 elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
13396 p_result = NULL; /* keep compiler quiet */
13397 break;
13398 }
13399
13400 if (p_result != NULL && oprid(p_result) == operid)
13401 nspname = NULL;
13402 else
13403 {
13404 nspname = get_namespace_name_or_temp(operform->oprnamespace);
13405 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
13406 }
13407
13408 appendStringInfoString(&buf, oprname);
13409
13410 if (nspname)
13412
13413 if (p_result != NULL)
13414 ReleaseSysCache(p_result);
13415
13416 ReleaseSysCache(opertup);
13417
13418 return buf.data;
13419}
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 13213 of file ruleutils.c.

13214{
13215 HeapTuple tp;
13216 Form_pg_class reltup;
13217 char *relname;
13218 char *nspname;
13219 char *result;
13220
13221 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13222 if (!HeapTupleIsValid(tp))
13223 elog(ERROR, "cache lookup failed for relation %u", relid);
13224 reltup = (Form_pg_class) GETSTRUCT(tp);
13225 relname = NameStr(reltup->relname);
13226
13227 nspname = get_namespace_name_or_temp(reltup->relnamespace);
13228 if (!nspname)
13229 elog(ERROR, "cache lookup failed for namespace %u",
13230 reltup->relnamespace);
13231
13232 result = quote_qualified_identifier(nspname, relname);
13233
13234 ReleaseSysCache(tp);
13235
13236 return result;
13237}
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:156

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

13511{
13512 HeapTuple tp;
13513 Form_pg_type typtup;
13514 char *typname;
13515 char *nspname;
13516 char *result;
13517
13518 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13519 if (!HeapTupleIsValid(tp))
13520 elog(ERROR, "cache lookup failed for type %u", typid);
13521 typtup = (Form_pg_type) GETSTRUCT(tp);
13522 typname = NameStr(typtup->typname);
13523
13524 nspname = get_namespace_name_or_temp(typtup->typnamespace);
13525 if (!nspname)
13526 elog(ERROR, "cache lookup failed for namespace %u",
13527 typtup->typnamespace);
13528
13529 result = quote_qualified_identifier(nspname, typname);
13530
13531 ReleaseSysCache(tp);
13532
13533 return result;
13534}

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

13154{
13155 HeapTuple tp;
13156 Form_pg_class reltup;
13157 bool need_qual;
13158 ListCell *nslist;
13159 char *relname;
13160 char *nspname;
13161 char *result;
13162
13163 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13164 if (!HeapTupleIsValid(tp))
13165 elog(ERROR, "cache lookup failed for relation %u", relid);
13166 reltup = (Form_pg_class) GETSTRUCT(tp);
13167 relname = NameStr(reltup->relname);
13168
13169 /* Check for conflicting CTE name */
13170 need_qual = false;
13171 foreach(nslist, namespaces)
13172 {
13173 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
13174 ListCell *ctlist;
13175
13176 foreach(ctlist, dpns->ctes)
13177 {
13178 CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
13179
13180 if (strcmp(cte->ctename, relname) == 0)
13181 {
13182 need_qual = true;
13183 break;
13184 }
13185 }
13186 if (need_qual)
13187 break;
13188 }
13189
13190 /* Otherwise, qualify the name if not visible in search path */
13191 if (!need_qual)
13192 need_qual = !RelationIsVisible(relid);
13193
13194 if (need_qual)
13195 nspname = get_namespace_name_or_temp(reltup->relnamespace);
13196 else
13197 nspname = NULL;
13198
13199 result = quote_qualified_identifier(nspname, relname);
13200
13201 ReleaseSysCache(tp);
13202
13203 return result;
13204}
bool RelationIsVisible(Oid relid)
Definition: namespace.c:913

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

11010{
11011 Aggref *aggref;
11012 Aggref *original_aggref = callback_arg;
11013
11014 if (!IsA(node, Aggref))
11015 elog(ERROR, "combining Aggref does not point to an Aggref");
11016
11017 aggref = (Aggref *) node;
11018 get_agg_expr(aggref, context, original_aggref);
11019}
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
Definition: ruleutils.c:10871

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

Referenced by get_agg_expr_helper().

◆ get_agg_expr()

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

Definition at line 10871 of file ruleutils.c.

10873{
10874 get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10875 false);
10876}
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:10883

References get_agg_expr_helper().

Referenced by get_agg_combine_expr(), and get_rule_expr().

◆ get_agg_expr_helper()

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

Definition at line 10883 of file ruleutils.c.

10886{
10887 StringInfo buf = context->buf;
10888 Oid argtypes[FUNC_MAX_ARGS];
10889 int nargs;
10890 bool use_variadic = false;
10891
10892 /*
10893 * For a combining aggregate, we look up and deparse the corresponding
10894 * partial aggregate instead. This is necessary because our input
10895 * argument list has been replaced; the new argument list always has just
10896 * one element, which will point to a partial Aggref that supplies us with
10897 * transition states to combine.
10898 */
10899 if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10900 {
10901 TargetEntry *tle;
10902
10903 Assert(list_length(aggref->args) == 1);
10904 tle = linitial_node(TargetEntry, aggref->args);
10905 resolve_special_varno((Node *) tle->expr, context,
10906 get_agg_combine_expr, original_aggref);
10907 return;
10908 }
10909
10910 /*
10911 * Mark as PARTIAL, if appropriate. We look to the original aggref so as
10912 * to avoid printing this when recursing from the code just above.
10913 */
10914 if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10915 appendStringInfoString(buf, "PARTIAL ");
10916
10917 /* Extract the argument types as seen by the parser */
10918 nargs = get_aggregate_argtypes(aggref, argtypes);
10919
10920 if (!funcname)
10921 funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10922 argtypes, aggref->aggvariadic,
10923 &use_variadic,
10924 context->inGroupBy);
10925
10926 /* Print the aggregate name, schema-qualified if needed */
10927 appendStringInfo(buf, "%s(%s", funcname,
10928 (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10929
10930 if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10931 {
10932 /*
10933 * Ordered-set aggregates do not use "*" syntax. Also, we needn't
10934 * worry about inserting VARIADIC. So we can just dump the direct
10935 * args as-is.
10936 */
10937 Assert(!aggref->aggvariadic);
10938 get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10939 Assert(aggref->aggorder != NIL);
10940 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10941 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10942 }
10943 else
10944 {
10945 /* aggstar can be set only in zero-argument aggregates */
10946 if (aggref->aggstar)
10948 else
10949 {
10950 ListCell *l;
10951 int i;
10952
10953 i = 0;
10954 foreach(l, aggref->args)
10955 {
10956 TargetEntry *tle = (TargetEntry *) lfirst(l);
10957 Node *arg = (Node *) tle->expr;
10958
10960 if (tle->resjunk)
10961 continue;
10962 if (i++ > 0)
10963 {
10964 if (is_json_objectagg)
10965 {
10966 /*
10967 * the ABSENT ON NULL and WITH UNIQUE args are printed
10968 * separately, so ignore them here
10969 */
10970 if (i > 2)
10971 break;
10972
10974 }
10975 else
10977 }
10978 if (use_variadic && i == nargs)
10979 appendStringInfoString(buf, "VARIADIC ");
10980 get_rule_expr(arg, context, true);
10981 }
10982 }
10983
10984 if (aggref->aggorder != NIL)
10985 {
10986 appendStringInfoString(buf, " ORDER BY ");
10987 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10988 }
10989 }
10990
10991 if (options)
10993
10994 if (aggref->aggfilter != NULL)
10995 {
10996 appendStringInfoString(buf, ") FILTER (WHERE ");
10997 get_rule_expr((Node *) aggref->aggfilter, context, false);
10998 }
10999
11001}
#define funcname
Definition: indent_codes.h:69
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:392
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:391
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1997
#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, bool inGroupBy)
Definition: ruleutils.c:13257
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:11009
static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6691
static void resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
Definition: ruleutils.c:7909
Oid aggfnoid
Definition: primnodes.h:461
List * aggdistinct
Definition: primnodes.h:491
List * aggdirectargs
Definition: primnodes.h:482
List * args
Definition: primnodes.h:485
Expr * aggfilter
Definition: primnodes.h:494
List * aggorder
Definition: primnodes.h:488
Expr * expr
Definition: primnodes.h:2219

References Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggorder, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, Aggref::args, Assert(), deparse_context::buf, buf, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_SKIPFINAL, TargetEntry::expr, FUNC_MAX_ARGS, funcname, generate_function_name(), get_agg_combine_expr(), get_aggregate_argtypes(), get_rule_expr(), get_rule_orderby(), i, deparse_context::inGroupBy, 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 
)
static

Definition at line 6108 of file ruleutils.c.

6109{
6110 StringInfo buf = context->buf;
6111 RangeTblEntry *values_rte;
6112 char *sep;
6113 ListCell *l;
6114
6115 if (PRETTY_INDENT(context))
6116 {
6117 context->indentLevel += PRETTYINDENT_STD;
6119 }
6120
6121 /*
6122 * If the query looks like SELECT * FROM (VALUES ...), then print just the
6123 * VALUES part. This reverses what transformValuesClause() did at parse
6124 * time.
6125 */
6126 values_rte = get_simple_values_rte(query, context->resultDesc);
6127 if (values_rte)
6128 {
6129 get_values_def(values_rte->values_lists, context);
6130 return;
6131 }
6132
6133 /*
6134 * Build up the query string - first we say SELECT
6135 */
6136 if (query->isReturn)
6137 appendStringInfoString(buf, "RETURN");
6138 else
6139 appendStringInfoString(buf, "SELECT");
6140
6141 /* Add the DISTINCT clause if given */
6142 if (query->distinctClause != NIL)
6143 {
6144 if (query->hasDistinctOn)
6145 {
6146 appendStringInfoString(buf, " DISTINCT ON (");
6147 sep = "";
6148 foreach(l, query->distinctClause)
6149 {
6151
6154 false, context);
6155 sep = ", ";
6156 }
6158 }
6159 else
6160 appendStringInfoString(buf, " DISTINCT");
6161 }
6162
6163 /* Then we tell what to select (the targetlist) */
6164 get_target_list(query->targetList, context);
6165
6166 /* Add the FROM clause if needed */
6167 get_from_clause(query, " FROM ", context);
6168
6169 /* Add the WHERE clause if given */
6170 if (query->jointree->quals != NULL)
6171 {
6172 appendContextKeyword(context, " WHERE ",
6174 get_rule_expr(query->jointree->quals, context, false);
6175 }
6176
6177 /* Add the GROUP BY clause if given */
6178 if (query->groupClause != NULL || query->groupingSets != NULL)
6179 {
6180 bool save_ingroupby;
6181
6182 appendContextKeyword(context, " GROUP BY ",
6184 if (query->groupDistinct)
6185 appendStringInfoString(buf, "DISTINCT ");
6186
6187 save_ingroupby = context->inGroupBy;
6188 context->inGroupBy = true;
6189
6190 if (query->groupingSets == NIL)
6191 {
6192 sep = "";
6193 foreach(l, query->groupClause)
6194 {
6196
6199 false, context);
6200 sep = ", ";
6201 }
6202 }
6203 else
6204 {
6205 sep = "";
6206 foreach(l, query->groupingSets)
6207 {
6208 GroupingSet *grp = lfirst(l);
6209
6211 get_rule_groupingset(grp, query->targetList, true, context);
6212 sep = ", ";
6213 }
6214 }
6215
6216 context->inGroupBy = save_ingroupby;
6217 }
6218
6219 /* Add the HAVING clause if given */
6220 if (query->havingQual != NULL)
6221 {
6222 appendContextKeyword(context, " HAVING ",
6224 get_rule_expr(query->havingQual, context, false);
6225 }
6226
6227 /* Add the WINDOW clause if needed */
6228 if (query->windowClause != NIL)
6229 get_rule_windowclause(query, context);
6230}
static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
Definition: ruleutils.c:9082
static void get_values_def(List *values_lists, deparse_context *context)
Definition: ruleutils.c:5724
static void get_from_clause(Query *query, const char *prefix, deparse_context *context)
Definition: ruleutils.c:12270
static void get_rule_groupingset(GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context)
Definition: ruleutils.c:6631
static void get_target_list(List *targetList, deparse_context *context)
Definition: ruleutils.c:6239
static Node * get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6562
static void get_rule_windowclause(Query *query, deparse_context *context)
Definition: ruleutils.c:6749
static RangeTblEntry * get_simple_values_rte(Query *query, TupleDesc resultDesc)
Definition: ruleutils.c:6039
Node * quals
Definition: primnodes.h:2338
bool groupDistinct
Definition: parsenodes.h:212
FromExpr * jointree
Definition: parsenodes.h:177
List * groupClause
Definition: parsenodes.h:211
Node * havingQual
Definition: parsenodes.h:216
List * windowClause
Definition: parsenodes.h:218
List * targetList
Definition: parsenodes.h:193
List * groupingSets
Definition: parsenodes.h:214
List * distinctClause
Definition: parsenodes.h:220
List * values_lists
Definition: parsenodes.h:1204
Index tleSortGroupRef
Definition: parsenodes.h:1452

References appendContextKeyword(), appendStringInfoChar(), appendStringInfoString(), deparse_context::buf, buf, Query::distinctClause, get_from_clause(), get_rule_expr(), get_rule_groupingset(), get_rule_sortgroupclause(), get_rule_windowclause(), get_simple_values_rte(), get_target_list(), get_values_def(), Query::groupClause, Query::groupDistinct, Query::groupingSets, Query::havingQual, deparse_context::indentLevel, deparse_context::inGroupBy, Query::jointree, lfirst, NIL, PRETTY_INDENT, PRETTYINDENT_STD, FromExpr::quals, deparse_context::resultDesc, 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 11401 of file ruleutils.c.

11404{
11405 StringInfo buf = context->buf;
11406
11407 /*
11408 * Since parse_coerce.c doesn't immediately collapse application of
11409 * length-coercion functions to constants, what we'll typically see in
11410 * such cases is a Const with typmod -1 and a length-coercion function
11411 * right above it. Avoid generating redundant output. However, beware of
11412 * suppressing casts when the user actually wrote something like
11413 * 'foo'::text::char(3).
11414 *
11415 * Note: it might seem that we are missing the possibility of needing to
11416 * print a COLLATE clause for such a Const. However, a Const could only
11417 * have nondefault collation in a post-constant-folding tree, in which the
11418 * length coercion would have been folded too. See also the special
11419 * handling of CollateExpr in coerce_to_target_type(): any collation
11420 * marking will be above the coercion node, not below it.
11421 */
11422 if (arg && IsA(arg, Const) &&
11423 ((Const *) arg)->consttype == resulttype &&
11424 ((Const *) arg)->consttypmod == -1)
11425 {
11426 /* Show the constant without normal ::typename decoration */
11427 get_const_expr((Const *) arg, context, -1);
11428 }
11429 else
11430 {
11431 if (!PRETTY_PAREN(context))
11433 get_rule_expr_paren(arg, context, false, parentNode);
11434 if (!PRETTY_PAREN(context))
11436 }
11437
11438 /*
11439 * Never emit resulttype(arg) functional notation. A pg_proc entry could
11440 * take precedence, and a resulttype in pg_temp would require schema
11441 * qualification that format_type_with_typemod() would usually omit. We've
11442 * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
11443 * would work fine.
11444 */
11445 appendStringInfo(buf, "::%s",
11446 format_type_with_typemod(resulttype, resulttypmod));
11447}
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:9155
#define PRETTY_PAREN(context)
Definition: ruleutils.c:101
static void get_const_expr(Const *constval, deparse_context *context, int showtype)
Definition: ruleutils.c:11465

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

Referenced by get_func_expr(), and get_rule_expr().

◆ get_column_alias_list()

static void get_column_alias_list ( deparse_columns colinfo,
deparse_context context 
)
static

Definition at line 12726 of file ruleutils.c.

12727{
12728 StringInfo buf = context->buf;
12729 int i;
12730 bool first = true;
12731
12732 /* Don't print aliases if not needed */
12733 if (!colinfo->printaliases)
12734 return;
12735
12736 for (i = 0; i < colinfo->num_new_cols; i++)
12737 {
12738 char *colname = colinfo->new_colnames[i];
12739
12740 if (first)
12741 {
12743 first = false;
12744 }
12745 else
12748 }
12749 if (!first)
12751}

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

Referenced by get_from_clause_item().

◆ get_const_collation()

static void get_const_collation ( Const constval,
deparse_context context 
)
static

Definition at line 11595 of file ruleutils.c.

11596{
11597 StringInfo buf = context->buf;
11598
11599 if (OidIsValid(constval->constcollid))
11600 {
11601 Oid typcollation = get_typcollation(constval->consttype);
11602
11603 if (constval->constcollid != typcollation)
11604 {
11605 appendStringInfo(buf, " COLLATE %s",
11606 generate_collation_name(constval->constcollid));
11607 }
11608 }
11609}
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3196
char * generate_collation_name(Oid collid)
Definition: ruleutils.c:13543
Oid consttype
Definition: primnodes.h:329

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

Referenced by get_const_expr().

◆ get_const_expr()

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

Definition at line 11465 of file ruleutils.c.

11466{
11467 StringInfo buf = context->buf;
11468 Oid typoutput;
11469 bool typIsVarlena;
11470 char *extval;
11471 bool needlabel = false;
11472
11473 if (constval->constisnull)
11474 {
11475 /*
11476 * Always label the type of a NULL constant to prevent misdecisions
11477 * about type when reparsing.
11478 */
11479 appendStringInfoString(buf, "NULL");
11480 if (showtype >= 0)
11481 {
11482 appendStringInfo(buf, "::%s",
11484 constval->consttypmod));
11485 get_const_collation(constval, context);
11486 }
11487 return;
11488 }
11489
11490 getTypeOutputInfo(constval->consttype,
11491 &typoutput, &typIsVarlena);
11492
11493 extval = OidOutputFunctionCall(typoutput, constval->constvalue);
11494
11495 switch (constval->consttype)
11496 {
11497 case INT4OID:
11498
11499 /*
11500 * INT4 can be printed without any decoration, unless it is
11501 * negative; in that case print it as '-nnn'::integer to ensure
11502 * that the output will re-parse as a constant, not as a constant
11503 * plus operator. In most cases we could get away with printing
11504 * (-nnn) instead, because of the way that gram.y handles negative
11505 * literals; but that doesn't work for INT_MIN, and it doesn't
11506 * seem that much prettier anyway.
11507 */
11508 if (extval[0] != '-')
11509 appendStringInfoString(buf, extval);
11510 else
11511 {
11512 appendStringInfo(buf, "'%s'", extval);
11513 needlabel = true; /* we must attach a cast */
11514 }
11515 break;
11516
11517 case NUMERICOID:
11518
11519 /*
11520 * NUMERIC can be printed without quotes if it looks like a float
11521 * constant (not an integer, and not Infinity or NaN) and doesn't
11522 * have a leading sign (for the same reason as for INT4).
11523 */
11524 if (isdigit((unsigned char) extval[0]) &&
11525 strcspn(extval, "eE.") != strlen(extval))
11526 {
11527 appendStringInfoString(buf, extval);
11528 }
11529 else
11530 {
11531 appendStringInfo(buf, "'%s'", extval);
11532 needlabel = true; /* we must attach a cast */
11533 }
11534 break;
11535
11536 case BOOLOID:
11537 if (strcmp(extval, "t") == 0)
11538 appendStringInfoString(buf, "true");
11539 else
11540 appendStringInfoString(buf, "false");
11541 break;
11542
11543 default:
11544 simple_quote_literal(buf, extval);
11545 break;
11546 }
11547
11548 pfree(extval);
11549
11550 if (showtype < 0)
11551 return;
11552
11553 /*
11554 * For showtype == 0, append ::typename unless the constant will be
11555 * implicitly typed as the right type when it is read in.
11556 *
11557 * XXX this code has to be kept in sync with the behavior of the parser,
11558 * especially make_const.
11559 */
11560 switch (constval->consttype)
11561 {
11562 case BOOLOID:
11563 case UNKNOWNOID:
11564 /* These types can be left unlabeled */
11565 needlabel = false;
11566 break;
11567 case INT4OID:
11568 /* We determined above whether a label is needed */
11569 break;
11570 case NUMERICOID:
11571
11572 /*
11573 * Float-looking constants will be typed as numeric, which we
11574 * checked above; but if there's a nondefault typmod we need to
11575 * show it.
11576 */
11577 needlabel |= (constval->consttypmod >= 0);
11578 break;
11579 default:
11580 needlabel = true;
11581 break;
11582 }
11583 if (needlabel || showtype > 0)
11584 appendStringInfo(buf, "::%s",
11586 constval->consttypmod));
11587
11588 get_const_collation(constval, context);
11589}
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:3047
void pfree(void *pointer)
Definition: mcxt.c:1528
static void simple_quote_literal(StringInfo buf, const char *val)
Definition: ruleutils.c:11793
static void get_const_collation(Const *constval, deparse_context *context)
Definition: ruleutils.c:11595

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

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

◆ get_delete_query_def()

static void get_delete_query_def ( Query query,
deparse_context context 
)
static

Definition at line 7355 of file ruleutils.c.

7356{
7357 StringInfo buf = context->buf;
7358 RangeTblEntry *rte;
7359
7360 /* Insert the WITH clause if given */
7361 get_with_clause(query, context);
7362
7363 /*
7364 * Start the query with DELETE FROM relname
7365 */
7366 rte = rt_fetch(query->resultRelation, query->rtable);
7367 Assert(rte->rtekind == RTE_RELATION);
7368 if (PRETTY_INDENT(context))
7369 {
7371 context->indentLevel += PRETTYINDENT_STD;
7372 }
7373 appendStringInfo(buf, "DELETE FROM %s%s",
7374 only_marker(rte),
7375 generate_relation_name(rte->relid, NIL));
7376
7377 /* Print the relation alias, if needed */
7378 get_rte_alias(rte, query->resultRelation, false, context);
7379
7380 /* Add the USING clause if given */
7381 get_from_clause(query, " USING ", context);
7382
7383 /* Add a WHERE clause if given */
7384 if (query->jointree->quals != NULL)
7385 {
7386 appendContextKeyword(context, " WHERE ",
7388 get_rule_expr(query->jointree->quals, context, false);
7389 }
7390
7391 /* Add RETURNING if present */
7392 if (query->returningList)
7393 get_returning_clause(query, context);
7394}
#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:12655
#define only_marker(rte)
Definition: ruleutils.c:550
static void get_returning_clause(Query *query, deparse_context *context)
Definition: ruleutils.c:6375
static void get_with_clause(Query *query, deparse_context *context)
Definition: ruleutils.c:5767
static char * generate_relation_name(Oid relid, List *namespaces)
Definition: ruleutils.c:13153
List * returningList
Definition: parsenodes.h:209
List * rtable
Definition: parsenodes.h:170

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), Assert(), deparse_context::buf, buf, generate_relation_name(), get_from_clause(), get_returning_clause(), get_rte_alias(), get_rule_expr(), get_with_clause(), deparse_context::indentLevel, Query::jointree, NIL, only_marker, PRETTY_INDENT, PRETTYINDENT_STD, FromExpr::quals, 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 12270 of file ruleutils.c.

12271{
12272 StringInfo buf = context->buf;
12273 bool first = true;
12274 ListCell *l;
12275
12276 /*
12277 * We use the query's jointree as a guide to what to print. However, we
12278 * must ignore auto-added RTEs that are marked not inFromCl. (These can
12279 * only appear at the top level of the jointree, so it's sufficient to
12280 * check here.) This check also ensures we ignore the rule pseudo-RTEs
12281 * for NEW and OLD.
12282 */
12283 foreach(l, query->jointree->fromlist)
12284 {
12285 Node *jtnode = (Node *) lfirst(l);
12286
12287 if (IsA(jtnode, RangeTblRef))
12288 {
12289 int varno = ((RangeTblRef *) jtnode)->rtindex;
12290 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12291
12292 if (!rte->inFromCl)
12293 continue;
12294 }
12295
12296 if (first)
12297 {
12298 appendContextKeyword(context, prefix,
12300 first = false;
12301
12302 get_from_clause_item(jtnode, query, context);
12303 }
12304 else
12305 {
12306 StringInfoData itembuf;
12307
12309
12310 /*
12311 * Put the new FROM item's text into itembuf so we can decide
12312 * after we've got it whether or not it needs to go on a new line.
12313 */
12314 initStringInfo(&itembuf);
12315 context->buf = &itembuf;
12316
12317 get_from_clause_item(jtnode, query, context);
12318
12319 /* Restore context's output buffer */
12320 context->buf = buf;
12321
12322 /* Consider line-wrapping if enabled */
12323 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
12324 {
12325 /* Does the new item start with a new line? */
12326 if (itembuf.len > 0 && itembuf.data[0] == '\n')
12327 {
12328 /* If so, we shouldn't add anything */
12329 /* instead, remove any trailing spaces currently in buf */
12331 }
12332 else
12333 {
12334 char *trailing_nl;
12335
12336 /* Locate the start of the current line in the buffer */
12337 trailing_nl = strrchr(buf->data, '\n');
12338 if (trailing_nl == NULL)
12339 trailing_nl = buf->data;
12340 else
12341 trailing_nl++;
12342
12343 /*
12344 * Add a newline, plus some indentation, if the new item
12345 * would cause an overflow.
12346 */
12347 if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
12351 }
12352 }
12353
12354 /* Add the new item */
12355 appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
12356
12357 /* clean up */
12358 pfree(itembuf.data);
12359 }
12360 }
12361}
#define PRETTYINDENT_VAR
Definition: ruleutils.c:83
static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
Definition: ruleutils.c:12364
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
List * fromlist
Definition: primnodes.h:2337

References appendBinaryStringInfo(), appendContextKeyword(), appendStringInfoString(), deparse_context::buf, buf, 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, Query::rtable, and deparse_context::wrapColumn.

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

◆ get_from_clause_coldeflist()

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

Definition at line 12766 of file ruleutils.c.

12769{
12770 StringInfo buf = context->buf;
12771 ListCell *l1;
12772 ListCell *l2;
12773 ListCell *l3;
12774 ListCell *l4;
12775 int i;
12776
12778
12779 i = 0;
12780 forfour(l1, rtfunc->funccoltypes,
12781 l2, rtfunc->funccoltypmods,
12782 l3, rtfunc->funccolcollations,
12783 l4, rtfunc->funccolnames)
12784 {
12785 Oid atttypid = lfirst_oid(l1);
12786 int32 atttypmod = lfirst_int(l2);
12787 Oid attcollation = lfirst_oid(l3);
12788 char *attname;
12789
12790 if (colinfo)
12791 attname = colinfo->colnames[i];
12792 else
12793 attname = strVal(lfirst(l4));
12794
12795 Assert(attname); /* shouldn't be any dropped columns here */
12796
12797 if (i > 0)
12799 appendStringInfo(buf, "%s %s",
12801 format_type_with_typemod(atttypid, atttypmod));
12802 if (OidIsValid(attcollation) &&
12803 attcollation != get_typcollation(atttypid))
12804 appendStringInfo(buf, " COLLATE %s",
12805 generate_collation_name(attcollation));
12806
12807 i++;
12808 }
12809
12811}
int32_t int32
Definition: c.h:498
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, deparse_context::buf, buf, deparse_columns::colnames, forfour, format_type_with_typemod(), generate_collation_name(), get_typcollation(), i, lfirst, lfirst_int, lfirst_oid, OidIsValid, quote_identifier(), and strVal.

Referenced by get_from_clause_item().

◆ get_from_clause_item()

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

Definition at line 12364 of file ruleutils.c.

12365{
12366 StringInfo buf = context->buf;
12368
12369 if (IsA(jtnode, RangeTblRef))
12370 {
12371 int varno = ((RangeTblRef *) jtnode)->rtindex;
12372 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12373 deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12374 RangeTblFunction *rtfunc1 = NULL;
12375
12376 if (rte->lateral)
12377 appendStringInfoString(buf, "LATERAL ");
12378
12379 /* Print the FROM item proper */
12380 switch (rte->rtekind)
12381 {
12382 case RTE_RELATION:
12383 /* Normal relation RTE */
12384 appendStringInfo(buf, "%s%s",
12385 only_marker(rte),
12386 generate_relation_name(rte->relid,
12387 context->namespaces));
12388 break;
12389 case RTE_SUBQUERY:
12390 /* Subquery RTE */
12392 get_query_def(rte->subquery, buf, context->namespaces, NULL,
12393 true,
12394 context->prettyFlags, context->wrapColumn,
12395 context->indentLevel);
12397 break;
12398 case RTE_FUNCTION:
12399 /* Function RTE */
12400 rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
12401
12402 /*
12403 * Omit ROWS FROM() syntax for just one function, unless it
12404 * has both a coldeflist and WITH ORDINALITY. If it has both,
12405 * we must use ROWS FROM() syntax to avoid ambiguity about
12406 * whether the coldeflist includes the ordinality column.
12407 */
12408 if (list_length(rte->functions) == 1 &&
12409 (rtfunc1->funccolnames == NIL || !rte->funcordinality))
12410 {
12411 get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
12412 /* we'll print the coldeflist below, if it has one */
12413 }
12414 else
12415 {
12416 bool all_unnest;
12417 ListCell *lc;
12418
12419 /*
12420 * If all the function calls in the list are to unnest,
12421 * and none need a coldeflist, then collapse the list back
12422 * down to UNNEST(args). (If we had more than one
12423 * built-in unnest function, this would get more
12424 * difficult.)
12425 *
12426 * XXX This is pretty ugly, since it makes not-terribly-
12427 * future-proof assumptions about what the parser would do
12428 * with the output; but the alternative is to emit our
12429 * nonstandard ROWS FROM() notation for what might have
12430 * been a perfectly spec-compliant multi-argument
12431 * UNNEST().
12432 */
12433 all_unnest = true;
12434 foreach(lc, rte->functions)
12435 {
12436 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12437
12438 if (!IsA(rtfunc->funcexpr, FuncExpr) ||
12439 ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
12440 rtfunc->funccolnames != NIL)
12441 {
12442 all_unnest = false;
12443 break;
12444 }
12445 }
12446
12447 if (all_unnest)
12448 {
12449 List *allargs = NIL;
12450
12451 foreach(lc, rte->functions)
12452 {
12453 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12454 List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
12455
12456 allargs = list_concat(allargs, args);
12457 }
12458
12459 appendStringInfoString(buf, "UNNEST(");
12460 get_rule_expr((Node *) allargs, context, true);
12462 }
12463 else
12464 {
12465 int funcno = 0;
12466
12467 appendStringInfoString(buf, "ROWS FROM(");
12468 foreach(lc, rte->functions)
12469 {
12470 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12471
12472 if (funcno > 0)
12474 get_rule_expr_funccall(rtfunc->funcexpr, context, true);
12475 if (rtfunc->funccolnames != NIL)
12476 {
12477 /* Reconstruct the column definition list */
12478 appendStringInfoString(buf, " AS ");
12480 NULL,
12481 context);
12482 }
12483 funcno++;
12484 }
12486 }
12487 /* prevent printing duplicate coldeflist below */
12488 rtfunc1 = NULL;
12489 }
12490 if (rte->funcordinality)
12491 appendStringInfoString(buf, " WITH ORDINALITY");
12492 break;
12493 case RTE_TABLEFUNC:
12494 get_tablefunc(rte->tablefunc, context, true);
12495 break;
12496 case RTE_VALUES:
12497 /* Values list RTE */
12499 get_values_def(rte->values_lists, context);
12501 break;
12502 case RTE_CTE:
12504 break;
12505 default:
12506 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
12507 break;
12508 }
12509
12510 /* Print the relation alias, if needed */
12511 get_rte_alias(rte, varno, false, context);
12512
12513 /* Print the column definitions or aliases, if needed */
12514 if (rtfunc1 && rtfunc1->funccolnames != NIL)
12515 {
12516 /* Reconstruct the columndef list, which is also the aliases */
12517 get_from_clause_coldeflist(rtfunc1, colinfo, context);
12518 }
12519 else
12520 {
12521 /* Else print column aliases as needed */
12522 get_column_alias_list(colinfo, context);
12523 }
12524
12525 /* Tablesample clause must go after any alias */
12526 if (rte->rtekind == RTE_RELATION && rte->tablesample)
12527 get_tablesample_def(rte->tablesample, context);
12528 }
12529 else if (IsA(jtnode, JoinExpr))
12530 {
12531 JoinExpr *j = (JoinExpr *) jtnode;
12532 deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
12533 bool need_paren_on_right;
12534
12535 need_paren_on_right = PRETTY_PAREN(context) &&
12536 !IsA(j->rarg, RangeTblRef) &&
12537 !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
12538
12539 if (!PRETTY_PAREN(context) || j->alias != NULL)
12541
12542 get_from_clause_item(j->larg, query, context);
12543
12544 switch (j->jointype)
12545 {
12546 case JOIN_INNER:
12547 if (j->quals)
12548 appendContextKeyword(context, " JOIN ",
12552 else
12553 appendContextKeyword(context, " CROSS JOIN ",
12557 break;
12558 case JOIN_LEFT:
12559 appendContextKeyword(context, " LEFT JOIN ",
12563 break;
12564 case JOIN_FULL:
12565 appendContextKeyword(context, " FULL JOIN ",
12569 break;
12570 case JOIN_RIGHT:
12571 appendContextKeyword(context, " RIGHT JOIN ",
12575 break;
12576 default:
12577 elog(ERROR, "unrecognized join type: %d",
12578 (int) j->jointype);
12579 }
12580
12581 if (need_paren_on_right)
12583 get_from_clause_item(j->rarg, query, context);
12584 if (need_paren_on_right)
12586
12587 if (j->usingClause)
12588 {
12589 ListCell *lc;
12590 bool first = true;
12591
12592 appendStringInfoString(buf, " USING (");
12593 /* Use the assigned names, not what's in usingClause */
12594 foreach(lc, colinfo->usingNames)
12595 {
12596 char *colname = (char *) lfirst(lc);
12597
12598 if (first)
12599 first = false;
12600 else
12603 }
12605
12606 if (j->join_using_alias)
12607 appendStringInfo(buf, " AS %s",
12608 quote_identifier(j->join_using_alias->aliasname));
12609 }
12610 else if (j->quals)
12611 {
12612 appendStringInfoString(buf, " ON ");
12613 if (!PRETTY_PAREN(context))
12615 get_rule_expr(j->quals, context, false);
12616 if (!PRETTY_PAREN(context))
12618 }
12619 else if (j->jointype != JOIN_INNER)
12620 {
12621 /* If we didn't say CROSS JOIN above, we must provide an ON */
12622 appendStringInfoString(buf, " ON TRUE");
12623 }
12624
12625 if (!PRETTY_PAREN(context) || j->alias != NULL)
12627
12628 /* Yes, it's correct to put alias after the right paren ... */
12629 if (j->alias != NULL)
12630 {
12631 /*
12632 * Note that it's correct to emit an alias clause if and only if
12633 * there was one originally. Otherwise we'd be converting a named
12634 * join to unnamed or vice versa, which creates semantic
12635 * subtleties we don't want. However, we might print a different
12636 * alias name than was there originally.
12637 */
12638 appendStringInfo(buf, " %s",
12640 context)));
12641 get_column_alias_list(colinfo, context);
12642 }
12643 }
12644 else
12645 elog(ERROR, "unrecognized node type: %d",
12646 (int) nodeTag(jtnode));
12647}
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
#define nodeTag(nodeptr)
Definition: nodes.h:139
@ JOIN_FULL
Definition: nodes.h:301
@ JOIN_INNER
Definition: nodes.h:299
@ JOIN_RIGHT
Definition: nodes.h:302
@ JOIN_LEFT
Definition: nodes.h:300
@ RTE_CTE
Definition: parsenodes.h:1032
@ RTE_VALUES
Definition: parsenodes.h:1031
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
@ RTE_FUNCTION
Definition: parsenodes.h:1029
@ RTE_TABLEFUNC
Definition: parsenodes.h:1030
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition: ruleutils.c:5133
#define PRETTYINDENT_JOIN
Definition: ruleutils.c:82
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
Definition: ruleutils.c:5624
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Definition: ruleutils.c:12817
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12726
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12766
static void get_rule_expr_funccall(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10683
#define deparse_columns_fetch(rangetable_index, dpns)
Definition: ruleutils.c:312
static void get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:12251
Definition: pg_list.h:54
char * ctename
Definition: parsenodes.h:1210
TableFunc * tablefunc
Definition: parsenodes.h:1198
bool funcordinality
Definition: parsenodes.h:1193
struct TableSampleClause * tablesample
Definition: parsenodes.h:1112
Query * subquery
Definition: parsenodes.h:1118
List * functions
Definition: parsenodes.h:1191
List * usingNames
Definition: ruleutils.c:299

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

Referenced by get_from_clause(), and get_from_clause_item().

◆ get_func_expr()

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

Definition at line 10775 of file ruleutils.c.

10777{
10778 StringInfo buf = context->buf;
10779 Oid funcoid = expr->funcid;
10780 Oid argtypes[FUNC_MAX_ARGS];
10781 int nargs;
10782 List *argnames;
10783 bool use_variadic;
10784 ListCell *l;
10785
10786 /*
10787 * If the function call came from an implicit coercion, then just show the
10788 * first argument --- unless caller wants to see implicit coercions.
10789 */
10790 if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
10791 {
10792 get_rule_expr_paren((Node *) linitial(expr->args), context,
10793 false, (Node *) expr);
10794 return;
10795 }
10796
10797 /*
10798 * If the function call came from a cast, then show the first argument
10799 * plus an explicit cast operation.
10800 */
10801 if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10802 expr->funcformat == COERCE_IMPLICIT_CAST)
10803 {
10804 Node *arg = linitial(expr->args);
10805 Oid rettype = expr->funcresulttype;
10806 int32 coercedTypmod;
10807
10808 /* Get the typmod if this is a length-coercion function */
10809 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10810
10811 get_coercion_expr(arg, context,
10812 rettype, coercedTypmod,
10813 (Node *) expr);
10814
10815 return;
10816 }
10817
10818 /*
10819 * If the function was called using one of the SQL spec's random special
10820 * syntaxes, try to reproduce that. If we don't recognize the function,
10821 * fall through.
10822 */
10823 if (expr->funcformat == COERCE_SQL_SYNTAX)
10824 {
10825 if (get_func_sql_syntax(expr, context))
10826 return;
10827 }
10828
10829 /*
10830 * Normal function: display as proname(args). First we need to extract
10831 * the argument datatypes.
10832 */
10833 if (list_length(expr->args) > FUNC_MAX_ARGS)
10834 ereport(ERROR,
10835 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10836 errmsg("too many arguments")));
10837 nargs = 0;
10838 argnames = NIL;
10839 foreach(l, expr->args)
10840 {
10841 Node *arg = (Node *) lfirst(l);
10842
10843 if (IsA(arg, NamedArgExpr))
10844 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10845 argtypes[nargs] = exprType(arg);
10846 nargs++;
10847 }
10848
10849 appendStringInfo(buf, "%s(",
10850 generate_function_name(funcoid, nargs,
10851 argnames, argtypes,
10852 expr->funcvariadic,
10853 &use_variadic,
10854 context->inGroupBy));
10855 nargs = 0;
10856 foreach(l, expr->args)
10857 {
10858 if (nargs++ > 0)
10860 if (use_variadic && lnext(expr->args, l) == NULL)
10861 appendStringInfoString(buf, "VARIADIC ");
10862 get_rule_expr((Node *) lfirst(l), context, true);
10863 }
10865}
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#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:557
@ COERCE_SQL_SYNTAX
Definition: primnodes.h:754
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:753
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:752
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Definition: ruleutils.c:11149
static void get_coercion_expr(Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
Definition: ruleutils.c:11401
Oid funcid
Definition: primnodes.h:767
List * args
Definition: primnodes.h:785

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, FuncExpr::args, deparse_context::buf, buf, COERCE_EXPLICIT_CAST, COERCE_IMPLICIT_CAST, COERCE_SQL_SYNTAX, ereport, errcode(), errmsg(), ERROR, exprIsLengthCoercion(), exprType(), FUNC_MAX_ARGS, FuncExpr::funcid, generate_function_name(), get_coercion_expr(), get_func_sql_syntax(), get_rule_expr(), get_rule_expr_paren(), deparse_context::inGroupBy, 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 11149 of file ruleutils.c.

11150{
11151 StringInfo buf = context->buf;
11152 Oid funcoid = expr->funcid;
11153
11154 switch (funcoid)
11155 {
11156 case F_TIMEZONE_INTERVAL_TIMESTAMP:
11157 case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
11158 case F_TIMEZONE_INTERVAL_TIMETZ:
11159 case F_TIMEZONE_TEXT_TIMESTAMP:
11160 case F_TIMEZONE_TEXT_TIMESTAMPTZ:
11161 case F_TIMEZONE_TEXT_TIMETZ:
11162 /* AT TIME ZONE ... note reversed argument order */
11164 get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
11165 (Node *) expr);
11166 appendStringInfoString(buf, " AT TIME ZONE ");
11167 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11168 (Node *) expr);
11170 return true;
11171
11172 case F_TIMEZONE_TIMESTAMP:
11173 case F_TIMEZONE_TIMESTAMPTZ:
11174 case F_TIMEZONE_TIMETZ:
11175 /* AT LOCAL */
11177 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11178 (Node *) expr);
11179 appendStringInfoString(buf, " AT LOCAL)");
11180 return true;
11181
11182 case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
11183 case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
11184 case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
11185 case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
11186 case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
11187 case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
11188 case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
11189 case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
11190 case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
11191 case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
11192 case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
11193 case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
11194 case F_OVERLAPS_TIME_TIME_TIME_TIME:
11195 /* (x1, x2) OVERLAPS (y1, y2) */
11197 get_rule_expr((Node *) linitial(expr->args), context, false);
11199 get_rule_expr((Node *) lsecond(expr->args), context, false);
11200 appendStringInfoString(buf, ") OVERLAPS (");
11201 get_rule_expr((Node *) lthird(expr->args), context, false);
11203 get_rule_expr((Node *) lfourth(expr->args), context, false);
11205 return true;
11206
11207 case F_EXTRACT_TEXT_DATE:
11208 case F_EXTRACT_TEXT_TIME:
11209 case F_EXTRACT_TEXT_TIMETZ:
11210 case F_EXTRACT_TEXT_TIMESTAMP:
11211 case F_EXTRACT_TEXT_TIMESTAMPTZ:
11212 case F_EXTRACT_TEXT_INTERVAL:
11213 /* EXTRACT (x FROM y) */
11214 appendStringInfoString(buf, "EXTRACT(");
11215 {
11216 Const *con = (Const *) linitial(expr->args);
11217
11218 Assert(IsA(con, Const) &&
11219 con->consttype == TEXTOID &&
11220 !con->constisnull);
11222 }
11223 appendStringInfoString(buf, " FROM ");
11224 get_rule_expr((Node *) lsecond(expr->args), context, false);
11226 return true;
11227
11228 case F_IS_NORMALIZED:
11229 /* IS xxx NORMALIZED */
11231 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11232 (Node *) expr);
11234 if (list_length(expr->args) == 2)
11235 {
11236 Const *con = (Const *) lsecond(expr->args);
11237
11238 Assert(IsA(con, Const) &&
11239 con->consttype == TEXTOID &&
11240 !con->constisnull);
11241 appendStringInfo(buf, " %s",
11242 TextDatumGetCString(con->constvalue));
11243 }
11244 appendStringInfoString(buf, " NORMALIZED)");
11245 return true;
11246
11247 case F_PG_COLLATION_FOR:
11248 /* COLLATION FOR */
11249 appendStringInfoString(buf, "COLLATION FOR (");
11250 get_rule_expr((Node *) linitial(expr->args), context, false);
11252 return true;
11253
11254 case F_NORMALIZE:
11255 /* NORMALIZE() */
11256 appendStringInfoString(buf, "NORMALIZE(");
11257 get_rule_expr((Node *) linitial(expr->args), context, false);
11258 if (list_length(expr->args) == 2)
11259 {
11260 Const *con = (Const *) lsecond(expr->args);
11261
11262 Assert(IsA(con, Const) &&
11263 con->consttype == TEXTOID &&
11264 !con->constisnull);
11265 appendStringInfo(buf, ", %s",
11266 TextDatumGetCString(con->constvalue));
11267 }
11269 return true;
11270
11271 case F_OVERLAY_BIT_BIT_INT4:
11272 case F_OVERLAY_BIT_BIT_INT4_INT4:
11273 case F_OVERLAY_BYTEA_BYTEA_INT4:
11274 case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
11275 case F_OVERLAY_TEXT_TEXT_INT4:
11276 case F_OVERLAY_TEXT_TEXT_INT4_INT4:
11277 /* OVERLAY() */
11278 appendStringInfoString(buf, "OVERLAY(");
11279 get_rule_expr((Node *) linitial(expr->args), context, false);
11280 appendStringInfoString(buf, " PLACING ");
11281 get_rule_expr((Node *) lsecond(expr->args), context, false);
11282 appendStringInfoString(buf, " FROM ");
11283 get_rule_expr((Node *) lthird(expr->args), context, false);
11284 if (list_length(expr->args) == 4)
11285 {
11286 appendStringInfoString(buf, " FOR ");
11287 get_rule_expr((Node *) lfourth(expr->args), context, false);
11288 }
11290 return true;
11291
11292 case F_POSITION_BIT_BIT:
11293 case F_POSITION_BYTEA_BYTEA:
11294 case F_POSITION_TEXT_TEXT:
11295 /* POSITION() ... extra parens since args are b_expr not a_expr */
11296 appendStringInfoString(buf, "POSITION((");
11297 get_rule_expr((Node *) lsecond(expr->args), context, false);
11298 appendStringInfoString(buf, ") IN (");
11299 get_rule_expr((Node *) linitial(expr->args), context, false);
11301 return true;
11302
11303 case F_SUBSTRING_BIT_INT4:
11304 case F_SUBSTRING_BIT_INT4_INT4:
11305 case F_SUBSTRING_BYTEA_INT4:
11306 case F_SUBSTRING_BYTEA_INT4_INT4:
11307 case F_SUBSTRING_TEXT_INT4:
11308 case F_SUBSTRING_TEXT_INT4_INT4:
11309 /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
11310 appendStringInfoString(buf, "SUBSTRING(");
11311 get_rule_expr((Node *) linitial(expr->args), context, false);
11312 appendStringInfoString(buf, " FROM ");
11313 get_rule_expr((Node *) lsecond(expr->args), context, false);
11314 if (list_length(expr->args) == 3)
11315 {
11316 appendStringInfoString(buf, " FOR ");
11317 get_rule_expr((Node *) lthird(expr->args), context, false);
11318 }
11320 return true;
11321
11322 case F_SUBSTRING_TEXT_TEXT_TEXT:
11323 /* SUBSTRING SIMILAR/ESCAPE */
11324 appendStringInfoString(buf, "SUBSTRING(");
11325 get_rule_expr((Node *) linitial(expr->args), context, false);
11326 appendStringInfoString(buf, " SIMILAR ");
11327 get_rule_expr((Node *) lsecond(expr->args), context, false);
11328 appendStringInfoString(buf, " ESCAPE ");
11329 get_rule_expr((Node *) lthird(expr->args), context, false);
11331 return true;
11332
11333 case F_BTRIM_BYTEA_BYTEA:
11334 case F_BTRIM_TEXT:
11335 case F_BTRIM_TEXT_TEXT:
11336 /* TRIM() */
11337 appendStringInfoString(buf, "TRIM(BOTH");
11338 if (list_length(expr->args) == 2)
11339 {
11341 get_rule_expr((Node *) lsecond(expr->args), context, false);
11342 }
11343 appendStringInfoString(buf, " FROM ");
11344 get_rule_expr((Node *) linitial(expr->args), context, false);
11346 return true;
11347
11348 case F_LTRIM_BYTEA_BYTEA:
11349 case F_LTRIM_TEXT:
11350 case F_LTRIM_TEXT_TEXT:
11351 /* TRIM() */
11352 appendStringInfoString(buf, "TRIM(LEADING");
11353 if (list_length(expr->args) == 2)
11354 {
11356 get_rule_expr((Node *) lsecond(expr->args), context, false);
11357 }
11358 appendStringInfoString(buf, " FROM ");
11359 get_rule_expr((Node *) linitial(expr->args), context, false);
11361 return true;
11362
11363 case F_RTRIM_BYTEA_BYTEA:
11364 case F_RTRIM_TEXT:
11365 case F_RTRIM_TEXT_TEXT:
11366 /* TRIM() */
11367 appendStringInfoString(buf, "TRIM(TRAILING");
11368 if (list_length(expr->args) == 2)
11369 {
11371 get_rule_expr((Node *) lsecond(expr->args), context, false);
11372 }
11373 appendStringInfoString(buf, " FROM ");
11374 get_rule_expr((Node *) linitial(expr->args), context, false);
11376 return true;
11377
11378 case F_SYSTEM_USER:
11379 appendStringInfoString(buf, "SYSTEM_USER");
11380 return true;
11381
11382 case F_XMLEXISTS:
11383 /* XMLEXISTS ... extra parens because args are c_expr */
11384 appendStringInfoString(buf, "XMLEXISTS((");
11385 get_rule_expr((Node *) linitial(expr->args), context, false);
11386 appendStringInfoString(buf, ") PASSING (");
11387 get_rule_expr((Node *) lsecond(expr->args), context, false);
11389 return true;
11390 }
11391 return false;
11392}
#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(), deparse_context::buf, buf, Const::consttype, FuncExpr::funcid, get_rule_expr(), get_rule_expr_paren(), IsA, lfourth, linitial, list_length(), lsecond, lthird, and TextDatumGetCString.

Referenced by get_func_expr().

◆ get_insert_query_def()

static void get_insert_query_def ( Query query,
deparse_context context 
)
static

Definition at line 6939 of file ruleutils.c.

6940{
6941 StringInfo buf = context->buf;
6942 RangeTblEntry *select_rte = NULL;
6943 RangeTblEntry *values_rte = NULL;
6944 RangeTblEntry *rte;
6945 char *sep;
6946 ListCell *l;
6947 List *strippedexprs;
6948
6949 /* Insert the WITH clause if given */
6950 get_with_clause(query, context);
6951
6952 /*
6953 * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6954 * single RTE for the SELECT or VALUES. Plain VALUES has neither.
6955 */
6956 foreach(l, query->rtable)
6957 {
6958 rte = (RangeTblEntry *) lfirst(l);
6959
6960 if (rte->rtekind == RTE_SUBQUERY)
6961 {
6962 if (select_rte)
6963 elog(ERROR, "too many subquery RTEs in INSERT");
6964 select_rte = rte;
6965 }
6966
6967 if (rte->rtekind == RTE_VALUES)
6968 {
6969 if (values_rte)
6970 elog(ERROR, "too many values RTEs in INSERT");
6971 values_rte = rte;
6972 }
6973 }
6974 if (select_rte && values_rte)
6975 elog(ERROR, "both subquery and values RTEs in INSERT");
6976
6977 /*
6978 * Start the query with INSERT INTO relname
6979 */
6980 rte = rt_fetch(query->resultRelation, query->rtable);
6981 Assert(rte->rtekind == RTE_RELATION);
6982
6983 if (PRETTY_INDENT(context))
6984 {
6985 context->indentLevel += PRETTYINDENT_STD;
6987 }
6988 appendStringInfo(buf, "INSERT INTO %s",
6989 generate_relation_name(rte->relid, NIL));
6990
6991 /* Print the relation alias, if needed; INSERT requires explicit AS */
6992 get_rte_alias(rte, query->resultRelation, true, context);
6993
6994 /* always want a space here */
6996
6997 /*
6998 * Add the insert-column-names list. Any indirection decoration needed on
6999 * the column names can be inferred from the top targetlist.
7000 */
7001 strippedexprs = NIL;
7002 sep = "";
7003 if (query->targetList)
7005 foreach(l, query->targetList)
7006 {
7007 TargetEntry *tle = (TargetEntry *) lfirst(l);
7008
7009 if (tle->resjunk)
7010 continue; /* ignore junk entries */
7011
7013 sep = ", ";
7014
7015 /*
7016 * Put out name of target column; look in the catalogs, not at
7017 * tle->resname, since resname will fail to track RENAME.
7018 */
7020 quote_identifier(get_attname(rte->relid,
7021 tle->resno,
7022 false)));
7023
7024 /*
7025 * Print any indirection needed (subfields or subscripts), and strip
7026 * off the top-level nodes representing the indirection assignments.
7027 * Add the stripped expressions to strippedexprs. (If it's a
7028 * single-VALUES statement, the stripped expressions are the VALUES to
7029 * print below. Otherwise they're just Vars and not really
7030 * interesting.)
7031 */
7032 strippedexprs = lappend(strippedexprs,
7033 processIndirection((Node *) tle->expr,
7034 context));
7035 }
7036 if (query->targetList)
7038
7039 if (query->override)
7040 {
7041 if (query->override == OVERRIDING_SYSTEM_VALUE)
7042 appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
7043 else if (query->override == OVERRIDING_USER_VALUE)
7044 appendStringInfoString(buf, "OVERRIDING USER VALUE ");
7045 }
7046
7047 if (select_rte)
7048 {
7049 /* Add the SELECT */
7050 get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
7051 false,
7052 context->prettyFlags, context->wrapColumn,
7053 context->indentLevel);
7054 }
7055 else if (values_rte)
7056 {
7057 /* Add the multi-VALUES expression lists */
7058 get_values_def(values_rte->values_lists, context);
7059 }
7060 else if (strippedexprs)
7061 {
7062 /* Add the single-VALUES expression list */
7063 appendContextKeyword(context, "VALUES (",
7065 get_rule_list_toplevel(strippedexprs, context, false);
7067 }
7068 else
7069 {
7070 /* No expressions, so it must be DEFAULT VALUES */
7071 appendStringInfoString(buf, "DEFAULT VALUES");
7072 }
7073
7074 /* Add ON CONFLICT if present */
7075 if (query->onConflict)
7076 {
7077 OnConflictExpr *confl = query->onConflict;
7078
7079 appendStringInfoString(buf, " ON CONFLICT");
7080
7081 if (confl->arbiterElems)
7082 {
7083 /* Add the single-VALUES expression list */
7085 get_rule_expr((Node *) confl->arbiterElems, context, false);
7087
7088 /* Add a WHERE clause (for partial indexes) if given */
7089 if (confl->arbiterWhere != NULL)
7090 {
7091 bool save_varprefix;
7092
7093 /*
7094 * Force non-prefixing of Vars, since parser assumes that they
7095 * belong to target relation. WHERE clause does not use
7096 * InferenceElem, so this is separately required.
7097 */
7098 save_varprefix = context->varprefix;
7099 context->varprefix = false;
7100
7101 appendContextKeyword(context, " WHERE ",
7103 get_rule_expr(confl->arbiterWhere, context, false);
7104
7105 context->varprefix = save_varprefix;
7106 }
7107 }
7108 else if (OidIsValid(confl->constraint))
7109 {
7110 char *constraint = get_constraint_name(confl->constraint);
7111
7112 if (!constraint)
7113 elog(ERROR, "cache lookup failed for constraint %u",
7114 confl->constraint);
7115 appendStringInfo(buf, " ON CONSTRAINT %s",
7116 quote_identifier(constraint));
7117 }
7118
7119 if (confl->action == ONCONFLICT_NOTHING)
7120 {
7121 appendStringInfoString(buf, " DO NOTHING");
7122 }
7123 else
7124 {
7125 appendStringInfoString(buf, " DO UPDATE SET ");
7126 /* Deparse targetlist */
7128 context, rte);
7129
7130 /* Add a WHERE clause if given */
7131 if (confl->onConflictWhere != NULL)
7132 {
7133 appendContextKeyword(context, " WHERE ",
7135 get_rule_expr(confl->onConflictWhere, context, false);
7136 }
7137 }
7138 }
7139
7140 /* Add RETURNING if present */
7141 if (query->returningList)
7142 get_returning_clause(query, context);
7143}
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1173
@ ONCONFLICT_NOTHING
Definition: nodes.h:425
@ OVERRIDING_SYSTEM_VALUE
Definition: primnodes.h:30
@ OVERRIDING_USER_VALUE
Definition: primnodes.h:29
static void get_rule_list_toplevel(List *lst, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10653
static Node * processIndirection(Node *node, deparse_context *context)
Definition: ruleutils.c:12921
static void get_update_query_targetlist_def(Query *query, List *targetList, deparse_context *context, RangeTblEntry *rte)
Definition: ruleutils.c:7203
List * arbiterElems
Definition: primnodes.h:2356
OnConflictAction action
Definition: primnodes.h:2353
List * onConflictSet
Definition: primnodes.h:2362
Node * onConflictWhere
Definition: primnodes.h:2363
Node * arbiterWhere
Definition: primnodes.h:2358
OnConflictExpr * onConflict
Definition: parsenodes.h:198
AttrNumber resno
Definition: primnodes.h:2221

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

Referenced by get_query_def().

◆ get_json_agg_constructor()

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

Definition at line 11768 of file ruleutils.c.

11770{
11772
11775
11776 if (IsA(ctor->func, Aggref))
11777 get_agg_expr_helper((Aggref *) ctor->func, context,
11778 (Aggref *) ctor->func,
11779 funcname, options.data, is_json_objectagg);
11780 else if (IsA(ctor->func, WindowFunc))
11781 get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
11782 funcname, options.data,
11783 is_json_objectagg);
11784 else
11785 elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
11786 nodeTag(ctor->func));
11787}
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:11036
static void get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
Definition: ruleutils.c:11738

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

Referenced by get_json_constructor().

◆ get_json_behavior()

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

Definition at line 9173 of file ruleutils.c.

9175{
9176 /*
9177 * The order of array elements must correspond to the order of
9178 * JsonBehaviorType members.
9179 */
9180 const char *behavior_names[] =
9181 {
9182 " NULL",
9183 " ERROR",
9184 " EMPTY",
9185 " TRUE",
9186 " FALSE",
9187 " UNKNOWN",
9188 " EMPTY ARRAY",
9189 " EMPTY OBJECT",
9190 " DEFAULT "
9191 };
9192
9193 if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
9194 elog(ERROR, "invalid json behavior type: %d", behavior->btype);
9195
9196 appendStringInfoString(context->buf, behavior_names[behavior->btype]);
9197
9198 if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
9199 get_rule_expr(behavior->expr, context, false);
9200
9201 appendStringInfo(context->buf, " ON %s", on);
9202}
#define lengthof(array)
Definition: c.h:759
@ JSON_BEHAVIOR_DEFAULT
Definition: primnodes.h:1778
Node * expr
Definition: primnodes.h:1796
JsonBehaviorType btype
Definition: primnodes.h:1795

References appendStringInfo(), appendStringInfoString(), JsonBehavior::btype, deparse_context::buf, 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 11672 of file ruleutils.c.

11674{
11675 StringInfo buf = context->buf;
11676 const char *funcname;
11677 bool is_json_object;
11678 int curridx;
11679 ListCell *lc;
11680
11681 if (ctor->type == JSCTOR_JSON_OBJECTAGG)
11682 {
11683 get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
11684 return;
11685 }
11686 else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
11687 {
11688 get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
11689 return;
11690 }
11691
11692 switch (ctor->type)
11693 {
11694 case JSCTOR_JSON_OBJECT:
11695 funcname = "JSON_OBJECT";
11696 break;
11697 case JSCTOR_JSON_ARRAY:
11698 funcname = "JSON_ARRAY";
11699 break;
11700 case JSCTOR_JSON_PARSE:
11701 funcname = "JSON";
11702 break;
11703 case JSCTOR_JSON_SCALAR:
11704 funcname = "JSON_SCALAR";
11705 break;
11707 funcname = "JSON_SERIALIZE";
11708 break;
11709 default:
11710 elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
11711 }
11712
11713 appendStringInfo(buf, "%s(", funcname);
11714
11715 is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
11716 foreach(lc, ctor->args)
11717 {
11718 curridx = foreach_current_index(lc);
11719 if (curridx > 0)
11720 {
11721 const char *sep;
11722
11723 sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
11725 }
11726
11727 get_rule_expr((Node *) lfirst(lc), context, true);
11728 }
11729
11732}
@ JSCTOR_JSON_SERIALIZE
Definition: primnodes.h:1701
@ JSCTOR_JSON_ARRAYAGG
Definition: primnodes.h:1698
@ JSCTOR_JSON_PARSE
Definition: primnodes.h:1699
@ JSCTOR_JSON_OBJECT
Definition: primnodes.h:1695
@ JSCTOR_JSON_SCALAR
Definition: primnodes.h:1700
@ JSCTOR_JSON_ARRAY
Definition: primnodes.h:1696
@ JSCTOR_JSON_OBJECTAGG
Definition: primnodes.h:1697
static void get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
Definition: ruleutils.c:11768
JsonConstructorType type
Definition: primnodes.h:1711

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

Referenced by get_rule_expr().

◆ get_json_constructor_options()

static void get_json_constructor_options ( JsonConstructorExpr ctor,
StringInfo  buf 
)
static

Definition at line 11738 of file ruleutils.c.

11739{
11740 if (ctor->absent_on_null)
11741 {
11742 if (ctor->type == JSCTOR_JSON_OBJECT ||
11743 ctor->type == JSCTOR_JSON_OBJECTAGG)
11744 appendStringInfoString(buf, " ABSENT ON NULL");
11745 }
11746 else
11747 {
11748 if (ctor->type == JSCTOR_JSON_ARRAY ||
11749 ctor->type == JSCTOR_JSON_ARRAYAGG)
11750 appendStringInfoString(buf, " NULL ON NULL");
11751 }
11752
11753 if (ctor->unique)
11754 appendStringInfoString(buf, " WITH UNIQUE KEYS");
11755
11756 /*
11757 * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
11758 * support one.
11759 */
11760 if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
11761 get_json_returning(ctor->returning, buf, true);
11762}
static void get_json_returning(JsonReturning *returning, StringInfo buf, bool json_format_by_default)
Definition: ruleutils.c:11652
JsonReturning * returning
Definition: primnodes.h:1715

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

9213{
9214 if (jsexpr->op == JSON_QUERY_OP)
9215 {
9216 if (jsexpr->wrapper == JSW_CONDITIONAL)
9217 appendStringInfoString(context->buf, " WITH CONDITIONAL WRAPPER");
9218 else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
9219 appendStringInfoString(context->buf, " WITH UNCONDITIONAL WRAPPER");
9220 /* The default */
9221 else if (jsexpr->wrapper == JSW_NONE || jsexpr->wrapper == JSW_UNSPEC)
9222 appendStringInfoString(context->buf, " WITHOUT WRAPPER");
9223
9224 if (jsexpr->omit_quotes)
9225 appendStringInfoString(context->buf, " OMIT QUOTES");
9226 /* The default */
9227 else
9228 appendStringInfoString(context->buf, " KEEP QUOTES");
9229 }
9230
9231 if (jsexpr->on_empty && jsexpr->on_empty->btype != default_behavior)
9232 get_json_behavior(jsexpr->on_empty, context, "EMPTY");
9233
9234 if (jsexpr->on_error && jsexpr->on_error->btype != default_behavior)
9235 get_json_behavior(jsexpr->on_error, context, "ERROR");
9236}
@ JSW_UNCONDITIONAL
Definition: primnodes.h:1758
@ JSW_CONDITIONAL
Definition: primnodes.h:1757
@ JSW_UNSPEC
Definition: primnodes.h:1755
@ JSW_NONE
Definition: primnodes.h:1756
@ JSON_QUERY_OP
Definition: primnodes.h:1808
static void get_json_behavior(JsonBehavior *behavior, deparse_context *context, const char *on)
Definition: ruleutils.c:9173
JsonBehavior * on_empty
Definition: primnodes.h:1844
JsonWrapper wrapper
Definition: primnodes.h:1855
JsonExprOp op
Definition: primnodes.h:1822
JsonBehavior * on_error
Definition: primnodes.h:1845
bool omit_quotes
Definition: primnodes.h:1858

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

11628{
11629 if (format->format_type == JS_FORMAT_DEFAULT)
11630 return;
11631
11633 format->format_type == JS_FORMAT_JSONB ?
11634 " FORMAT JSONB" : " FORMAT JSON");
11635
11636 if (format->encoding != JS_ENC_DEFAULT)
11637 {
11638 const char *encoding;
11639
11640 encoding =
11641 format->encoding == JS_ENC_UTF16 ? "UTF16" :
11642 format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
11643
11644 appendStringInfo(buf, " ENCODING %s", encoding);
11645 }
11646}
static char format
int32 encoding
Definition: pg_database.h:41
@ JS_FORMAT_JSONB
Definition: primnodes.h:1645
@ JS_FORMAT_DEFAULT
Definition: primnodes.h:1643
@ JS_ENC_DEFAULT
Definition: primnodes.h:1631
@ JS_ENC_UTF32
Definition: primnodes.h:1634
@ JS_ENC_UTF16
Definition: primnodes.h:1633

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

11616{
11617 if (IsA(path_spec, Const))
11618 get_const_expr((Const *) path_spec, context, -1);
11619 else
11620 get_rule_expr(path_spec, context, showimplicit);
11621}

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

Referenced by get_json_table_columns(), and get_rule_expr().

◆ get_json_returning()

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

Definition at line 11652 of file ruleutils.c.

11654{
11655 if (!OidIsValid(returning->typid))
11656 return;
11657
11658 appendStringInfo(buf, " RETURNING %s",
11660 returning->typmod));
11661
11662 if (!json_format_by_default ||
11663 returning->format->format_type !=
11664 (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
11665 get_json_format(returning->format, buf);
11666}
@ JS_FORMAT_JSON
Definition: primnodes.h:1644
static void get_json_format(JsonFormat *format, StringInfo buf)
Definition: ruleutils.c:11627
JsonFormatType format_type
Definition: primnodes.h:1656
JsonFormat * format
Definition: primnodes.h:1668

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

12183{
12184 StringInfo buf = context->buf;
12185 JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
12187
12188 appendStringInfoString(buf, "JSON_TABLE(");
12189
12190 if (PRETTY_INDENT(context))
12191 context->indentLevel += PRETTYINDENT_VAR;
12192
12193 appendContextKeyword(context, "", 0, 0, 0);
12194
12195 get_rule_expr(jexpr->formatted_expr, context, showimplicit);
12196
12198
12199 get_const_expr(root->path->value, context, -1);
12200
12201 appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
12202
12203 if (jexpr->passing_values)
12204 {
12205 ListCell *lc1,
12206 *lc2;
12207 bool needcomma = false;
12208
12210 appendContextKeyword(context, "PASSING ", 0, 0, 0);
12211
12212 if (PRETTY_INDENT(context))
12213 context->indentLevel += PRETTYINDENT_VAR;
12214
12215 forboth(lc1, jexpr->passing_names,
12216 lc2, jexpr->passing_values)
12217 {
12218 if (needcomma)
12220 needcomma = true;
12221
12222 appendContextKeyword(context, "", 0, 0, 0);
12223
12224 get_rule_expr((Node *) lfirst(lc2), context, false);
12225 appendStringInfo(buf, " AS %s",
12226 quote_identifier((lfirst_node(String, lc1))->sval)
12227 );
12228 }
12229
12230 if (PRETTY_INDENT(context))
12231 context->indentLevel -= PRETTYINDENT_VAR;
12232 }
12233
12234 get_json_table_columns(tf, castNode(JsonTablePathScan, tf->plan), context,
12235 showimplicit);
12236
12238 get_json_behavior(jexpr->on_error, context, "ERROR");
12239
12240 if (PRETTY_INDENT(context))
12241 context->indentLevel -= PRETTYINDENT_VAR;
12242
12243 appendContextKeyword(context, ")", 0, 0, 0);
12244}
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
@ JSON_BEHAVIOR_EMPTY_ARRAY
Definition: primnodes.h:1776
tree ctl root
Definition: radixtree.h:1857
static void get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:12076
Node * formatted_expr
Definition: primnodes.h:1828
List * passing_values
Definition: primnodes.h:1841
List * passing_names
Definition: primnodes.h:1840
Definition: value.h:64
Node * docexpr
Definition: primnodes.h:120

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), JsonBehavior::btype, deparse_context::buf, buf, castNode, TableFunc::docexpr, forboth, JsonExpr::formatted_expr, get_const_expr(), get_json_behavior(), get_json_table_columns(), get_rule_expr(), deparse_context::indentLevel, JSON_BEHAVIOR_EMPTY_ARRAY, 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 12076 of file ruleutils.c.

12079{
12080 StringInfo buf = context->buf;
12081 ListCell *lc_colname;
12082 ListCell *lc_coltype;
12083 ListCell *lc_coltypmod;
12084 ListCell *lc_colvalexpr;
12085 int colnum = 0;
12086
12088 appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
12089
12090 if (PRETTY_INDENT(context))
12091 context->indentLevel += PRETTYINDENT_VAR;
12092
12093 forfour(lc_colname, tf->colnames,
12094 lc_coltype, tf->coltypes,
12095 lc_coltypmod, tf->coltypmods,
12096 lc_colvalexpr, tf->colvalexprs)
12097 {
12098 char *colname = strVal(lfirst(lc_colname));
12099 JsonExpr *colexpr;
12100 Oid typid;
12101 int32 typmod;
12102 bool ordinality;
12103 JsonBehaviorType default_behavior;
12104
12105 typid = lfirst_oid(lc_coltype);
12106 typmod = lfirst_int(lc_coltypmod);
12107 colexpr = castNode(JsonExpr, lfirst(lc_colvalexpr));
12108
12109 /* Skip columns that don't belong to this scan. */
12110 if (scan->colMin < 0 || colnum < scan->colMin)
12111 {
12112 colnum++;
12113 continue;
12114 }
12115 if (colnum > scan->colMax)
12116 break;
12117
12118 if (colnum > scan->colMin)
12120
12121 colnum++;
12122
12123 ordinality = !colexpr;
12124
12125 appendContextKeyword(context, "", 0, 0, 0);
12126
12127 appendStringInfo(buf, "%s %s", quote_identifier(colname),
12128 ordinality ? "FOR ORDINALITY" :
12129 format_type_with_typemod(typid, typmod));
12130 if (ordinality)
12131 continue;
12132
12133 /*
12134 * Set default_behavior to guide get_json_expr_options() on whether to
12135 * emit the ON ERROR / EMPTY clauses.
12136 */
12137 if (colexpr->op == JSON_EXISTS_OP)
12138 {
12139 appendStringInfoString(buf, " EXISTS");
12140 default_behavior = JSON_BEHAVIOR_FALSE;
12141 }
12142 else
12143 {
12144 if (colexpr->op == JSON_QUERY_OP)
12145 {
12146 char typcategory;
12147 bool typispreferred;
12148
12149 get_type_category_preferred(typid, &typcategory, &typispreferred);
12150
12151 if (typcategory == TYPCATEGORY_STRING)
12153 colexpr->format->format_type == JS_FORMAT_JSONB ?
12154 " FORMAT JSONB" : " FORMAT JSON");
12155 }
12156
12157 default_behavior = JSON_BEHAVIOR_NULL;
12158 }
12159
12160 appendStringInfoString(buf, " PATH ");
12161
12162 get_json_path_spec(colexpr->path_spec, context, showimplicit);
12163
12164 get_json_expr_options(colexpr, context, default_behavior);
12165 }
12166
12167 if (scan->child)
12168 get_json_table_nested_columns(tf, scan->child, context, showimplicit,
12169 scan->colMin >= 0);
12170
12171 if (PRETTY_INDENT(context))
12172 context->indentLevel -= PRETTYINDENT_VAR;
12173
12174 appendContextKeyword(context, ")", 0, 0, 0);
12175}
void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
Definition: lsyscache.c:2850
JsonBehaviorType
Definition: primnodes.h:1769
@ JSON_BEHAVIOR_FALSE
Definition: primnodes.h:1774
@ JSON_BEHAVIOR_NULL
Definition: primnodes.h:1770
@ JSON_EXISTS_OP
Definition: primnodes.h:1807
static void get_json_expr_options(JsonExpr *jsexpr, deparse_context *context, JsonBehaviorType default_behavior)
Definition: ruleutils.c:9211
static void get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11615
static void get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan, deparse_context *context, bool showimplicit, bool needcomma)
Definition: ruleutils.c:12044
JsonFormat * format
Definition: primnodes.h:1831
Node * path_spec
Definition: primnodes.h:1834
JsonTablePlan * child
Definition: primnodes.h:1912

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), deparse_context::buf, buf, castNode, JsonTablePathScan::child, JsonTablePathScan::colMax, JsonTablePathScan::colMin, forfour, JsonExpr::format, JsonFormat::format_type, format_type_with_typemod(), get_json_expr_options(), get_json_path_spec(), get_json_table_nested_columns(), get_type_category_preferred(), deparse_context::indentLevel, JS_FORMAT_JSONB, JSON_BEHAVIOR_FALSE, JSON_BEHAVIOR_NULL, JSON_EXISTS_OP, JSON_QUERY_OP, lfirst, lfirst_int, lfirst_oid, 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 12044 of file ruleutils.c.

12047{
12049 {
12051
12052 if (needcomma)
12053 appendStringInfoChar(context->buf, ',');
12054
12055 appendStringInfoChar(context->buf, ' ');
12056 appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
12057 get_const_expr(scan->path->value, context, -1);
12058 appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
12059 get_json_table_columns(tf, scan, context, showimplicit);
12060 }
12061 else if (IsA(plan, JsonTableSiblingJoin))
12062 {
12064
12065 get_json_table_nested_columns(tf, join->lplan, context, showimplicit,
12066 needcomma);
12067 get_json_table_nested_columns(tf, join->rplan, context, showimplicit,
12068 true);
12069 }
12070}
JsonTablePath * path
Definition: primnodes.h:1903
Const * value
Definition: primnodes.h:1876
JsonTablePlan * rplan
Definition: primnodes.h:1933
JsonTablePlan * lplan
Definition: primnodes.h:1932

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

Referenced by get_json_table_columns(), and get_json_table_nested_columns().

◆ get_merge_query_def()

static void get_merge_query_def ( Query query,
deparse_context context 
)
static

Definition at line 7402 of file ruleutils.c.

7403{
7404 StringInfo buf = context->buf;
7405 RangeTblEntry *rte;
7406 ListCell *lc;
7407 bool haveNotMatchedBySource;
7408
7409 /* Insert the WITH clause if given */
7410 get_with_clause(query, context);
7411
7412 /*
7413 * Start the query with MERGE INTO relname
7414 */
7415 rte = rt_fetch(query->resultRelation, query->rtable);
7416 Assert(rte->rtekind == RTE_RELATION);
7417 if (PRETTY_INDENT(context))
7418 {
7420 context->indentLevel += PRETTYINDENT_STD;
7421 }
7422 appendStringInfo(buf, "MERGE INTO %s%s",
7423 only_marker(rte),
7424 generate_relation_name(rte->relid, NIL));
7425
7426 /* Print the relation alias, if needed */
7427 get_rte_alias(rte, query->resultRelation, false, context);
7428
7429 /* Print the source relation and join clause */
7430 get_from_clause(query, " USING ", context);
7431 appendContextKeyword(context, " ON ",
7433 get_rule_expr(query->mergeJoinCondition, context, false);
7434
7435 /*
7436 * Test for any NOT MATCHED BY SOURCE actions. If there are none, then
7437 * any NOT MATCHED BY TARGET actions are output as "WHEN NOT MATCHED", per
7438 * SQL standard. Otherwise, we have a non-SQL-standard query, so output
7439 * "BY SOURCE" / "BY TARGET" qualifiers for all NOT MATCHED actions, to be
7440 * more explicit.
7441 */
7442 haveNotMatchedBySource = false;
7443 foreach(lc, query->mergeActionList)
7444 {
7446
7447 if (action->matchKind == MERGE_WHEN_NOT_MATCHED_BY_SOURCE)
7448 {
7449 haveNotMatchedBySource = true;
7450 break;
7451 }
7452 }
7453
7454 /* Print each merge action */
7455 foreach(lc, query->mergeActionList)
7456 {
7458
7459 appendContextKeyword(context, " WHEN ",
7461 switch (action->matchKind)
7462 {
7463 case MERGE_WHEN_MATCHED:
7464 appendStringInfoString(buf, "MATCHED");
7465 break;
7467 appendStringInfoString(buf, "NOT MATCHED BY SOURCE");
7468 break;
7470 if (haveNotMatchedBySource)
7471 appendStringInfoString(buf, "NOT MATCHED BY TARGET");
7472 else
7473 appendStringInfoString(buf, "NOT MATCHED");
7474 break;
7475 default:
7476 elog(ERROR, "unrecognized matchKind: %d",
7477 (int) action->matchKind);
7478 }
7479
7480 if (action->qual)
7481 {
7482 appendContextKeyword(context, " AND ",
7484 get_rule_expr(action->qual, context, false);
7485 }
7486 appendContextKeyword(context, " THEN ",
7488
7489 if (action->commandType == CMD_INSERT)
7490 {
7491 /* This generally matches get_insert_query_def() */
7492 List *strippedexprs = NIL;
7493 const char *sep = "";
7494 ListCell *lc2;
7495
7496 appendStringInfoString(buf, "INSERT");
7497
7498 if (action->targetList)
7500 foreach(lc2, action->targetList)
7501 {
7502 TargetEntry *tle = (TargetEntry *) lfirst(lc2);
7503
7504 Assert(!tle->resjunk);
7505
7507 sep = ", ";
7508
7510 quote_identifier(get_attname(rte->relid,
7511 tle->resno,
7512 false)));
7513 strippedexprs = lappend(strippedexprs,
7514 processIndirection((Node *) tle->expr,
7515 context));
7516 }
7517 if (action->targetList)
7519
7520 if (action->override)
7521 {
7522 if (action->override == OVERRIDING_SYSTEM_VALUE)
7523 appendStringInfoString(buf, " OVERRIDING SYSTEM VALUE");
7524 else if (action->override == OVERRIDING_USER_VALUE)
7525 appendStringInfoString(buf, " OVERRIDING USER VALUE");
7526 }
7527
7528 if (strippedexprs)
7529 {
7530 appendContextKeyword(context, " VALUES (",
7532 get_rule_list_toplevel(strippedexprs, context, false);
7534 }
7535 else
7536 appendStringInfoString(buf, " DEFAULT VALUES");
7537 }
7538 else if (action->commandType == CMD_UPDATE)
7539 {
7540 appendStringInfoString(buf, "UPDATE SET ");
7541 get_update_query_targetlist_def(query, action->targetList,
7542 context, rte);
7543 }
7544 else if (action->commandType == CMD_DELETE)
7545 appendStringInfoString(buf, "DELETE");
7546 else if (action->commandType == CMD_NOTHING)
7547 appendStringInfoString(buf, "DO NOTHING");
7548 }
7549
7550 /* Add RETURNING if present */
7551 if (query->returningList)
7552 get_returning_clause(query, context);
7553}
@ CMD_INSERT
Definition: nodes.h:273
@ CMD_DELETE
Definition: nodes.h:274
@ CMD_UPDATE
Definition: nodes.h:272
@ CMD_NOTHING
Definition: nodes.h:278
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition: primnodes.h:2003
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition: primnodes.h:2002
@ MERGE_WHEN_MATCHED
Definition: primnodes.h:2001
Node * mergeJoinCondition
Definition: parsenodes.h:191
List * mergeActionList
Definition: parsenodes.h:180

References generate_unaccent_rules::action, appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), deparse_context::buf, buf, CMD_DELETE, CMD_INSERT, CMD_NOTHING, CMD_UPDATE, elog, ERROR, TargetEntry::expr, generate_relation_name(), get_attname(), get_from_clause(), get_returning_clause(), get_rte_alias(), get_rule_expr(), get_rule_list_toplevel(), get_update_query_targetlist_def(), get_with_clause(), deparse_context::indentLevel, 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(), 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 8017 of file ruleutils.c.

8019{
8020 RangeTblEntry *rte;
8022 int netlevelsup;
8023 deparse_namespace *dpns;
8024 int varno;
8025 AttrNumber varattno;
8026 TupleDesc tupleDesc;
8027 Node *expr;
8028
8029 /*
8030 * If it's a RowExpr that was expanded from a whole-row Var, use the
8031 * column names attached to it. (We could let get_expr_result_tupdesc()
8032 * handle this, but it's much cheaper to just pull out the name we need.)
8033 */
8034 if (IsA(var, RowExpr))
8035 {
8036 RowExpr *r = (RowExpr *) var;
8037
8038 if (fieldno > 0 && fieldno <= list_length(r->colnames))
8039 return strVal(list_nth(r->colnames, fieldno - 1));
8040 }
8041
8042 /*
8043 * If it's a Param of type RECORD, try to find what the Param refers to.
8044 */
8045 if (IsA(var, Param))
8046 {
8047 Param *param = (Param *) var;
8048 ListCell *ancestor_cell;
8049
8050 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8051 if (expr)
8052 {
8053 /* Found a match, so recurse to decipher the field name */
8054 deparse_namespace save_dpns;
8055 const char *result;
8056
8057 push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8058 result = get_name_for_var_field((Var *) expr, fieldno,
8059 0, context);
8060 pop_ancestor_plan(dpns, &save_dpns);
8061 return result;
8062 }
8063 }
8064
8065 /*
8066 * If it's a Var of type RECORD, we have to find what the Var refers to;
8067 * if not, we can use get_expr_result_tupdesc().
8068 */
8069 if (!IsA(var, Var) ||
8070 var->vartype != RECORDOID)
8071 {
8072 tupleDesc = get_expr_result_tupdesc((Node *) var, false);
8073 /* Got the tupdesc, so we can extract the field name */
8074 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8075 return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8076 }
8077
8078 /* Find appropriate nesting depth */
8079 netlevelsup = var->varlevelsup + levelsup;
8080 if (netlevelsup >= list_length(context->namespaces))
8081 elog(ERROR, "bogus varlevelsup: %d offset %d",
8082 var->varlevelsup, levelsup);
8083 dpns = (deparse_namespace *) list_nth(context->namespaces,
8084 netlevelsup);
8085
8086 /*
8087 * If we have a syntactic referent for the Var, and we're working from a
8088 * parse tree, prefer to use the syntactic referent. Otherwise, fall back
8089 * on the semantic referent. (See comments in get_variable().)
8090 */
8091 if (var->varnosyn > 0 && dpns->plan == NULL)
8092 {
8093 varno = var->varnosyn;
8094 varattno = var->varattnosyn;
8095 }
8096 else
8097 {
8098 varno = var->varno;
8099 varattno = var->varattno;
8100 }
8101
8102 /*
8103 * Try to find the relevant RTE in this rtable. In a plan tree, it's
8104 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
8105 * down into the subplans, or INDEX_VAR, which is resolved similarly.
8106 *
8107 * Note: unlike get_variable and resolve_special_varno, we need not worry
8108 * about inheritance mapping: a child Var should have the same datatype as
8109 * its parent, and here we're really only interested in the Var's type.
8110 */
8111 if (varno >= 1 && varno <= list_length(dpns->rtable))
8112 {
8113 rte = rt_fetch(varno, dpns->rtable);
8114 attnum = varattno;
8115 }
8116 else if (varno == OUTER_VAR && dpns->outer_tlist)
8117 {
8118 TargetEntry *tle;
8119 deparse_namespace save_dpns;
8120 const char *result;
8121
8122 tle = get_tle_by_resno(dpns->outer_tlist, varattno);
8123 if (!tle)
8124 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
8125
8126 Assert(netlevelsup == 0);
8127 push_child_plan(dpns, dpns->outer_plan, &save_dpns);
8128
8129 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8130 levelsup, context);
8131
8132 pop_child_plan(dpns, &save_dpns);
8133 return result;
8134 }
8135 else if (varno == INNER_VAR && dpns->inner_tlist)
8136 {
8137 TargetEntry *tle;
8138 deparse_namespace save_dpns;
8139 const char *result;
8140
8141 tle = get_tle_by_resno(dpns->inner_tlist, varattno);
8142 if (!tle)
8143 elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
8144
8145 Assert(netlevelsup == 0);
8146 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8147
8148 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8149 levelsup, context);
8150
8151 pop_child_plan(dpns, &save_dpns);
8152 return result;
8153 }
8154 else if (varno == INDEX_VAR && dpns->index_tlist)
8155 {
8156 TargetEntry *tle;
8157 const char *result;
8158
8159 tle = get_tle_by_resno(dpns->index_tlist, varattno);
8160 if (!tle)
8161 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
8162
8163 Assert(netlevelsup == 0);
8164
8165 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8166 levelsup, context);
8167
8168 return result;
8169 }
8170 else
8171 {
8172 elog(ERROR, "bogus varno: %d", varno);
8173 return NULL; /* keep compiler quiet */
8174 }
8175
8177 {
8178 /* Var is whole-row reference to RTE, so select the right field */
8179 return get_rte_attribute_name(rte, fieldno);
8180 }
8181
8182 /*
8183 * This part has essentially the same logic as the parser's
8184 * expandRecordVariable() function, but we are dealing with a different
8185 * representation of the input context, and we only need one field name
8186 * not a TupleDesc. Also, we need special cases for finding subquery and
8187 * CTE subplans when deparsing Plan trees.
8188 */
8189 expr = (Node *) var; /* default if we can't drill down */
8190
8191 switch (rte->rtekind)
8192 {
8193 case RTE_RELATION:
8194 case RTE_VALUES:
8196 case RTE_RESULT:
8197
8198 /*
8199 * This case should not occur: a column of a table, values list,
8200 * or ENR shouldn't have type RECORD. Fall through and fail (most
8201 * likely) at the bottom.
8202 */
8203 break;
8204 case RTE_SUBQUERY:
8205 /* Subselect-in-FROM: examine sub-select's output expr */
8206 {
8207 if (rte->subquery)
8208 {
8210 attnum);
8211
8212 if (ste == NULL || ste->resjunk)
8213 elog(ERROR, "subquery %s does not have attribute %d",
8214 rte->eref->aliasname, attnum);
8215 expr = (Node *) ste->expr;
8216 if (IsA(expr, Var))
8217 {
8218 /*
8219 * Recurse into the sub-select to see what its Var
8220 * refers to. We have to build an additional level of
8221 * namespace to keep in step with varlevelsup in the
8222 * subselect; furthermore, the subquery RTE might be
8223 * from an outer query level, in which case the
8224 * namespace for the subselect must have that outer
8225 * level as parent namespace.
8226 */
8227 List *save_nslist = context->namespaces;
8228 List *parent_namespaces;
8229 deparse_namespace mydpns;
8230 const char *result;
8231
8232 parent_namespaces = list_copy_tail(context->namespaces,
8233 netlevelsup);
8234
8235 set_deparse_for_query(&mydpns, rte->subquery,
8236 parent_namespaces);
8237
8238 context->namespaces = lcons(&mydpns, parent_namespaces);
8239
8240 result = get_name_for_var_field((Var *) expr, fieldno,
8241 0, context);
8242
8243 context->namespaces = save_nslist;
8244
8245 return result;
8246 }
8247 /* else fall through to inspect the expression */
8248 }
8249 else
8250 {
8251 /*
8252 * We're deparsing a Plan tree so we don't have complete
8253 * RTE entries (in particular, rte->subquery is NULL). But
8254 * the only place we'd normally see a Var directly
8255 * referencing a SUBQUERY RTE is in a SubqueryScan plan
8256 * node, and we can look into the child plan's tlist
8257 * instead. An exception occurs if the subquery was
8258 * proven empty and optimized away: then we'd find such a
8259 * Var in a childless Result node, and there's nothing in
8260 * the plan tree that would let us figure out what it had
8261 * originally referenced. In that case, fall back on
8262 * printing "fN", analogously to the default column names
8263 * for RowExprs.
8264 */
8265 TargetEntry *tle;
8266 deparse_namespace save_dpns;
8267 const char *result;
8268
8269 if (!dpns->inner_plan)
8270 {
8271 char *dummy_name = palloc(32);
8272
8273 Assert(dpns->plan && IsA(dpns->plan, Result));
8274 snprintf(dummy_name, 32, "f%d", fieldno);
8275 return dummy_name;
8276 }
8277 Assert(dpns->plan && IsA(dpns->plan, SubqueryScan));
8278
8279 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8280 if (!tle)
8281 elog(ERROR, "bogus varattno for subquery var: %d",
8282 attnum);
8283 Assert(netlevelsup == 0);
8284 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8285
8286 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8287 levelsup, context);
8288
8289 pop_child_plan(dpns, &save_dpns);
8290 return result;
8291 }
8292 }
8293 break;
8294 case RTE_JOIN:
8295 /* Join RTE --- recursively inspect the alias variable */
8296 if (rte->joinaliasvars == NIL)
8297 elog(ERROR, "cannot decompile join alias var in plan tree");
8298 Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
8299 expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
8300 Assert(expr != NULL);
8301 /* we intentionally don't strip implicit coercions here */
8302 if (IsA(expr, Var))
8303 return get_name_for_var_field((Var *) expr, fieldno,
8304 var->varlevelsup + levelsup,
8305 context);
8306 /* else fall through to inspect the expression */
8307 break;
8308 case RTE_FUNCTION:
8309 case RTE_TABLEFUNC:
8310
8311 /*
8312 * We couldn't get here unless a function is declared with one of
8313 * its result columns as RECORD, which is not allowed.
8314 */
8315 break;
8316 case RTE_CTE:
8317 /* CTE reference: examine subquery's output expr */
8318 {
8319 CommonTableExpr *cte = NULL;
8320 Index ctelevelsup;
8321 ListCell *lc;
8322
8323 /*
8324 * Try to find the referenced CTE using the namespace stack.
8325 */
8326 ctelevelsup = rte->ctelevelsup + netlevelsup;
8327 if (ctelevelsup >= list_length(context->namespaces))
8328 lc = NULL;
8329 else
8330 {
8331 deparse_namespace *ctedpns;
8332
8333 ctedpns = (deparse_namespace *)
8334 list_nth(context->namespaces, ctelevelsup);
8335 foreach(lc, ctedpns->ctes)
8336 {
8337 cte = (CommonTableExpr *) lfirst(lc);
8338 if (strcmp(cte->ctename, rte->ctename) == 0)
8339 break;
8340 }
8341 }
8342 if (lc != NULL)
8343 {
8344 Query *ctequery = (Query *) cte->ctequery;
8346 attnum);
8347
8348 if (ste == NULL || ste->resjunk)
8349 elog(ERROR, "CTE %s does not have attribute %d",
8350 rte->eref->aliasname, attnum);
8351 expr = (Node *) ste->expr;
8352 if (IsA(expr, Var))
8353 {
8354 /*
8355 * Recurse into the CTE to see what its Var refers to.
8356 * We have to build an additional level of namespace
8357 * to keep in step with varlevelsup in the CTE;
8358 * furthermore it could be an outer CTE (compare
8359 * SUBQUERY case above).
8360 */
8361 List *save_nslist = context->namespaces;
8362 List *parent_namespaces;
8363 deparse_namespace mydpns;
8364 const char *result;
8365
8366 parent_namespaces = list_copy_tail(context->namespaces,
8367 ctelevelsup);
8368
8369 set_deparse_for_query(&mydpns, ctequery,
8370 parent_namespaces);
8371
8372 context->namespaces = lcons(&mydpns, parent_namespaces);
8373
8374 result = get_name_for_var_field((Var *) expr, fieldno,
8375 0, context);
8376
8377 context->namespaces = save_nslist;
8378
8379 return result;
8380 }
8381 /* else fall through to inspect the expression */
8382 }
8383 else
8384 {
8385 /*
8386 * We're deparsing a Plan tree so we don't have a CTE
8387 * list. But the only places we'd normally see a Var
8388 * directly referencing a CTE RTE are in CteScan or
8389 * WorkTableScan plan nodes. For those cases,
8390 * set_deparse_plan arranged for dpns->inner_plan to be
8391 * the plan node that emits the CTE or RecursiveUnion
8392 * result, and we can look at its tlist instead. As
8393 * above, this can fail if the CTE has been proven empty,
8394 * in which case fall back to "fN".
8395 */
8396 TargetEntry *tle;
8397 deparse_namespace save_dpns;
8398 const char *result;
8399
8400 if (!dpns->inner_plan)
8401 {
8402 char *dummy_name = palloc(32);
8403
8404 Assert(dpns->plan && IsA(dpns->plan, Result));
8405 snprintf(dummy_name, 32, "f%d", fieldno);
8406 return dummy_name;
8407 }
8408 Assert(dpns->plan && (IsA(dpns->plan, CteScan) ||
8409 IsA(dpns->plan, WorkTableScan)));
8410
8411 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8412 if (!tle)
8413 elog(ERROR, "bogus varattno for subquery var: %d",
8414 attnum);
8415 Assert(netlevelsup == 0);
8416 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8417
8418 result = get_name_for_var_field((Var *) tle->expr, fieldno,
8419 levelsup, context);
8420
8421 pop_child_plan(dpns, &save_dpns);
8422 return result;
8423 }
8424 }
8425 break;
8426 case RTE_GROUP:
8427
8428 /*
8429 * We couldn't get here: any Vars that reference the RTE_GROUP RTE
8430 * should have been replaced with the underlying grouping
8431 * expressions.
8432 */
8433 break;
8434 }
8435
8436 /*
8437 * We now have an expression we can't expand any more, so see if
8438 * get_expr_result_tupdesc() can do anything with it.
8439 */
8440 tupleDesc = get_expr_result_tupdesc(expr, false);
8441 /* Got the tupdesc, so we can extract the field name */
8442 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8443 return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8444}
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
void * palloc(Size size)
Definition: mcxt.c:1321
char * get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
#define GetCTETargetList(cte)
Definition: parsenodes.h:1719
@ RTE_JOIN
Definition: parsenodes.h:1028
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1033
@ RTE_RESULT
Definition: parsenodes.h:1034
@ RTE_GROUP
Definition: parsenodes.h:1037
int16 attnum
Definition: pg_attribute.h:74
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define snprintf
Definition: port.h:239
#define OUTER_VAR
Definition: primnodes.h:243
#define INNER_VAR
Definition: primnodes.h:242
#define INDEX_VAR
Definition: primnodes.h:244
static void set_deparse_for_query(deparse_namespace *dpns, Query *query, List *parent_namespaces)
Definition: ruleutils.c:4029
static const char * get_name_for_var_field(Var *var, int fieldno, int levelsup, deparse_context *context)
Definition: ruleutils.c:8017
static void pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5331
static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns)
Definition: ruleutils.c:5310
static Node * find_param_referent(Param *param, deparse_context *context, deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
Definition: ruleutils.c:8455
static void pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5280
static void push_child_plan(deparse_namespace *dpns, Plan *plan, deparse_namespace *save_dpns)
Definition: ruleutils.c:5263
Index ctelevelsup
Definition: parsenodes.h:1212
Definition: primnodes.h:262
AttrNumber varattno
Definition: primnodes.h:274
int varno
Definition: primnodes.h:269
Index varlevelsup
Definition: primnodes.h:294
List * inner_tlist
Definition: ruleutils.c:181
List * outer_tlist
Definition: ruleutils.c:180
List * index_tlist
Definition: ruleutils.c:182
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

References Assert(), attname, attnum, RangeTblEntry::ctelevelsup, RangeTblEntry::ctename, CommonTableExpr::ctename, CommonTableExpr::ctequery, deparse_namespace::ctes, elog, ERROR, TargetEntry::expr, find_param_referent(), get_expr_result_tupdesc(), get_name_for_var_field(), 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(), deparse_context::namespaces, NameStr, NIL, deparse_namespace::outer_plan, deparse_namespace::outer_tlist, OUTER_VAR, palloc(), 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_GROUP, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, set_deparse_for_query(), snprintf, strVal, RangeTblEntry::subquery, Query::targetList, TupleDescAttr(), Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by get_name_for_var_field(), and get_rule_expr().

◆ get_opclass_name()

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

Definition at line 12861 of file ruleutils.c.

12863{
12864 HeapTuple ht_opc;
12865 Form_pg_opclass opcrec;
12866 char *opcname;
12867 char *nspname;
12868
12869 ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
12870 if (!HeapTupleIsValid(ht_opc))
12871 elog(ERROR, "cache lookup failed for opclass %u", opclass);
12872 opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
12873
12874 if (!OidIsValid(actual_datatype) ||
12875 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
12876 {
12877 /* Okay, we need the opclass name. Do we need to qualify it? */
12878 opcname = NameStr(opcrec->opcname);
12879 if (OpclassIsVisible(opclass))
12880 appendStringInfo(buf, " %s", quote_identifier(opcname));
12881 else
12882 {
12883 nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
12884 appendStringInfo(buf, " %s.%s",
12885 quote_identifier(nspname),
12886 quote_identifier(opcname));
12887 }
12888 }
12889 ReleaseSysCache(ht_opc);
12890}
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2345
bool OpclassIsVisible(Oid opcid)
Definition: namespace.c:2154
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 10735 of file ruleutils.c.

10736{
10737 StringInfo buf = context->buf;
10738 Oid opno = expr->opno;
10739 List *args = expr->args;
10740
10741 if (!PRETTY_PAREN(context))
10743 if (list_length(args) == 2)
10744 {
10745 /* binary operator */
10746 Node *arg1 = (Node *) linitial(args);
10747 Node *arg2 = (Node *) lsecond(args);
10748
10749 get_rule_expr_paren(arg1, context, true, (Node *) expr);
10750 appendStringInfo(buf, " %s ",
10752 exprType(arg1),
10753 exprType(arg2)));
10754 get_rule_expr_paren(arg2, context, true, (Node *) expr);
10755 }
10756 else
10757 {
10758 /* prefix operator */
10759 Node *arg = (Node *) linitial(args);
10760
10761 appendStringInfo(buf, "%s ",
10763 InvalidOid,
10764 exprType(arg)));
10765 get_rule_expr_paren(arg, context, true, (Node *) expr);
10766 }
10767 if (!PRETTY_PAREN(context))
10769}
static char * generate_operator_name(Oid operid, Oid arg1, Oid arg2)
Definition: ruleutils.c:13362
Oid opno
Definition: primnodes.h:835
List * args
Definition: primnodes.h:853

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

Referenced by get_rule_expr().

◆ get_parameter()

static void get_parameter ( Param param,
deparse_context context 
)
static

Definition at line 8687 of file ruleutils.c.

8688{
8689 Node *expr;
8690 deparse_namespace *dpns;
8691 ListCell *ancestor_cell;
8692 SubPlan *subplan;
8693 int column;
8694
8695 /*
8696 * If it's a PARAM_EXEC parameter, try to locate the expression from which
8697 * the parameter was computed. This stanza handles only cases in which
8698 * the Param represents an input to the subplan we are currently in.
8699 */
8700 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8701 if (expr)
8702 {
8703 /* Found a match, so print it */
8704 deparse_namespace save_dpns;
8705 bool save_varprefix;
8706 bool need_paren;
8707
8708 /* Switch attention to the ancestor plan node */
8709 push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8710
8711 /*
8712 * Force prefixing of Vars, since they won't belong to the relation
8713 * being scanned in the original plan node.
8714 */
8715 save_varprefix = context->varprefix;
8716 context->varprefix = true;
8717
8718 /*
8719 * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8720 * upper-level Param, which wouldn't need extra parentheses.
8721 * Otherwise, insert parens to ensure the expression looks atomic.
8722 */
8723 need_paren = !(IsA(expr, Var) ||
8724 IsA(expr, Aggref) ||
8725 IsA(expr, GroupingFunc) ||
8726 IsA(expr, Param));
8727 if (need_paren)
8728 appendStringInfoChar(context->buf, '(');
8729
8730 get_rule_expr(expr, context, false);
8731
8732 if (need_paren)
8733 appendStringInfoChar(context->buf, ')');
8734
8735 context->varprefix = save_varprefix;
8736
8737 pop_ancestor_plan(dpns, &save_dpns);
8738
8739 return;
8740 }
8741
8742 /*
8743 * Alternatively, maybe it's a subplan output, which we print as a
8744 * reference to the subplan. (We could drill down into the subplan and
8745 * print the relevant targetlist expression, but that has been deemed too
8746 * confusing since it would violate normal SQL scope rules. Also, we're
8747 * relying on this reference to show that the testexpr containing the
8748 * Param has anything to do with that subplan at all.)
8749 */
8750 subplan = find_param_generator(param, context, &column);
8751 if (subplan)
8752 {
8753 appendStringInfo(context->buf, "(%s%s).col%d",
8754 subplan->useHashTable ? "hashed " : "",
8755 subplan->plan_name, column + 1);
8756
8757 return;
8758 }
8759
8760 /*
8761 * If it's an external parameter, see if the outermost namespace provides
8762 * function argument names.
8763 */
8764 if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8765 {
8766 dpns = llast(context->namespaces);
8767 if (dpns->argnames &&
8768 param->paramid > 0 &&
8769 param->paramid <= dpns->numargs)
8770 {
8771 char *argname = dpns->argnames[param->paramid - 1];
8772
8773 if (argname)
8774 {
8775 bool should_qualify = false;
8776 ListCell *lc;
8777
8778 /*
8779 * Qualify the parameter name if there are any other deparse
8780 * namespaces with range tables. This avoids qualifying in
8781 * trivial cases like "RETURN a + b", but makes it safe in all
8782 * other cases.
8783 */
8784 foreach(lc, context->namespaces)
8785 {
8786 deparse_namespace *depns = lfirst(lc);
8787
8788 if (depns->rtable_names != NIL)
8789 {
8790 should_qualify = true;
8791 break;
8792 }
8793 }
8794 if (should_qualify)
8795 {
8797 appendStringInfoChar(context->buf, '.');
8798 }
8799
8800 appendStringInfoString(context->buf, quote_identifier(argname));
8801 return;
8802 }
8803 }
8804 }
8805
8806 /*
8807 * Not PARAM_EXEC, or couldn't find referent: just print $N.
8808 *
8809 * It's a bug if we get here for anything except PARAM_EXTERN Params, but
8810 * in production builds printing $N seems more useful than failing.
8811 */
8812 Assert(param->paramkind == PARAM_EXTERN);
8813
8814 appendStringInfo(context->buf, "$%d", param->paramid);
8815}
#define llast(l)
Definition: pg_list.h:198
@ PARAM_EXTERN
Definition: primnodes.h:384
static SubPlan * find_param_generator(Param *param, deparse_context *context, int *column_p)
Definition: ruleutils.c:8569
char * plan_name
Definition: primnodes.h:1089
bool useHashTable
Definition: primnodes.h:1096
char ** argnames
Definition: ruleutils.c:186

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

Referenced by get_rule_expr().

◆ get_query_def()

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

Definition at line 5624 of file ruleutils.c.

5627{
5628 deparse_context context;
5629 deparse_namespace dpns;
5630 int rtable_size;
5631
5632 /* Guard against excessively long or deeply-nested queries */
5635
5636 rtable_size = query->hasGroupRTE ?
5637 list_length(query->rtable) - 1 :
5638 list_length(query->rtable);
5639
5640 /*
5641 * Replace any Vars in the query's targetlist and havingQual that
5642 * reference GROUP outputs with the underlying grouping expressions.
5643 */
5644 if (query->hasGroupRTE)
5645 {
5646 query->targetList = (List *)
5647 flatten_group_exprs(NULL, query, (Node *) query->targetList);
5648 query->havingQual =
5649 flatten_group_exprs(NULL, query, query->havingQual);
5650 }
5651
5652 /*
5653 * Before we begin to examine the query, acquire locks on referenced
5654 * relations, and fix up deleted columns in JOIN RTEs. This ensures
5655 * consistent results. Note we assume it's OK to scribble on the passed
5656 * querytree!
5657 *
5658 * We are only deparsing the query (we are not about to execute it), so we
5659 * only need AccessShareLock on the relations it mentions.
5660 */
5661 AcquireRewriteLocks(query, false, false);
5662
5663 context.buf = buf;
5664 context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5665 context.resultDesc = NULL;
5666 context.targetList = NIL;
5667 context.windowClause = NIL;
5668 context.varprefix = (parentnamespace != NIL ||
5669 rtable_size != 1);
5670 context.prettyFlags = prettyFlags;
5671 context.wrapColumn = wrapColumn;
5672 context.indentLevel = startIndent;
5673 context.colNamesVisible = colNamesVisible;
5674 context.inGroupBy = false;
5675 context.varInOrderBy = false;
5676 context.appendparents = NULL;
5677
5678 set_deparse_for_query(&dpns, query, parentnamespace);
5679
5680 switch (query->commandType)
5681 {
5682 case CMD_SELECT:
5683 /* We set context.resultDesc only if it's a SELECT */
5684 context.resultDesc = resultDesc;
5685 get_select_query_def(query, &context);
5686 break;
5687
5688 case CMD_UPDATE:
5689 get_update_query_def(query, &context);
5690 break;
5691
5692 case CMD_INSERT:
5693 get_insert_query_def(query, &context);
5694 break;
5695
5696 case CMD_DELETE:
5697 get_delete_query_def(query, &context);
5698 break;
5699
5700 case CMD_MERGE:
5701 get_merge_query_def(query, &context);
5702 break;
5703
5704 case CMD_NOTHING:
5705 appendStringInfoString(buf, "NOTHING");
5706 break;
5707
5708 case CMD_UTILITY:
5709 get_utility_query_def(query, &context);
5710 break;
5711
5712 default:
5713 elog(ERROR, "unrecognized query command type: %d",
5714 query->commandType);
5715 break;
5716 }
5717}
List * list_copy(const List *oldlist)
Definition: list.c:1573
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
@ CMD_MERGE
Definition: nodes.h:275
@ CMD_UTILITY
Definition: nodes.h:276
@ CMD_SELECT
Definition: nodes.h:271
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
static void get_delete_query_def(Query *query, deparse_context *context)
Definition: ruleutils.c:7355
static void get_insert_query_def(Query *query, deparse_context *context)
Definition: ruleutils.c:6939
static void get_utility_query_def(Query *query, deparse_context *context)
Definition: ruleutils.c:7561
static void get_merge_query_def(Query *query, deparse_context *context)
Definition: ruleutils.c:7402
static void get_update_query_def(Query *query, deparse_context *context)
Definition: ruleutils.c:7151
static void get_select_query_def(Query *query, deparse_context *context)
Definition: ruleutils.c:5906
void check_stack_depth(void)
Definition: stack_depth.c:95
CmdType commandType
Definition: parsenodes.h:121
Node * flatten_group_exprs(PlannerInfo *root, Query *query, Node *node)
Definition: var.c:968

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

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

◆ get_range_partbound_string()

char * get_range_partbound_string ( List bound_datums)

Definition at line 13676 of file ruleutils.c.

13677{
13678 deparse_context context;
13680 ListCell *cell;
13681 char *sep;
13682
13683 memset(&context, 0, sizeof(deparse_context));
13684 context.buf = buf;
13685
13687 sep = "";
13688 foreach(cell, bound_datums)
13689 {
13690 PartitionRangeDatum *datum =
13692
13695 appendStringInfoString(buf, "MINVALUE");
13696 else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
13697 appendStringInfoString(buf, "MAXVALUE");
13698 else
13699 {
13700 Const *val = castNode(Const, datum->value);
13701
13702 get_const_expr(val, &context, -1);
13703 }
13704 sep = ", ";
13705 }
13707
13708 return buf->data;
13709}
long val
Definition: informix.c:689
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition: parsenodes.h:937
@ PARTITION_RANGE_DATUM_MINVALUE
Definition: parsenodes.h:935
StringInfo makeStringInfo(void)
Definition: stringinfo.c:72
PartitionRangeDatumKind kind
Definition: parsenodes.h:944

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

Referenced by check_new_partition_bound(), and get_rule_expr().

◆ get_relation_name()

static char * get_relation_name ( Oid  relid)
static

Definition at line 13133 of file ruleutils.c.

13134{
13135 char *relname = get_rel_name(relid);
13136
13137 if (!relname)
13138 elog(ERROR, "cache lookup failed for relation %u", relid);
13139 return relname;
13140}
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2068

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

13589{
13590 Datum *options;
13591 int noptions;
13592 int i;
13593
13594 deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
13595 &options, NULL, &noptions);
13596
13597 for (i = 0; i < noptions; i++)
13598 {
13600 char *name;
13601 char *separator;
13602 char *value;
13603
13604 /*
13605 * Each array element should have the form name=value. If the "=" is
13606 * missing for some reason, treat it like an empty value.
13607 */
13608 name = option;
13609 separator = strchr(option, '=');
13610 if (separator)
13611 {
13612 *separator = '\0';
13613 value = separator + 1;
13614 }
13615 else
13616 value = "";
13617
13618 if (i > 0)
13621
13622 /*
13623 * In general we need to quote the value; but to avoid unnecessary
13624 * clutter, do not quote if it is an identifier that would not need
13625 * quoting. (We could also allow numbers, but that is a bit trickier
13626 * than it looks --- for example, are leading zeroes significant? We
13627 * don't want to assume very much here about what custom reloptions
13628 * might mean.)
13629 */
13632 else
13634
13635 pfree(option);
13636 }
13637}
static struct @165 value
static size_t noptions

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

static void get_returning_clause ( Query query,
deparse_context context 
)
static

Definition at line 6375 of file ruleutils.c.

6376{
6377 StringInfo buf = context->buf;
6378
6379 if (query->returningList)
6380 {
6381 bool have_with = false;
6382
6383 appendContextKeyword(context, " RETURNING",
6385
6386 /* Add WITH (OLD/NEW) options, if they're not the defaults */
6387 if (query->returningOldAlias && strcmp(query->returningOldAlias, "old") != 0)
6388 {
6389 appendStringInfo(buf, " WITH (OLD AS %s",
6390 quote_identifier(query->returningOldAlias));
6391 have_with = true;
6392 }
6393 if (query->returningNewAlias && strcmp(query->returningNewAlias, "new") != 0)
6394 {
6395 if (have_with)
6396 appendStringInfo(buf, ", NEW AS %s",
6397 quote_identifier(query->returningNewAlias));
6398 else
6399 {
6400 appendStringInfo(buf, " WITH (NEW AS %s",
6401 quote_identifier(query->returningNewAlias));
6402 have_with = true;
6403 }
6404 }
6405 if (have_with)
6407
6408 /* Add the returning expressions themselves */
6409 get_target_list(query->returningList, context);
6410 }
6411}

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), deparse_context::buf, buf, get_target_list(), PRETTYINDENT_STD, quote_identifier(), and Query::returningList.

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

◆ get_rtable_name()

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

Definition at line 5133 of file ruleutils.c.

5134{
5136
5137 Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
5138 return (char *) list_nth(dpns->rtable_names, rtindex - 1);
5139}

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

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

◆ get_rte_alias()

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

Definition at line 12655 of file ruleutils.c.

12657{
12659 char *refname = get_rtable_name(varno, context);
12660 deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12661 bool printalias = false;
12662
12663 if (rte->alias != NULL)
12664 {
12665 /* Always print alias if user provided one */
12666 printalias = true;
12667 }
12668 else if (colinfo->printaliases)
12669 {
12670 /* Always print alias if we need to print column aliases */
12671 printalias = true;
12672 }
12673 else if (rte->rtekind == RTE_RELATION)
12674 {
12675 /*
12676 * No need to print alias if it's same as relation name (this would
12677 * normally be the case, but not if set_rtable_names had to resolve a
12678 * conflict).
12679 */
12680 if (strcmp(refname, get_relation_name(rte->relid)) != 0)
12681 printalias = true;
12682 }
12683 else if (rte->rtekind == RTE_FUNCTION)
12684 {
12685 /*
12686 * For a function RTE, always print alias. This covers possible
12687 * renaming of the function and/or instability of the FigureColname
12688 * rules for things that aren't simple functions. Note we'd need to
12689 * force it anyway for the columndef list case.
12690 */
12691 printalias = true;
12692 }
12693 else if (rte->rtekind == RTE_SUBQUERY ||
12694 rte->rtekind == RTE_VALUES)
12695 {
12696 /*
12697 * For a subquery, always print alias. This makes the output
12698 * SQL-spec-compliant, even though we allow such aliases to be omitted
12699 * on input.
12700 */
12701 printalias = true;
12702 }
12703 else if (rte->rtekind == RTE_CTE)
12704 {
12705 /*
12706 * No need to print alias if it's same as CTE name (this would
12707 * normally be the case, but not if set_rtable_names had to resolve a
12708 * conflict).
12709 */
12710 if (strcmp(refname, rte->ctename) != 0)
12711 printalias = true;
12712 }
12713
12714 if (printalias)
12715 appendStringInfo(context->buf, "%s%s",
12716 use_as ? " AS " : " ",
12717 quote_identifier(refname));
12718}
static char * get_relation_name(Oid relid)
Definition: ruleutils.c:13133

References appendStringInfo(), deparse_context::buf, RangeTblEntry::ctename, deparse_columns_fetch, get_relation_name(), get_rtable_name(), linitial, deparse_context::namespaces, deparse_columns::printaliases, quote_identifier(), 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 9252 of file ruleutils.c.

9254{
9255 StringInfo buf = context->buf;
9256
9257 if (node == NULL)
9258 return;
9259
9260 /* Guard against excessively long or deeply-nested queries */
9263
9264 /*
9265 * Each level of get_rule_expr must emit an indivisible term
9266 * (parenthesized if necessary) to ensure result is reparsed into the same
9267 * expression tree. The only exception is that when the input is a List,
9268 * we emit the component items comma-separated with no surrounding
9269 * decoration; this is convenient for most callers.
9270 */
9271 switch (nodeTag(node))
9272 {
9273 case T_Var:
9274 (void) get_variable((Var *) node, 0, false, context);
9275 break;
9276
9277 case T_Const:
9278 get_const_expr((Const *) node, context, 0);
9279 break;
9280
9281 case T_Param:
9282 get_parameter((Param *) node, context);
9283 break;
9284
9285 case T_Aggref:
9286 get_agg_expr((Aggref *) node, context, (Aggref *) node);
9287 break;
9288
9289 case T_GroupingFunc:
9290 {
9291 GroupingFunc *gexpr = (GroupingFunc *) node;
9292
9293 appendStringInfoString(buf, "GROUPING(");
9294 get_rule_expr((Node *) gexpr->args, context, true);
9296 }
9297 break;
9298
9299 case T_WindowFunc:
9300 get_windowfunc_expr((WindowFunc *) node, context);
9301 break;
9302
9303 case T_MergeSupportFunc:
9304 appendStringInfoString(buf, "MERGE_ACTION()");
9305 break;
9306
9307 case T_SubscriptingRef:
9308 {
9309 SubscriptingRef *sbsref = (SubscriptingRef *) node;
9310 bool need_parens;
9311
9312 /*
9313 * If the argument is a CaseTestExpr, we must be inside a
9314 * FieldStore, ie, we are assigning to an element of an array
9315 * within a composite column. Since we already punted on
9316 * displaying the FieldStore's target information, just punt
9317 * here too, and display only the assignment source
9318 * expression.
9319 */
9320 if (IsA(sbsref->refexpr, CaseTestExpr))
9321 {
9322 Assert(sbsref->refassgnexpr);
9323 get_rule_expr((Node *) sbsref->refassgnexpr,
9324 context, showimplicit);
9325 break;
9326 }
9327
9328 /*
9329 * Parenthesize the argument unless it's a simple Var or a
9330 * FieldSelect. (In particular, if it's another
9331 * SubscriptingRef, we *must* parenthesize to avoid
9332 * confusion.)
9333 */
9334 need_parens = !IsA(sbsref->refexpr, Var) &&
9335 !IsA(sbsref->refexpr, FieldSelect);
9336 if (need_parens)
9338 get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
9339 if (need_parens)
9341
9342 /*
9343 * If there's a refassgnexpr, we want to print the node in the
9344 * format "container[subscripts] := refassgnexpr". This is
9345 * not legal SQL, so decompilation of INSERT or UPDATE
9346 * statements should always use processIndirection as part of
9347 * the statement-level syntax. We should only see this when
9348 * EXPLAIN tries to print the targetlist of a plan resulting
9349 * from such a statement.
9350 */
9351 if (sbsref->refassgnexpr)
9352 {
9353 Node *refassgnexpr;
9354
9355 /*
9356 * Use processIndirection to print this node's subscripts
9357 * as well as any additional field selections or
9358 * subscripting in immediate descendants. It returns the
9359 * RHS expr that is actually being "assigned".
9360 */
9361 refassgnexpr = processIndirection(node, context);
9362 appendStringInfoString(buf, " := ");
9363 get_rule_expr(refassgnexpr, context, showimplicit);
9364 }
9365 else
9366 {
9367 /* Just an ordinary container fetch, so print subscripts */
9368 printSubscripts(sbsref, context);
9369 }
9370 }
9371 break;
9372
9373 case T_FuncExpr:
9374 get_func_expr((FuncExpr *) node, context, showimplicit);
9375 break;
9376
9377 case T_NamedArgExpr:
9378 {
9379 NamedArgExpr *na = (NamedArgExpr *) node;
9380
9381 appendStringInfo(buf, "%s => ", quote_identifier(na->name));
9382 get_rule_expr((Node *) na->arg, context, showimplicit);
9383 }
9384 break;
9385
9386 case T_OpExpr:
9387 get_oper_expr((OpExpr *) node, context);
9388 break;
9389
9390 case T_DistinctExpr:
9391 {
9392 DistinctExpr *expr = (DistinctExpr *) node;
9393 List *args = expr->args;
9394 Node *arg1 = (Node *) linitial(args);
9395 Node *arg2 = (Node *) lsecond(args);
9396
9397 if (!PRETTY_PAREN(context))
9399 get_rule_expr_paren(arg1, context, true, node);
9400 appendStringInfoString(buf, " IS DISTINCT FROM ");
9401 get_rule_expr_paren(arg2, context, true, node);
9402 if (!PRETTY_PAREN(context))
9404 }
9405 break;
9406
9407 case T_NullIfExpr:
9408 {
9409 NullIfExpr *nullifexpr = (NullIfExpr *) node;
9410
9411 appendStringInfoString(buf, "NULLIF(");
9412 get_rule_expr((Node *) nullifexpr->args, context, true);
9414 }
9415 break;
9416
9417 case T_ScalarArrayOpExpr:
9418 {
9419 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
9420 List *args = expr->args;
9421 Node *arg1 = (Node *) linitial(args);
9422 Node *arg2 = (Node *) lsecond(args);
9423
9424 if (!PRETTY_PAREN(context))
9426 get_rule_expr_paren(arg1, context, true, node);
9427 appendStringInfo(buf, " %s %s (",
9429 exprType(arg1),
9431 expr->useOr ? "ANY" : "ALL");
9432 get_rule_expr_paren(arg2, context, true, node);
9433
9434 /*
9435 * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
9436 * a bare sub-SELECT. Since we're here, the sub-SELECT must
9437 * be meant as a scalar sub-SELECT yielding an array value to
9438 * be used in ScalarArrayOpExpr; but the grammar will
9439 * preferentially interpret such a construct as an ANY/ALL
9440 * SubLink. To prevent misparsing the output that way, insert
9441 * a dummy coercion (which will be stripped by parse analysis,
9442 * so no inefficiency is added in dump and reload). This is
9443 * indeed most likely what the user wrote to get the construct
9444 * accepted in the first place.
9445 */
9446 if (IsA(arg2, SubLink) &&
9447 ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
9448 appendStringInfo(buf, "::%s",
9450 exprTypmod(arg2)));
9452 if (!PRETTY_PAREN(context))
9454 }
9455 break;
9456
9457 case T_BoolExpr:
9458 {
9459 BoolExpr *expr = (BoolExpr *) node;
9460 Node *first_arg = linitial(expr->args);
9461 ListCell *arg;
9462
9463 switch (expr->boolop)
9464 {
9465 case AND_EXPR:
9466 if (!PRETTY_PAREN(context))
9468 get_rule_expr_paren(first_arg, context,
9469 false, node);
9470 for_each_from(arg, expr->args, 1)
9471 {
9472 appendStringInfoString(buf, " AND ");
9473 get_rule_expr_paren((Node *) lfirst(arg), context,
9474 false, node);
9475 }
9476 if (!PRETTY_PAREN(context))
9478 break;
9479
9480 case OR_EXPR:
9481 if (!PRETTY_PAREN(context))
9483 get_rule_expr_paren(first_arg, context,
9484 false, node);
9485 for_each_from(arg, expr->args, 1)
9486 {
9487 appendStringInfoString(buf, " OR ");
9488 get_rule_expr_paren((Node *) lfirst(arg), context,
9489 false, node);
9490 }
9491 if (!PRETTY_PAREN(context))
9493 break;
9494
9495 case NOT_EXPR:
9496 if (!PRETTY_PAREN(context))
9498 appendStringInfoString(buf, "NOT ");
9499 get_rule_expr_paren(first_arg, context,
9500 false, node);
9501 if (!PRETTY_PAREN(context))
9503 break;
9504
9505 default:
9506 elog(ERROR, "unrecognized boolop: %d",
9507 (int) expr->boolop);
9508 }
9509 }
9510 break;
9511
9512 case T_SubLink:
9513 get_sublink_expr((SubLink *) node, context);
9514 break;
9515
9516 case T_SubPlan:
9517 {
9518 SubPlan *subplan = (SubPlan *) node;
9519
9520 /*
9521 * We cannot see an already-planned subplan in rule deparsing,
9522 * only while EXPLAINing a query plan. We don't try to
9523 * reconstruct the original SQL, just reference the subplan
9524 * that appears elsewhere in EXPLAIN's result. It does seem
9525 * useful to show the subLinkType and testexpr (if any), and
9526 * we also note whether the subplan will be hashed.
9527 */
9528 switch (subplan->subLinkType)
9529 {
9530 case EXISTS_SUBLINK:
9531 appendStringInfoString(buf, "EXISTS(");
9532 Assert(subplan->testexpr == NULL);
9533 break;
9534 case ALL_SUBLINK:
9535 appendStringInfoString(buf, "(ALL ");
9536 Assert(subplan->testexpr != NULL);
9537 break;
9538 case ANY_SUBLINK:
9539 appendStringInfoString(buf, "(ANY ");
9540 Assert(subplan->testexpr != NULL);
9541 break;
9542 case ROWCOMPARE_SUBLINK:
9543 /* Parenthesizing the testexpr seems sufficient */
9545 Assert(subplan->testexpr != NULL);
9546 break;
9547 case EXPR_SUBLINK:
9548 /* No need to decorate these subplan references */
9550 Assert(subplan->testexpr == NULL);
9551 break;
9552 case MULTIEXPR_SUBLINK:
9553 /* MULTIEXPR isn't executed in the normal way */
9554 appendStringInfoString(buf, "(rescan ");
9555 Assert(subplan->testexpr == NULL);
9556 break;
9557 case ARRAY_SUBLINK:
9558 appendStringInfoString(buf, "ARRAY(");
9559 Assert(subplan->testexpr == NULL);
9560 break;
9561 case CTE_SUBLINK:
9562 /* This case is unreachable within expressions */
9563 appendStringInfoString(buf, "CTE(");
9564 Assert(subplan->testexpr == NULL);
9565 break;
9566 }
9567
9568 if (subplan->testexpr != NULL)
9569 {
9570 deparse_namespace *dpns;
9571
9572 /*
9573 * Push SubPlan into ancestors list while deparsing
9574 * testexpr, so that we can handle PARAM_EXEC references
9575 * to the SubPlan's paramIds. (This makes it look like
9576 * the SubPlan is an "ancestor" of the current plan node,
9577 * which is a little weird, but it does no harm.) In this
9578 * path, we don't need to mention the SubPlan explicitly,
9579 * because the referencing Params will show its existence.
9580 */
9581 dpns = (deparse_namespace *) linitial(context->namespaces);
9582 dpns->ancestors = lcons(subplan, dpns->ancestors);
9583
9584 get_rule_expr(subplan->testexpr, context, showimplicit);
9586
9587 dpns->ancestors = list_delete_first(dpns->ancestors);
9588 }
9589 else
9590 {
9591 /* No referencing Params, so show the SubPlan's name */
9592 if (subplan->useHashTable)
9593 appendStringInfo(buf, "hashed %s)", subplan->plan_name);
9594 else
9595 appendStringInfo(buf, "%s)", subplan->plan_name);
9596 }
9597 }
9598 break;
9599
9600 case T_AlternativeSubPlan:
9601 {
9602 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
9603 ListCell *lc;
9604
9605 /*
9606 * This case cannot be reached in normal usage, since no
9607 * AlternativeSubPlan can appear either in parsetrees or
9608 * finished plan trees. We keep it just in case somebody
9609 * wants to use this code to print planner data structures.
9610 */
9611 appendStringInfoString(buf, "(alternatives: ");
9612 foreach(lc, asplan->subplans)
9613 {
9614 SubPlan *splan = lfirst_node(SubPlan, lc);
9615
9616 if (splan->useHashTable)
9617 appendStringInfo(buf, "hashed %s", splan->plan_name);
9618 else
9620 if (lnext(asplan->subplans, lc))
9621 appendStringInfoString(buf, " or ");
9622 }
9624 }
9625 break;
9626
9627 case T_FieldSelect:
9628 {
9629 FieldSelect *fselect = (FieldSelect *) node;
9630 Node *arg = (Node *) fselect->arg;
9631 int fno = fselect->fieldnum;
9632 const char *fieldname;
9633 bool need_parens;
9634
9635 /*
9636 * Parenthesize the argument unless it's an SubscriptingRef or
9637 * another FieldSelect. Note in particular that it would be
9638 * WRONG to not parenthesize a Var argument; simplicity is not
9639 * the issue here, having the right number of names is.
9640 */
9641 need_parens = !IsA(arg, SubscriptingRef) &&
9642 !IsA(arg, FieldSelect);
9643 if (need_parens)
9645 get_rule_expr(arg, context, true);
9646 if (need_parens)
9648
9649 /*
9650 * Get and print the field name.
9651 */
9652 fieldname = get_name_for_var_field((Var *) arg, fno,
9653 0, context);
9654 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
9655 }
9656 break;
9657
9658 case T_FieldStore:
9659 {
9660 FieldStore *fstore = (FieldStore *) node;
9661 bool need_parens;
9662
9663 /*
9664 * There is no good way to represent a FieldStore as real SQL,
9665 * so decompilation of INSERT or UPDATE statements should
9666 * always use processIndirection as part of the
9667 * statement-level syntax. We should only get here when
9668 * EXPLAIN tries to print the targetlist of a plan resulting
9669 * from such a statement. The plan case is even harder than
9670 * ordinary rules would be, because the planner tries to
9671 * collapse multiple assignments to the same field or subfield
9672 * into one FieldStore; so we can see a list of target fields
9673 * not just one, and the arguments could be FieldStores
9674 * themselves. We don't bother to try to print the target
9675 * field names; we just print the source arguments, with a
9676 * ROW() around them if there's more than one. This isn't
9677 * terribly complete, but it's probably good enough for
9678 * EXPLAIN's purposes; especially since anything more would be
9679 * either hopelessly confusing or an even poorer
9680 * representation of what the plan is actually doing.
9681 */
9682 need_parens = (list_length(fstore->newvals) != 1);
9683 if (need_parens)
9684 appendStringInfoString(buf, "ROW(");
9685 get_rule_expr((Node *) fstore->newvals, context, showimplicit);
9686 if (need_parens)
9688 }
9689 break;
9690
9691 case T_RelabelType:
9692 {
9693 RelabelType *relabel = (RelabelType *) node;
9694 Node *arg = (Node *) relabel->arg;
9695
9696 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
9697 !showimplicit)
9698 {
9699 /* don't show the implicit cast */
9700 get_rule_expr_paren(arg, context, false, node);
9701 }
9702 else
9703 {
9704 get_coercion_expr(arg, context,
9705 relabel->resulttype,
9706 relabel->resulttypmod,
9707 node);
9708 }
9709 }
9710 break;
9711
9712 case T_CoerceViaIO:
9713 {
9714 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
9715 Node *arg = (Node *) iocoerce->arg;
9716
9717 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9718 !showimplicit)
9719 {
9720 /* don't show the implicit cast */
9721 get_rule_expr_paren(arg, context, false, node);
9722 }
9723 else
9724 {
9725 get_coercion_expr(arg, context,
9726 iocoerce->resulttype,
9727 -1,
9728 node);
9729 }
9730 }
9731 break;
9732
9733 case T_ArrayCoerceExpr:
9734 {
9735 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
9736 Node *arg = (Node *) acoerce->arg;
9737
9738 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9739 !showimplicit)
9740 {
9741 /* don't show the implicit cast */
9742 get_rule_expr_paren(arg, context, false, node);
9743 }
9744 else
9745 {
9746 get_coercion_expr(arg, context,
9747 acoerce->resulttype,
9748 acoerce->resulttypmod,
9749 node);
9750 }
9751 }
9752 break;
9753
9754 case T_ConvertRowtypeExpr:
9755 {
9757 Node *arg = (Node *) convert->arg;
9758
9759 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
9760 !showimplicit)
9761 {
9762 /* don't show the implicit cast */
9763 get_rule_expr_paren(arg, context, false, node);
9764 }
9765 else
9766 {
9767 get_coercion_expr(arg, context,
9768 convert->resulttype, -1,
9769 node);
9770 }
9771 }
9772 break;
9773
9774 case T_CollateExpr:
9775 {
9776 CollateExpr *collate = (CollateExpr *) node;
9777 Node *arg = (Node *) collate->arg;
9778
9779 if (!PRETTY_PAREN(context))
9781 get_rule_expr_paren(arg, context, showimplicit, node);
9782 appendStringInfo(buf, " COLLATE %s",
9784 if (!PRETTY_PAREN(context))
9786 }
9787 break;
9788
9789 case T_CaseExpr:
9790 {
9791 CaseExpr *caseexpr = (CaseExpr *) node;
9792 ListCell *temp;
9793
9794 appendContextKeyword(context, "CASE",
9795 0, PRETTYINDENT_VAR, 0);
9796 if (caseexpr->arg)
9797 {
9799 get_rule_expr((Node *) caseexpr->arg, context, true);
9800 }
9801 foreach(temp, caseexpr->args)
9802 {
9803 CaseWhen *when = (CaseWhen *) lfirst(temp);
9804 Node *w = (Node *) when->expr;
9805
9806 if (caseexpr->arg)
9807 {
9808 /*
9809 * The parser should have produced WHEN clauses of the
9810 * form "CaseTestExpr = RHS", possibly with an
9811 * implicit coercion inserted above the CaseTestExpr.
9812 * For accurate decompilation of rules it's essential
9813 * that we show just the RHS. However in an
9814 * expression that's been through the optimizer, the
9815 * WHEN clause could be almost anything (since the
9816 * equality operator could have been expanded into an
9817 * inline function). If we don't recognize the form
9818 * of the WHEN clause, just punt and display it as-is.
9819 */
9820 if (IsA(w, OpExpr))
9821 {
9822 List *args = ((OpExpr *) w)->args;
9823
9824 if (list_length(args) == 2 &&
9826 CaseTestExpr))
9827 w = (Node *) lsecond(args);
9828 }
9829 }
9830
9831 if (!PRETTY_INDENT(context))
9833 appendContextKeyword(context, "WHEN ",
9834 0, 0, 0);
9835 get_rule_expr(w, context, false);
9836 appendStringInfoString(buf, " THEN ");
9837 get_rule_expr((Node *) when->result, context, true);
9838 }
9839 if (!PRETTY_INDENT(context))
9841 appendContextKeyword(context, "ELSE ",
9842 0, 0, 0);
9843 get_rule_expr((Node *) caseexpr->defresult, context, true);
9844 if (!PRETTY_INDENT(context))
9846 appendContextKeyword(context, "END",
9847 -PRETTYINDENT_VAR, 0, 0);
9848 }
9849 break;
9850
9851 case T_CaseTestExpr:
9852 {
9853 /*
9854 * Normally we should never get here, since for expressions
9855 * that can contain this node type we attempt to avoid
9856 * recursing to it. But in an optimized expression we might
9857 * be unable to avoid that (see comments for CaseExpr). If we
9858 * do see one, print it as CASE_TEST_EXPR.
9859 */
9860 appendStringInfoString(buf, "CASE_TEST_EXPR");
9861 }
9862 break;
9863
9864 case T_ArrayExpr:
9865 {
9866 ArrayExpr *arrayexpr = (ArrayExpr *) node;
9867
9868 appendStringInfoString(buf, "ARRAY[");
9869 get_rule_expr((Node *) arrayexpr->elements, context, true);
9871
9872 /*
9873 * If the array isn't empty, we assume its elements are
9874 * coerced to the desired type. If it's empty, though, we
9875 * need an explicit coercion to the array type.
9876 */
9877 if (arrayexpr->elements == NIL)
9878 appendStringInfo(buf, "::%s",
9879 format_type_with_typemod(arrayexpr->array_typeid, -1));
9880 }
9881 break;
9882
9883 case T_RowExpr:
9884 {
9885 RowExpr *rowexpr = (RowExpr *) node;
9886 TupleDesc tupdesc = NULL;
9887 ListCell *arg;
9888 int i;
9889 char *sep;
9890
9891 /*
9892 * If it's a named type and not RECORD, we may have to skip
9893 * dropped columns and/or claim there are NULLs for added
9894 * columns.
9895 */
9896 if (rowexpr->row_typeid != RECORDOID)
9897 {
9898 tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
9899 Assert(list_length(rowexpr->args) <= tupdesc->natts);
9900 }
9901
9902 /*
9903 * SQL99 allows "ROW" to be omitted when there is more than
9904 * one column, but for simplicity we always print it.
9905 */
9906 appendStringInfoString(buf, "ROW(");
9907 sep = "";
9908 i = 0;
9909 foreach(arg, rowexpr->args)
9910 {
9911 Node *e = (Node *) lfirst(arg);
9912
9913 if (tupdesc == NULL ||
9914 !TupleDescAttr(tupdesc, i)->attisdropped)
9915 {
9917 /* Whole-row Vars need special treatment here */
9918 get_rule_expr_toplevel(e, context, true);
9919 sep = ", ";
9920 }
9921 i++;
9922 }
9923 if (tupdesc != NULL)
9924 {
9925 while (i < tupdesc->natts)
9926 {
9927 if (!TupleDescAttr(tupdesc, i)->attisdropped)
9928 {
9930 appendStringInfoString(buf, "NULL");
9931 sep = ", ";
9932 }
9933 i++;
9934 }
9935
9936 ReleaseTupleDesc(tupdesc);
9937 }
9939 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
9940 appendStringInfo(buf, "::%s",
9941 format_type_with_typemod(rowexpr->row_typeid, -1));
9942 }
9943 break;
9944
9945 case T_RowCompareExpr:
9946 {
9947 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
9948
9949 /*
9950 * SQL99 allows "ROW" to be omitted when there is more than
9951 * one column, but for simplicity we always print it. Within
9952 * a ROW expression, whole-row Vars need special treatment, so
9953 * use get_rule_list_toplevel.
9954 */
9955 appendStringInfoString(buf, "(ROW(");
9956 get_rule_list_toplevel(rcexpr->largs, context, true);
9957
9958 /*
9959 * We assume that the name of the first-column operator will
9960 * do for all the rest too. This is definitely open to
9961 * failure, eg if some but not all operators were renamed
9962 * since the construct was parsed, but there seems no way to
9963 * be perfect.
9964 */
9965 appendStringInfo(buf, ") %s ROW(",
9966 generate_operator_name(linitial_oid(rcexpr->opnos),
9967 exprType(linitial(rcexpr->largs)),
9968 exprType(linitial(rcexpr->rargs))));
9969 get_rule_list_toplevel(rcexpr->rargs, context, true);
9971 }
9972 break;
9973
9974 case T_CoalesceExpr:
9975 {
9976 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
9977
9978 appendStringInfoString(buf, "COALESCE(");
9979 get_rule_expr((Node *) coalesceexpr->args, context, true);
9981 }
9982 break;
9983
9984 case T_MinMaxExpr:
9985 {
9986 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
9987
9988 switch (minmaxexpr->op)
9989 {
9990 case IS_GREATEST:
9991 appendStringInfoString(buf, "GREATEST(");
9992 break;
9993 case IS_LEAST:
9994 appendStringInfoString(buf, "LEAST(");
9995 break;
9996 }
9997 get_rule_expr((Node *) minmaxexpr->args, context, true);
9999 }
10000 break;
10001
10002 case T_SQLValueFunction:
10003 {
10004 SQLValueFunction *svf = (SQLValueFunction *) node;
10005
10006 /*
10007 * Note: this code knows that typmod for time, timestamp, and
10008 * timestamptz just prints as integer.
10009 */
10010 switch (svf->op)
10011 {
10012 case SVFOP_CURRENT_DATE:
10013 appendStringInfoString(buf, "CURRENT_DATE");
10014 break;
10015 case SVFOP_CURRENT_TIME:
10016 appendStringInfoString(buf, "CURRENT_TIME");
10017 break;
10019 appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
10020 break;
10022 appendStringInfoString(buf, "CURRENT_TIMESTAMP");
10023 break;
10025 appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
10026 svf->typmod);
10027 break;
10028 case SVFOP_LOCALTIME:
10029 appendStringInfoString(buf, "LOCALTIME");
10030 break;
10031 case SVFOP_LOCALTIME_N:
10032 appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
10033 break;
10035 appendStringInfoString(buf, "LOCALTIMESTAMP");
10036 break;
10038 appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
10039 svf->typmod);
10040 break;
10041 case SVFOP_CURRENT_ROLE:
10042 appendStringInfoString(buf, "CURRENT_ROLE");
10043 break;
10044 case SVFOP_CURRENT_USER:
10045 appendStringInfoString(buf, "CURRENT_USER");
10046 break;
10047 case SVFOP_USER:
10048 appendStringInfoString(buf, "USER");
10049 break;
10050 case SVFOP_SESSION_USER:
10051 appendStringInfoString(buf, "SESSION_USER");
10052 break;
10054 appendStringInfoString(buf, "CURRENT_CATALOG");
10055 break;
10057 appendStringInfoString(buf, "CURRENT_SCHEMA");
10058 break;
10059 }
10060 }
10061 break;
10062
10063 case T_XmlExpr:
10064 {
10065 XmlExpr *xexpr = (XmlExpr *) node;
10066 bool needcomma = false;
10067 ListCell *arg;
10068 ListCell *narg;
10069 Const *con;
10070
10071 switch (xexpr->op)
10072 {
10073 case IS_XMLCONCAT:
10074 appendStringInfoString(buf, "XMLCONCAT(");
10075 break;
10076 case IS_XMLELEMENT:
10077 appendStringInfoString(buf, "XMLELEMENT(");
10078 break;
10079 case IS_XMLFOREST:
10080 appendStringInfoString(buf, "XMLFOREST(");
10081 break;
10082 case IS_XMLPARSE:
10083 appendStringInfoString(buf, "XMLPARSE(");
10084 break;
10085 case IS_XMLPI:
10086 appendStringInfoString(buf, "XMLPI(");
10087 break;
10088 case IS_XMLROOT:
10089 appendStringInfoString(buf, "XMLROOT(");
10090 break;
10091 case IS_XMLSERIALIZE:
10092 appendStringInfoString(buf, "XMLSERIALIZE(");
10093 break;
10094 case IS_DOCUMENT:
10095 break;
10096 }
10097 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
10098 {
10099 if (xexpr->xmloption == XMLOPTION_DOCUMENT)
10100 appendStringInfoString(buf, "DOCUMENT ");
10101 else
10102 appendStringInfoString(buf, "CONTENT ");
10103 }
10104 if (xexpr->name)
10105 {
10106 appendStringInfo(buf, "NAME %s",
10108 needcomma = true;
10109 }
10110 if (xexpr->named_args)
10111 {
10112 if (xexpr->op != IS_XMLFOREST)
10113 {
10114 if (needcomma)
10116 appendStringInfoString(buf, "XMLATTRIBUTES(");
10117 needcomma = false;
10118 }
10119 forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
10120 {
10121 Node *e = (Node *) lfirst(arg);
10122 char *argname = strVal(lfirst(narg));
10123
10124 if (needcomma)
10126 get_rule_expr((Node *) e, context, true);
10127 appendStringInfo(buf, " AS %s",
10129 needcomma = true;
10130 }
10131 if (xexpr->op != IS_XMLFOREST)
10133 }
10134 if (xexpr->args)
10135 {
10136 if (needcomma)
10138 switch (xexpr->op)
10139 {
10140 case IS_XMLCONCAT:
10141 case IS_XMLELEMENT:
10142 case IS_XMLFOREST:
10143 case IS_XMLPI:
10144 case IS_XMLSERIALIZE:
10145 /* no extra decoration needed */
10146 get_rule_expr((Node *) xexpr->args, context, true);
10147 break;
10148 case IS_XMLPARSE:
10149 Assert(list_length(xexpr->args) == 2);
10150
10151 get_rule_expr((Node *) linitial(xexpr->args),
10152 context, true);
10153
10154 con = lsecond_node(Const, xexpr->args);
10155 Assert(!con->constisnull);
10156 if (DatumGetBool(con->constvalue))
10158 " PRESERVE WHITESPACE");
10159 else
10161 " STRIP WHITESPACE");
10162 break;
10163 case IS_XMLROOT:
10164 Assert(list_length(xexpr->args) == 3);
10165
10166 get_rule_expr((Node *) linitial(xexpr->args),
10167 context, true);
10168
10169 appendStringInfoString(buf, ", VERSION ");
10170 con = (Const *) lsecond(xexpr->args);
10171 if (IsA(con, Const) &&
10172 con->constisnull)
10173 appendStringInfoString(buf, "NO VALUE");
10174 else
10175 get_rule_expr((Node *) con, context, false);
10176
10177 con = lthird_node(Const, xexpr->args);
10178 if (con->constisnull)
10179 /* suppress STANDALONE NO VALUE */ ;
10180 else
10181 {
10182 switch (DatumGetInt32(con->constvalue))
10183 {
10184 case XML_STANDALONE_YES:
10186 ", STANDALONE YES");
10187 break;
10188 case XML_STANDALONE_NO:
10190 ", STANDALONE NO");
10191 break;
10194 ", STANDALONE NO VALUE");
10195 break;
10196 default:
10197 break;
10198 }
10199 }
10200 break;
10201 case IS_DOCUMENT:
10202 get_rule_expr_paren((Node *) xexpr->args, context, false, node);
10203 break;
10204 }
10205 }
10206 if (xexpr->op == IS_XMLSERIALIZE)
10207 {
10208 appendStringInfo(buf, " AS %s",
10209 format_type_with_typemod(xexpr->type,
10210 xexpr->typmod));
10211 if (xexpr->indent)
10212 appendStringInfoString(buf, " INDENT");
10213 else
10214 appendStringInfoString(buf, " NO INDENT");
10215 }
10216
10217 if (xexpr->op == IS_DOCUMENT)
10218 appendStringInfoString(buf, " IS DOCUMENT");
10219 else
10221 }
10222 break;
10223
10224 case T_NullTest:
10225 {
10226 NullTest *ntest = (NullTest *) node;
10227
10228 if (!PRETTY_PAREN(context))
10230 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
10231
10232 /*
10233 * For scalar inputs, we prefer to print as IS [NOT] NULL,
10234 * which is shorter and traditional. If it's a rowtype input
10235 * but we're applying a scalar test, must print IS [NOT]
10236 * DISTINCT FROM NULL to be semantically correct.
10237 */
10238 if (ntest->argisrow ||
10239 !type_is_rowtype(exprType((Node *) ntest->arg)))
10240 {
10241 switch (ntest->nulltesttype)
10242 {
10243 case IS_NULL:
10244 appendStringInfoString(buf, " IS NULL");
10245 break;
10246 case IS_NOT_NULL:
10247 appendStringInfoString(buf, " IS NOT NULL");
10248 break;
10249 default:
10250 elog(ERROR, "unrecognized nulltesttype: %d",
10251 (int) ntest->nulltesttype);
10252 }
10253 }
10254 else
10255 {
10256 switch (ntest->nulltesttype)
10257 {
10258 case IS_NULL:
10259 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
10260 break;
10261 case IS_NOT_NULL:
10262 appendStringInfoString(buf, " IS DISTINCT FROM NULL");
10263 break;
10264 default:
10265 elog(ERROR, "unrecognized nulltesttype: %d",
10266 (int) ntest->nulltesttype);
10267 }
10268 }
10269 if (!PRETTY_PAREN(context))
10271 }
10272 break;
10273
10274 case T_BooleanTest:
10275 {
10276 BooleanTest *btest = (BooleanTest *) node;
10277
10278 if (!PRETTY_PAREN(context))
10280 get_rule_expr_paren((Node *) btest->arg, context, false, node);
10281 switch (btest->booltesttype)
10282 {
10283 case IS_TRUE:
10284 appendStringInfoString(buf, " IS TRUE");
10285 break;
10286 case IS_NOT_TRUE:
10287 appendStringInfoString(buf, " IS NOT TRUE");
10288 break;
10289 case IS_FALSE:
10290 appendStringInfoString(buf, " IS FALSE");
10291 break;
10292 case IS_NOT_FALSE:
10293 appendStringInfoString(buf, " IS NOT FALSE");
10294 break;
10295 case IS_UNKNOWN:
10296 appendStringInfoString(buf, " IS UNKNOWN");
10297 break;
10298 case IS_NOT_UNKNOWN:
10299 appendStringInfoString(buf, " IS NOT UNKNOWN");
10300 break;
10301 default:
10302 elog(ERROR, "unrecognized booltesttype: %d",
10303 (int) btest->booltesttype);
10304 }
10305 if (!PRETTY_PAREN(context))
10307 }
10308 break;
10309
10310 case T_CoerceToDomain:
10311 {
10312 CoerceToDomain *ctest = (CoerceToDomain *) node;
10313 Node *arg = (Node *) ctest->arg;
10314
10315 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
10316 !showimplicit)
10317 {
10318 /* don't show the implicit cast */
10319 get_rule_expr(arg, context, false);
10320 }
10321 else
10322 {
10323 get_coercion_expr(arg, context,
10324 ctest->resulttype,
10325 ctest->resulttypmod,
10326 node);
10327 }
10328 }
10329 break;
10330
10331 case T_CoerceToDomainValue:
10332 appendStringInfoString(buf, "VALUE");
10333 break;
10334
10335 case T_SetToDefault:
10336 appendStringInfoString(buf, "DEFAULT");
10337 break;
10338
10339 case T_CurrentOfExpr:
10340 {
10341 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
10342
10343 if (cexpr->cursor_name)
10344 appendStringInfo(buf, "CURRENT OF %s",
10346 else
10347 appendStringInfo(buf, "CURRENT OF $%d",
10348 cexpr->cursor_param);
10349 }
10350 break;
10351
10352 case T_NextValueExpr:
10353 {
10354 NextValueExpr *nvexpr = (NextValueExpr *) node;
10355
10356 /*
10357 * This isn't exactly nextval(), but that seems close enough
10358 * for EXPLAIN's purposes.
10359 */
10360 appendStringInfoString(buf, "nextval(");
10363 NIL));
10365 }
10366 break;
10367
10368 case T_InferenceElem:
10369 {
10370 InferenceElem *iexpr = (InferenceElem *) node;
10371 bool save_varprefix;
10372 bool need_parens;
10373
10374 /*
10375 * InferenceElem can only refer to target relation, so a
10376 * prefix is not useful, and indeed would cause parse errors.
10377 */
10378 save_varprefix = context->varprefix;
10379 context->varprefix = false;
10380
10381 /*
10382 * Parenthesize the element unless it's a simple Var or a bare
10383 * function call. Follows pg_get_indexdef_worker().
10384 */
10385 need_parens = !IsA(iexpr->expr, Var);
10386 if (IsA(iexpr->expr, FuncExpr) &&
10387 ((FuncExpr *) iexpr->expr)->funcformat ==
10389 need_parens = false;
10390
10391 if (need_parens)
10393 get_rule_expr((Node *) iexpr->expr,
10394 context, false);
10395 if (need_parens)
10397
10398 context->varprefix = save_varprefix;
10399
10400 if (iexpr->infercollid)
10401 appendStringInfo(buf, " COLLATE %s",
10403
10404 /* Add the operator class name, if not default */
10405 if (iexpr->inferopclass)
10406 {
10407 Oid inferopclass = iexpr->inferopclass;
10408 Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
10409
10410 get_opclass_name(inferopclass, inferopcinputtype, buf);
10411 }
10412 }
10413 break;
10414
10415 case T_ReturningExpr:
10416 {
10417 ReturningExpr *retExpr = (ReturningExpr *) node;
10418
10419 /*
10420 * We cannot see a ReturningExpr in rule deparsing, only while
10421 * EXPLAINing a query plan (ReturningExpr nodes are only ever
10422 * adding during query rewriting). Just display the expression
10423 * returned (an expanded view column).
10424 */
10425 get_rule_expr((Node *) retExpr->retexpr, context, showimplicit);
10426 }
10427 break;
10428
10429 case T_PartitionBoundSpec:
10430 {
10431 PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
10432 ListCell *cell;
10433 char *sep;
10434
10435 if (spec->is_default)
10436 {
10437 appendStringInfoString(buf, "DEFAULT");
10438 break;
10439 }
10440
10441 switch (spec->strategy)
10442 {
10444 Assert(spec->modulus > 0 && spec->remainder >= 0);
10445 Assert(spec->modulus > spec->remainder);
10446
10447 appendStringInfoString(buf, "FOR VALUES");
10448 appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
10449 spec->modulus, spec->remainder);
10450 break;
10451
10453 Assert(spec->listdatums != NIL);
10454
10455 appendStringInfoString(buf, "FOR VALUES IN (");
10456 sep = "";
10457 foreach(cell, spec->listdatums)
10458 {
10459 Const *val = lfirst_node(Const, cell);
10460
10462 get_const_expr(val, context, -1);
10463 sep = ", ";
10464 }
10465
10467 break;
10468
10470 Assert(spec->lowerdatums != NIL &&
10471 spec->upperdatums != NIL &&
10472 list_length(spec->lowerdatums) ==
10473 list_length(spec->upperdatums));
10474
10475 appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
10478 break;
10479
10480 default:
10481 elog(ERROR, "unrecognized partition strategy: %d",
10482 (int) spec->strategy);
10483 break;
10484 }
10485 }
10486 break;
10487
10488 case T_JsonValueExpr:
10489 {
10490 JsonValueExpr *jve = (JsonValueExpr *) node;
10491
10492 get_rule_expr((Node *) jve->raw_expr, context, false);
10493 get_json_format(jve->format, context->buf);
10494 }
10495 break;
10496
10497 case T_JsonConstructorExpr:
10498 get_json_constructor((JsonConstructorExpr *) node, context, false);
10499 break;
10500
10501 case T_JsonIsPredicate:
10502 {
10503 JsonIsPredicate *pred = (JsonIsPredicate *) node;
10504
10505 if (!PRETTY_PAREN(context))
10506 appendStringInfoChar(context->buf, '(');
10507
10508 get_rule_expr_paren(pred->expr, context, true, node);
10509
10510 appendStringInfoString(context->buf, " IS JSON");
10511
10512 /* TODO: handle FORMAT clause */
10513
10514 switch (pred->item_type)
10515 {
10516 case JS_TYPE_SCALAR:
10517 appendStringInfoString(context->buf, " SCALAR");
10518 break;
10519 case JS_TYPE_ARRAY:
10520 appendStringInfoString(context->buf, " ARRAY");
10521 break;
10522 case JS_TYPE_OBJECT:
10523 appendStringInfoString(context->buf, " OBJECT");
10524 break;
10525 default:
10526 break;
10527 }
10528
10529 if (pred->unique_keys)
10530 appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
10531
10532 if (!PRETTY_PAREN(context))
10533 appendStringInfoChar(context->buf, ')');
10534 }
10535 break;
10536
10537 case T_JsonExpr:
10538 {
10539 JsonExpr *jexpr = (JsonExpr *) node;
10540
10541 switch (jexpr->op)
10542 {
10543 case JSON_EXISTS_OP:
10544 appendStringInfoString(buf, "JSON_EXISTS(");
10545 break;
10546 case JSON_QUERY_OP:
10547 appendStringInfoString(buf, "JSON_QUERY(");
10548 break;
10549 case JSON_VALUE_OP:
10550 appendStringInfoString(buf, "JSON_VALUE(");
10551 break;
10552 default:
10553 elog(ERROR, "unrecognized JsonExpr op: %d",
10554 (int) jexpr->op);
10555 }
10556
10557 get_rule_expr(jexpr->formatted_expr, context, showimplicit);
10558
10560
10561 get_json_path_spec(jexpr->path_spec, context, showimplicit);
10562
10563 if (jexpr->passing_values)
10564 {
10565 ListCell *lc1,
10566 *lc2;
10567 bool needcomma = false;
10568
10569 appendStringInfoString(buf, " PASSING ");
10570
10571 forboth(lc1, jexpr->passing_names,
10572 lc2, jexpr->passing_values)
10573 {
10574 if (needcomma)
10576 needcomma = true;
10577
10578 get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
10579 appendStringInfo(buf, " AS %s",
10580 quote_identifier(lfirst_node(String, lc1)->sval));
10581 }
10582 }
10583
10584 if (jexpr->op != JSON_EXISTS_OP ||
10585 jexpr->returning->typid != BOOLOID)
10586 get_json_returning(jexpr->returning, context->buf,
10587 jexpr->op == JSON_QUERY_OP);
10588
10589 get_json_expr_options(jexpr, context,
10590 jexpr->op != JSON_EXISTS_OP ?
10593
10595 }
10596 break;
10597
10598 case T_List:
10599 {
10600 char *sep;
10601 ListCell *l;
10602
10603 sep = "";
10604 foreach(l, (List *) node)
10605 {
10607 get_rule_expr((Node *) lfirst(l), context, showimplicit);
10608 sep = ", ";
10609 }
10610 }
10611 break;
10612
10613 case T_TableFunc:
10614 get_tablefunc((TableFunc *) node, context, showimplicit);
10615 break;
10616
10617 default:
10618 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
10619 break;
10620 }
10621}
List * list_delete_first(List *list)
Definition: list.c:943
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1304
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2795
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2972
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
Node * strip_implicit_coercions(Node *node)
Definition: nodeFuncs.c:705
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:885
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:883
@ PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:884
#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:95
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207
e
Definition: preproc-init.c:82
@ IS_NOT_TRUE
Definition: primnodes.h:1981
@ IS_NOT_FALSE
Definition: primnodes.h:1981
@ IS_NOT_UNKNOWN
Definition: primnodes.h:1981
@ IS_TRUE
Definition: primnodes.h:1981
@ IS_UNKNOWN
Definition: primnodes.h:1981
@ IS_FALSE
Definition: primnodes.h:1981
@ ARRAY_SUBLINK
Definition: primnodes.h:1020
@ ANY_SUBLINK
Definition: primnodes.h:1016
@ CTE_SUBLINK
Definition: primnodes.h:1021
@ EXPR_SUBLINK
Definition: primnodes.h:1018
@ ROWCOMPARE_SUBLINK
Definition: primnodes.h:1017
@ ALL_SUBLINK
Definition: primnodes.h:1015
@ EXISTS_SUBLINK
Definition: primnodes.h:1014
@ IS_LEAST
Definition: primnodes.h:1508
@ IS_GREATEST
Definition: primnodes.h:1507
@ AND_EXPR
Definition: primnodes.h:948
@ OR_EXPR
Definition: primnodes.h:948
@ NOT_EXPR
Definition: primnodes.h:948
@ XMLOPTION_DOCUMENT
Definition: primnodes.h:1597
@ SVFOP_CURRENT_CATALOG
Definition: primnodes.h:1554
@ SVFOP_LOCALTIME_N
Definition: primnodes.h:1547
@ SVFOP_CURRENT_TIMESTAMP
Definition: primnodes.h:1544
@ SVFOP_LOCALTIME
Definition: primnodes.h:1546
@ SVFOP_CURRENT_TIMESTAMP_N
Definition: primnodes.h:1545
@ SVFOP_CURRENT_ROLE
Definition: primnodes.h:1550
@ SVFOP_USER
Definition: primnodes.h:1552
@ SVFOP_CURRENT_SCHEMA
Definition: primnodes.h:1555
@ SVFOP_LOCALTIMESTAMP_N
Definition: primnodes.h:1549
@ SVFOP_CURRENT_DATE
Definition: primnodes.h:1541
@ SVFOP_CURRENT_TIME_N
Definition: primnodes.h:1543
@ SVFOP_CURRENT_TIME
Definition: primnodes.h:1542
@ SVFOP_LOCALTIMESTAMP
Definition: primnodes.h:1548
@ SVFOP_CURRENT_USER
Definition: primnodes.h:1551
@ SVFOP_SESSION_USER
Definition: primnodes.h:1553
@ IS_DOCUMENT
Definition: primnodes.h:1592
@ IS_XMLFOREST
Definition: primnodes.h:1587
@ IS_XMLCONCAT
Definition: primnodes.h:1585
@ IS_XMLPI
Definition: primnodes.h:1589
@ IS_XMLPARSE
Definition: primnodes.h:1588
@ IS_XMLSERIALIZE
Definition: primnodes.h:1591
@ IS_XMLROOT
Definition: primnodes.h:1590
@ IS_XMLELEMENT
Definition: primnodes.h:1586
@ JSON_VALUE_OP
Definition: primnodes.h:1809
@ COERCE_EXPLICIT_CALL
Definition: primnodes.h:751
@ IS_NULL
Definition: primnodes.h:1957
@ IS_NOT_NULL
Definition: primnodes.h:1957
@ JS_TYPE_ARRAY
Definition: primnodes.h:1729
@ JS_TYPE_OBJECT
Definition: primnodes.h:1728
@ JS_TYPE_SCALAR
Definition: primnodes.h:1730
static void get_sublink_expr(SubLink *sublink, deparse_context *context)
Definition: ruleutils.c:11820
static void get_parameter(Param *param, deparse_context *context)
Definition: ruleutils.c:8687
static void get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11672
static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
Definition: ruleutils.c:12999
static void get_oper_expr(OpExpr *expr, deparse_context *context)
Definition: ruleutils.c:10735
static void get_func_expr(FuncExpr *expr, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10775
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:13676
static void get_rule_expr_toplevel(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10635
static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
Definition: ruleutils.c:11025
static char * get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
Definition: ruleutils.c:7606
BoolExprType boolop
Definition: primnodes.h:956
List * args
Definition: primnodes.h:957
BoolTestType booltesttype
Definition: primnodes.h:1988
Expr * arg
Definition: primnodes.h:1987
Expr * arg
Definition: primnodes.h:1330
Expr * defresult
Definition: primnodes.h:1332
List * args
Definition: primnodes.h:1331
List * args
Definition: primnodes.h:1497
Expr * arg
Definition: primnodes.h:1224
Oid resulttype
Definition: primnodes.h:1225
Expr * arg
Definition: primnodes.h:1296
char * cursor_name
Definition: primnodes.h:2103
AttrNumber fieldnum
Definition: primnodes.h:1146
Expr * arg
Definition: primnodes.h:1145
List * newvals
Definition: primnodes.h:1177
JsonReturning * returning
Definition: primnodes.h:1837
JsonValueType item_type
Definition: primnodes.h:1742
JsonFormat * format
Definition: primnodes.h:1690
Expr * raw_expr
Definition: primnodes.h:1688
List * args
Definition: primnodes.h:1523
MinMaxOp op
Definition: primnodes.h:1521
Expr * arg
Definition: primnodes.h:808
NullTestType nulltesttype
Definition: primnodes.h:1964
Expr * arg
Definition: primnodes.h:1963
Oid resulttype
Definition: primnodes.h:1202
Expr * arg
Definition: primnodes.h:1201
Expr * retexpr
Definition: primnodes.h:2157
List * args
Definition: primnodes.h:1428
SQLValueFunctionOp op
Definition: primnodes.h:1561
Node * testexpr
Definition: primnodes.h:1084
Expr * refassgnexpr
Definition: primnodes.h:720
Expr * refexpr
Definition: primnodes.h:718
List * args
Definition: primnodes.h:1613
bool indent
Definition: primnodes.h:1617
List * named_args
Definition: primnodes.h:1609
XmlExprOp op
Definition: primnodes.h:1605
Definition: type.h:89
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:219
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1922
char * map_xml_name_to_sql_identifier(const char *name)
Definition: xml.c:2447
@ 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, deparse_context::buf, buf, CHECK_FOR_INTERRUPTS, check_stack_depth(), COERCE_EXPLICIT_CALL, COERCE_EXPLICIT_CAST, COERCE_IMPLICIT_CAST, CollateExpr::collOid, convert(), CTE_SUBLINK, CurrentOfExpr::cursor_name, CurrentOfExpr::cursor_param, DatumGetBool(), DatumGetInt32(), CaseExpr::defresult, 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(), get_rule_expr_paren(), get_rule_expr_toplevel(), get_rule_list_toplevel(), get_sublink_expr(), get_tablefunc(), get_variable(), get_windowfunc_expr(), i, if(), XmlExpr::indent, 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, deparse_context::namespaces, 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, ReturningExpr::retexpr, JsonExpr::returning, ROWCOMPARE_SUBLINK, NextValueExpr::seqid, simple_quote_literal(), 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, deparse_context::varprefix, 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(), get_rule_expr_funccall(), get_rule_expr_paren(), get_rule_expr_toplevel(), get_rule_sortgroupclause(), 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_window_frame_options(), 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 10683 of file ruleutils.c.

10685{
10686 if (looks_like_function(node))
10687 get_rule_expr(node, context, showimplicit);
10688 else
10689 {
10690 StringInfo buf = context->buf;
10691
10692 appendStringInfoString(buf, "CAST(");
10693 /* no point in showing any top-level implicit cast */
10694 get_rule_expr(node, context, false);
10695 appendStringInfo(buf, " AS %s)",
10697 exprTypmod(node)));
10698 }
10699}
static bool looks_like_function(Node *node)
Definition: ruleutils.c:10706

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

9157{
9158 bool need_paren;
9159
9160 need_paren = PRETTY_PAREN(context) &&
9161 !isSimpleNode(node, parentNode, context->prettyFlags);
9162
9163 if (need_paren)
9164 appendStringInfoChar(context->buf, '(');
9165
9166 get_rule_expr(node, context, showimplicit);
9167
9168 if (need_paren)
9169 appendStringInfoChar(context->buf, ')');
9170}
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
Definition: ruleutils.c:8850

References appendStringInfoChar(), deparse_context::buf, get_rule_expr(), isSimpleNode(), PRETTY_PAREN, and deparse_context::prettyFlags.

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

10637{
10638 if (node && IsA(node, Var))
10639 (void) get_variable((Var *) node, 0, true, context);
10640 else
10641 get_rule_expr(node, context, showimplicit);
10642}

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

6633{
6634 ListCell *l;
6635 StringInfo buf = context->buf;
6636 bool omit_child_parens = true;
6637 char *sep = "";
6638
6639 switch (gset->kind)
6640 {
6641 case GROUPING_SET_EMPTY:
6643 return;
6644
6646 {
6647 if (!omit_parens || list_length(gset->content) != 1)
6649
6650 foreach(l, gset->content)
6651 {
6652 Index ref = lfirst_int(l);
6653
6655 get_rule_sortgroupclause(ref, targetlist,
6656 false, context);
6657 sep = ", ";
6658 }
6659
6660 if (!omit_parens || list_length(gset->content) != 1)
6662 }
6663 return;
6664
6666 appendStringInfoString(buf, "ROLLUP(");
6667 break;
6668 case GROUPING_SET_CUBE:
6669 appendStringInfoString(buf, "CUBE(");
6670 break;
6671 case GROUPING_SET_SETS:
6672 appendStringInfoString(buf, "GROUPING SETS (");
6673 omit_child_parens = false;
6674 break;
6675 }
6676
6677 foreach(l, gset->content)
6678 {
6680 get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6681 sep = ", ";
6682 }
6683
6685}
@ GROUPING_SET_CUBE
Definition: parsenodes.h:1516
@ GROUPING_SET_SIMPLE
Definition: parsenodes.h:1514
@ GROUPING_SET_ROLLUP
Definition: parsenodes.h:1515
@ GROUPING_SET_SETS
Definition: parsenodes.h:1517
@ GROUPING_SET_EMPTY
Definition: parsenodes.h:1513
List * content
Definition: parsenodes.h:1524

References appendStringInfoChar(), appendStringInfoString(), deparse_context::buf, buf, GroupingSet::content, get_rule_groupingset(), 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(), and get_rule_groupingset().

◆ get_rule_list_toplevel()

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

Definition at line 10653 of file ruleutils.c.

10655{
10656 const char *sep;
10657 ListCell *lc;
10658
10659 sep = "";
10660 foreach(lc, lst)
10661 {
10662 Node *e = (Node *) lfirst(lc);
10663
10664 appendStringInfoString(context->buf, sep);
10665 get_rule_expr_toplevel(e, context, showimplicit);
10666 sep = ", ";
10667 }
10668}

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

6693{
6694 StringInfo buf = context->buf;
6695 const char *sep;
6696 ListCell *l;
6697
6698 sep = "";
6699 foreach(l, orderList)
6700 {
6702 Node *sortexpr;
6703 Oid sortcoltype;
6704 TypeCacheEntry *typentry;
6705
6707 sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6708 force_colno, context);
6709 sortcoltype = exprType(sortexpr);
6710 /* See whether operator is default < or > for datatype */
6711 typentry = lookup_type_cache(sortcoltype,
6713 if (srt->sortop == typentry->lt_opr)
6714 {
6715 /* ASC is default, so emit nothing for it */
6716 if (srt->nulls_first)
6717 appendStringInfoString(buf, " NULLS FIRST");
6718 }
6719 else if (srt->sortop == typentry->gt_opr)
6720 {
6721 appendStringInfoString(buf, " DESC");
6722 /* DESC defaults to NULLS FIRST */
6723 if (!srt->nulls_first)
6724 appendStringInfoString(buf, " NULLS LAST");
6725 }
6726 else
6727 {
6728 appendStringInfo(buf, " USING %s",
6730 sortcoltype,
6731 sortcoltype));
6732 /* be specific to eliminate ambiguity */
6733 if (srt->nulls_first)
6734 appendStringInfoString(buf, " NULLS FIRST");
6735 else
6736 appendStringInfoString(buf, " NULLS LAST");
6737 }
6738 sep = ", ";
6739 }
6740}
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_GT_OPR
Definition: typcache.h:140
#define TYPECACHE_LT_OPR
Definition: typcache.h:139

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

6564{
6565 StringInfo buf = context->buf;
6566 TargetEntry *tle;
6567 Node *expr;
6568
6569 tle = get_sortgroupref_tle(ref, tlist);
6570 expr = (Node *) tle->expr;
6571
6572 /*
6573 * Use column-number form if requested by caller. Otherwise, if
6574 * expression is a constant, force it to be dumped with an explicit cast
6575 * as decoration --- this is because a simple integer constant is
6576 * ambiguous (and will be misinterpreted by findTargetlistEntrySQL92()) if
6577 * we dump it without any decoration. Similarly, if it's just a Var,
6578 * there is risk of misinterpretation if the column name is reassigned in
6579 * the SELECT list, so we may need to force table qualification. And, if
6580 * it's anything more complex than a simple Var, then force extra parens
6581 * around it, to ensure it can't be misinterpreted as a cube() or rollup()
6582 * construct.
6583 */
6584 if (force_colno)
6585 {
6586 Assert(!tle->resjunk);
6587 appendStringInfo(buf, "%d", tle->resno);
6588 }
6589 else if (!expr)
6590 /* do nothing, probably can't happen */ ;
6591 else if (IsA(expr, Const))
6592 get_const_expr((Const *) expr, context, 1);
6593 else if (IsA(expr, Var))
6594 {
6595 /* Tell get_variable to check for name conflict */
6596 bool save_varinorderby = context->varInOrderBy;
6597
6598 context->varInOrderBy = true;
6599 (void) get_variable((Var *) expr, 0, false, context);
6600 context->varInOrderBy = save_varinorderby;
6601 }
6602 else
6603 {
6604 /*
6605 * We must force parens for function-like expressions even if
6606 * PRETTY_PAREN is off, since those are the ones in danger of
6607 * misparsing. For other expressions we need to force them only if
6608 * PRETTY_PAREN is on, since otherwise the expression will output them
6609 * itself. (We can't skip the parens.)
6610 */
6611 bool need_paren = (PRETTY_PAREN(context)
6612 || IsA(expr, FuncExpr)
6613 || IsA(expr, Aggref)
6614 || IsA(expr, WindowFunc)
6615 || IsA(expr, JsonConstructorExpr));
6616
6617 if (need_paren)
6618 appendStringInfoChar(context->buf, '(');
6619 get_rule_expr(expr, context, true);
6620 if (need_paren)
6621 appendStringInfoChar(context->buf, ')');
6622 }
6623
6624 return expr;
6625}
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition: tlist.c:345

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

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

6750{
6751 StringInfo buf = context->buf;
6752 const char *sep;
6753 ListCell *l;
6754
6755 sep = NULL;
6756 foreach(l, query->windowClause)
6757 {
6758 WindowClause *wc = (WindowClause *) lfirst(l);
6759
6760 if (wc->name == NULL)
6761 continue; /* ignore anonymous windows */
6762
6763 if (sep == NULL)
6764 appendContextKeyword(context, " WINDOW ",
6766 else
6768
6769 appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6770
6771 get_rule_windowspec(wc, query->targetList, context);
6772
6773 sep = ", ";
6774 }
6775}
static void get_rule_windowspec(WindowClause *wc, List *targetList, deparse_context *context)
Definition: ruleutils.c:6781

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

6783{
6784 StringInfo buf = context->buf;
6785 bool needspace = false;
6786 const char *sep;
6787 ListCell *l;
6788
6790 if (wc->refname)
6791 {
6793 needspace = true;
6794 }
6795 /* partition clauses are always inherited, so only print if no refname */
6796 if (wc->partitionClause && !wc->refname)
6797 {
6798 if (needspace)
6800 appendStringInfoString(buf, "PARTITION BY ");
6801 sep = "";
6802 foreach(l, wc->partitionClause)
6803 {
6805
6808 false, context);
6809 sep = ", ";
6810 }
6811 needspace = true;
6812 }
6813 /* print ordering clause only if not inherited */
6814 if (wc->orderClause && !wc->copiedOrder)
6815 {
6816 if (needspace)
6818 appendStringInfoString(buf, "ORDER BY ");
6819 get_rule_orderby(wc->orderClause, targetList, false, context);
6820 needspace = true;
6821 }
6822 /* framing clause is never inherited, so print unless it's default */
6824 {
6825 if (needspace)
6828 wc->startOffset, wc->endOffset,
6829 context);
6830 }
6832}
#define FRAMEOPTION_NONDEFAULT
Definition: parsenodes.h:592
static void get_window_frame_options(int frameOptions, Node *startOffset, Node *endOffset, deparse_context *context)
Definition: ruleutils.c:6838
Node * startOffset
Definition: parsenodes.h:1561
List * partitionClause
Definition: parsenodes.h:1557
Node * endOffset
Definition: parsenodes.h:1562
List * orderClause
Definition: parsenodes.h:1559

References appendStringInfoChar(), appendStringInfoString(), deparse_context::buf, buf, WindowClause::endOffset, FRAMEOPTION_NONDEFAULT, WindowClause::frameOptions, get_rule_orderby(), get_rule_sortgroupclause(), get_window_frame_options(), 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 
)
static

Definition at line 5906 of file ruleutils.c.

5907{
5908 StringInfo buf = context->buf;
5909 bool force_colno;
5910 ListCell *l;
5911
5912 /* Insert the WITH clause if given */
5913 get_with_clause(query, context);
5914
5915 /* Subroutines may need to consult the SELECT targetlist and windowClause */
5916 context->targetList = query->targetList;
5917 context->windowClause = query->windowClause;
5918
5919 /*
5920 * If the Query node has a setOperations tree, then it's the top level of
5921 * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5922 * fields are interesting in the top query itself.
5923 */
5924 if (query->setOperations)
5925 {
5926 get_setop_query(query->setOperations, query, context);
5927 /* ORDER BY clauses must be simple in this case */
5928 force_colno = true;
5929 }
5930 else
5931 {
5932 get_basic_select_query(query, context);
5933 force_colno = false;
5934 }
5935
5936 /* Add the ORDER BY clause if given */
5937 if (query->sortClause != NIL)
5938 {
5939 appendContextKeyword(context, " ORDER BY ",
5941 get_rule_orderby(query->sortClause, query->targetList,
5942 force_colno, context);
5943 }
5944
5945 /*
5946 * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5947 * standard spelling of LIMIT.
5948 */
5949 if (query->limitOffset != NULL)
5950 {
5951 appendContextKeyword(context, " OFFSET ",
5953 get_rule_expr(query->limitOffset, context, false);
5954 }
5955 if (query->limitCount != NULL)
5956 {
5957 if (query->limitOption == LIMIT_OPTION_WITH_TIES)
5958 {
5959 /*
5960 * The limitCount arg is a c_expr, so it needs parens. Simple
5961 * literals and function expressions would not need parens, but
5962 * unfortunately it's hard to tell if the expression will be
5963 * printed as a simple literal like 123 or as a typecast
5964 * expression, like '-123'::int4. The grammar accepts the former
5965 * without quoting, but not the latter.
5966 */
5967 appendContextKeyword(context, " FETCH FIRST ",
5970 get_rule_expr(query->limitCount, context, false);
5972 appendStringInfoString(buf, " ROWS WITH TIES");
5973 }
5974 else
5975 {
5976 appendContextKeyword(context, " LIMIT ",
5978 if (IsA(query->limitCount, Const) &&
5979 ((Const *) query->limitCount)->constisnull)
5981 else
5982 get_rule_expr(query->limitCount, context, false);
5983 }
5984 }
5985
5986 /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5987 if (query->hasForUpdate)
5988 {
5989 foreach(l, query->rowMarks)
5990 {
5991 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5992
5993 /* don't print implicit clauses */
5994 if (rc->pushedDown)
5995 continue;
5996
5997 switch (rc->strength)
5998 {
5999 case LCS_NONE:
6000 /* we intentionally throw an error for LCS_NONE */
6001 elog(ERROR, "unrecognized LockClauseStrength %d",
6002 (int) rc->strength);
6003 break;
6004 case LCS_FORKEYSHARE:
6005 appendContextKeyword(context, " FOR KEY SHARE",
6007 break;
6008 case LCS_FORSHARE:
6009 appendContextKeyword(context, " FOR SHARE",
6011 break;
6012 case LCS_FORNOKEYUPDATE:
6013 appendContextKeyword(context, " FOR NO KEY UPDATE",
6015 break;
6016 case LCS_FORUPDATE:
6017 appendContextKeyword(context, " FOR UPDATE",
6019 break;
6020 }
6021
6022 appendStringInfo(buf, " OF %s",
6024 context)));
6025 if (rc->waitPolicy == LockWaitError)
6026 appendStringInfoString(buf, " NOWAIT");
6027 else if (rc->waitPolicy == LockWaitSkip)
6028 appendStringInfoString(buf, " SKIP LOCKED");
6029 }
6030 }
6031}
@ 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:438
static void get_setop_query(Node *setOp, Query *query, deparse_context *context)
Definition: ruleutils.c:6414
static void get_basic_select_query(Query *query, deparse_context *context)
Definition: ruleutils.c:6108
List * rowMarks
Definition: parsenodes.h:228
Node * limitCount
Definition: parsenodes.h:225
Node * setOperations
Definition: parsenodes.h:230
Node * limitOffset
Definition: parsenodes.h:224
LimitOption limitOption
Definition: parsenodes.h:226
List * sortClause
Definition: parsenodes.h:222
LockClauseStrength strength
Definition: parsenodes.h:1594
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1595

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), deparse_context::buf, buf, 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, deparse_context::targetList, Query::targetList, RowMarkClause::waitPolicy, deparse_context::windowClause, and Query::windowClause.

Referenced by get_query_def().

◆ get_setop_query()

static void get_setop_query ( Node setOp,
Query query,
deparse_context context 
)
static

Definition at line 6414 of file ruleutils.c.

6415{
6416 StringInfo buf = context->buf;
6417 bool need_paren;
6418
6419 /* Guard against excessively long or deeply-nested queries */
6422
6423 if (IsA(setOp, RangeTblRef))
6424 {
6425 RangeTblRef *rtr = (RangeTblRef *) setOp;
6426 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6427 Query *subquery = rte->subquery;
6428
6429 Assert(subquery != NULL);
6430
6431 /*
6432 * We need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y.
6433 * Also add parens if the leaf query contains its own set operations.
6434 * (That shouldn't happen unless one of the other clauses is also
6435 * present, see transformSetOperationTree; but let's be safe.)
6436 */
6437 need_paren = (subquery->cteList ||
6438 subquery->sortClause ||
6439 subquery->rowMarks ||
6440 subquery->limitOffset ||
6441 subquery->limitCount ||
6442 subquery->setOperations);
6443 if (need_paren)
6445 get_query_def(subquery, buf, context->namespaces,
6446 context->resultDesc, context->colNamesVisible,
6447 context->prettyFlags, context->wrapColumn,
6448 context->indentLevel);
6449 if (need_paren)
6451 }
6452 else if (IsA(setOp, SetOperationStmt))
6453 {
6454 SetOperationStmt *op = (SetOperationStmt *) setOp;
6455 int subindent;
6456 bool save_colnamesvisible;
6457
6458 /*
6459 * We force parens when nesting two SetOperationStmts, except when the
6460 * lefthand input is another setop of the same kind. Syntactically,
6461 * we could omit parens in rather more cases, but it seems best to use
6462 * parens to flag cases where the setop operator changes. If we use
6463 * parens, we also increase the indentation level for the child query.
6464 *
6465 * There are some cases in which parens are needed around a leaf query
6466 * too, but those are more easily handled at the next level down (see
6467 * code above).
6468 */
6469 if (IsA(op->larg, SetOperationStmt))
6470 {
6471 SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6472
6473 if (op->op == lop->op && op->all == lop->all)
6474 need_paren = false;
6475 else
6476 need_paren = true;
6477 }
6478 else
6479 need_paren = false;
6480
6481 if (need_paren)
6482 {
6484 subindent = PRETTYINDENT_STD;
6485 appendContextKeyword(context, "", subindent, 0, 0);
6486 }
6487 else
6488 subindent = 0;
6489
6490 get_setop_query(op->larg, query, context);
6491
6492 if (need_paren)
6493 appendContextKeyword(context, ") ", -subindent, 0, 0);
6494 else if (PRETTY_INDENT(context))
6495 appendContextKeyword(context, "", -subindent, 0, 0);
6496 else
6498
6499 switch (op->op)
6500 {
6501 case SETOP_UNION:
6502 appendStringInfoString(buf, "UNION ");
6503 break;
6504 case SETOP_INTERSECT:
6505 appendStringInfoString(buf, "INTERSECT ");
6506 break;
6507 case SETOP_EXCEPT:
6508 appendStringInfoString(buf, "EXCEPT ");
6509 break;
6510 default:
6511 elog(ERROR, "unrecognized set op: %d",
6512 (int) op->op);
6513 }
6514 if (op->all)
6515 appendStringInfoString(buf, "ALL ");
6516
6517 /* Always parenthesize if RHS is another setop */
6518 need_paren = IsA(op->rarg, SetOperationStmt);
6519
6520 /*
6521 * The indentation code here is deliberately a bit different from that
6522 * for the lefthand input, because we want the line breaks in
6523 * different places.
6524 */
6525 if (need_paren)
6526 {
6528 subindent = PRETTYINDENT_STD;
6529 }
6530 else
6531 subindent = 0;
6532 appendContextKeyword(context, "", subindent, 0, 0);
6533
6534 /*
6535 * The output column names of the RHS sub-select don't matter.
6536 */
6537 save_colnamesvisible = context->colNamesVisible;
6538 context->colNamesVisible = false;
6539
6540 get_setop_query(op->rarg, query, context);
6541
6542 context->colNamesVisible = save_colnamesvisible;
6543
6544 if (PRETTY_INDENT(context))
6545 context->indentLevel -= subindent;
6546 if (need_paren)
6547 appendContextKeyword(context, ")", 0, 0, 0);
6548 }
6549 else
6550 {
6551 elog(ERROR, "unrecognized node type: %d",
6552 (int) nodeTag(setOp));
6553 }
6554}
@ SETOP_INTERSECT
Definition: parsenodes.h:2169
@ SETOP_UNION
Definition: parsenodes.h:2168
@ SETOP_EXCEPT
Definition: parsenodes.h:2170
List * cteList
Definition: parsenodes.h:168
SetOperation op
Definition: parsenodes.h:2247

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

Referenced by get_select_query_def(), and get_setop_query().

◆ get_simple_binary_op_name()

static const char * get_simple_binary_op_name ( OpExpr expr)
static

Definition at line 8824 of file ruleutils.c.

8825{
8826 List *args = expr->args;
8827
8828 if (list_length(args) == 2)
8829 {
8830 /* binary operator */
8831 Node *arg1 = (Node *) linitial(args);
8832 Node *arg2 = (Node *) lsecond(args);
8833 const char *op;
8834
8835 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
8836 if (strlen(op) == 1)
8837 return op;
8838 }
8839 return NULL;
8840}

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

6040{
6041 RangeTblEntry *result = NULL;
6042 ListCell *lc;
6043
6044 /*
6045 * We want to detect a match even if the Query also contains OLD or NEW
6046 * rule RTEs. So the idea is to scan the rtable and see if there is only
6047 * one inFromCl RTE that is a VALUES RTE.
6048 */
6049 foreach(lc, query->rtable)
6050 {
6051 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
6052
6053 if (rte->rtekind == RTE_VALUES && rte->inFromCl)
6054 {
6055 if (result)
6056 return NULL; /* multiple VALUES (probably not possible) */
6057 result = rte;
6058 }
6059 else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
6060 continue; /* ignore rule entries */
6061 else
6062 return NULL; /* something else -> not simple VALUES */
6063 }
6064
6065 /*
6066 * We don't need to check the targetlist in any great detail, because
6067 * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
6068 * appear inside auto-generated sub-queries with very restricted
6069 * structure. However, DefineView might have modified the tlist by
6070 * injecting new column aliases, or we might have some other column
6071 * aliases forced by a resultDesc. We can only simplify if the RTE's
6072 * column names match the names that get_target_list() would select.
6073 */
6074 if (result)
6075 {
6076 ListCell *lcn;
6077 int colno;
6078
6079 if (list_length(query->targetList) != list_length(result->eref->colnames))
6080 return NULL; /* this probably cannot happen */
6081 colno = 0;
6082 forboth(lc, query->targetList, lcn, result->eref->colnames)
6083 {
6084 TargetEntry *tle = (TargetEntry *) lfirst(lc);
6085 char *cname = strVal(lfirst(lcn));
6086 char *colname;
6087
6088 if (tle->resjunk)
6089 return NULL; /* this probably cannot happen */
6090
6091 /* compute name that get_target_list would use for column */
6092 colno++;
6093 if (resultDesc && colno <= resultDesc->natts)
6094 colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6095 else
6096 colname = tle->resname;
6097
6098 /* does it match the VALUES RTE? */
6099 if (colname == NULL || strcmp(colname, cname) != 0)
6100 return NULL; /* column name has been changed */
6101 }
6102 }
6103
6104 return result;
6105}

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

7889{
7890 StringInfo buf = context->buf;
7891
7892 /*
7893 * For a non-Var referent, force parentheses because our caller probably
7894 * assumed a Var is a simple expression.
7895 */
7896 if (!IsA(node, Var))
7898 get_rule_expr(node, context, true);
7899 if (!IsA(node, Var))
7901}

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

11821{
11822 StringInfo buf = context->buf;
11823 Query *query = (Query *) (sublink->subselect);
11824 char *opname = NULL;
11825 bool need_paren;
11826
11827 if (sublink->subLinkType == ARRAY_SUBLINK)
11828 appendStringInfoString(buf, "ARRAY(");
11829 else
11831
11832 /*
11833 * Note that we print the name of only the first operator, when there are
11834 * multiple combining operators. This is an approximation that could go
11835 * wrong in various scenarios (operators in different schemas, renamed
11836 * operators, etc) but there is not a whole lot we can do about it, since
11837 * the syntax allows only one operator to be shown.
11838 */
11839 if (sublink->testexpr)
11840 {
11841 if (IsA(sublink->testexpr, OpExpr))
11842 {
11843 /* single combining operator */
11844 OpExpr *opexpr = (OpExpr *) sublink->testexpr;
11845
11846 get_rule_expr(linitial(opexpr->args), context, true);
11847 opname = generate_operator_name(opexpr->opno,
11848 exprType(linitial(opexpr->args)),
11849 exprType(lsecond(opexpr->args)));
11850 }
11851 else if (IsA(sublink->testexpr, BoolExpr))
11852 {
11853 /* multiple combining operators, = or <> cases */
11854 char *sep;
11855 ListCell *l;
11856
11858 sep = "";
11859 foreach(l, ((BoolExpr *) sublink->testexpr)->args)
11860 {
11861 OpExpr *opexpr = lfirst_node(OpExpr, l);
11862
11864 get_rule_expr(linitial(opexpr->args), context, true);
11865 if (!opname)
11866 opname = generate_operator_name(opexpr->opno,
11867 exprType(linitial(opexpr->args)),
11868 exprType(lsecond(opexpr->args)));
11869 sep = ", ";
11870 }
11872 }
11873 else if (IsA(sublink->testexpr, RowCompareExpr))
11874 {
11875 /* multiple combining operators, < <= > >= cases */
11876 RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
11877
11879 get_rule_expr((Node *) rcexpr->largs, context, true);
11880 opname = generate_operator_name(linitial_oid(rcexpr->opnos),
11881 exprType(linitial(rcexpr->largs)),
11882 exprType(linitial(rcexpr->rargs)));
11884 }
11885 else
11886 elog(ERROR, "unrecognized testexpr type: %d",
11887 (int) nodeTag(sublink->testexpr));
11888 }
11889
11890 need_paren = true;
11891
11892 switch (sublink->subLinkType)
11893 {
11894 case EXISTS_SUBLINK:
11895 appendStringInfoString(buf, "EXISTS ");
11896 break;
11897
11898 case ANY_SUBLINK:
11899 if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
11900 appendStringInfoString(buf, " IN ");
11901 else
11902 appendStringInfo(buf, " %s ANY ", opname);
11903 break;
11904
11905 case ALL_SUBLINK:
11906 appendStringInfo(buf, " %s ALL ", opname);
11907 break;
11908
11909 case ROWCOMPARE_SUBLINK:
11910 appendStringInfo(buf, " %s ", opname);
11911 break;
11912
11913 case EXPR_SUBLINK:
11914 case MULTIEXPR_SUBLINK:
11915 case ARRAY_SUBLINK:
11916 need_paren = false;
11917 break;
11918
11919 case CTE_SUBLINK: /* shouldn't occur in a SubLink */
11920 default:
11921 elog(ERROR, "unrecognized sublink type: %d",
11922 (int) sublink->subLinkType);
11923 break;
11924 }
11925
11926 if (need_paren)
11928
11929 get_query_def(query, buf, context->namespaces, NULL, false,
11930 context->prettyFlags, context->wrapColumn,
11931 context->indentLevel);
11932
11933 if (need_paren)
11935 else
11937}

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

Referenced by get_rule_expr().

◆ get_tablefunc()

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

Definition at line 12251 of file ruleutils.c.

12252{
12253 /* XMLTABLE and JSON_TABLE are the only existing implementations. */
12254
12255 if (tf->functype == TFT_XMLTABLE)
12256 get_xmltable(tf, context, showimplicit);
12257 else if (tf->functype == TFT_JSON_TABLE)
12258 get_json_table(tf, context, showimplicit);
12259}
@ TFT_XMLTABLE
Definition: primnodes.h:100
@ TFT_JSON_TABLE
Definition: primnodes.h:101
static void get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11945
static void get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:12182
TableFuncType functype
Definition: primnodes.h:114

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

12818{
12819 StringInfo buf = context->buf;
12820 Oid argtypes[1];
12821 int nargs;
12822 ListCell *l;
12823
12824 /*
12825 * We should qualify the handler's function name if it wouldn't be
12826 * resolved by lookup in the current search path.
12827 */
12828 argtypes[0] = INTERNALOID;
12829 appendStringInfo(buf, " TABLESAMPLE %s (",
12830 generate_function_name(tablesample->tsmhandler, 1,
12831 NIL, argtypes,
12832 false, NULL, false));
12833
12834 nargs = 0;
12835 foreach(l, tablesample->args)
12836 {
12837 if (nargs++ > 0)
12839 get_rule_expr((Node *) lfirst(l), context, false);
12840 }
12842
12843 if (tablesample->repeatable != NULL)
12844 {
12845 appendStringInfoString(buf, " REPEATABLE (");
12846 get_rule_expr((Node *) tablesample->repeatable, context, false);
12848 }
12849}

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), TableSampleClause::args, deparse_context::buf, buf, 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 
)
static

Definition at line 6239 of file ruleutils.c.

6240{
6241 StringInfo buf = context->buf;
6242 StringInfoData targetbuf;
6243 bool last_was_multiline = false;
6244 char *sep;
6245 int colno;
6246 ListCell *l;
6247
6248 /* we use targetbuf to hold each TLE's text temporarily */
6249 initStringInfo(&targetbuf);
6250
6251 sep = " ";
6252 colno = 0;
6253 foreach(l, targetList)
6254 {
6255 TargetEntry *tle = (TargetEntry *) lfirst(l);
6256 char *colname;
6257 char *attname;
6258
6259 if (tle->resjunk)
6260 continue; /* ignore junk entries */
6261
6263 sep = ", ";
6264 colno++;
6265
6266 /*
6267 * Put the new field text into targetbuf so we can decide after we've
6268 * got it whether or not it needs to go on a new line.
6269 */
6270 resetStringInfo(&targetbuf);
6271 context->buf = &targetbuf;
6272
6273 /*
6274 * We special-case Var nodes rather than using get_rule_expr. This is
6275 * needed because get_rule_expr will display a whole-row Var as
6276 * "foo.*", which is the preferred notation in most contexts, but at
6277 * the top level of a SELECT list it's not right (the parser will
6278 * expand that notation into multiple columns, yielding behavior
6279 * different from a whole-row Var). We need to call get_variable
6280 * directly so that we can tell it to do the right thing, and so that
6281 * we can get the attribute name which is the default AS label.
6282 */
6283 if (tle->expr && (IsA(tle->expr, Var)))
6284 {
6285 attname = get_variable((Var *) tle->expr, 0, true, context);
6286 }
6287 else
6288 {
6289 get_rule_expr((Node *) tle->expr, context, true);
6290
6291 /*
6292 * When colNamesVisible is true, we should always show the
6293 * assigned column name explicitly. Otherwise, show it only if
6294 * it's not FigureColname's fallback.
6295 */
6296 attname = context->colNamesVisible ? NULL : "?column?";
6297 }
6298
6299 /*
6300 * Figure out what the result column should be called. In the context
6301 * of a view, use the view's tuple descriptor (so as to pick up the
6302 * effects of any column RENAME that's been done on the view).
6303 * Otherwise, just use what we can find in the TLE.
6304 */
6305 if (context->resultDesc && colno <= context->resultDesc->natts)
6306 colname = NameStr(TupleDescAttr(context->resultDesc,
6307 colno - 1)->attname);
6308 else
6309 colname = tle->resname;
6310
6311 /* Show AS unless the column's name is correct as-is */
6312 if (colname) /* resname could be NULL */
6313 {
6314 if (attname == NULL || strcmp(attname, colname) != 0)
6315 appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6316 }
6317
6318 /* Restore context's output buffer */
6319 context->buf = buf;
6320
6321 /* Consider line-wrapping if enabled */
6322 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6323 {
6324 int leading_nl_pos;
6325
6326 /* Does the new field start with a new line? */
6327 if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
6328 leading_nl_pos = 0;
6329 else
6330 leading_nl_pos = -1;
6331
6332 /* If so, we shouldn't add anything */
6333 if (leading_nl_pos >= 0)
6334 {
6335 /* instead, remove any trailing spaces currently in buf */
6337 }
6338 else
6339 {
6340 char *trailing_nl;
6341
6342 /* Locate the start of the current line in the output buffer */
6343 trailing_nl = strrchr(buf->data, '\n');
6344 if (trailing_nl == NULL)
6345 trailing_nl = buf->data;
6346 else
6347 trailing_nl++;
6348
6349 /*
6350 * Add a newline, plus some indentation, if the new field is
6351 * not the first and either the new field would cause an
6352 * overflow or the last field used more than one line.
6353 */
6354 if (colno > 1 &&
6355 ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
6356 last_was_multiline))
6359 }
6360
6361 /* Remember this field's multiline status for next iteration */
6362 last_was_multiline =
6363 (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6364 }
6365
6366 /* Add the new field */
6367 appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
6368 }
6369
6370 /* clean up */
6371 pfree(targetbuf.data);
6372}
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:126

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

Referenced by get_basic_select_query(), and get_returning_clause().

◆ get_update_query_def()

static void get_update_query_def ( Query query,
deparse_context context 
)
static

Definition at line 7151 of file ruleutils.c.

7152{
7153 StringInfo buf = context->buf;
7154 RangeTblEntry *rte;
7155
7156 /* Insert the WITH clause if given */
7157 get_with_clause(query, context);
7158
7159 /*
7160 * Start the query with UPDATE relname SET
7161 */
7162 rte = rt_fetch(query->resultRelation, query->rtable);
7163 Assert(rte->rtekind == RTE_RELATION);
7164 if (PRETTY_INDENT(context))
7165 {
7167 context->indentLevel += PRETTYINDENT_STD;
7168 }
7169 appendStringInfo(buf, "UPDATE %s%s",
7170 only_marker(rte),
7171 generate_relation_name(rte->relid, NIL));
7172
7173 /* Print the relation alias, if needed */
7174 get_rte_alias(rte, query->resultRelation, false, context);
7175
7176 appendStringInfoString(buf, " SET ");
7177
7178 /* Deparse targetlist */
7179 get_update_query_targetlist_def(query, query->targetList, context, rte);
7180
7181 /* Add the FROM clause if needed */
7182 get_from_clause(query, " FROM ", context);
7183
7184 /* Add a WHERE clause if given */
7185 if (query->jointree->quals != NULL)
7186 {
7187 appendContextKeyword(context, " WHERE ",
7189 get_rule_expr(query->jointree->quals, context, false);
7190 }
7191
7192 /* Add RETURNING if present */
7193 if (query->returningList)
7194 get_returning_clause(query, context);
7195}

References appendContextKeyword(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), deparse_context::buf, buf, generate_relation_name(), get_from_clause(), get_returning_clause(), get_rte_alias(), get_rule_expr(), get_update_query_targetlist_def(), get_with_clause(), deparse_context::indentLevel, Query::jointree, NIL, only_marker, PRETTY_INDENT, PRETTYINDENT_STD, FromExpr::quals, 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 7203 of file ruleutils.c.

7205{
7206 StringInfo buf = context->buf;
7207 ListCell *l;
7208 ListCell *next_ma_cell;
7209 int remaining_ma_columns;
7210 const char *sep;
7211 SubLink *cur_ma_sublink;
7212 List *ma_sublinks;
7213
7214 /*
7215 * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
7216 * into a list. We expect them to appear, in ID order, in resjunk tlist
7217 * entries.
7218 */
7219 ma_sublinks = NIL;
7220 if (query->hasSubLinks) /* else there can't be any */
7221 {
7222 foreach(l, targetList)
7223 {
7224 TargetEntry *tle = (TargetEntry *) lfirst(l);
7225
7226 if (tle->resjunk && IsA(tle->expr, SubLink))
7227 {
7228 SubLink *sl = (SubLink *) tle->expr;
7229
7231 {
7232 ma_sublinks = lappend(ma_sublinks, sl);
7233 Assert(sl->subLinkId == list_length(ma_sublinks));
7234 }
7235 }
7236 }
7237 }
7238 next_ma_cell = list_head(ma_sublinks);
7239 cur_ma_sublink = NULL;
7240 remaining_ma_columns = 0;
7241
7242 /* Add the comma separated list of 'attname = value' */
7243 sep = "";
7244 foreach(l, targetList)
7245 {
7246 TargetEntry *tle = (TargetEntry *) lfirst(l);
7247 Node *expr;
7248
7249 if (tle->resjunk)
7250 continue; /* ignore junk entries */
7251
7252 /* Emit separator (OK whether we're in multiassignment or not) */
7254 sep = ", ";
7255
7256 /*
7257 * Check to see if we're starting a multiassignment group: if so,
7258 * output a left paren.
7259 */
7260 if (next_ma_cell != NULL && cur_ma_sublink == NULL)
7261 {
7262 /*
7263 * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
7264 * Param. That could be buried under FieldStores and
7265 * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
7266 * and underneath those there could be an implicit type coercion.
7267 * Because we would ignore implicit type coercions anyway, we
7268 * don't need to be as careful as processIndirection() is about
7269 * descending past implicit CoerceToDomains.
7270 */
7271 expr = (Node *) tle->expr;
7272 while (expr)
7273 {
7274 if (IsA(expr, FieldStore))
7275 {
7276 FieldStore *fstore = (FieldStore *) expr;
7277
7278 expr = (Node *) linitial(fstore->newvals);
7279 }
7280 else if (IsA(expr, SubscriptingRef))
7281 {
7282 SubscriptingRef *sbsref = (SubscriptingRef *) expr;
7283
7284 if (sbsref->refassgnexpr == NULL)
7285 break;
7286
7287 expr = (Node *) sbsref->refassgnexpr;
7288 }
7289 else if (IsA(expr, CoerceToDomain))
7290 {
7291 CoerceToDomain *cdomain = (CoerceToDomain *) expr;
7292
7293 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
7294 break;
7295 expr = (Node *) cdomain->arg;
7296 }
7297 else
7298 break;
7299 }
7300 expr = strip_implicit_coercions(expr);
7301
7302 if (expr && IsA(expr, Param) &&
7303 ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
7304 {
7305 cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
7306 next_ma_cell = lnext(ma_sublinks, next_ma_cell);
7307 remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
7308 Assert(((Param *) expr)->paramid ==
7309 ((cur_ma_sublink->subLinkId << 16) | 1));
7311 }
7312 }
7313
7314 /*
7315 * Put out name of target column; look in the catalogs, not at
7316 * tle->resname, since resname will fail to track RENAME.
7317 */
7319 quote_identifier(get_attname(rte->relid,
7320 tle->resno,
7321 false)));
7322
7323 /*
7324 * Print any indirection needed (subfields or subscripts), and strip
7325 * off the top-level nodes representing the indirection assignments.
7326 */
7327 expr = processIndirection((Node *) tle->expr, context);
7328
7329 /*
7330 * If we're in a multiassignment, skip printing anything more, unless
7331 * this is the last column; in which case, what we print should be the
7332 * sublink, not the Param.
7333 */
7334 if (cur_ma_sublink != NULL)
7335 {
7336 if (--remaining_ma_columns > 0)
7337 continue; /* not the last column of multiassignment */
7339 expr = (Node *) cur_ma_sublink;
7340 cur_ma_sublink = NULL;
7341 }
7342
7344
7345 get_rule_expr(expr, context, false);
7346 }
7347}
while(p+4<=pend)
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
@ PARAM_MULTIEXPR
Definition: primnodes.h:387
int count_nonjunk_tlist_entries(List *tlist)
Definition: tlist.c:186

References appendStringInfoChar(), appendStringInfoString(), CoerceToDomain::arg, Assert(), deparse_context::buf, buf, COERCE_IMPLICIT_CAST, 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, 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 7561 of file ruleutils.c.

7562{
7563 StringInfo buf = context->buf;
7564
7565 if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7566 {
7567 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7568
7569 appendContextKeyword(context, "",
7570 0, PRETTYINDENT_STD, 1);
7571 appendStringInfo(buf, "NOTIFY %s",
7572 quote_identifier(stmt->conditionname));
7573 if (stmt->payload)
7574 {
7576 simple_quote_literal(buf, stmt->payload);
7577 }
7578 }
7579 else
7580 {
7581 /* Currently only NOTIFY utility commands can appear in rules */
7582 elog(ERROR, "unexpected utility statement type");
7583 }
7584}
#define stmt
Definition: indent_codes.h:59
Node * utilityStmt
Definition: parsenodes.h:136

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

5725{
5726 StringInfo buf = context->buf;
5727 bool first_list = true;
5728 ListCell *vtl;
5729
5730 appendStringInfoString(buf, "VALUES ");
5731
5732 foreach(vtl, values_lists)
5733 {
5734 List *sublist = (List *) lfirst(vtl);
5735 bool first_col = true;
5736 ListCell *lc;
5737
5738 if (first_list)
5739 first_list = false;
5740 else
5742
5744 foreach(lc, sublist)
5745 {
5746 Node *col = (Node *) lfirst(lc);
5747
5748 if (first_col)
5749 first_col = false;
5750 else
5752
5753 /*
5754 * Print the value. Whole-row Vars need special treatment.
5755 */
5756 get_rule_expr_toplevel(col, context, false);
5757 }
5759 }
5760}

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

7607{
7608 StringInfo buf = context->buf;
7609 RangeTblEntry *rte;
7611 int netlevelsup;
7612 deparse_namespace *dpns;
7613 int varno;
7614 AttrNumber varattno;
7615 deparse_columns *colinfo;
7616 char *refname;
7617 char *attname;
7618 bool need_prefix;
7619
7620 /* Find appropriate nesting depth */
7621 netlevelsup = var->varlevelsup + levelsup;
7622 if (netlevelsup >= list_length(context->namespaces))
7623 elog(ERROR, "bogus varlevelsup: %d offset %d",
7624 var->varlevelsup, levelsup);
7625 dpns = (deparse_namespace *) list_nth(context->namespaces,
7626 netlevelsup);
7627
7628 /*
7629 * If we have a syntactic referent for the Var, and we're working from a
7630 * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7631 * on the semantic referent. (Forcing use of the semantic referent when
7632 * printing plan trees is a design choice that's perhaps more motivated by
7633 * backwards compatibility than anything else. But it does have the
7634 * advantage of making plans more explicit.)
7635 */
7636 if (var->varnosyn > 0 && dpns->plan == NULL)
7637 {
7638 varno = var->varnosyn;
7639 varattno = var->varattnosyn;
7640 }
7641 else
7642 {
7643 varno = var->varno;
7644 varattno = var->varattno;
7645 }
7646
7647 /*
7648 * Try to find the relevant RTE in this rtable. In a plan tree, it's
7649 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7650 * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7651 * find the aliases previously assigned for this RTE.
7652 */
7653 if (varno >= 1 && varno <= list_length(dpns->rtable))
7654 {
7655 /*
7656 * We might have been asked to map child Vars to some parent relation.
7657 */
7658 if (context->appendparents && dpns->appendrels)
7659 {
7660 int pvarno = varno;
7661 AttrNumber pvarattno = varattno;
7662 AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7663 bool found = false;
7664
7665 /* Only map up to inheritance parents, not UNION ALL appendrels */
7666 while (appinfo &&
7667 rt_fetch(appinfo->parent_relid,
7668 dpns->rtable)->rtekind == RTE_RELATION)
7669 {
7670 found = false;
7671 if (pvarattno > 0) /* system columns stay as-is */
7672 {
7673 if (pvarattno > appinfo->num_child_cols)
7674 break; /* safety check */
7675 pvarattno = appinfo->parent_colnos[pvarattno - 1];
7676 if (pvarattno == 0)
7677 break; /* Var is local to child */
7678 }
7679
7680 pvarno = appinfo->parent_relid;
7681 found = true;
7682
7683 /* If the parent is itself a child, continue up. */
7684 Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7685 appinfo = dpns->appendrels[pvarno];
7686 }
7687
7688 /*
7689 * If we found an ancestral rel, and that rel is included in
7690 * appendparents, print that column not the original one.
7691 */
7692 if (found && bms_is_member(pvarno, context->appendparents))
7693 {
7694 varno = pvarno;
7695 varattno = pvarattno;
7696 }
7697 }
7698
7699 rte = rt_fetch(varno, dpns->rtable);
7700
7701 /* might be returning old/new column value */
7703 refname = dpns->ret_old_alias;
7704 else if (var->varreturningtype == VAR_RETURNING_NEW)
7705 refname = dpns->ret_new_alias;
7706 else
7707 refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7708
7709 colinfo = deparse_columns_fetch(varno, dpns);
7710 attnum = varattno;
7711 }
7712 else
7713 {
7714 resolve_special_varno((Node *) var, context,
7715 get_special_variable, NULL);
7716 return NULL;
7717 }
7718
7719 /*
7720 * The planner will sometimes emit Vars referencing resjunk elements of a
7721 * subquery's target list (this is currently only possible if it chooses
7722 * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7723 * Although we prefer to print subquery-referencing Vars using the
7724 * subquery's alias, that's not possible for resjunk items since they have
7725 * no alias. So in that case, drill down to the subplan and print the
7726 * contents of the referenced tlist item. This works because in a plan
7727 * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
7728 * we'll have set dpns->inner_plan to reference the child plan node.
7729 */
7730 if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7731 attnum > list_length(rte->eref->colnames) &&
7732 dpns->inner_plan)
7733 {
7734 TargetEntry *tle;
7735 deparse_namespace save_dpns;
7736
7737 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7738 if (!tle)
7739 elog(ERROR, "invalid attnum %d for relation \"%s\"",
7740 attnum, rte->eref->aliasname);
7741
7742 Assert(netlevelsup == 0);
7743 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7744
7745 /*
7746 * Force parentheses because our caller probably assumed a Var is a
7747 * simple expression.
7748 */
7749 if (!IsA(tle->expr, Var))
7751 get_rule_expr((Node *) tle->expr, context, true);
7752 if (!IsA(tle->expr, Var))
7754
7755 pop_child_plan(dpns, &save_dpns);
7756 return NULL;
7757 }
7758
7759 /*
7760 * If it's an unnamed join, look at the expansion of the alias variable.
7761 * If it's a simple reference to one of the input vars, then recursively
7762 * print the name of that var instead. When it's not a simple reference,
7763 * we have to just print the unqualified join column name. (This can only
7764 * happen with "dangerous" merged columns in a JOIN USING; we took pains
7765 * previously to make the unqualified column name unique in such cases.)
7766 *
7767 * This wouldn't work in decompiling plan trees, because we don't store
7768 * joinaliasvars lists after planning; but a plan tree should never
7769 * contain a join alias variable.
7770 */
7771 if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7772 {
7773 if (rte->joinaliasvars == NIL)
7774 elog(ERROR, "cannot decompile join alias var in plan tree");
7775 if (attnum > 0)
7776 {
7777 Var *aliasvar;
7778
7779 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7780 /* we intentionally don't strip implicit coercions here */
7781 if (aliasvar && IsA(aliasvar, Var))
7782 {
7783 return get_variable(aliasvar, var->varlevelsup + levelsup,
7784 istoplevel, context);
7785 }
7786 }
7787
7788 /*
7789 * Unnamed join has no refname. (Note: since it's unnamed, there is
7790 * no way the user could have referenced it to create a whole-row Var
7791 * for it. So we don't have to cover that case below.)
7792 */
7793 Assert(refname == NULL);
7794 }
7795
7797 attname = NULL;
7798 else if (attnum > 0)
7799 {
7800 /* Get column name to use from the colinfo struct */
7801 if (attnum > colinfo->num_cols)
7802 elog(ERROR, "invalid attnum %d for relation \"%s\"",
7803 attnum, rte->eref->aliasname);
7804 attname = colinfo->colnames[attnum - 1];
7805
7806 /*
7807 * If we find a Var referencing a dropped column, it seems better to
7808 * print something (anything) than to fail. In general this should
7809 * not happen, but it used to be possible for some cases involving
7810 * functions returning named composite types, and perhaps there are
7811 * still bugs out there.
7812 */
7813 if (attname == NULL)
7814 attname = "?dropped?column?";
7815 }
7816 else
7817 {
7818 /* System column - name is fixed, get it from the catalog */
7820 }
7821
7822 need_prefix = (context->varprefix || attname == NULL ||
7824
7825 /*
7826 * If we're considering a plain Var in an ORDER BY (but not GROUP BY)
7827 * clause, we may need to add a table-name prefix to prevent
7828 * findTargetlistEntrySQL92 from misinterpreting the name as an
7829 * output-column name. To avoid cluttering the output with unnecessary
7830 * prefixes, do so only if there is a name match to a SELECT tlist item
7831 * that is different from the Var.
7832 */
7833 if (context->varInOrderBy && !context->inGroupBy && !need_prefix)
7834 {
7835 int colno = 0;
7836
7837 foreach_node(TargetEntry, tle, context->targetList)
7838 {
7839 char *colname;
7840
7841 if (tle->resjunk)
7842 continue; /* ignore junk entries */
7843 colno++;
7844
7845 /* This must match colname-choosing logic in get_target_list() */
7846 if (context->resultDesc && colno <= context->resultDesc->natts)
7847 colname = NameStr(TupleDescAttr(context->resultDesc,
7848 colno - 1)->attname);
7849 else
7850 colname = tle->resname;
7851
7852 if (colname && strcmp(colname, attname) == 0 &&
7853 !equal(var, tle->expr))
7854 {
7855 need_prefix = true;
7856 break;
7857 }
7858 }
7859 }
7860
7861 if (refname && need_prefix)
7862 {
7865 }
7866 if (attname)
7868 else
7869 {
7871 if (istoplevel)
7872 appendStringInfo(buf, "::%s",
7873 format_type_with_typemod(var->vartype,
7874 var->vartypmod));
7875 }
7876
7877 return attname;
7878}
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
@ VAR_RETURNING_OLD
Definition: primnodes.h:257
@ VAR_RETURNING_NEW
Definition: primnodes.h:258
@ VAR_RETURNING_DEFAULT
Definition: primnodes.h:256
static void get_special_variable(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:7888
Index parent_relid
Definition: pathnodes.h:3110
int num_child_cols
Definition: pathnodes.h:3146
VarReturningType varreturningtype
Definition: primnodes.h:297
char * ret_old_alias
Definition: ruleutils.c:170
char * ret_new_alias
Definition: ruleutils.c:171

References deparse_context::appendparents, deparse_namespace::appendrels, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), attname, attnum, bms_is_member(), deparse_context::buf, buf, deparse_columns::colnames, deparse_columns_fetch, elog, equal(), ERROR, TargetEntry::expr, foreach_node, format_type_with_typemod(), get_rte_attribute_name(), get_rule_expr(), get_special_variable(), get_tle_by_resno(), get_variable(), deparse_context::inGroupBy, deparse_namespace::inner_plan, deparse_namespace::inner_tlist, InvalidAttrNumber, IsA, list_length(), list_nth(), deparse_context::namespaces, NameStr, TupleDescData::natts, 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(), deparse_context::resultDesc, deparse_namespace::ret_new_alias, deparse_namespace::ret_old_alias, rt_fetch, deparse_namespace::rtable, deparse_namespace::rtable_names, RTE_CTE, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, deparse_context::targetList, TupleDescAttr(), VAR_RETURNING_DEFAULT, VAR_RETURNING_NEW, VAR_RETURNING_OLD, Var::varattno, deparse_context::varInOrderBy, Var::varlevelsup, Var::varno, deparse_context::varprefix, and Var::varreturningtype.

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

◆ get_window_frame_options()

static void get_window_frame_options ( int  frameOptions,
Node startOffset,
Node endOffset,
deparse_context context 
)
static

Definition at line 6838 of file ruleutils.c.

6841{
6842 StringInfo buf = context->buf;
6843
6844 if (frameOptions & FRAMEOPTION_NONDEFAULT)
6845 {
6846 if (frameOptions & FRAMEOPTION_RANGE)
6847 appendStringInfoString(buf, "RANGE ");
6848 else if (frameOptions & FRAMEOPTION_ROWS)
6849 appendStringInfoString(buf, "ROWS ");
6850 else if (frameOptions & FRAMEOPTION_GROUPS)
6851 appendStringInfoString(buf, "GROUPS ");
6852 else
6853 Assert(false);
6854 if (frameOptions & FRAMEOPTION_BETWEEN)
6855 appendStringInfoString(buf, "BETWEEN ");
6856 if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
6857 appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
6858 else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW)
6859 appendStringInfoString(buf, "CURRENT ROW ");
6860 else if (frameOptions & FRAMEOPTION_START_OFFSET)
6861 {
6862 get_rule_expr(startOffset, context, false);
6863 if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
6864 appendStringInfoString(buf, " PRECEDING ");
6865 else if (frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
6866 appendStringInfoString(buf, " FOLLOWING ");
6867 else
6868 Assert(false);
6869 }
6870 else
6871 Assert(false);
6872 if (frameOptions & FRAMEOPTION_BETWEEN)
6873 {
6874 appendStringInfoString(buf, "AND ");
6875 if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
6876 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
6877 else if (frameOptions & FRAMEOPTION_END_CURRENT_ROW)
6878 appendStringInfoString(buf, "CURRENT ROW ");
6879 else if (frameOptions & FRAMEOPTION_END_OFFSET)
6880 {
6881 get_rule_expr(endOffset, context, false);
6882 if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
6883 appendStringInfoString(buf, " PRECEDING ");
6884 else if (frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
6885 appendStringInfoString(buf, " FOLLOWING ");
6886 else
6887 Assert(false);
6888 }
6889 else
6890 Assert(false);
6891 }
6892 if (frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
6893 appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6894 else if (frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6895 appendStringInfoString(buf, "EXCLUDE GROUP ");
6896 else if (frameOptions & FRAMEOPTION_EXCLUDE_TIES)
6897 appendStringInfoString(buf, "EXCLUDE TIES ");
6898 /* we will now have a trailing space; remove it */
6899 buf->data[--(buf->len)] = '\0';
6900 }
6901}
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:602
#define FRAMEOPTION_END_OFFSET
Definition: parsenodes.h:613
#define FRAMEOPTION_EXCLUDE_CURRENT_ROW
Definition: parsenodes.h:607
#define FRAMEOPTION_END_OFFSET_PRECEDING
Definition: parsenodes.h:604
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:597
#define FRAMEOPTION_START_CURRENT_ROW
Definition: parsenodes.h:601
#define FRAMEOPTION_START_OFFSET
Definition: parsenodes.h:611
#define FRAMEOPTION_END_OFFSET_FOLLOWING
Definition: parsenodes.h:606
#define FRAMEOPTION_EXCLUDE_TIES
Definition: parsenodes.h:609
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:593
#define FRAMEOPTION_EXCLUDE_GROUP
Definition: parsenodes.h:608
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:595
#define FRAMEOPTION_BETWEEN
Definition: parsenodes.h:596
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING
Definition: parsenodes.h:600
#define FRAMEOPTION_START_OFFSET_PRECEDING
Definition: parsenodes.h:603
#define FRAMEOPTION_START_OFFSET_FOLLOWING
Definition: parsenodes.h:605
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:594

References appendStringInfoString(), Assert(), deparse_context::buf, buf, 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, and get_rule_expr().

Referenced by get_rule_windowspec(), and get_window_frame_options_for_explain().

◆ get_window_frame_options_for_explain()

char * get_window_frame_options_for_explain ( int  frameOptions,
Node startOffset,
Node endOffset,
List dpcontext,
bool  forceprefix 
)

Definition at line 6907 of file ruleutils.c.

6910{
6912 deparse_context context;
6913
6915 context.buf = &buf;
6916 context.namespaces = dpcontext;
6917 context.resultDesc = NULL;
6918 context.targetList = NIL;
6919 context.windowClause = NIL;
6920 context.varprefix = forceprefix;
6921 context.prettyFlags = 0;
6923 context.indentLevel = 0;
6924 context.colNamesVisible = true;
6925 context.inGroupBy = false;
6926 context.varInOrderBy = false;
6927 context.appendparents = NULL;
6928
6929 get_window_frame_options(frameOptions, startOffset, endOffset, &context);
6930
6931 return buf.data;
6932}

References deparse_context::appendparents, deparse_context::buf, buf, deparse_context::colNamesVisible, get_window_frame_options(), deparse_context::indentLevel, deparse_context::inGroupBy, initStringInfo(), deparse_context::namespaces, NIL, deparse_context::prettyFlags, deparse_context::resultDesc, deparse_context::targetList, deparse_context::varInOrderBy, deparse_context::varprefix, deparse_context::windowClause, WRAP_COLUMN_DEFAULT, and deparse_context::wrapColumn.

Referenced by show_window_def().

◆ get_windowfunc_expr()

static void get_windowfunc_expr ( WindowFunc wfunc,
deparse_context context 
)
static

Definition at line 11025 of file ruleutils.c.

11026{
11027 get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
11028}

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

11039{
11040 StringInfo buf = context->buf;
11041 Oid argtypes[FUNC_MAX_ARGS];
11042 int nargs;
11043 List *argnames;
11044 ListCell *l;
11045
11046 if (list_length(wfunc->args) > FUNC_MAX_ARGS)
11047 ereport(ERROR,
11048 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
11049 errmsg("too many arguments")));
11050 nargs = 0;
11051 argnames = NIL;
11052 foreach(l, wfunc->args)
11053 {
11054 Node *arg = (Node *) lfirst(l);
11055
11056 if (IsA(arg, NamedArgExpr))
11057 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
11058 argtypes[nargs] = exprType(arg);
11059 nargs++;
11060 }
11061
11062 if (!funcname)
11063 funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
11064 argtypes, false, NULL,
11065 context->inGroupBy);
11066
11067 appendStringInfo(buf, "%s(", funcname);
11068
11069 /* winstar can be set only in zero-argument aggregates */
11070 if (wfunc->winstar)
11072 else
11073 {
11074 if (is_json_objectagg)
11075 {
11076 get_rule_expr((Node *) linitial(wfunc->args), context, false);
11078 get_rule_expr((Node *) lsecond(wfunc->args), context, false);
11079 }
11080 else
11081 get_rule_expr((Node *) wfunc->args, context, true);
11082 }
11083
11084 if (options)
11086
11087 if (wfunc->aggfilter != NULL)
11088 {
11089 appendStringInfoString(buf, ") FILTER (WHERE ");
11090 get_rule_expr((Node *) wfunc->aggfilter, context, false);
11091 }
11092
11093 appendStringInfoString(buf, ") OVER ");
11094
11095 if (context->windowClause)
11096 {
11097 /* Query-decompilation case: search the windowClause list */
11098 foreach(l, context->windowClause)
11099 {
11100 WindowClause *wc = (WindowClause *) lfirst(l);
11101
11102 if (wc->winref == wfunc->winref)
11103 {
11104 if (wc->name)
11106 else
11107 get_rule_windowspec(wc, context->targetList, context);
11108 break;
11109 }
11110 }
11111 if (l == NULL)
11112 elog(ERROR, "could not find window clause for winref %u",
11113 wfunc->winref);
11114 }
11115 else
11116 {
11117 /*
11118 * In EXPLAIN, search the namespace stack for a matching WindowAgg
11119 * node (probably it's always the first entry), and print winname.
11120 */
11121 foreach(l, context->namespaces)
11122 {
11124
11125 if (dpns->plan && IsA(dpns->plan, WindowAgg))
11126 {
11127 WindowAgg *wagg = (WindowAgg *) dpns->plan;
11128
11129 if (wagg->winref == wfunc->winref)
11130 {
11132 break;
11133 }
11134 }
11135 }
11136 if (l == NULL)
11137 elog(ERROR, "could not find window clause for winref %u",
11138 wfunc->winref);
11139 }
11140}
char * winname
Definition: plannodes.h:1178
Index winref
Definition: plannodes.h:1181
List * args
Definition: primnodes.h:592
Index winref
Definition: primnodes.h:598
Expr * aggfilter
Definition: primnodes.h:594
Oid winfnoid
Definition: primnodes.h:584

References WindowFunc::aggfilter, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, WindowFunc::args, deparse_context::buf, buf, elog, ereport, errcode(), errmsg(), ERROR, exprType(), FUNC_MAX_ARGS, funcname, generate_function_name(), get_rule_expr(), get_rule_windowspec(), if(), deparse_context::inGroupBy, IsA, lappend(), lfirst, linitial, list_length(), lsecond, deparse_context::namespaces, NIL, deparse_namespace::plan, quote_identifier(), deparse_context::targetList, deparse_context::windowClause, WindowFunc::winfnoid, WindowAgg::winname, WindowClause::winref, WindowAgg::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 5767 of file ruleutils.c.

5768{
5769 StringInfo buf = context->buf;
5770 const char *sep;
5771 ListCell *l;
5772
5773 if (query->cteList == NIL)
5774 return;
5775
5776 if (PRETTY_INDENT(context))
5777 {
5778 context->indentLevel += PRETTYINDENT_STD;
5780 }
5781
5782 if (query->hasRecursive)
5783 sep = "WITH RECURSIVE ";
5784 else
5785 sep = "WITH ";
5786 foreach(l, query->cteList)
5787 {
5789
5792 if (cte->aliascolnames)
5793 {
5794 bool first = true;
5795 ListCell *col;
5796
5798 foreach(col, cte->aliascolnames)
5799 {
5800 if (first)
5801 first = false;
5802 else
5806 }
5808 }
5809 appendStringInfoString(buf, " AS ");
5810 switch (cte->ctematerialized)
5811 {
5813 break;
5815 appendStringInfoString(buf, "MATERIALIZED ");
5816 break;
5818 appendStringInfoString(buf, "NOT MATERIALIZED ");
5819 break;
5820 }
5822 if (PRETTY_INDENT(context))
5823 appendContextKeyword(context, "", 0, 0, 0);
5824 get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5825 true,
5826 context->prettyFlags, context->wrapColumn,
5827 context->indentLevel);
5828 if (PRETTY_INDENT(context))
5829 appendContextKeyword(context, "", 0, 0, 0);
5831
5832 if (cte->search_clause)
5833 {
5834 bool first = true;
5835 ListCell *lc;
5836
5837 appendStringInfo(buf, " SEARCH %s FIRST BY ",
5838 cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
5839
5840 foreach(lc, cte->search_clause->search_col_list)
5841 {
5842 if (first)
5843 first = false;
5844 else
5848 }
5849
5850 appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
5851 }
5852
5853 if (cte->cycle_clause)
5854 {
5855 bool first = true;
5856 ListCell *lc;
5857
5858 appendStringInfoString(buf, " CYCLE ");
5859
5860 foreach(lc, cte->cycle_clause->cycle_col_list)
5861 {
5862 if (first)
5863 first = false;
5864 else
5868 }
5869
5870 appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5871
5872 {
5873 Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5874 Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5875
5876 if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5877 cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5878 {
5879 appendStringInfoString(buf, " TO ");
5880 get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
5881 appendStringInfoString(buf, " DEFAULT ");
5882 get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
5883 }
5884 }
5885
5886 appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5887 }
5888
5889 sep = ", ";
5890 }
5891
5892 if (PRETTY_INDENT(context))
5893 {
5894 context->indentLevel -= PRETTYINDENT_STD;
5895 appendContextKeyword(context, "", 0, 0, 0);
5896 }
5897 else
5899}
@ CTEMaterializeNever
Definition: parsenodes.h:1654
@ CTEMaterializeAlways
Definition: parsenodes.h:1653
@ CTEMaterializeDefault
Definition: parsenodes.h:1652
CTEMaterialize ctematerialized
Definition: parsenodes.h:1693

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

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

11946{
11947 StringInfo buf = context->buf;
11948
11949 appendStringInfoString(buf, "XMLTABLE(");
11950
11951 if (tf->ns_uris != NIL)
11952 {
11953 ListCell *lc1,
11954 *lc2;
11955 bool first = true;
11956
11957 appendStringInfoString(buf, "XMLNAMESPACES (");
11958 forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
11959 {
11960 Node *expr = (Node *) lfirst(lc1);
11961 String *ns_node = lfirst_node(String, lc2);
11962
11963 if (!first)
11965 else
11966 first = false;
11967
11968 if (ns_node != NULL)
11969 {
11970 get_rule_expr(expr, context, showimplicit);
11971 appendStringInfo(buf, " AS %s",
11972 quote_identifier(strVal(ns_node)));
11973 }
11974 else
11975 {
11976 appendStringInfoString(buf, "DEFAULT ");
11977 get_rule_expr(expr, context, showimplicit);
11978 }
11979 }
11981 }
11982
11984 get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
11985 appendStringInfoString(buf, ") PASSING (");
11986 get_rule_expr((Node *) tf->docexpr, context, showimplicit);
11988
11989 if (tf->colexprs != NIL)
11990 {
11991 ListCell *l1;
11992 ListCell *l2;
11993 ListCell *l3;
11994 ListCell *l4;
11995 ListCell *l5;
11996 int colnum = 0;
11997
11998 appendStringInfoString(buf, " COLUMNS ");
11999 forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
12000 l4, tf->colexprs, l5, tf->coldefexprs)
12001 {
12002 char *colname = strVal(lfirst(l1));
12003 Oid typid = lfirst_oid(l2);
12004 int32 typmod = lfirst_int(l3);
12005 Node *colexpr = (Node *) lfirst(l4);
12006 Node *coldefexpr = (Node *) lfirst(l5);
12007 bool ordinality = (tf->ordinalitycol == colnum);
12008 bool notnull = bms_is_member(colnum, tf->notnulls);
12009
12010 if (colnum > 0)
12012 colnum++;
12013
12014 appendStringInfo(buf, "%s %s", quote_identifier(colname),
12015 ordinality ? "FOR ORDINALITY" :
12016 format_type_with_typemod(typid, typmod));
12017 if (ordinality)
12018 continue;
12019
12020 if (coldefexpr != NULL)
12021 {
12022 appendStringInfoString(buf, " DEFAULT (");
12023 get_rule_expr((Node *) coldefexpr, context, showimplicit);
12025 }
12026 if (colexpr != NULL)
12027 {
12028 appendStringInfoString(buf, " PATH (");
12029 get_rule_expr((Node *) colexpr, context, showimplicit);
12031 }
12032 if (notnull)
12033 appendStringInfoString(buf, " NOT NULL");
12034 }
12035 }
12036
12038}
#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5)
Definition: pg_list.h:588
Node * rowexpr
Definition: primnodes.h:122
List * colexprs
Definition: primnodes.h:132

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), bms_is_member(), deparse_context::buf, buf, TableFunc::colexprs, 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 4140 of file ruleutils.c.

4141{
4142 if (IsA(jtnode, RangeTblRef))
4143 {
4144 /* nothing to do here */
4145 }
4146 else if (IsA(jtnode, FromExpr))
4147 {
4148 FromExpr *f = (FromExpr *) jtnode;
4149 ListCell *lc;
4150
4151 foreach(lc, f->fromlist)
4152 {
4153 if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
4154 return true;
4155 }
4156 }
4157 else if (IsA(jtnode, JoinExpr))
4158 {
4159 JoinExpr *j = (JoinExpr *) jtnode;
4160
4161 /* Is it an unnamed JOIN with USING? */
4162 if (j->alias == NULL && j->usingClause)
4163 {
4164 /*
4165 * Yes, so check each join alias var to see if any of them are not
4166 * simple references to underlying columns. If so, we have a
4167 * dangerous situation and must pick unique aliases.
4168 */
4169 RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4170
4171 /* We need only examine the merged columns */
4172 for (int i = 0; i < jrte->joinmergedcols; i++)
4173 {
4174 Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4175
4176 if (!IsA(aliasvar, Var))
4177 return true;
4178 }
4179 }
4180
4181 /* Nope, but inspect children */
4182 if (has_dangerous_join_using(dpns, j->larg))
4183 return true;
4184 if (has_dangerous_join_using(dpns, j->rarg))
4185 return true;
4186 }
4187 else
4188 elog(ERROR, "unrecognized node type: %d",
4189 (int) nodeTag(jtnode));
4190 return false;
4191}
static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
Definition: ruleutils.c:4140

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

Referenced by has_dangerous_join_using(), and set_deparse_for_query().

◆ identify_join_columns()

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

Definition at line 5065 of file ruleutils.c.

5067{
5068 int numjoincols;
5069 int jcolno;
5070 int rcolno;
5071 ListCell *lc;
5072
5073 /* Extract left/right child RT indexes */
5074 if (IsA(j->larg, RangeTblRef))
5075 colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
5076 else if (IsA(j->larg, JoinExpr))
5077 colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
5078 else
5079 elog(ERROR, "unrecognized node type in jointree: %d",
5080 (int) nodeTag(j->larg));
5081 if (IsA(j->rarg, RangeTblRef))
5082 colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
5083 else if (IsA(j->rarg, JoinExpr))
5084 colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
5085 else
5086 elog(ERROR, "unrecognized node type in jointree: %d",
5087 (int) nodeTag(j->rarg));
5088
5089 /* Assert children will be processed earlier than join in second pass */
5090 Assert(colinfo->leftrti < j->rtindex);
5091 Assert(colinfo->rightrti < j->rtindex);
5092
5093 /* Initialize result arrays with zeroes */
5094 numjoincols = list_length(jrte->joinaliasvars);
5095 Assert(numjoincols == list_length(jrte->eref->colnames));
5096 colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
5097 colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
5098
5099 /*
5100 * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
5101 * Recall that the column(s) merged due to USING are the first column(s)
5102 * of the join output. We need not do anything special while scanning
5103 * joinleftcols, but while scanning joinrightcols we must distinguish
5104 * merged from unmerged columns.
5105 */
5106 jcolno = 0;
5107 foreach(lc, jrte->joinleftcols)
5108 {
5109 int leftattno = lfirst_int(lc);
5110
5111 colinfo->leftattnos[jcolno++] = leftattno;
5112 }
5113 rcolno = 0;
5114 foreach(lc, jrte->joinrightcols)
5115 {
5116 int rightattno = lfirst_int(lc);
5117
5118 if (rcolno < jrte->joinmergedcols) /* merged column? */
5119 colinfo->rightattnos[rcolno] = rightattno;
5120 else
5121 colinfo->rightattnos[jcolno++] = rightattno;
5122 rcolno++;
5123 }
5124 Assert(jcolno == numjoincols);
5125}
int * rightattnos
Definition: ruleutils.c:298
int * leftattnos
Definition: ruleutils.c:297

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

3447{
3448 return (!argmodes
3449 || argmodes[nth] == PROARGMODE_IN
3450 || argmodes[nth] == PROARGMODE_INOUT
3451 || argmodes[nth] == PROARGMODE_VARIADIC);
3452}

Referenced by pg_get_function_arg_default().

◆ isSimpleNode()

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

Definition at line 8850 of file ruleutils.c.

8851{
8852 if (!node)
8853 return false;
8854
8855 switch (nodeTag(node))
8856 {
8857 case T_Var:
8858 case T_Const:
8859 case T_Param:
8860 case T_CoerceToDomainValue:
8861 case T_SetToDefault:
8862 case T_CurrentOfExpr:
8863 /* single words: always simple */
8864 return true;
8865
8866 case T_SubscriptingRef:
8867 case T_ArrayExpr:
8868 case T_RowExpr:
8869 case T_CoalesceExpr:
8870 case T_MinMaxExpr:
8871 case T_SQLValueFunction:
8872 case T_XmlExpr:
8873 case T_NextValueExpr:
8874 case T_NullIfExpr:
8875 case T_Aggref:
8876 case T_GroupingFunc:
8877 case T_WindowFunc:
8878 case T_MergeSupportFunc:
8879 case T_FuncExpr:
8880 case T_JsonConstructorExpr:
8881 case T_JsonExpr:
8882 /* function-like: name(..) or name[..] */
8883 return true;
8884
8885 /* CASE keywords act as parentheses */
8886 case T_CaseExpr:
8887 return true;
8888
8889 case T_FieldSelect:
8890
8891 /*
8892 * appears simple since . has top precedence, unless parent is
8893 * T_FieldSelect itself!
8894 */
8895 return !IsA(parentNode, FieldSelect);
8896
8897 case T_FieldStore:
8898
8899 /*
8900 * treat like FieldSelect (probably doesn't matter)
8901 */
8902 return !IsA(parentNode, FieldStore);
8903
8904 case T_CoerceToDomain:
8905 /* maybe simple, check args */
8906 return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8907 node, prettyFlags);
8908 case T_RelabelType:
8909 return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8910 node, prettyFlags);
8911 case T_CoerceViaIO:
8912 return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
8913 node, prettyFlags);
8914 case T_ArrayCoerceExpr:
8915 return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8916 node, prettyFlags);
8917 case T_ConvertRowtypeExpr:
8918 return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8919 node, prettyFlags);
8920 case T_ReturningExpr:
8921 return isSimpleNode((Node *) ((ReturningExpr *) node)->retexpr,
8922 node, prettyFlags);
8923
8924 case T_OpExpr:
8925 {
8926 /* depends on parent node type; needs further checking */
8927 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8928 {
8929 const char *op;
8930 const char *parentOp;
8931 bool is_lopriop;
8932 bool is_hipriop;
8933 bool is_lopriparent;
8934 bool is_hipriparent;
8935
8936 op = get_simple_binary_op_name((OpExpr *) node);
8937 if (!op)
8938 return false;
8939
8940 /* We know only the basic operators + - and * / % */
8941 is_lopriop = (strchr("+-", *op) != NULL);
8942 is_hipriop = (strchr("*/%", *op) != NULL);
8943 if (!(is_lopriop || is_hipriop))
8944 return false;
8945
8946 parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8947 if (!parentOp)
8948 return false;
8949
8950 is_lopriparent = (strchr("+-", *parentOp) != NULL);
8951 is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8952 if (!(is_lopriparent || is_hipriparent))
8953 return false;
8954
8955 if (is_hipriop && is_lopriparent)
8956 return true; /* op binds tighter than parent */
8957
8958 if (is_lopriop && is_hipriparent)
8959 return false;
8960
8961 /*
8962 * Operators are same priority --- can skip parens only if
8963 * we have (a - b) - c, not a - (b - c).
8964 */
8965 if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
8966 return true;
8967
8968 return false;
8969 }
8970 /* else do the same stuff as for T_SubLink et al. */
8971 }
8972 /* FALLTHROUGH */
8973
8974 case T_SubLink:
8975 case T_NullTest:
8976 case T_BooleanTest:
8977 case T_DistinctExpr:
8978 case T_JsonIsPredicate:
8979 switch (nodeTag(parentNode))
8980 {
8981 case T_FuncExpr:
8982 {
8983 /* special handling for casts and COERCE_SQL_SYNTAX */
8984 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8985
8986 if (type == COERCE_EXPLICIT_CAST ||
8989 return false;
8990 return true; /* own parentheses */
8991 }
8992 case T_BoolExpr: /* lower precedence */
8993 case T_SubscriptingRef: /* other separators */
8994 case T_ArrayExpr: /* other separators */
8995 case T_RowExpr: /* other separators */
8996 case T_CoalesceExpr: /* own parentheses */
8997 case T_MinMaxExpr: /* own parentheses */
8998 case T_XmlExpr: /* own parentheses */
8999 case T_NullIfExpr: /* other separators */
9000 case T_Aggref: /* own parentheses */
9001 case T_GroupingFunc: /* own parentheses */
9002 case T_WindowFunc: /* own parentheses */
9003 case T_CaseExpr: /* other separators */
9004 return true;
9005 default:
9006 return false;
9007 }
9008
9009 case T_BoolExpr:
9010 switch (nodeTag(parentNode))
9011 {
9012 case T_BoolExpr:
9013 if (prettyFlags & PRETTYFLAG_PAREN)
9014 {
9016 BoolExprType parentType;
9017
9018 type = ((BoolExpr *) node)->boolop;
9019 parentType = ((BoolExpr *) parentNode)->boolop;
9020 switch (type)
9021 {
9022 case NOT_EXPR:
9023 case AND_EXPR:
9024 if (parentType == AND_EXPR || parentType == OR_EXPR)
9025 return true;
9026 break;
9027 case OR_EXPR:
9028 if (parentType == OR_EXPR)
9029 return true;
9030 break;
9031 }
9032 }
9033 return false;
9034 case T_FuncExpr:
9035 {
9036 /* special handling for casts and COERCE_SQL_SYNTAX */
9037 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
9038
9039 if (type == COERCE_EXPLICIT_CAST ||
9042 return false;
9043 return true; /* own parentheses */
9044 }
9045 case T_SubscriptingRef: /* other separators */
9046 case T_ArrayExpr: /* other separators */
9047 case T_RowExpr: /* other separators */
9048 case T_CoalesceExpr: /* own parentheses */
9049 case T_MinMaxExpr: /* own parentheses */
9050 case T_XmlExpr: /* own parentheses */
9051 case T_NullIfExpr: /* other separators */
9052 case T_Aggref: /* own parentheses */
9053 case T_GroupingFunc: /* own parentheses */
9054 case T_WindowFunc: /* own parentheses */
9055 case T_CaseExpr: /* other separators */
9056 case T_JsonExpr: /* own parentheses */
9057 return true;
9058 default:
9059 return false;
9060 }
9061
9062 case T_JsonValueExpr:
9063 /* maybe simple, check args */
9064 return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
9065 node, prettyFlags);
9066
9067 default:
9068 break;
9069 }
9070 /* those we don't know: in dubio complexo */
9071 return false;
9072}
BoolExprType
Definition: primnodes.h:947
CoercionForm
Definition: primnodes.h:750
static const char * get_simple_binary_op_name(OpExpr *expr)
Definition: ruleutils.c:8824
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, isSimpleNode(), linitial, nodeTag, NOT_EXPR, OR_EXPR, PRETTYFLAG_PAREN, and type.

Referenced by get_rule_expr_paren(), and isSimpleNode().

◆ looks_like_function()

static bool looks_like_function ( Node node)
static

Definition at line 10706 of file ruleutils.c.

10707{
10708 if (node == NULL)
10709 return false; /* probably shouldn't happen */
10710 switch (nodeTag(node))
10711 {
10712 case T_FuncExpr:
10713 /* OK, unless it's going to deparse as a cast */
10714 return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
10715 ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
10716 case T_NullIfExpr:
10717 case T_CoalesceExpr:
10718 case T_MinMaxExpr:
10719 case T_SQLValueFunction:
10720 case T_XmlExpr:
10721 case T_JsonExpr:
10722 /* these are all accepted by func_expr_common_subexpr */
10723 return true;
10724 default:
10725 break;
10726 }
10727 return false;
10728}

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

4925{
4926 /*
4927 * If the selected name isn't unique, append digits to make it so. For a
4928 * very long input name, we might have to truncate to stay within
4929 * NAMEDATALEN.
4930 */
4931 if (!colname_is_unique(colname, dpns, colinfo))
4932 {
4933 int colnamelen = strlen(colname);
4934 char *modname = (char *) palloc(colnamelen + 16);
4935 int i = 0;
4936
4937 do
4938 {
4939 i++;
4940 for (;;)
4941 {
4942 memcpy(modname, colname, colnamelen);
4943 sprintf(modname + colnamelen, "_%d", i);
4944 if (strlen(modname) < NAMEDATALEN)
4945 break;
4946 /* drop chars from colname to keep all the digits */
4947 colnamelen = pg_mbcliplen(colname, colnamelen,
4948 colnamelen - 1);
4949 }
4950 } while (!colname_is_unique(modname, dpns, colinfo));
4951 colname = modname;
4952 }
4953 return colname;
4954}
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1084
#define sprintf
Definition: port.h:241
static bool colname_is_unique(const char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
Definition: ruleutils.c:4848

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

5349{
5350 char *rulename;
5351 char ev_type;
5352 Oid ev_class;
5353 bool is_instead;
5354 char *ev_qual;
5355 char *ev_action;
5356 List *actions;
5357 Relation ev_relation;
5358 TupleDesc viewResultDesc = NULL;
5359 int fno;
5360 Datum dat;
5361 bool isnull;
5362
5363 /*
5364 * Get the attribute values from the rules tuple
5365 */
5366 fno = SPI_fnumber(rulettc, "rulename");
5367 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5368 Assert(!isnull);
5369 rulename = NameStr(*(DatumGetName(dat)));
5370
5371 fno = SPI_fnumber(rulettc, "ev_type");
5372 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5373 Assert(!isnull);
5374 ev_type = DatumGetChar(dat);
5375
5376 fno = SPI_fnumber(rulettc, "ev_class");
5377 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5378 Assert(!isnull);
5379 ev_class = DatumGetObjectId(dat);
5380
5381 fno = SPI_fnumber(rulettc, "is_instead");
5382 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5383 Assert(!isnull);
5384 is_instead = DatumGetBool(dat);
5385
5386 fno = SPI_fnumber(rulettc, "ev_qual");
5387 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5388 Assert(ev_qual != NULL);
5389
5390 fno = SPI_fnumber(rulettc, "ev_action");
5391 ev_action = SPI_getvalue(ruletup, rulettc, fno);
5392 Assert(ev_action != NULL);
5393 actions = (List *) stringToNode(ev_action);
5394 if (actions == NIL)
5395 elog(ERROR, "invalid empty ev_action list");
5396
5397 ev_relation = table_open(ev_class, AccessShareLock);
5398
5399 /*
5400 * Build the rules definition text
5401 */
5402 appendStringInfo(buf, "CREATE RULE %s AS",
5403 quote_identifier(rulename));
5404
5405 if (prettyFlags & PRETTYFLAG_INDENT)
5406 appendStringInfoString(buf, "\n ON ");
5407 else
5408 appendStringInfoString(buf, " ON ");
5409
5410 /* The event the rule is fired for */
5411 switch (ev_type)
5412 {
5413 case '1':
5414 appendStringInfoString(buf, "SELECT");
5415 viewResultDesc = RelationGetDescr(ev_relation);
5416 break;
5417
5418 case '2':
5419 appendStringInfoString(buf, "UPDATE");
5420 break;
5421
5422 case '3':
5423 appendStringInfoString(buf, "INSERT");
5424 break;
5425
5426 case '4':
5427 appendStringInfoString(buf, "DELETE");
5428 break;
5429
5430 default:
5431 ereport(ERROR,
5432 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5433 errmsg("rule \"%s\" has unsupported event type %d",
5434 rulename, ev_type)));
5435 break;
5436 }
5437
5438 /* The relation the rule is fired on */
5439 appendStringInfo(buf, " TO %s",
5440 (prettyFlags & PRETTYFLAG_SCHEMA) ?
5441 generate_relation_name(ev_class, NIL) :
5443
5444 /* If the rule has an event qualification, add it */
5445 if (strcmp(ev_qual, "<>") != 0)
5446 {
5447 Node *qual;
5448 Query *query;
5449 deparse_context context;
5450 deparse_namespace dpns;
5451
5452 if (prettyFlags & PRETTYFLAG_INDENT)
5454 appendStringInfoString(buf, " WHERE ");
5455
5456 qual = stringToNode(ev_qual);
5457
5458 /*
5459 * We need to make a context for recognizing any Vars in the qual
5460 * (which can only be references to OLD and NEW). Use the rtable of
5461 * the first query in the action list for this purpose.
5462 */
5463 query = (Query *) linitial(actions);
5464
5465 /*
5466 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5467 * into the SELECT, and that's what we need to look at. (Ugly kluge
5468 * ... try to fix this when we redesign querytrees.)
5469 */
5470 query = getInsertSelectQuery(query, NULL);
5471
5472 /* Must acquire locks right away; see notes in get_query_def() */
5473 AcquireRewriteLocks(query, false, false);
5474
5475 context.buf = buf;
5476 context.namespaces = list_make1(&dpns);
5477 context.resultDesc = NULL;
5478 context.targetList = NIL;
5479 context.windowClause = NIL;
5480 context.varprefix = (list_length(query->rtable) != 1);
5481 context.prettyFlags = prettyFlags;
5483 context.indentLevel = PRETTYINDENT_STD;
5484 context.colNamesVisible = true;
5485 context.inGroupBy = false;
5486 context.varInOrderBy = false;
5487 context.appendparents = NULL;
5488
5489 set_deparse_for_query(&dpns, query, NIL);
5490
5491 get_rule_expr(qual, &context, false);
5492 }
5493
5494 appendStringInfoString(buf, " DO ");
5495
5496 /* The INSTEAD keyword (if so) */
5497 if (is_instead)
5498 appendStringInfoString(buf, "INSTEAD ");
5499
5500 /* Finally the rules actions */
5501 if (list_length(actions) > 1)
5502 {
5504 Query *query;
5505
5507 foreach(action, actions)
5508 {
5509 query = (Query *) lfirst(action);
5510 get_query_def(query, buf, NIL, viewResultDesc, true,
5511 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5512 if (prettyFlags)
5514 else
5516 }
5518 }
5519 else
5520 {
5521 Query *query;
5522
5523 query = (Query *) linitial(actions);
5524 get_query_def(query, buf, NIL, viewResultDesc, true,
5525 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5527 }
5528
5529 table_close(ev_relation, AccessShareLock);
5530}
static Name DatumGetName(Datum X)
Definition: postgres.h:365
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:247
static char DatumGetChar(Datum X)
Definition: postgres.h:117
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetDescr(relation)
Definition: rel.h:542
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
static char * generate_qualified_relation_name(Oid relid)
Definition: ruleutils.c:13213
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Definition: spi.c:1175
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition: spi.c:1220
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1252
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, deparse_context::appendparents, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), deparse_context::buf, buf, deparse_context::colNamesVisible, DatumGetBool(), DatumGetChar(), DatumGetName(), DatumGetObjectId(), elog, ereport, errcode(), errmsg(), ERROR, generate_qualified_relation_name(), generate_relation_name(), get_query_def(), get_rule_expr(), getInsertSelectQuery(), deparse_context::indentLevel, deparse_context::inGroupBy, lfirst, linitial, list_length(), list_make1, deparse_context::namespaces, NameStr, NIL, PRETTYFLAG_INDENT, PRETTYFLAG_SCHEMA, deparse_context::prettyFlags, PRETTYINDENT_STD, quote_identifier(), RelationGetDescr, deparse_context::resultDesc, Query::rtable, set_deparse_for_query(), SPI_fnumber(), SPI_getbinval(), SPI_getvalue(), stringToNode(), table_close(), table_open(), deparse_context::targetList, deparse_context::varInOrderBy, deparse_context::varprefix, deparse_context::windowClause, WRAP_COLUMN_DEFAULT, and deparse_context::wrapColumn.

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

5541{
5542 Query *query;
5543 char ev_type;
5544 Oid ev_class;
5545 bool is_instead;
5546 char *ev_qual;
5547 char *ev_action;
5548 List *actions;
5549 Relation ev_relation;
5550 int fno;
5551 Datum dat;
5552 bool isnull;
5553
5554 /*
5555 * Get the attribute values from the rules tuple
5556 */
5557 fno = SPI_fnumber(rulettc, "ev_type");
5558 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5559 Assert(!isnull);
5560 ev_type = DatumGetChar(dat);
5561
5562 fno = SPI_fnumber(rulettc, "ev_class");
5563 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5564 Assert(!isnull);
5565 ev_class = DatumGetObjectId(dat);
5566
5567 fno = SPI_fnumber(rulettc, "is_instead");
5568 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5569 Assert(!isnull);
5570 is_instead = DatumGetBool(dat);
5571
5572 fno = SPI_fnumber(rulettc, "ev_qual");
5573 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5574 Assert(ev_qual != NULL);
5575
5576 fno = SPI_fnumber(rulettc, "ev_action");
5577 ev_action = SPI_getvalue(ruletup, rulettc, fno);
5578 Assert(ev_action != NULL);
5579 actions = (List *) stringToNode(ev_action);
5580
5581 if (list_length(actions) != 1)
5582 {
5583 /* keep output buffer empty and leave */
5584 return;
5585 }
5586
5587 query = (Query *) linitial(actions);
5588
5589 if (ev_type != '1' || !is_instead ||
5590 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5591 {
5592 /* keep output buffer empty and leave */
5593 return;
5594 }
5595
5596 ev_relation = table_open(ev_class, AccessShareLock);
5597
5598 get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
5599 prettyFlags, wrapColumn, 0);
5601
5602 table_close(ev_relation, AccessShareLock);
5603}

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

2147{
2148 Oid constraintId = PG_GETARG_OID(0);
2149 int prettyFlags;
2150 char *res;
2151
2152 prettyFlags = PRETTYFLAG_INDENT;
2153
2154 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2155
2156 if (res == NULL)
2158
2160}
#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:13575
static char * pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, int prettyFlags, bool missing_ok)
Definition: ruleutils.c:2193

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

◆ pg_get_constraintdef_command()

char * pg_get_constraintdef_command ( Oid  constraintId)

Definition at line 2184 of file ruleutils.c.

2185{
2186 return pg_get_constraintdef_worker(constraintId, true, 0, false);
2187}

References pg_get_constraintdef_worker().

Referenced by RememberConstraintForRebuilding().

◆ pg_get_constraintdef_ext()

Datum pg_get_constraintdef_ext ( PG_FUNCTION_ARGS  )

Definition at line 2163 of file ruleutils.c.

2164{
2165 Oid constraintId = PG_GETARG_OID(0);
2166 bool pretty = PG_GETARG_BOOL(1);
2167 int prettyFlags;
2168 char *res;
2169
2170 prettyFlags = GET_PRETTY_FLAGS(pretty);
2171
2172 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2173
2174 if (res == NULL)
2176
2178}
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define GET_PRETTY_FLAGS(pretty)
Definition: ruleutils.c:93

References GET_PRETTY_FLAGS, pg_get_constraintdef_worker(), PG_GETARG_BOOL, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, 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 2193 of file ruleutils.c.

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

References AccessShareLock, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), attnum, BTEqualStrategyNumber, buf, 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 2675 of file ruleutils.c.

2676{
2677 text *expr = PG_GETARG_TEXT_PP(0);
2678 Oid relid = PG_GETARG_OID(1);
2679 text *result;
2680 int prettyFlags;
2681
2682 prettyFlags = PRETTYFLAG_INDENT;
2683
2684 result = pg_get_expr_worker(expr, relid, prettyFlags);
2685 if (result)
2686 PG_RETURN_TEXT_P(result);
2687 else
2689}
#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:2710
Definition: c.h:658

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

2693{
2694 text *expr = PG_GETARG_TEXT_PP(0);
2695 Oid relid = PG_GETARG_OID(1);
2696 bool pretty = PG_GETARG_BOOL(2);
2697 text *result;
2698 int prettyFlags;
2699
2700 prettyFlags = GET_PRETTY_FLAGS(pretty);
2701
2702 result = pg_get_expr_worker(expr, relid, prettyFlags);
2703 if (result)
2704 PG_RETURN_TEXT_P(result);
2705 else
2707}

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

2711{
2712 Node *node;
2713 Node *tst;
2714 Relids relids;
2715 List *context;
2716 char *exprstr;
2717 Relation rel = NULL;
2718 char *str;
2719
2720 /* Convert input pg_node_tree (really TEXT) object to C string */
2721 exprstr = text_to_cstring(expr);
2722
2723 /* Convert expression to node tree */
2724 node = (Node *) stringToNode(exprstr);
2725
2726 pfree(exprstr);
2727
2728 /*
2729 * Throw error if the input is a querytree rather than an expression tree.
2730 * While we could support queries here, there seems no very good reason
2731 * to. In most such catalog columns, we'll see a List of Query nodes, or
2732 * even nested Lists, so drill down to a non-List node before checking.
2733 */
2734 tst = node;
2735 while (tst && IsA(tst, List))
2736 tst = linitial((List *) tst);
2737 if (tst && IsA(tst, Query))
2738 ereport(ERROR,
2739 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2740 errmsg("input is a query, not an expression")));
2741
2742 /*
2743 * Throw error if the expression contains Vars we won't be able to
2744 * deparse.
2745 */
2746 relids = pull_varnos(NULL, node);
2747 if (OidIsValid(relid))
2748 {
2749 if (!bms_is_subset(relids, bms_make_singleton(1)))
2750 ereport(ERROR,
2751 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2752 errmsg("expression contains variables of more than one relation")));
2753 }
2754 else
2755 {
2756 if (!bms_is_empty(relids))
2757 ereport(ERROR,
2758 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2759 errmsg("expression contains variables")));
2760 }
2761
2762 /*
2763 * Prepare deparse context if needed. If we are deparsing with a relid,
2764 * we need to transiently open and lock the rel, to make sure it won't go
2765 * away underneath us. (set_relation_column_names would lock it anyway,
2766 * so this isn't really introducing any new behavior.)
2767 */
2768 if (OidIsValid(relid))
2769 {
2770 rel = try_relation_open(relid, AccessShareLock);
2771 if (rel == NULL)
2772 return NULL;
2773 context = deparse_context_for(RelationGetRelationName(rel), relid);
2774 }
2775 else
2776 context = NIL;
2777
2778 /* Deparse */
2779 str = deparse_expression_pretty(node, context, false, false,
2780 prettyFlags, 0);
2781
2782 if (rel != NULL)
2784
2785 return string_to_text(str);
2786}
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
#define bms_is_empty(a)
Definition: bitmapset.h:118
#define RelationGetRelationName(relation)
Definition: rel.h:550
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:114
char * text_to_cstring(const text *t)
Definition: varlena.c:225

References AccessShareLock, bms_is_empty, bms_is_subset(), bms_make_singleton(), 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 3486 of file ruleutils.c.

3487{
3488 Oid funcid = PG_GETARG_OID(0);
3489 int32 nth_arg = PG_GETARG_INT32(1);
3490 HeapTuple proctup;
3491 Form_pg_proc proc;
3492 int numargs;
3493 Oid *argtypes;
3494 char **argnames;
3495 char *argmodes;
3496 int i;
3497 List *argdefaults;
3498 Node *node;
3499 char *str;
3500 int nth_inputarg;
3501 Datum proargdefaults;
3502 bool isnull;
3503 int nth_default;
3504
3505 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3506 if (!HeapTupleIsValid(proctup))
3508
3509 numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3510 if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3511 {
3512 ReleaseSysCache(proctup);
3514 }
3515
3516 nth_inputarg = 0;
3517 for (i = 0; i < nth_arg; i++)
3518 if (is_input_argument(i, argmodes))
3519 nth_inputarg++;
3520
3521 proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3522 Anum_pg_proc_proargdefaults,
3523 &isnull);
3524 if (isnull)
3525 {
3526 ReleaseSysCache(proctup);
3528 }
3529
3530 str = TextDatumGetCString(proargdefaults);
3531 argdefaults = castNode(List, stringToNode(str));
3532 pfree(str);
3533
3534 proc = (Form_pg_proc) GETSTRUCT(proctup);
3535
3536 /*
3537 * Calculate index into proargdefaults: proargdefaults corresponds to the
3538 * last N input arguments, where N = pronargdefaults.
3539 */
3540 nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3541
3542 if (nth_default < 0 || nth_default >= list_length(argdefaults))
3543 {
3544 ReleaseSysCache(proctup);
3546 }
3547 node = list_nth(argdefaults, nth_default);
3548 str = deparse_expression(node, NIL, false, false);
3549
3550 ReleaseSysCache(proctup);
3551
3553}
#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
static bool is_input_argument(int nth, const char *argmodes)
Definition: ruleutils.c:3446
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3645

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

3180{
3181 Oid funcid = PG_GETARG_OID(0);
3183 HeapTuple proctup;
3184
3185 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3186 if (!HeapTupleIsValid(proctup))
3188
3190
3191 (void) print_function_arguments(&buf, proctup, false, true);
3192
3193 ReleaseSysCache(proctup);
3194
3196}
static int print_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults)
Definition: ruleutils.c:3298

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

3206{
3207 Oid funcid = PG_GETARG_OID(0);
3209 HeapTuple proctup;
3210
3211 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3212 if (!HeapTupleIsValid(proctup))
3214
3216
3217 (void) print_function_arguments(&buf, proctup, false, false);
3218
3219 ReleaseSysCache(proctup);
3220
3222}

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

3231{
3232 Oid funcid = PG_GETARG_OID(0);
3234 HeapTuple proctup;
3235
3236 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3237 if (!HeapTupleIsValid(proctup))
3239
3240 if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3241 {
3242 ReleaseSysCache(proctup);
3244 }
3245
3247
3248 print_function_rettype(&buf, proctup);
3249
3250 ReleaseSysCache(proctup);
3251
3253}
static void print_function_rettype(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3260

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

3611{
3612 Oid funcid = PG_GETARG_OID(0);
3614 HeapTuple proctup;
3615 bool isnull;
3616
3618
3619 /* Look up the function */
3620 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3621 if (!HeapTupleIsValid(proctup))
3623
3624 (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3625 if (isnull)
3626 {
3627 ReleaseSysCache(proctup);
3629 }
3630
3631 print_function_sqlbody(&buf, proctup);
3632
3633 ReleaseSysCache(proctup);
3634
3636}
static void print_function_sqlbody(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3556
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:204

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

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

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

1179{
1180 Oid indexrelid = PG_GETARG_OID(0);
1181 int prettyFlags;
1182 char *res;
1183
1184 prettyFlags = PRETTYFLAG_INDENT;
1185
1186 res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1187 false, false,
1188 false, false,
1189 prettyFlags, true);
1190
1191 if (res == NULL)
1193
1195}

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

◆ pg_get_indexdef_columns()

char * pg_get_indexdef_columns ( Oid  indexrelid,
bool  pretty 
)

Definition at line 1235 of file ruleutils.c.

1236{
1237 int prettyFlags;
1238
1239 prettyFlags = GET_PRETTY_FLAGS(pretty);
1240
1241 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1242 true, true,
1243 false, false,
1244 prettyFlags, false);
1245}

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

1250{
1251 bool pretty = ((flags & RULE_INDEXDEF_PRETTY) != 0);
1252 bool keys_only = ((flags & RULE_INDEXDEF_KEYS_ONLY) != 0);
1253 int prettyFlags;
1254
1255 prettyFlags = GET_PRETTY_FLAGS(pretty);
1256
1257 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1258 true, keys_only,
1259 false, false,
1260 prettyFlags, false);
1261}
#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 1198 of file ruleutils.c.

1199{
1200 Oid indexrelid = PG_GETARG_OID(0);
1201 int32 colno = PG_GETARG_INT32(1);
1202 bool pretty = PG_GETARG_BOOL(2);
1203 int prettyFlags;
1204 char *res;
1205
1206 prettyFlags = GET_PRETTY_FLAGS(pretty);
1207
1208 res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1209 colno != 0, false,
1210 false, false,
1211 prettyFlags, true);
1212
1213 if (res == NULL)
1215
1217}

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

◆ pg_get_indexdef_string()

char * pg_get_indexdef_string ( Oid  indexrelid)

Definition at line 1225 of file ruleutils.c.

1226{
1227 return pg_get_indexdef_worker(indexrelid, 0, NULL,
1228 false, false,
1229 true, true,
1230 0, false);
1231}

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

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

References IndexAmRoutine::amcanorder, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), attname, attnum, buf, 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 2128 of file ruleutils.c.

2129{
2130 Expr *constr_expr;
2131 List *context;
2132
2133 constr_expr = get_partition_qual_relid(partitionId);
2134 context = deparse_context_for(aliasname, partitionId);
2135
2136 return deparse_expression((Node *) constr_expr, context, true, false);
2137}
Expr * get_partition_qual_relid(Oid relid)
Definition: partcache.c:299

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

2097{
2098 Oid relationId = PG_GETARG_OID(0);
2099 Expr *constr_expr;
2100 int prettyFlags;
2101 List *context;
2102 char *consrc;
2103
2104 constr_expr = get_partition_qual_relid(relationId);
2105
2106 /* Quick exit if no partition constraint */
2107 if (constr_expr == NULL)
2109
2110 /*
2111 * Deparse and return the constraint expression.
2112 */
2113 prettyFlags = PRETTYFLAG_INDENT;
2114 context = deparse_context_for(get_relation_name(relationId), relationId);
2115 consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2116 false, prettyFlags, 0);
2117
2119}

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

1910{
1911 Oid relid = PG_GETARG_OID(0);
1912 char *res;
1913
1914 res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1915
1916 if (res == NULL)
1918
1920}
static char * pg_get_partkeydef_worker(Oid relid, int prettyFlags, bool attrsOnly, bool missing_ok)
Definition: ruleutils.c:1937

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

◆ pg_get_partkeydef_columns()

char * pg_get_partkeydef_columns ( Oid  relid,
bool  pretty 
)

Definition at line 1924 of file ruleutils.c.

1925{
1926 int prettyFlags;
1927
1928 prettyFlags = GET_PRETTY_FLAGS(pretty);
1929
1930 return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1931}

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

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

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), attname, attnum, buf, 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 1588 of file ruleutils.c.

1589{
1591 int prettyFlags;
1592
1593 prettyFlags = GET_PRETTY_FLAGS(pretty);
1594
1596
1597 get_query_def(query, &buf, NIL, NULL, true,
1598 prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1599
1600 return buf.data;
1601}

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

561{
562 Oid ruleoid = PG_GETARG_OID(0);
563 int prettyFlags;
564 char *res;
565
566 prettyFlags = PRETTYFLAG_INDENT;
567
568 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
569
570 if (res == NULL)
572
574}
static char * pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
Definition: ruleutils.c:597

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

◆ pg_get_ruledef_ext()

Datum pg_get_ruledef_ext ( PG_FUNCTION_ARGS  )

Definition at line 578 of file ruleutils.c.

579{
580 Oid ruleoid = PG_GETARG_OID(0);
581 bool pretty = PG_GETARG_BOOL(1);
582 int prettyFlags;
583 char *res;
584
585 prettyFlags = GET_PRETTY_FLAGS(pretty);
586
587 res = pg_get_ruledef_worker(ruleoid, prettyFlags);
588
589 if (res == NULL)
591
593}

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

◆ pg_get_ruledef_worker()

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

Definition at line 597 of file ruleutils.c.

598{
599 Datum args[1];
600 char nulls[1];
601 int spirc;
602 HeapTuple ruletup;
603 TupleDesc rulettc;
605
606 /*
607 * Do this first so that string is alloc'd in outer context not SPI's.
608 */
610
611 /*
612 * Connect to SPI manager
613 */
614 SPI_connect();
615
616 /*
617 * On the first call prepare the plan to lookup pg_rewrite. We read
618 * pg_rewrite over the SPI manager instead of using the syscache to be
619 * checked for read access on pg_rewrite.
620 */
621 if (plan_getrulebyoid == NULL)
622 {
623 Oid argtypes[1];
625
626 argtypes[0] = OIDOID;
627 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
628 if (plan == NULL)
629 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
632 }
633
634 /*
635 * Get the pg_rewrite tuple for this rule
636 */
637 args[0] = ObjectIdGetDatum(ruleoid);
638 nulls[0] = ' ';
639 spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
640 if (spirc != SPI_OK_SELECT)
641 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
642 if (SPI_processed != 1)
643 {
644 /*
645 * There is no tuple data available here, just keep the output buffer
646 * empty.
647 */
648 }
649 else
650 {
651 /*
652 * Get the rule's definition and put it into executor's memory
653 */
654 ruletup = SPI_tuptable->vals[0];
655 rulettc = SPI_tuptable->tupdesc;
656 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
657 }
658
659 /*
660 * Disconnect from SPI manager
661 */
662 if (SPI_finish() != SPI_OK_FINISH)
663 elog(ERROR, "SPI_finish failed");
664
665 if (buf.len == 0)
666 return NULL;
667
668 return buf.data;
669}
static const char *const query_getrulebyoid
Definition: ruleutils.c:334
static SPIPlanPtr plan_getrulebyoid
Definition: ruleutils.c:333
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
Definition: ruleutils.c:5347
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:672
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:860
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:976
#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_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 2833 of file ruleutils.c.

2834{
2835 text *tablename = PG_GETARG_TEXT_PP(0);
2836 text *columnname = PG_GETARG_TEXT_PP(1);
2837 RangeVar *tablerv;
2838 Oid tableOid;
2839 char *column;
2841 Oid sequenceId = InvalidOid;
2842 Relation depRel;
2843 ScanKeyData key[3];
2844 SysScanDesc scan;
2845 HeapTuple tup;
2846
2847 /* Look up table name. Can't lock it - we might not have privileges. */
2849 tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2850
2851 /* Get the number of the column */
2852 column = text_to_cstring(columnname);
2853
2854 attnum = get_attnum(tableOid, column);
2856 ereport(ERROR,
2857 (errcode(ERRCODE_UNDEFINED_COLUMN),
2858 errmsg("column \"%s\" of relation \"%s\" does not exist",
2859 column, tablerv->relname)));
2860
2861 /* Search the dependency table for the dependent sequence */
2862 depRel = table_open(DependRelationId, AccessShareLock);
2863
2864 ScanKeyInit(&key[0],
2865 Anum_pg_depend_refclassid,
2866 BTEqualStrategyNumber, F_OIDEQ,
2867 ObjectIdGetDatum(RelationRelationId));
2868 ScanKeyInit(&key[1],
2869 Anum_pg_depend_refobjid,
2870 BTEqualStrategyNumber, F_OIDEQ,
2871 ObjectIdGetDatum(tableOid));
2872 ScanKeyInit(&key[2],
2873 Anum_pg_depend_refobjsubid,
2874 BTEqualStrategyNumber, F_INT4EQ,
2876
2877 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2878 NULL, 3, key);
2879
2880 while (HeapTupleIsValid(tup = systable_getnext(scan)))
2881 {
2882 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2883
2884 /*
2885 * Look for an auto dependency (serial column) or internal dependency
2886 * (identity column) of a sequence on a column. (We need the relkind
2887 * test because indexes can also have auto dependencies on columns.)
2888 */
2889 if (deprec->classid == RelationRelationId &&
2890 deprec->objsubid == 0 &&
2891 (deprec->deptype == DEPENDENCY_AUTO ||
2892 deprec->deptype == DEPENDENCY_INTERNAL) &&
2893 get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2894 {
2895 sequenceId = deprec->objid;
2896 break;
2897 }
2898 }
2899
2900 systable_endscan(scan);
2902
2903 if (OidIsValid(sequenceId))
2904 {
2905 char *result;
2906
2907 result = generate_qualified_relation_name(sequenceId);
2908
2910 }
2911
2913}
@ 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:950
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2143
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3554
#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:217
char * relname
Definition: primnodes.h:83
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3467

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

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

1609{
1610 Oid statextid = PG_GETARG_OID(0);
1611 char *res;
1612
1613 res = pg_get_statisticsobj_worker(statextid, false, true);
1614
1615 if (res == NULL)
1617
1619}
static char * pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
Definition: ruleutils.c:1654

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

◆ pg_get_statisticsobjdef_columns()

Datum pg_get_statisticsobjdef_columns ( PG_FUNCTION_ARGS  )

Definition at line 1637 of file ruleutils.c.

1638{
1639 Oid statextid = PG_GETARG_OID(0);
1640 char *res;
1641
1642 res = pg_get_statisticsobj_worker(statextid, true, true);
1643
1644 if (res == NULL)
1646
1648}

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

◆ pg_get_statisticsobjdef_expressions()

Datum pg_get_statisticsobjdef_expressions ( PG_FUNCTION_ARGS  )

Definition at line 1838 of file ruleutils.c.

1839{
1840 Oid statextid = PG_GETARG_OID(0);
1841 Form_pg_statistic_ext statextrec;
1842 HeapTuple statexttup;
1843 Datum datum;
1844 List *context;
1845 ListCell *lc;
1846 List *exprs = NIL;
1847 bool has_exprs;
1848 char *tmp;
1849 ArrayBuildState *astate = NULL;
1850
1851 statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1852
1853 if (!HeapTupleIsValid(statexttup))
1855
1856 /* Does the stats object have expressions? */
1857 has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1858
1859 /* no expressions? we're done */
1860 if (!has_exprs)
1861 {
1862 ReleaseSysCache(statexttup);
1864 }
1865
1866 statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1867
1868 /*
1869 * Get the statistics expressions, and deparse them into text values.
1870 */
1871 datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1872 Anum_pg_statistic_ext_stxexprs);
1873 tmp = TextDatumGetCString(datum);
1874 exprs = (List *) stringToNode(tmp);
1875 pfree(tmp);
1876
1877 context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1878 statextrec->stxrelid);
1879
1880 foreach(lc, exprs)
1881 {
1882 Node *expr = (Node *) lfirst(lc);
1883 char *str;
1884 int prettyFlags = PRETTYFLAG_INDENT;
1885
1886 str = deparse_expression_pretty(expr, context, false, false,
1887 prettyFlags, 0);
1888
1889 astate = accumArrayResult(astate,
1891 false,
1892 TEXTOID,
1894 }
1895
1896 ReleaseSysCache(statexttup);
1897
1899}
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5350
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5420
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
text * cstring_to_text(const char *s)
Definition: varlena.c:192

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

1628{
1629 return pg_get_statisticsobj_worker(statextid, false, false);
1630}

References pg_get_statisticsobj_worker().

Referenced by RememberStatisticsForRebuilding().

◆ pg_get_triggerdef()

Datum pg_get_triggerdef ( PG_FUNCTION_ARGS  )

Definition at line 871 of file ruleutils.c.

872{
873 Oid trigid = PG_GETARG_OID(0);
874 char *res;
875
876 res = pg_get_triggerdef_worker(trigid, false);
877
878 if (res == NULL)
880
882}
static char * pg_get_triggerdef_worker(Oid trigid, bool pretty)
Definition: ruleutils.c:900

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

◆ pg_get_triggerdef_ext()

Datum pg_get_triggerdef_ext ( PG_FUNCTION_ARGS  )

Definition at line 885 of file ruleutils.c.

886{
887 Oid trigid = PG_GETARG_OID(0);
888 bool pretty = PG_GETARG_BOOL(1);
889 char *res;
890
891 res = pg_get_triggerdef_worker(trigid, pretty);
892
893 if (res == NULL)
895
897}

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

◆ pg_get_triggerdef_worker()

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

Definition at line 900 of file ruleutils.c.

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

Referenced by pg_get_triggerdef(), and pg_get_triggerdef_ext().

◆ pg_get_userbyid()

Datum pg_get_userbyid ( PG_FUNCTION_ARGS  )

Definition at line 2795 of file ruleutils.c.

2796{
2797 Oid roleid = PG_GETARG_OID(0);
2798 Name result;
2799 HeapTuple roletup;
2800 Form_pg_authid role_rec;
2801
2802 /*
2803 * Allocate space for the result
2804 */
2805 result = (Name) palloc(NAMEDATALEN);
2806 memset(NameStr(*result), 0, NAMEDATALEN);
2807
2808 /*
2809 * Get the pg_authid entry and print the result
2810 */
2811 roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2812 if (HeapTupleIsValid(roletup))
2813 {
2814 role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2815 *result = role_rec->rolname;
2816 ReleaseSysCache(roletup);
2817 }
2818 else
2819 sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2820
2821 PG_RETURN_NAME(result);
2822}
NameData * Name
Definition: c.h:715
#define PG_RETURN_NAME(x)
Definition: fmgr.h:363
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:56
Definition: c.h:712

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

679{
680 /* By OID */
681 Oid viewoid = PG_GETARG_OID(0);
682 int prettyFlags;
683 char *res;
684
685 prettyFlags = PRETTYFLAG_INDENT;
686
687 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
688
689 if (res == NULL)
691
693}
static char * pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
Definition: ruleutils.c:789

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

◆ pg_get_viewdef_ext()

Datum pg_get_viewdef_ext ( PG_FUNCTION_ARGS  )

Definition at line 697 of file ruleutils.c.

698{
699 /* By OID */
700 Oid viewoid = PG_GETARG_OID(0);
701 bool pretty = PG_GETARG_BOOL(1);
702 int prettyFlags;
703 char *res;
704
705 prettyFlags = GET_PRETTY_FLAGS(pretty);
706
707 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
708
709 if (res == NULL)
711
713}

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

◆ pg_get_viewdef_name()

Datum pg_get_viewdef_name ( PG_FUNCTION_ARGS  )

Definition at line 736 of file ruleutils.c.

737{
738 /* By qualified name */
739 text *viewname = PG_GETARG_TEXT_PP(0);
740 int prettyFlags;
741 RangeVar *viewrel;
742 Oid viewoid;
743 char *res;
744
745 prettyFlags = PRETTYFLAG_INDENT;
746
747 /* Look up view name. Can't lock it - we might not have privileges. */
749 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
750
751 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
752
753 if (res == NULL)
755
757}

References makeRangeVarFromNameList(), NoLock, pg_get_viewdef_worker(), PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, PRETTYFLAG_INDENT, RangeVarGetRelid, 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 761 of file ruleutils.c.

762{
763 /* By qualified name */
764 text *viewname = PG_GETARG_TEXT_PP(0);
765 bool pretty = PG_GETARG_BOOL(1);
766 int prettyFlags;
767 RangeVar *viewrel;
768 Oid viewoid;
769 char *res;
770
771 prettyFlags = GET_PRETTY_FLAGS(pretty);
772
773 /* Look up view name. Can't lock it - we might not have privileges. */
775 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
776
777 res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
778
779 if (res == NULL)
781
783}

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

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

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

717{
718 /* By OID */
719 Oid viewoid = PG_GETARG_OID(0);
720 int wrap = PG_GETARG_INT32(1);
721 int prettyFlags;
722 char *res;
723
724 /* calling this implies we want pretty printing */
725 prettyFlags = GET_PRETTY_FLAGS(true);
726
727 res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
728
729 if (res == NULL)
731
733}

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

◆ pop_ancestor_plan()

static void pop_ancestor_plan ( deparse_namespace dpns,
deparse_namespace save_dpns 
)
static

Definition at line 5331 of file ruleutils.c.

5332{
5333 /* Free the ancestor list made in push_ancestor_plan */
5334 list_free(dpns->ancestors);
5335
5336 /* Restore fields changed by push_ancestor_plan */
5337 *dpns = *save_dpns;
5338}
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 5280 of file ruleutils.c.

5281{
5282 List *ancestors;
5283
5284 /* Get rid of ancestors list cell added by push_child_plan */
5285 ancestors = list_delete_first(dpns->ancestors);
5286
5287 /* Restore fields changed by push_child_plan */
5288 *dpns = *save_dpns;
5289
5290 /* Make sure dpns->ancestors is right (may be unnecessary) */
5291 dpns->ancestors = ancestors;
5292}

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

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

3261{
3262 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3263 int ntabargs = 0;
3264 StringInfoData rbuf;
3265
3266 initStringInfo(&rbuf);
3267
3268 if (proc->proretset)
3269 {
3270 /* It might be a table function; try to print the arguments */
3271 appendStringInfoString(&rbuf, "TABLE(");
3272 ntabargs = print_function_arguments(&rbuf, proctup, true, false);
3273 if (ntabargs > 0)
3274 appendStringInfoChar(&rbuf, ')');
3275 else
3276 resetStringInfo(&rbuf);
3277 }
3278
3279 if (ntabargs == 0)
3280 {
3281 /* Not a table function, so do the normal thing */
3282 if (proc->proretset)
3283 appendStringInfoString(&rbuf, "SETOF ");
3284 appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3285 }
3286
3287 appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3288}

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

3557{
3558 int numargs;
3559 Oid *argtypes;
3560 char **argnames;
3561 char *argmodes;
3562 deparse_namespace dpns = {0};
3563 Datum tmp;
3564 Node *n;
3565
3566 dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
3567 numargs = get_func_arg_info(proctup,
3568 &argtypes, &argnames, &argmodes);
3569 dpns.numargs = numargs;
3570 dpns.argnames = argnames;
3571
3572 tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
3574
3575 if (IsA(n, List))
3576 {
3577 List *stmts;
3578 ListCell *lc;
3579
3580 stmts = linitial(castNode(List, n));
3581
3582 appendStringInfoString(buf, "BEGIN ATOMIC\n");
3583
3584 foreach(lc, stmts)
3585 {
3586 Query *query = lfirst_node(Query, lc);
3587
3588 /* It seems advisable to get at least AccessShareLock on rels */
3589 AcquireRewriteLocks(query, false, false);
3590 get_query_def(query, buf, list_make1(&dpns), NULL, false,
3594 }
3595
3597 }
3598 else
3599 {
3600 Query *query = castNode(Query, n);
3601
3602 /* It seems advisable to get at least AccessShareLock on rels */
3603 AcquireRewriteLocks(query, false, false);
3604 get_query_def(query, buf, list_make1(&dpns), NULL, false,
3605 0, WRAP_COLUMN_DEFAULT, 0);
3606 }
3607}
char * pstrdup(const char *in)
Definition: mcxt.c:1703

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

3459{
3460 Oid *trftypes;
3461 int ntypes;
3462
3463 ntypes = get_func_trftypes(proctup, &trftypes);
3464 if (ntypes > 0)
3465 {
3466 int i;
3467
3468 appendStringInfoString(buf, " TRANSFORM ");
3469 for (i = 0; i < ntypes; i++)
3470 {
3471 if (i != 0)
3473 appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3474 }
3476 }
3477}
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 12999 of file ruleutils.c.

13000{
13001 StringInfo buf = context->buf;
13002 ListCell *lowlist_item;
13003 ListCell *uplist_item;
13004
13005 lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
13006 foreach(uplist_item, sbsref->refupperindexpr)
13007 {
13009 if (lowlist_item)
13010 {
13011 /* If subexpression is NULL, get_rule_expr prints nothing */
13012 get_rule_expr((Node *) lfirst(lowlist_item), context, false);
13014 lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
13015 }
13016 /* If subexpression is NULL, get_rule_expr prints nothing */
13017 get_rule_expr((Node *) lfirst(uplist_item), context, false);
13019 }
13020}
List * refupperindexpr
Definition: primnodes.h:710
List * reflowerindexpr
Definition: primnodes.h:716

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

12922{
12923 StringInfo buf = context->buf;
12924 CoerceToDomain *cdomain = NULL;
12925
12926 for (;;)
12927 {
12928 if (node == NULL)
12929 break;
12930 if (IsA(node, FieldStore))
12931 {
12932 FieldStore *fstore = (FieldStore *) node;
12933 Oid typrelid;
12934 char *fieldname;
12935
12936 /* lookup tuple type */
12937 typrelid = get_typ_typrelid(fstore->resulttype);
12938 if (!OidIsValid(typrelid))
12939 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
12940 format_type_be(fstore->resulttype));
12941
12942 /*
12943 * Print the field name. There should only be one target field in
12944 * stored rules. There could be more than that in executable
12945 * target lists, but this function cannot be used for that case.
12946 */
12947 Assert(list_length(fstore->fieldnums) == 1);
12948 fieldname = get_attname(typrelid,
12949 linitial_int(fstore->fieldnums), false);
12950 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
12951
12952 /*
12953 * We ignore arg since it should be an uninteresting reference to
12954 * the target column or subcolumn.
12955 */
12956 node = (Node *) linitial(fstore->newvals);
12957 }
12958 else if (IsA(node, SubscriptingRef))
12959 {
12960 SubscriptingRef *sbsref = (SubscriptingRef *) node;
12961
12962 if (sbsref->refassgnexpr == NULL)
12963 break;
12964
12965 printSubscripts(sbsref, context);
12966
12967 /*
12968 * We ignore refexpr since it should be an uninteresting reference
12969 * to the target column or subcolumn.
12970 */
12971 node = (Node *) sbsref->refassgnexpr;
12972 }
12973 else if (IsA(node, CoerceToDomain))
12974 {
12975 cdomain = (CoerceToDomain *) node;
12976 /* If it's an explicit domain coercion, we're done */
12977 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
12978 break;
12979 /* Tentatively descend past the CoerceToDomain */
12980 node = (Node *) cdomain->arg;
12981 }
12982 else
12983 break;
12984 }
12985
12986 /*
12987 * If we descended past a CoerceToDomain whose argument turned out not to
12988 * be a FieldStore or array assignment, back up to the CoerceToDomain.
12989 * (This is not enough to be fully correct if there are nested implicit
12990 * CoerceToDomains, but such cases shouldn't ever occur.)
12991 */
12992 if (cdomain && node == (Node *) cdomain->arg)
12993 node = (Node *) cdomain;
12994
12995 return node;
12996}
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2871
#define linitial_int(l)
Definition: pg_list.h:179

References appendStringInfo(), CoerceToDomain::arg, Assert(), deparse_context::buf, buf, COERCE_IMPLICIT_CAST, 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 5310 of file ruleutils.c.

5312{
5313 Plan *plan = (Plan *) lfirst(ancestor_cell);
5314
5315 /* Save state for restoration later */
5316 *save_dpns = *dpns;
5317
5318 /* Build a new ancestor list with just this node's ancestors */
5319 dpns->ancestors =
5321 list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5322
5323 /* Set attention on selected ancestor */
5324 set_deparse_plan(dpns, plan);
5325}
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:5152

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

5265{
5266 /* Save state for restoration later */
5267 *save_dpns = *dpns;
5268
5269 /* Link current plan node into ancestors list */
5270 dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5271
5272 /* Set attention on selected child */
5273 set_deparse_plan(dpns, plan);
5274}

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

13030{
13031 /*
13032 * Can avoid quoting if ident starts with a lowercase letter or underscore
13033 * and contains only lowercase letters, digits, and underscores, *and* is
13034 * not any SQL keyword. Otherwise, supply quotes.
13035 */
13036 int nquotes = 0;
13037 bool safe;
13038 const char *ptr;
13039 char *result;
13040 char *optr;
13041
13042 /*
13043 * would like to use <ctype.h> macros here, but they might yield unwanted
13044 * locale-specific results...
13045 */
13046 safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
13047
13048 for (ptr = ident; *ptr; ptr++)
13049 {
13050 char ch = *ptr;
13051
13052 if ((ch >= 'a' && ch <= 'z') ||
13053 (ch >= '0' && ch <= '9') ||
13054 (ch == '_'))
13055 {
13056 /* okay */
13057 }
13058 else
13059 {
13060 safe = false;
13061 if (ch == '"')
13062 nquotes++;
13063 }
13064 }
13065
13067 safe = false;
13068
13069 if (safe)
13070 {
13071 /*
13072 * Check for keyword. We quote keywords except for unreserved ones.
13073 * (In some cases we could avoid quoting a col_name or type_func_name
13074 * keyword, but it seems much harder than it's worth to tell that.)
13075 *
13076 * Note: ScanKeywordLookup() does case-insensitive comparison, but
13077 * that's fine, since we already know we have all-lower-case.
13078 */
13079 int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
13080
13081 if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
13082 safe = false;
13083 }
13084
13085 if (safe)
13086 return ident; /* no change needed */
13087
13088 result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
13089
13090 optr = result;
13091 *optr++ = '"';
13092 for (ptr = ident; *ptr; ptr++)
13093 {
13094 char ch = *ptr;
13095
13096 if (ch == '"')
13097 *optr++ = '"';
13098 *optr++ = ch;
13099 }
13100 *optr++ = '"';
13101 *optr = '\0';
13102
13103 return result;
13104}
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:339

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_returning_clause(), 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(), overexplain_alias(), overexplain_range_table(), 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(), process_extension_updates(), processIndirection(), quote_ident(), quote_object_name(), quote_qualified_identifier(), regnamespaceout(), regoperout(), regroleout(), ReplicationSlotDropAtPubNode(), sepgsql_attribute_post_create(), sepgsql_database_post_create(), sepgsql_relation_post_create(), sepgsql_schema_post_create(), serialize_deflist(), set_frozenxids(), show_sortorder_options(), show_window_def(), text_format_string_conversion(), tuple_to_stringinfo(), and worker_spi_main().

◆ quote_qualified_identifier()

◆ removeStringInfoSpaces()

static void removeStringInfoSpaces ( StringInfo  str)
static

Definition at line 9136 of file ruleutils.c.

9137{
9138 while (str->len > 0 && str->data[str->len - 1] == ' ')
9139 str->data[--(str->len)] = '\0';
9140}

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

7911{
7912 Var *var;
7913 deparse_namespace *dpns;
7914
7915 /* This function is recursive, so let's be paranoid. */
7917
7918 /* If it's not a Var, invoke the callback. */
7919 if (!IsA(node, Var))
7920 {
7921 (*callback) (node, context, callback_arg);
7922 return;
7923 }
7924
7925 /* Find appropriate nesting depth */
7926 var = (Var *) node;
7927 dpns = (deparse_namespace *) list_nth(context->namespaces,
7928 var->varlevelsup);
7929
7930 /*
7931 * If varno is special, recurse. (Don't worry about varnosyn; if we're
7932 * here, we already decided not to use that.)
7933 */
7934 if (var->varno == OUTER_VAR && dpns->outer_tlist)
7935 {
7936 TargetEntry *tle;
7937 deparse_namespace save_dpns;
7938 Bitmapset *save_appendparents;
7939
7940 tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
7941 if (!tle)
7942 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7943
7944 /*
7945 * If we're descending to the first child of an Append or MergeAppend,
7946 * update appendparents. This will affect deparsing of all Vars
7947 * appearing within the eventually-resolved subexpression.
7948 */
7949 save_appendparents = context->appendparents;
7950
7951 if (IsA(dpns->plan, Append))
7952 context->appendparents = bms_union(context->appendparents,
7953 ((Append *) dpns->plan)->apprelids);
7954 else if (IsA(dpns->plan, MergeAppend))
7955 context->appendparents = bms_union(context->appendparents,
7956 ((MergeAppend *) dpns->plan)->apprelids);
7957
7958 push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7959 resolve_special_varno((Node *) tle->expr, context,
7960 callback, callback_arg);
7961 pop_child_plan(dpns, &save_dpns);
7962 context->appendparents = save_appendparents;
7963 return;
7964 }
7965 else if (var->varno == INNER_VAR && dpns->inner_tlist)
7966 {
7967 TargetEntry *tle;
7968 deparse_namespace save_dpns;
7969
7970 tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
7971 if (!tle)
7972 elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7973
7974 push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7975 resolve_special_varno((Node *) tle->expr, context,
7976 callback, callback_arg);
7977 pop_child_plan(dpns, &save_dpns);
7978 return;
7979 }
7980 else if (var->varno == INDEX_VAR && dpns->index_tlist)
7981 {
7982 TargetEntry *tle;
7983
7984 tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
7985 if (!tle)
7986 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
7987
7988 resolve_special_varno((Node *) tle->expr, context,
7989 callback, callback_arg);
7990 return;
7991 }
7992 else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
7993 elog(ERROR, "bogus varno: %d", var->varno);
7994
7995 /* Not special. Just invoke the callback. */
7996 (*callback) (node, context, callback_arg);
7997}
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 deparse_context::appendparents, bms_union(), callback(), check_stack_depth(), 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_context::namespaces, deparse_namespace::outer_plan, deparse_namespace::outer_tlist, OUTER_VAR, deparse_namespace::plan, pop_child_plan(), push_child_plan(), resolve_special_varno(), deparse_namespace::rtable, Var::varattno, Var::varlevelsup, and Var::varno.

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

◆ select_rtable_names_for_explain()

List * select_rtable_names_for_explain ( List rtable,
Bitmapset rels_used 
)

Definition at line 3855 of file ruleutils.c.

3856{
3857 deparse_namespace dpns;
3858
3859 memset(&dpns, 0, sizeof(dpns));
3860 dpns.rtable = rtable;
3861 dpns.subplans = NIL;
3862 dpns.ctes = NIL;
3863 dpns.appendrels = NULL;
3864 set_rtable_names(&dpns, NIL, rels_used);
3865 /* We needn't bother computing column aliases yet */
3866
3867 return dpns.rtable_names;
3868}

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

3826{
3827 deparse_namespace *dpns;
3828
3829 /* Should always have one-entry namespace list for Plan deparsing */
3830 Assert(list_length(dpcontext) == 1);
3831 dpns = (deparse_namespace *) linitial(dpcontext);
3832
3833 /* Set our attention on the specific plan node passed in */
3834 dpns->ancestors = ancestors;
3835 set_deparse_plan(dpns, plan);
3836
3837 /* For ModifyTable, set aliases for OLD and NEW in RETURNING */
3838 if (IsA(plan, ModifyTable))
3839 {
3840 dpns->ret_old_alias = ((ModifyTable *) plan)->returningOldAlias;
3841 dpns->ret_new_alias = ((ModifyTable *) plan)->returningNewAlias;
3842 }
3843
3844 return dpcontext;
3845}

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

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

◆ set_deparse_for_query()

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

Definition at line 4029 of file ruleutils.c.

4031{
4032 ListCell *lc;
4033 ListCell *lc2;
4034
4035 /* Initialize *dpns and fill rtable/ctes links */
4036 memset(dpns, 0, sizeof(deparse_namespace));
4037 dpns->rtable = query->rtable;
4038 dpns->subplans = NIL;
4039 dpns->ctes = query->cteList;
4040 dpns->appendrels = NULL;
4041 dpns->ret_old_alias = query->returningOldAlias;
4042 dpns->ret_new_alias = query->returningNewAlias;
4043
4044 /* Assign a unique relation alias to each RTE */
4045 set_rtable_names(dpns, parent_namespaces, NULL);
4046
4047 /* Initialize dpns->rtable_columns to contain zeroed structs */
4048 dpns->rtable_columns = NIL;
4049 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4051 palloc0(sizeof(deparse_columns)));
4052
4053 /* If it's a utility query, it won't have a jointree */
4054 if (query->jointree)
4055 {
4056 /* Detect whether global uniqueness of USING names is needed */
4057 dpns->unique_using =
4058 has_dangerous_join_using(dpns, (Node *) query->jointree);
4059
4060 /*
4061 * Select names for columns merged by USING, via a recursive pass over
4062 * the query jointree.
4063 */
4064 set_using_names(dpns, (Node *) query->jointree, NIL);
4065 }
4066
4067 /*
4068 * Now assign remaining column aliases for each RTE. We do this in a
4069 * linear scan of the rtable, so as to process RTEs whether or not they
4070 * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
4071 * etc). JOIN RTEs must be processed after their children, but this is
4072 * okay because they appear later in the rtable list than their children
4073 * (cf Asserts in identify_join_columns()).
4074 */
4075 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4076 {
4077 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4078 deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4079
4080 if (rte->rtekind == RTE_JOIN)
4081 set_join_column_names(dpns, rte, colinfo);
4082 else
4083 set_relation_column_names(dpns, rte, colinfo);
4084 }
4085}
static void set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition: ruleutils.c:4375
static void set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
Definition: ruleutils.c:4210
static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition: ruleutils.c:4578
List * rtable_columns
Definition: ruleutils.c:166

References deparse_namespace::appendrels, Query::cteList, deparse_namespace::ctes, forboth, has_dangerous_join_using(), Query::jointree, lappend(), lfirst, list_length(), NIL, palloc0(), deparse_namespace::ret_new_alias, deparse_namespace::ret_old_alias, 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 5152 of file ruleutils.c.

5153{
5154 dpns->plan = plan;
5155
5156 /*
5157 * We special-case Append and MergeAppend to pretend that the first child
5158 * plan is the OUTER referent; we have to interpret OUTER Vars in their
5159 * tlists according to one of the children, and the first one is the most
5160 * natural choice.
5161 */
5162 if (IsA(plan, Append))
5163 dpns->outer_plan = linitial(((Append *) plan)->appendplans);
5164 else if (IsA(plan, MergeAppend))
5165 dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
5166 else
5167 dpns->outer_plan = outerPlan(plan);
5168
5169 if (dpns->outer_plan)
5170 dpns->outer_tlist = dpns->outer_plan->targetlist;
5171 else
5172 dpns->outer_tlist = NIL;
5173
5174 /*
5175 * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
5176 * use OUTER because that could someday conflict with the normal meaning.)
5177 * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
5178 * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
5179 * that as INNER referent.
5180 *
5181 * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
5182 * INNER referent. This is the join from the target relation to the data
5183 * source, and all INNER_VAR Vars in other parts of the query refer to its
5184 * targetlist.
5185 *
5186 * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
5187 * excluded expression's tlist. (Similar to the SubqueryScan we don't want
5188 * to reuse OUTER, it's used for RETURNING in some modify table cases,
5189 * although not INSERT .. CONFLICT).
5190 */
5191 if (IsA(plan, SubqueryScan))
5192 dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
5193 else if (IsA(plan, CteScan))
5194 dpns->inner_plan = list_nth(dpns->subplans,
5195 ((CteScan *) plan)->ctePlanId - 1);
5196 else if (IsA(plan, WorkTableScan))
5197 dpns->inner_plan = find_recursive_union(dpns,
5198 (WorkTableScan *) plan);
5199 else if (IsA(plan, ModifyTable))
5200 {
5201 if (((ModifyTable *) plan)->operation == CMD_MERGE)
5202 dpns->inner_plan = outerPlan(plan);
5203 else
5204 dpns->inner_plan = plan;
5205 }
5206 else
5207 dpns->inner_plan = innerPlan(plan);
5208
5209 if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
5210 dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5211 else if (dpns->inner_plan)
5212 dpns->inner_tlist = dpns->inner_plan->targetlist;
5213 else
5214 dpns->inner_tlist = NIL;
5215
5216 /* Set up referent for INDEX_VAR Vars, if needed */
5217 if (IsA(plan, IndexOnlyScan))
5218 dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5219 else if (IsA(plan, ForeignScan))
5220 dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5221 else if (IsA(plan, CustomScan))
5222 dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5223 else
5224 dpns->index_tlist = NIL;
5225}
#define outerPlan(node)
Definition: plannodes.h:234
static Plan * find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
Definition: ruleutils.c:5233

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

4580{
4581 deparse_columns *leftcolinfo;
4582 deparse_columns *rightcolinfo;
4583 bool changed_any;
4584 int noldcolumns;
4585 int nnewcolumns;
4586 Bitmapset *leftmerged = NULL;
4587 Bitmapset *rightmerged = NULL;
4588 int i;
4589 int j;
4590 int ic;
4591 int jc;
4592
4593 /* Look up the previously-filled-in child deparse_columns structs */
4594 leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4595 rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4596
4597 /*
4598 * Ensure colinfo->colnames has a slot for each column. (It could be long
4599 * enough already, if we pushed down a name for the last column.) Note:
4600 * it's possible that one or both inputs now have more columns than there
4601 * were when the query was parsed, but we'll deal with that below. We
4602 * only need entries in colnames for pre-existing columns.
4603 */
4604 noldcolumns = list_length(rte->eref->colnames);
4605 expand_colnames_array_to(colinfo, noldcolumns);
4606 Assert(colinfo->num_cols == noldcolumns);
4607
4608 /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4609 build_colinfo_names_hash(colinfo);
4610
4611 /*
4612 * Scan the join output columns, select an alias for each one, and store
4613 * it in colinfo->colnames. If there are USING columns, set_using_names()
4614 * already selected their names, so we can start the loop at the first
4615 * non-merged column.
4616 */
4617 changed_any = false;
4618 for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4619 {
4620 char *colname = colinfo->colnames[i];
4621 char *real_colname;
4622
4623 /* Join column must refer to at least one input column */
4624 Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4625
4626 /* Get the child column name */
4627 if (colinfo->leftattnos[i] > 0)
4628 real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4629 else if (colinfo->rightattnos[i] > 0)
4630 real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4631 else
4632 {
4633 /* We're joining system columns --- use eref name */
4634 real_colname = strVal(list_nth(rte->eref->colnames, i));
4635 }
4636
4637 /* If child col has been dropped, no need to assign a join colname */
4638 if (real_colname == NULL)
4639 {
4640 colinfo->colnames[i] = NULL;
4641 continue;
4642 }
4643
4644 /* In an unnamed join, just report child column names as-is */
4645 if (rte->alias == NULL)
4646 {
4647 colinfo->colnames[i] = real_colname;
4648 add_to_names_hash(colinfo, real_colname);
4649 continue;
4650 }
4651
4652 /* If alias already assigned, that's what to use */
4653 if (colname == NULL)
4654 {
4655 /* If user wrote an alias, prefer that over real column name */
4656 if (rte->alias && i < list_length(rte->alias->colnames))
4657 colname = strVal(list_nth(rte->alias->colnames, i));
4658 else
4659 colname = real_colname;
4660
4661 /* Unique-ify and insert into colinfo */
4662 colname = make_colname_unique(colname, dpns, colinfo);
4663
4664 colinfo->colnames[i] = colname;
4665 add_to_names_hash(colinfo, colname);
4666 }
4667
4668 /* Remember if any assigned aliases differ from "real" name */
4669 if (!changed_any && strcmp(colname, real_colname) != 0)
4670 changed_any = true;
4671 }
4672
4673 /*
4674 * Calculate number of columns the join would have if it were re-parsed
4675 * now, and create storage for the new_colnames and is_new_col arrays.
4676 *
4677 * Note: colname_is_unique will be consulting new_colnames[] during the
4678 * loops below, so its not-yet-filled entries must be zeroes.
4679 */
4680 nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4681 list_length(colinfo->usingNames);
4682 colinfo->num_new_cols = nnewcolumns;
4683 colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
4684 colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
4685
4686 /*
4687 * Generating the new_colnames array is a bit tricky since any new columns
4688 * added since parse time must be inserted in the right places. This code
4689 * must match the parser, which will order a join's columns as merged
4690 * columns first (in USING-clause order), then non-merged columns from the
4691 * left input (in attnum order), then non-merged columns from the right
4692 * input (ditto). If one of the inputs is itself a join, its columns will
4693 * be ordered according to the same rule, which means newly-added columns
4694 * might not be at the end. We can figure out what's what by consulting
4695 * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4696 *
4697 * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4698 * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4699 * meanings for the current child RTE.
4700 */
4701
4702 /* Handle merged columns; they are first and can't be new */
4703 i = j = 0;
4704 while (i < noldcolumns &&
4705 colinfo->leftattnos[i] != 0 &&
4706 colinfo->rightattnos[i] != 0)
4707 {
4708 /* column name is already determined and known unique */
4709 colinfo->new_colnames[j] = colinfo->colnames[i];
4710 colinfo->is_new_col[j] = false;
4711
4712 /* build bitmapsets of child attnums of merged columns */
4713 if (colinfo->leftattnos[i] > 0)
4714 leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
4715 if (colinfo->rightattnos[i] > 0)
4716 rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4717
4718 i++, j++;
4719 }
4720
4721 /* Handle non-merged left-child columns */
4722 ic = 0;
4723 for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4724 {
4725 char *child_colname = leftcolinfo->new_colnames[jc];
4726
4727 if (!leftcolinfo->is_new_col[jc])
4728 {
4729 /* Advance ic to next non-dropped old column of left child */
4730 while (ic < leftcolinfo->num_cols &&
4731 leftcolinfo->colnames[ic] == NULL)
4732 ic++;
4733 Assert(ic < leftcolinfo->num_cols);
4734 ic++;
4735 /* If it is a merged column, we already processed it */
4736 if (bms_is_member(ic, leftmerged))
4737 continue;
4738 /* Else, advance i to the corresponding existing join column */
4739 while (i < colinfo->num_cols &&
4740 colinfo->colnames[i] == NULL)
4741 i++;
4742 Assert(i < colinfo->num_cols);
4743 Assert(ic == colinfo->leftattnos[i]);
4744 /* Use the already-assigned name of this column */
4745 colinfo->new_colnames[j] = colinfo->colnames[i];
4746 i++;
4747 }
4748 else
4749 {
4750 /*
4751 * Unique-ify the new child column name and assign, unless we're
4752 * in an unnamed join, in which case just copy
4753 */
4754 if (rte->alias != NULL)
4755 {
4756 colinfo->new_colnames[j] =
4757 make_colname_unique(child_colname, dpns, colinfo);
4758 if (!changed_any &&
4759 strcmp(colinfo->new_colnames[j], child_colname) != 0)
4760 changed_any = true;
4761 }
4762 else
4763 colinfo->new_colnames[j] = child_colname;
4764 add_to_names_hash(colinfo, colinfo->new_colnames[j]);
4765 }
4766
4767 colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4768 j++;
4769 }
4770
4771 /* Handle non-merged right-child columns in exactly the same way */
4772 ic = 0;
4773 for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4774 {
4775 char *child_colname = rightcolinfo->new_colnames[jc];
4776
4777 if (!rightcolinfo->is_new_col[jc])
4778 {
4779 /* Advance ic to next non-dropped old column of right child */
4780 while (ic < rightcolinfo->num_cols &&
4781 rightcolinfo->colnames[ic] == NULL)
4782 ic++;
4783 Assert(ic < rightcolinfo->num_cols);
4784 ic++;
4785 /* If it is a merged column, we already processed it */
4786 if (bms_is_member(ic, rightmerged))
4787 continue;
4788 /* Else, advance i to the corresponding existing join column */
4789 while (i < colinfo->num_cols &&
4790 colinfo->colnames[i] == NULL)
4791 i++;
4792 Assert(i < colinfo->num_cols);
4793 Assert(ic == colinfo->rightattnos[i]);
4794 /* Use the already-assigned name of this column */
4795 colinfo->new_colnames[j] = colinfo->colnames[i];
4796 i++;
4797 }
4798 else
4799 {
4800 /*
4801 * Unique-ify the new child column name and assign, unless we're
4802 * in an unnamed join, in which case just copy
4803 */
4804 if (rte->alias != NULL)
4805 {
4806 colinfo->new_colnames[j] =
4807 make_colname_unique(child_colname, dpns, colinfo);
4808 if (!changed_any &&
4809 strcmp(colinfo->new_colnames[j], child_colname) != 0)
4810 changed_any = true;
4811 }
4812 else
4813 colinfo->new_colnames[j] = child_colname;
4814 add_to_names_hash(colinfo, colinfo->new_colnames[j]);
4815 }
4816
4817 colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4818 j++;
4819 }
4820
4821 /* Assert we processed the right number of columns */
4822#ifdef USE_ASSERT_CHECKING
4823 while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4824 i++;
4825 Assert(i == colinfo->num_cols);
4826 Assert(j == nnewcolumns);
4827#endif
4828
4829 /* We're now done needing the colinfo's names_hash */
4831
4832 /*
4833 * For a named join, print column aliases if we changed any from the child
4834 * names. Unnamed joins cannot print aliases.
4835 */
4836 if (rte->alias != NULL)
4837 colinfo->printaliases = changed_any;
4838 else
4839 colinfo->printaliases = false;
4840}
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:4923
static void build_colinfo_names_hash(deparse_columns *colinfo)
Definition: ruleutils.c:4978
static void expand_colnames_array_to(deparse_columns *colinfo, int n)
Definition: ruleutils.c:4962
static void destroy_colinfo_names_hash(deparse_columns *colinfo)
Definition: ruleutils.c:5049
bool * is_new_col
Definition: ruleutils.c:270

References add_to_names_hash(), Assert(), bms_add_member(), bms_is_member(), build_colinfo_names_hash(), deparse_columns::colnames, deparse_columns_fetch, destroy_colinfo_names_hash(), 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 4375 of file ruleutils.c.

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

References AccessShareLock, add_to_names_hash(), Assert(), build_colinfo_names_hash(), deparse_columns::colnames, destroy_colinfo_names_hash(), 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, RTE_FUNCTION, RTE_RELATION, RTE_TABLEFUNC, RangeTblEntry::rtekind, strVal, TupleDescAttr(), and VAR_RETURNING_DEFAULT.

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

3886{
3887 HASHCTL hash_ctl;
3888 HTAB *names_hash;
3889 NameHashEntry *hentry;
3890 bool found;
3891 int rtindex;
3892 ListCell *lc;
3893
3894 dpns->rtable_names = NIL;
3895 /* nothing more to do if empty rtable */
3896 if (dpns->rtable == NIL)
3897 return;
3898
3899 /*
3900 * We use a hash table to hold known names, so that this process is O(N)
3901 * not O(N^2) for N names.
3902 */
3903 hash_ctl.keysize = NAMEDATALEN;
3904 hash_ctl.entrysize = sizeof(NameHashEntry);
3905 hash_ctl.hcxt = CurrentMemoryContext;
3906 names_hash = hash_create("set_rtable_names names",
3907 list_length(dpns->rtable),
3908 &hash_ctl,
3910
3911 /* Preload the hash table with names appearing in parent_namespaces */
3912 foreach(lc, parent_namespaces)
3913 {
3914 deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3915 ListCell *lc2;
3916
3917 foreach(lc2, olddpns->rtable_names)
3918 {
3919 char *oldname = (char *) lfirst(lc2);
3920
3921 if (oldname == NULL)
3922 continue;
3923 hentry = (NameHashEntry *) hash_search(names_hash,
3924 oldname,
3925 HASH_ENTER,
3926 &found);
3927 /* we do not complain about duplicate names in parent namespaces */
3928 hentry->counter = 0;
3929 }
3930 }
3931
3932 /* Now we can scan the rtable */
3933 rtindex = 1;
3934 foreach(lc, dpns->rtable)
3935 {
3936 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3937 char *refname;
3938
3939 /* Just in case this takes an unreasonable amount of time ... */
3941
3942 if (rels_used && !bms_is_member(rtindex, rels_used))
3943 {
3944 /* Ignore unreferenced RTE */
3945 refname = NULL;
3946 }
3947 else if (rte->alias)
3948 {
3949 /* If RTE has a user-defined alias, prefer that */
3950 refname = rte->alias->aliasname;
3951 }
3952 else if (rte->rtekind == RTE_RELATION)
3953 {
3954 /* Use the current actual name of the relation */
3955 refname = get_rel_name(rte->relid);
3956 }
3957 else if (rte->rtekind == RTE_JOIN)
3958 {
3959 /* Unnamed join has no refname */
3960 refname = NULL;
3961 }
3962 else
3963 {
3964 /* Otherwise use whatever the parser assigned */
3965 refname = rte->eref->aliasname;
3966 }
3967
3968 /*
3969 * If the selected name isn't unique, append digits to make it so, and
3970 * make a new hash entry for it once we've got a unique name. For a
3971 * very long input name, we might have to truncate to stay within
3972 * NAMEDATALEN.
3973 */
3974 if (refname)
3975 {
3976 hentry = (NameHashEntry *) hash_search(names_hash,
3977 refname,
3978 HASH_ENTER,
3979 &found);
3980 if (found)
3981 {
3982 /* Name already in use, must choose a new one */
3983 int refnamelen = strlen(refname);
3984 char *modname = (char *) palloc(refnamelen + 16);
3985 NameHashEntry *hentry2;
3986
3987 do
3988 {
3989 hentry->counter++;
3990 for (;;)
3991 {
3992 memcpy(modname, refname, refnamelen);
3993 sprintf(modname + refnamelen, "_%d", hentry->counter);
3994 if (strlen(modname) < NAMEDATALEN)
3995 break;
3996 /* drop chars from refname to keep all the digits */
3997 refnamelen = pg_mbcliplen(refname, refnamelen,
3998 refnamelen - 1);
3999 }
4000 hentry2 = (NameHashEntry *) hash_search(names_hash,
4001 modname,
4002 HASH_ENTER,
4003 &found);
4004 } while (found);
4005 hentry2->counter = 0; /* init new hash entry */
4006 refname = modname;
4007 }
4008 else
4009 {
4010 /* Name not previously used, need only initialize hentry */
4011 hentry->counter = 0;
4012 }
4013 }
4014
4015 dpns->rtable_names = lappend(dpns->rtable_names, refname);
4016 rtindex++;
4017 }
4018
4019 hash_destroy(names_hash);
4020}
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(), 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 4098 of file ruleutils.c.

4099{
4100 ListCell *lc;
4101 ListCell *lc2;
4102
4103 /* Initialize dpns->rtable_columns to contain zeroed structs */
4104 dpns->rtable_columns = NIL;
4105 while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4107 palloc0(sizeof(deparse_columns)));
4108
4109 /* Assign unique column aliases within each non-join RTE */
4110 forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4111 {
4112 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4113 deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4114
4115 if (rte->rtekind != RTE_JOIN)
4116 set_relation_column_names(dpns, rte, colinfo);
4117 }
4118}

References forboth, lappend(), lfirst, list_length(), NIL, palloc0(), deparse_namespace::rtable, deparse_namespace::rtable_columns, RTE_JOIN, RangeTblEntry::rtekind, 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 4210 of file ruleutils.c.

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

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, set_using_names(), strVal, deparse_namespace::unique_using, deparse_namespace::using_names, and deparse_columns::usingNames.

Referenced by set_deparse_for_query(), and set_using_names().

◆ simple_quote_literal()

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

Definition at line 11793 of file ruleutils.c.

11794{
11795 const char *valptr;
11796
11797 /*
11798 * We form the string literal according to the prevailing setting of
11799 * standard_conforming_strings; we never use E''. User is responsible for
11800 * making sure result is used correctly.
11801 */
11803 for (valptr = val; *valptr; valptr++)
11804 {
11805 char ch = *valptr;
11806
11810 }
11812}
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1134
bool standard_conforming_strings
Definition: scan.l:70

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

Referenced by pg_get_ruledef_worker().

◆ plan_getviewrule

SPIPlanPtr plan_getviewrule = NULL
static

Definition at line 335 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 334 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 336 of file ruleutils.c.

Referenced by pg_get_viewdef_worker().

◆ quote_all_identifiers

bool quote_all_identifiers = false

Definition at line 339 of file ruleutils.c.

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