PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 13510 of file ruleutils.c.

13511{
13512 HeapTuple typetup;
13513 Form_pg_type typform;
13514 char *typname;
13515 char *nspname;
13516
13517 typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13518 if (!HeapTupleIsValid(typetup))
13519 elog(ERROR, "cache lookup failed for type %u", typid);
13520 typform = (Form_pg_type) GETSTRUCT(typetup);
13521
13522 typname = NameStr(typform->typname);
13523 nspname = get_namespace_name_or_temp(typform->typnamespace);
13524
13525 appendStringInfo(buf, "::%s.%s",
13527
13528 ReleaseSysCache(typetup);
13529}
#define NameStr(name)
Definition: c.h:751
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#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:3557
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:262
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:13058
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220

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

5036{
5037 if (colinfo->names_hash)
5038 (void) hash_search(colinfo->names_hash,
5039 name,
5040 HASH_ENTER,
5041 NULL);
5042}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
@ 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 9091 of file ruleutils.c.

9093{
9094 StringInfo buf = context->buf;
9095
9096 if (PRETTY_INDENT(context))
9097 {
9098 int indentAmount;
9099
9100 context->indentLevel += indentBefore;
9101
9102 /* remove any trailing spaces currently in the buffer ... */
9104 /* ... then add a newline and some spaces */
9106
9107 if (context->indentLevel < PRETTYINDENT_LIMIT)
9108 indentAmount = Max(context->indentLevel, 0) + indentPlus;
9109 else
9110 {
9111 /*
9112 * If we're indented more than PRETTYINDENT_LIMIT characters, try
9113 * to conserve horizontal space by reducing the per-level
9114 * indentation. For best results the scale factor here should
9115 * divide all the indent amounts that get added to indentLevel
9116 * (PRETTYINDENT_STD, etc). It's important that the indentation
9117 * not grow unboundedly, else deeply-nested trees use O(N^2)
9118 * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
9119 */
9120 indentAmount = PRETTYINDENT_LIMIT +
9121 (context->indentLevel - PRETTYINDENT_LIMIT) /
9122 (PRETTYINDENT_STD / 2);
9123 indentAmount %= PRETTYINDENT_LIMIT;
9124 /* scale/wrap logic affects indentLevel, but not indentPlus */
9125 indentAmount += indentPlus;
9126 }
9127 appendStringInfoSpaces(buf, indentAmount);
9128
9130
9131 context->indentLevel += indentAfter;
9132 if (context->indentLevel < 0)
9133 context->indentLevel = 0;
9134 }
9135 else
9137}
#define Max(x, y)
Definition: c.h:997
const char * str
static void removeStringInfoSpaces(StringInfo str)
Definition: ruleutils.c:9145
#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 4977 of file ruleutils.c.

4978{
4979 HASHCTL hash_ctl;
4980 int i;
4981 ListCell *lc;
4982
4983 /*
4984 * Use a hash table only for RTEs with at least 32 columns. (The cutoff
4985 * is somewhat arbitrary, but let's choose it so that this code does get
4986 * exercised in the regression tests.)
4987 */
4988 if (colinfo->num_cols < 32)
4989 return;
4990
4991 /*
4992 * Set up the hash table. The entries are just strings with no other
4993 * payload.
4994 */
4995 hash_ctl.keysize = NAMEDATALEN;
4996 hash_ctl.entrysize = NAMEDATALEN;
4997 hash_ctl.hcxt = CurrentMemoryContext;
4998 colinfo->names_hash = hash_create("deparse_columns names",
4999 colinfo->num_cols + colinfo->num_new_cols,
5000 &hash_ctl,
5002
5003 /*
5004 * Preload the hash table with any names already present (these would have
5005 * come from set_using_names).
5006 */
5007 for (i = 0; i < colinfo->num_cols; i++)
5008 {
5009 char *oldname = colinfo->colnames[i];
5010
5011 if (oldname)
5012 add_to_names_hash(colinfo, oldname);
5013 }
5014
5015 for (i = 0; i < colinfo->num_new_cols; i++)
5016 {
5017 char *oldname = colinfo->new_colnames[i];
5018
5019 if (oldname)
5020 add_to_names_hash(colinfo, oldname);
5021 }
5022
5023 foreach(lc, colinfo->parentUsing)
5024 {
5025 char *oldname = (char *) lfirst(lc);
5026
5027 add_to_names_hash(colinfo, oldname);
5028 }
5029}
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:358
#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:160
#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:5035
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 4847 of file ruleutils.c.

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

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

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

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

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

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

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

3674{
3676 deparse_context context;
3677
3679 context.buf = &buf;
3680 context.namespaces = dpcontext;
3681 context.resultDesc = NULL;
3682 context.targetList = NIL;
3683 context.windowClause = NIL;
3684 context.varprefix = forceprefix;
3685 context.prettyFlags = prettyFlags;
3687 context.indentLevel = startIndent;
3688 context.colNamesVisible = true;
3689 context.inGroupBy = false;
3690 context.varInOrderBy = false;
3691 context.appendparents = NULL;
3692
3693 get_rule_expr(expr, &context, showimplicit);
3694
3695 return buf.data;
3696}
#define WRAP_COLUMN_DEFAULT
Definition: ruleutils.c:98
static void get_rule_expr(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:9261
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 5048 of file ruleutils.c.

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

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

4962{
4963 if (n > colinfo->num_cols)
4964 {
4965 if (colinfo->colnames == NULL)
4966 colinfo->colnames = palloc0_array(char *, n);
4967 else
4968 colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4969 colinfo->num_cols = n;
4970 }
4971}
#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 8570 of file ruleutils.c.

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

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

8668{
8669 foreach_node(SubPlan, subplan, plan->initPlan)
8670 {
8671 foreach_int(paramid, subplan->setParam)
8672 {
8673 if (paramid == param->paramid)
8674 {
8675 /* Found a match, so return it. */
8676 *column_p = foreach_current_index(paramid);
8677 return subplan;
8678 }
8679 }
8680 }
8681 return NULL;
8682}
#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 8456 of file ruleutils.c.

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

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

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

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

13675{
13676 char *result = NULL;
13677 HeapTuple tuple;
13678 Datum reloptions;
13679 bool isnull;
13680
13681 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13682 if (!HeapTupleIsValid(tuple))
13683 elog(ERROR, "cache lookup failed for relation %u", relid);
13684
13685 reloptions = SysCacheGetAttr(RELOID, tuple,
13686 Anum_pg_class_reloptions, &isnull);
13687 if (!isnull)
13688 {
13690
13692 get_reloptions(&buf, reloptions);
13693
13694 result = buf.data;
13695 }
13696
13697 ReleaseSysCache(tuple);
13698
13699 return result;
13700}
static void get_reloptions(StringInfo buf, Datum reloptions)
Definition: ruleutils.c:13619
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:595

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

13575{
13576 HeapTuple tp;
13577 Form_pg_collation colltup;
13578 char *collname;
13579 char *nspname;
13580 char *result;
13581
13582 tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
13583 if (!HeapTupleIsValid(tp))
13584 elog(ERROR, "cache lookup failed for collation %u", collid);
13585 colltup = (Form_pg_collation) GETSTRUCT(tp);
13586 collname = NameStr(colltup->collname);
13587
13589 nspname = get_namespace_name_or_temp(colltup->collnamespace);
13590 else
13591 nspname = NULL;
13592
13593 result = quote_qualified_identifier(nspname, collname);
13594
13595 ReleaseSysCache(tp);
13596
13597 return result;
13598}
Oid collid
bool CollationIsVisible(Oid collid)
Definition: namespace.c:2474
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:58
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:13142

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

13289{
13290 char *result;
13291 HeapTuple proctup;
13292 Form_pg_proc procform;
13293 char *proname;
13294 bool use_variadic;
13295 char *nspname;
13296 FuncDetailCode p_result;
13297 int fgc_flags;
13298 Oid p_funcid;
13299 Oid p_rettype;
13300 bool p_retset;
13301 int p_nvargs;
13302 Oid p_vatype;
13303 Oid *p_true_typeids;
13304 bool force_qualify = false;
13305
13306 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
13307 if (!HeapTupleIsValid(proctup))
13308 elog(ERROR, "cache lookup failed for function %u", funcid);
13309 procform = (Form_pg_proc) GETSTRUCT(proctup);
13310 proname = NameStr(procform->proname);
13311
13312 /*
13313 * Due to parser hacks to avoid needing to reserve CUBE, we need to force
13314 * qualification of some function names within GROUP BY.
13315 */
13316 if (inGroupBy)
13317 {
13318 if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
13319 force_qualify = true;
13320 }
13321
13322 /*
13323 * Determine whether VARIADIC should be printed. We must do this first
13324 * since it affects the lookup rules in func_get_detail().
13325 *
13326 * We always print VARIADIC if the function has a merged variadic-array
13327 * argument. Note that this is always the case for functions taking a
13328 * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
13329 * and printed the array elements as separate arguments, the call could
13330 * match a newer non-VARIADIC function.
13331 */
13332 if (use_variadic_p)
13333 {
13334 /* Parser should not have set funcvariadic unless fn is variadic */
13335 Assert(!has_variadic || OidIsValid(procform->provariadic));
13336 use_variadic = has_variadic;
13337 *use_variadic_p = use_variadic;
13338 }
13339 else
13340 {
13341 Assert(!has_variadic);
13342 use_variadic = false;
13343 }
13344
13345 /*
13346 * The idea here is to schema-qualify only if the parser would fail to
13347 * resolve the correct function given the unqualified func name with the
13348 * specified argtypes and VARIADIC flag. But if we already decided to
13349 * force qualification, then we can skip the lookup and pretend we didn't
13350 * find it.
13351 */
13352 if (!force_qualify)
13354 NIL, argnames, nargs, argtypes,
13355 !use_variadic, true, false,
13356 &fgc_flags,
13357 &p_funcid, &p_rettype,
13358 &p_retset, &p_nvargs, &p_vatype,
13359 &p_true_typeids, NULL);
13360 else
13361 {
13362 p_result = FUNCDETAIL_NOTFOUND;
13363 p_funcid = InvalidOid;
13364 }
13365
13366 if ((p_result == FUNCDETAIL_NORMAL ||
13367 p_result == FUNCDETAIL_AGGREGATE ||
13368 p_result == FUNCDETAIL_WINDOWFUNC) &&
13369 p_funcid == funcid)
13370 nspname = NULL;
13371 else
13372 nspname = get_namespace_name_or_temp(procform->pronamespace);
13373
13374 result = quote_qualified_identifier(nspname, proname);
13375
13376 ReleaseSysCache(proctup);
13377
13378 return result;
13379}
#define OidIsValid(objectId)
Definition: c.h:774
FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, bool include_out_arguments, int *fgc_flags, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, Oid **true_typeids, List **argdefaults)
Definition: parse_func.c:1513
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:37
unsigned int Oid
Definition: postgres_ext.h:32
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 12928 of file ruleutils.c.

12929{
12931
12933 get_opclass_name(opclass, InvalidOid, &buf);
12934
12935 return &buf.data[1]; /* get_opclass_name() prepends space */
12936}
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Definition: ruleutils.c:12890

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

13474{
13475 HeapTuple opertup;
13476 Form_pg_operator operform;
13477 char *oprname;
13478 char *nspname;
13479
13480 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
13481 if (!HeapTupleIsValid(opertup))
13482 elog(ERROR, "cache lookup failed for operator %u", opoid);
13483 operform = (Form_pg_operator) GETSTRUCT(opertup);
13484 Assert(operform->oprkind == 'b');
13485 oprname = NameStr(operform->oprname);
13486
13487 nspname = get_namespace_name(operform->oprnamespace);
13488
13489 appendStringInfoString(buf, leftop);
13490 if (leftoptype != operform->oprleft)
13491 add_cast_to(buf, operform->oprleft);
13492 appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
13493 appendStringInfoString(buf, oprname);
13494 appendStringInfo(buf, ") %s", rightop);
13495 if (rightoptype != operform->oprright)
13496 add_cast_to(buf, operform->oprright);
13497
13498 ReleaseSysCache(opertup);
13499}
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3533
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static void add_cast_to(StringInfo buf, Oid typid)
Definition: ruleutils.c:13510

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

13394{
13396 HeapTuple opertup;
13397 Form_pg_operator operform;
13398 char *oprname;
13399 char *nspname;
13400 Operator p_result;
13401
13403
13404 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
13405 if (!HeapTupleIsValid(opertup))
13406 elog(ERROR, "cache lookup failed for operator %u", operid);
13407 operform = (Form_pg_operator) GETSTRUCT(opertup);
13408 oprname = NameStr(operform->oprname);
13409
13410 /*
13411 * The idea here is to schema-qualify only if the parser would fail to
13412 * resolve the correct operator given the unqualified op name with the
13413 * specified argtypes.
13414 */
13415 switch (operform->oprkind)
13416 {
13417 case 'b':
13418 p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
13419 true, -1);
13420 break;
13421 case 'l':
13422 p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
13423 true, -1);
13424 break;
13425 default:
13426 elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
13427 p_result = NULL; /* keep compiler quiet */
13428 break;
13429 }
13430
13431 if (p_result != NULL && oprid(p_result) == operid)
13432 nspname = NULL;
13433 else
13434 {
13435 nspname = get_namespace_name_or_temp(operform->oprnamespace);
13436 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
13437 }
13438
13439 appendStringInfoString(&buf, oprname);
13440
13441 if (nspname)
13443
13444 if (p_result != NULL)
13445 ReleaseSysCache(p_result);
13446
13447 ReleaseSysCache(opertup);
13448
13449 return buf.data;
13450}
Operator left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
Definition: parse_oper.c:521
Oid oprid(Operator op)
Definition: parse_oper.c:239
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:371

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

13243{
13244 HeapTuple tp;
13245 Form_pg_class reltup;
13246 char *relname;
13247 char *nspname;
13248 char *result;
13249
13250 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13251 if (!HeapTupleIsValid(tp))
13252 elog(ERROR, "cache lookup failed for relation %u", relid);
13253 reltup = (Form_pg_class) GETSTRUCT(tp);
13254 relname = NameStr(reltup->relname);
13255
13256 nspname = get_namespace_name_or_temp(reltup->relnamespace);
13257 if (!nspname)
13258 elog(ERROR, "cache lookup failed for namespace %u",
13259 reltup->relnamespace);
13260
13261 result = quote_qualified_identifier(nspname, relname);
13262
13263 ReleaseSysCache(tp);
13264
13265 return result;
13266}
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 13541 of file ruleutils.c.

13542{
13543 HeapTuple tp;
13544 Form_pg_type typtup;
13545 char *typname;
13546 char *nspname;
13547 char *result;
13548
13549 tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13550 if (!HeapTupleIsValid(tp))
13551 elog(ERROR, "cache lookup failed for type %u", typid);
13552 typtup = (Form_pg_type) GETSTRUCT(tp);
13553 typname = NameStr(typtup->typname);
13554
13555 nspname = get_namespace_name_or_temp(typtup->typnamespace);
13556 if (!nspname)
13557 elog(ERROR, "cache lookup failed for namespace %u",
13558 typtup->typnamespace);
13559
13560 result = quote_qualified_identifier(nspname, typname);
13561
13562 ReleaseSysCache(tp);
13563
13564 return result;
13565}

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

13183{
13184 HeapTuple tp;
13185 Form_pg_class reltup;
13186 bool need_qual;
13187 ListCell *nslist;
13188 char *relname;
13189 char *nspname;
13190 char *result;
13191
13192 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13193 if (!HeapTupleIsValid(tp))
13194 elog(ERROR, "cache lookup failed for relation %u", relid);
13195 reltup = (Form_pg_class) GETSTRUCT(tp);
13196 relname = NameStr(reltup->relname);
13197
13198 /* Check for conflicting CTE name */
13199 need_qual = false;
13200 foreach(nslist, namespaces)
13201 {
13202 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
13203 ListCell *ctlist;
13204
13205 foreach(ctlist, dpns->ctes)
13206 {
13207 CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
13208
13209 if (strcmp(cte->ctename, relname) == 0)
13210 {
13211 need_qual = true;
13212 break;
13213 }
13214 }
13215 if (need_qual)
13216 break;
13217 }
13218
13219 /* Otherwise, qualify the name if not visible in search path */
13220 if (!need_qual)
13221 need_qual = !RelationIsVisible(relid);
13222
13223 if (need_qual)
13224 nspname = get_namespace_name_or_temp(reltup->relnamespace);
13225 else
13226 nspname = NULL;
13227
13228 result = quote_qualified_identifier(nspname, relname);
13229
13230 ReleaseSysCache(tp);
13231
13232 return result;
13233}
bool RelationIsVisible(Oid relid)
Definition: namespace.c:912

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

11034{
11035 Aggref *aggref;
11036 Aggref *original_aggref = callback_arg;
11037
11038 if (!IsA(node, Aggref))
11039 elog(ERROR, "combining Aggref does not point to an Aggref");
11040
11041 aggref = (Aggref *) node;
11042 get_agg_expr(aggref, context, original_aggref);
11043}
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
Definition: ruleutils.c:10895

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

10897{
10898 get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10899 false);
10900}
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:10907

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

10910{
10911 StringInfo buf = context->buf;
10912 Oid argtypes[FUNC_MAX_ARGS];
10913 int nargs;
10914 bool use_variadic = false;
10915
10916 /*
10917 * For a combining aggregate, we look up and deparse the corresponding
10918 * partial aggregate instead. This is necessary because our input
10919 * argument list has been replaced; the new argument list always has just
10920 * one element, which will point to a partial Aggref that supplies us with
10921 * transition states to combine.
10922 */
10923 if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10924 {
10925 TargetEntry *tle;
10926
10927 Assert(list_length(aggref->args) == 1);
10928 tle = linitial_node(TargetEntry, aggref->args);
10929 resolve_special_varno((Node *) tle->expr, context,
10930 get_agg_combine_expr, original_aggref);
10931 return;
10932 }
10933
10934 /*
10935 * Mark as PARTIAL, if appropriate. We look to the original aggref so as
10936 * to avoid printing this when recursing from the code just above.
10937 */
10938 if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10939 appendStringInfoString(buf, "PARTIAL ");
10940
10941 /* Extract the argument types as seen by the parser */
10942 nargs = get_aggregate_argtypes(aggref, argtypes);
10943
10944 if (!funcname)
10945 funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10946 argtypes, aggref->aggvariadic,
10947 &use_variadic,
10948 context->inGroupBy);
10949
10950 /* Print the aggregate name, schema-qualified if needed */
10951 appendStringInfo(buf, "%s(%s", funcname,
10952 (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10953
10954 if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10955 {
10956 /*
10957 * Ordered-set aggregates do not use "*" syntax. Also, we needn't
10958 * worry about inserting VARIADIC. So we can just dump the direct
10959 * args as-is.
10960 */
10961 Assert(!aggref->aggvariadic);
10962 get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10963 Assert(aggref->aggorder != NIL);
10964 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10965 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10966 }
10967 else
10968 {
10969 /* aggstar can be set only in zero-argument aggregates */
10970 if (aggref->aggstar)
10972 else
10973 {
10974 ListCell *l;
10975 int i;
10976
10977 i = 0;
10978 foreach(l, aggref->args)
10979 {
10980 TargetEntry *tle = (TargetEntry *) lfirst(l);
10981 Node *arg = (Node *) tle->expr;
10982
10984 if (tle->resjunk)
10985 continue;
10986 if (i++ > 0)
10987 {
10988 if (is_json_objectagg)
10989 {
10990 /*
10991 * the ABSENT ON NULL and WITH UNIQUE args are printed
10992 * separately, so ignore them here
10993 */
10994 if (i > 2)
10995 break;
10996
10998 }
10999 else
11001 }
11002 if (use_variadic && i == nargs)
11003 appendStringInfoString(buf, "VARIADIC ");
11004 get_rule_expr(arg, context, true);
11005 }
11006 }
11007
11008 if (aggref->aggorder != NIL)
11009 {
11010 appendStringInfoString(buf, " ORDER BY ");
11011 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
11012 }
11013 }
11014
11015 if (options)
11017
11018 if (aggref->aggfilter != NULL)
11019 {
11020 appendStringInfoString(buf, ") FILTER (WHERE ");
11021 get_rule_expr((Node *) aggref->aggfilter, context, false);
11022 }
11023
11025}
#define funcname
Definition: indent_codes.h:69
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:396
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:395
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:2023
#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:13286
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:11033
static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6692
static void resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
Definition: ruleutils.c:7910
Oid aggfnoid
Definition: primnodes.h:463
List * aggdistinct
Definition: primnodes.h:493
List * aggdirectargs
Definition: primnodes.h:484
List * args
Definition: primnodes.h:487
Expr * aggfilter
Definition: primnodes.h:496
List * aggorder
Definition: primnodes.h:490
Expr * expr
Definition: primnodes.h:2239

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

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

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::groupByAll, 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 11430 of file ruleutils.c.

11433{
11434 StringInfo buf = context->buf;
11435
11436 /*
11437 * Since parse_coerce.c doesn't immediately collapse application of
11438 * length-coercion functions to constants, what we'll typically see in
11439 * such cases is a Const with typmod -1 and a length-coercion function
11440 * right above it. Avoid generating redundant output. However, beware of
11441 * suppressing casts when the user actually wrote something like
11442 * 'foo'::text::char(3).
11443 *
11444 * Note: it might seem that we are missing the possibility of needing to
11445 * print a COLLATE clause for such a Const. However, a Const could only
11446 * have nondefault collation in a post-constant-folding tree, in which the
11447 * length coercion would have been folded too. See also the special
11448 * handling of CollateExpr in coerce_to_target_type(): any collation
11449 * marking will be above the coercion node, not below it.
11450 */
11451 if (arg && IsA(arg, Const) &&
11452 ((Const *) arg)->consttype == resulttype &&
11453 ((Const *) arg)->consttypmod == -1)
11454 {
11455 /* Show the constant without normal ::typename decoration */
11456 get_const_expr((Const *) arg, context, -1);
11457 }
11458 else
11459 {
11460 if (!PRETTY_PAREN(context))
11462 get_rule_expr_paren(arg, context, false, parentNode);
11463 if (!PRETTY_PAREN(context))
11465 }
11466
11467 /*
11468 * Never emit resulttype(arg) functional notation. A pg_proc entry could
11469 * take precedence, and a resulttype in pg_temp would require schema
11470 * qualification that format_type_with_typemod() would usually omit. We've
11471 * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
11472 * would work fine.
11473 */
11474 appendStringInfo(buf, "::%s",
11475 format_type_with_typemod(resulttype, resulttypmod));
11476}
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:9164
#define PRETTY_PAREN(context)
Definition: ruleutils.c:101
static void get_const_expr(Const *constval, deparse_context *context, int showtype)
Definition: ruleutils.c:11494

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

12756{
12757 StringInfo buf = context->buf;
12758 int i;
12759 bool first = true;
12760
12761 /* Don't print aliases if not needed */
12762 if (!colinfo->printaliases)
12763 return;
12764
12765 for (i = 0; i < colinfo->num_new_cols; i++)
12766 {
12767 char *colname = colinfo->new_colnames[i];
12768
12769 if (first)
12770 {
12772 first = false;
12773 }
12774 else
12777 }
12778 if (!first)
12780}

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

11625{
11626 StringInfo buf = context->buf;
11627
11628 if (OidIsValid(constval->constcollid))
11629 {
11630 Oid typcollation = get_typcollation(constval->consttype);
11631
11632 if (constval->constcollid != typcollation)
11633 {
11634 appendStringInfo(buf, " COLLATE %s",
11635 generate_collation_name(constval->constcollid));
11636 }
11637 }
11638}
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3223
char * generate_collation_name(Oid collid)
Definition: ruleutils.c:13574
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 11494 of file ruleutils.c.

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

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

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

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

12300{
12301 StringInfo buf = context->buf;
12302 bool first = true;
12303 ListCell *l;
12304
12305 /*
12306 * We use the query's jointree as a guide to what to print. However, we
12307 * must ignore auto-added RTEs that are marked not inFromCl. (These can
12308 * only appear at the top level of the jointree, so it's sufficient to
12309 * check here.) This check also ensures we ignore the rule pseudo-RTEs
12310 * for NEW and OLD.
12311 */
12312 foreach(l, query->jointree->fromlist)
12313 {
12314 Node *jtnode = (Node *) lfirst(l);
12315
12316 if (IsA(jtnode, RangeTblRef))
12317 {
12318 int varno = ((RangeTblRef *) jtnode)->rtindex;
12319 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12320
12321 if (!rte->inFromCl)
12322 continue;
12323 }
12324
12325 if (first)
12326 {
12327 appendContextKeyword(context, prefix,
12329 first = false;
12330
12331 get_from_clause_item(jtnode, query, context);
12332 }
12333 else
12334 {
12335 StringInfoData itembuf;
12336
12338
12339 /*
12340 * Put the new FROM item's text into itembuf so we can decide
12341 * after we've got it whether or not it needs to go on a new line.
12342 */
12343 initStringInfo(&itembuf);
12344 context->buf = &itembuf;
12345
12346 get_from_clause_item(jtnode, query, context);
12347
12348 /* Restore context's output buffer */
12349 context->buf = buf;
12350
12351 /* Consider line-wrapping if enabled */
12352 if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
12353 {
12354 /* Does the new item start with a new line? */
12355 if (itembuf.len > 0 && itembuf.data[0] == '\n')
12356 {
12357 /* If so, we shouldn't add anything */
12358 /* instead, remove any trailing spaces currently in buf */
12360 }
12361 else
12362 {
12363 char *trailing_nl;
12364
12365 /* Locate the start of the current line in the buffer */
12366 trailing_nl = strrchr(buf->data, '\n');
12367 if (trailing_nl == NULL)
12368 trailing_nl = buf->data;
12369 else
12370 trailing_nl++;
12371
12372 /*
12373 * Add a newline, plus some indentation, if the new item
12374 * would cause an overflow.
12375 */
12376 if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
12380 }
12381 }
12382
12383 /* Add the new item */
12384 appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
12385
12386 /* clean up */
12387 pfree(itembuf.data);
12388 }
12389 }
12390}
#define PRETTYINDENT_VAR
Definition: ruleutils.c:83
static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
Definition: ruleutils.c:12393
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
List * fromlist
Definition: primnodes.h:2357

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

12798{
12799 StringInfo buf = context->buf;
12800 ListCell *l1;
12801 ListCell *l2;
12802 ListCell *l3;
12803 ListCell *l4;
12804 int i;
12805
12807
12808 i = 0;
12809 forfour(l1, rtfunc->funccoltypes,
12810 l2, rtfunc->funccoltypmods,
12811 l3, rtfunc->funccolcollations,
12812 l4, rtfunc->funccolnames)
12813 {
12814 Oid atttypid = lfirst_oid(l1);
12815 int32 atttypmod = lfirst_int(l2);
12816 Oid attcollation = lfirst_oid(l3);
12817 char *attname;
12818
12819 if (colinfo)
12820 attname = colinfo->colnames[i];
12821 else
12822 attname = strVal(lfirst(l4));
12823
12824 Assert(attname); /* shouldn't be any dropped columns here */
12825
12826 if (i > 0)
12828 appendStringInfo(buf, "%s %s",
12830 format_type_with_typemod(atttypid, atttypmod));
12831 if (OidIsValid(attcollation) &&
12832 attcollation != get_typcollation(atttypid))
12833 appendStringInfo(buf, " COLLATE %s",
12834 generate_collation_name(attcollation));
12835
12836 i++;
12837 }
12838
12840}
int32_t int32
Definition: c.h:534
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 12393 of file ruleutils.c.

12394{
12395 StringInfo buf = context->buf;
12397
12398 if (IsA(jtnode, RangeTblRef))
12399 {
12400 int varno = ((RangeTblRef *) jtnode)->rtindex;
12401 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12402 deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12403 RangeTblFunction *rtfunc1 = NULL;
12404
12405 if (rte->lateral)
12406 appendStringInfoString(buf, "LATERAL ");
12407
12408 /* Print the FROM item proper */
12409 switch (rte->rtekind)
12410 {
12411 case RTE_RELATION:
12412 /* Normal relation RTE */
12413 appendStringInfo(buf, "%s%s",
12414 only_marker(rte),
12415 generate_relation_name(rte->relid,
12416 context->namespaces));
12417 break;
12418 case RTE_SUBQUERY:
12419 /* Subquery RTE */
12421 get_query_def(rte->subquery, buf, context->namespaces, NULL,
12422 true,
12423 context->prettyFlags, context->wrapColumn,
12424 context->indentLevel);
12426 break;
12427 case RTE_FUNCTION:
12428 /* Function RTE */
12429 rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
12430
12431 /*
12432 * Omit ROWS FROM() syntax for just one function, unless it
12433 * has both a coldeflist and WITH ORDINALITY. If it has both,
12434 * we must use ROWS FROM() syntax to avoid ambiguity about
12435 * whether the coldeflist includes the ordinality column.
12436 */
12437 if (list_length(rte->functions) == 1 &&
12438 (rtfunc1->funccolnames == NIL || !rte->funcordinality))
12439 {
12440 get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
12441 /* we'll print the coldeflist below, if it has one */
12442 }
12443 else
12444 {
12445 bool all_unnest;
12446 ListCell *lc;
12447
12448 /*
12449 * If all the function calls in the list are to unnest,
12450 * and none need a coldeflist, then collapse the list back
12451 * down to UNNEST(args). (If we had more than one
12452 * built-in unnest function, this would get more
12453 * difficult.)
12454 *
12455 * XXX This is pretty ugly, since it makes not-terribly-
12456 * future-proof assumptions about what the parser would do
12457 * with the output; but the alternative is to emit our
12458 * nonstandard ROWS FROM() notation for what might have
12459 * been a perfectly spec-compliant multi-argument
12460 * UNNEST().
12461 */
12462 all_unnest = true;
12463 foreach(lc, rte->functions)
12464 {
12465 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12466
12467 if (!IsA(rtfunc->funcexpr, FuncExpr) ||
12468 ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
12469 rtfunc->funccolnames != NIL)
12470 {
12471 all_unnest = false;
12472 break;
12473 }
12474 }
12475
12476 if (all_unnest)
12477 {
12478 List *allargs = NIL;
12479
12480 foreach(lc, rte->functions)
12481 {
12482 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12483 List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
12484
12485 allargs = list_concat(allargs, args);
12486 }
12487
12488 appendStringInfoString(buf, "UNNEST(");
12489 get_rule_expr((Node *) allargs, context, true);
12491 }
12492 else
12493 {
12494 int funcno = 0;
12495
12496 appendStringInfoString(buf, "ROWS FROM(");
12497 foreach(lc, rte->functions)
12498 {
12499 RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12500
12501 if (funcno > 0)
12503 get_rule_expr_funccall(rtfunc->funcexpr, context, true);
12504 if (rtfunc->funccolnames != NIL)
12505 {
12506 /* Reconstruct the column definition list */
12507 appendStringInfoString(buf, " AS ");
12509 NULL,
12510 context);
12511 }
12512 funcno++;
12513 }
12515 }
12516 /* prevent printing duplicate coldeflist below */
12517 rtfunc1 = NULL;
12518 }
12519 if (rte->funcordinality)
12520 appendStringInfoString(buf, " WITH ORDINALITY");
12521 break;
12522 case RTE_TABLEFUNC:
12523 get_tablefunc(rte->tablefunc, context, true);
12524 break;
12525 case RTE_VALUES:
12526 /* Values list RTE */
12528 get_values_def(rte->values_lists, context);
12530 break;
12531 case RTE_CTE:
12533 break;
12534 default:
12535 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
12536 break;
12537 }
12538
12539 /* Print the relation alias, if needed */
12540 get_rte_alias(rte, varno, false, context);
12541
12542 /* Print the column definitions or aliases, if needed */
12543 if (rtfunc1 && rtfunc1->funccolnames != NIL)
12544 {
12545 /* Reconstruct the columndef list, which is also the aliases */
12546 get_from_clause_coldeflist(rtfunc1, colinfo, context);
12547 }
12548 else
12549 {
12550 /* Else print column aliases as needed */
12551 get_column_alias_list(colinfo, context);
12552 }
12553
12554 /* Tablesample clause must go after any alias */
12555 if (rte->rtekind == RTE_RELATION && rte->tablesample)
12556 get_tablesample_def(rte->tablesample, context);
12557 }
12558 else if (IsA(jtnode, JoinExpr))
12559 {
12560 JoinExpr *j = (JoinExpr *) jtnode;
12561 deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
12562 bool need_paren_on_right;
12563
12564 need_paren_on_right = PRETTY_PAREN(context) &&
12565 !IsA(j->rarg, RangeTblRef) &&
12566 !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
12567
12568 if (!PRETTY_PAREN(context) || j->alias != NULL)
12570
12571 get_from_clause_item(j->larg, query, context);
12572
12573 switch (j->jointype)
12574 {
12575 case JOIN_INNER:
12576 if (j->quals)
12577 appendContextKeyword(context, " JOIN ",
12581 else
12582 appendContextKeyword(context, " CROSS JOIN ",
12586 break;
12587 case JOIN_LEFT:
12588 appendContextKeyword(context, " LEFT JOIN ",
12592 break;
12593 case JOIN_FULL:
12594 appendContextKeyword(context, " FULL JOIN ",
12598 break;
12599 case JOIN_RIGHT:
12600 appendContextKeyword(context, " RIGHT JOIN ",
12604 break;
12605 default:
12606 elog(ERROR, "unrecognized join type: %d",
12607 (int) j->jointype);
12608 }
12609
12610 if (need_paren_on_right)
12612 get_from_clause_item(j->rarg, query, context);
12613 if (need_paren_on_right)
12615
12616 if (j->usingClause)
12617 {
12618 ListCell *lc;
12619 bool first = true;
12620
12621 appendStringInfoString(buf, " USING (");
12622 /* Use the assigned names, not what's in usingClause */
12623 foreach(lc, colinfo->usingNames)
12624 {
12625 char *colname = (char *) lfirst(lc);
12626
12627 if (first)
12628 first = false;
12629 else
12632 }
12634
12635 if (j->join_using_alias)
12636 appendStringInfo(buf, " AS %s",
12637 quote_identifier(j->join_using_alias->aliasname));
12638 }
12639 else if (j->quals)
12640 {
12641 appendStringInfoString(buf, " ON ");
12642 if (!PRETTY_PAREN(context))
12644 get_rule_expr(j->quals, context, false);
12645 if (!PRETTY_PAREN(context))
12647 }
12648 else if (j->jointype != JOIN_INNER)
12649 {
12650 /* If we didn't say CROSS JOIN above, we must provide an ON */
12651 appendStringInfoString(buf, " ON TRUE");
12652 }
12653
12654 if (!PRETTY_PAREN(context) || j->alias != NULL)
12656
12657 /* Yes, it's correct to put alias after the right paren ... */
12658 if (j->alias != NULL)
12659 {
12660 /*
12661 * Note that it's correct to emit an alias clause if and only if
12662 * there was one originally. Otherwise we'd be converting a named
12663 * join to unnamed or vice versa, which creates semantic
12664 * subtleties we don't want. However, we might print a different
12665 * alias name than was there originally.
12666 */
12667 appendStringInfo(buf, " %s",
12669 context)));
12670 get_column_alias_list(colinfo, context);
12671 }
12672 }
12673 else
12674 elog(ERROR, "unrecognized node type: %d",
12675 (int) nodeTag(jtnode));
12676}
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
#define nodeTag(nodeptr)
Definition: nodes.h:139
@ JOIN_FULL
Definition: nodes.h:305
@ JOIN_INNER
Definition: nodes.h:303
@ JOIN_RIGHT
Definition: nodes.h:306
@ JOIN_LEFT
Definition: nodes.h:304
@ RTE_CTE
Definition: parsenodes.h:1049
@ RTE_VALUES
Definition: parsenodes.h:1048
@ RTE_SUBQUERY
Definition: parsenodes.h:1044
@ RTE_FUNCTION
Definition: parsenodes.h:1046
@ RTE_TABLEFUNC
Definition: parsenodes.h:1047
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition: ruleutils.c:5132
#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:5623
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Definition: ruleutils.c:12846
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12755
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12795
static void get_rule_expr_funccall(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10707
#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:12280
Definition: pg_list.h:54
char * ctename
Definition: parsenodes.h:1227
TableFunc * tablefunc
Definition: parsenodes.h:1215
bool funcordinality
Definition: parsenodes.h:1210
struct TableSampleClause * tablesample
Definition: parsenodes.h:1129
Query * subquery
Definition: parsenodes.h:1135
List * functions
Definition: parsenodes.h:1208
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 10799 of file ruleutils.c.

10801{
10802 StringInfo buf = context->buf;
10803 Oid funcoid = expr->funcid;
10804 Oid argtypes[FUNC_MAX_ARGS];
10805 int nargs;
10806 List *argnames;
10807 bool use_variadic;
10808 ListCell *l;
10809
10810 /*
10811 * If the function call came from an implicit coercion, then just show the
10812 * first argument --- unless caller wants to see implicit coercions.
10813 */
10814 if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
10815 {
10816 get_rule_expr_paren((Node *) linitial(expr->args), context,
10817 false, (Node *) expr);
10818 return;
10819 }
10820
10821 /*
10822 * If the function call came from a cast, then show the first argument
10823 * plus an explicit cast operation.
10824 */
10825 if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10826 expr->funcformat == COERCE_IMPLICIT_CAST)
10827 {
10828 Node *arg = linitial(expr->args);
10829 Oid rettype = expr->funcresulttype;
10830 int32 coercedTypmod;
10831
10832 /* Get the typmod if this is a length-coercion function */
10833 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10834
10835 get_coercion_expr(arg, context,
10836 rettype, coercedTypmod,
10837 (Node *) expr);
10838
10839 return;
10840 }
10841
10842 /*
10843 * If the function was called using one of the SQL spec's random special
10844 * syntaxes, try to reproduce that. If we don't recognize the function,
10845 * fall through.
10846 */
10847 if (expr->funcformat == COERCE_SQL_SYNTAX)
10848 {
10849 if (get_func_sql_syntax(expr, context))
10850 return;
10851 }
10852
10853 /*
10854 * Normal function: display as proname(args). First we need to extract
10855 * the argument datatypes.
10856 */
10857 if (list_length(expr->args) > FUNC_MAX_ARGS)
10858 ereport(ERROR,
10859 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10860 errmsg("too many arguments")));
10861 nargs = 0;
10862 argnames = NIL;
10863 foreach(l, expr->args)
10864 {
10865 Node *arg = (Node *) lfirst(l);
10866
10867 if (IsA(arg, NamedArgExpr))
10868 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10869 argtypes[nargs] = exprType(arg);
10870 nargs++;
10871 }
10872
10873 appendStringInfo(buf, "%s(",
10874 generate_function_name(funcoid, nargs,
10875 argnames, argtypes,
10876 expr->funcvariadic,
10877 &use_variadic,
10878 context->inGroupBy));
10879 nargs = 0;
10880 foreach(l, expr->args)
10881 {
10882 if (nargs++ > 0)
10884 if (use_variadic && lnext(expr->args, l) == NULL)
10885 appendStringInfoString(buf, "VARIADIC ");
10886 get_rule_expr((Node *) lfirst(l), context, true);
10887 }
10889}
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereport(elevel,...)
Definition: elog.h:150
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:769
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:768
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:767
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Definition: ruleutils.c:11178
static void get_coercion_expr(Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
Definition: ruleutils.c:11430
Oid funcid
Definition: primnodes.h:782
List * args
Definition: primnodes.h:800

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

11179{
11180 StringInfo buf = context->buf;
11181 Oid funcoid = expr->funcid;
11182
11183 switch (funcoid)
11184 {
11185 case F_TIMEZONE_INTERVAL_TIMESTAMP:
11186 case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
11187 case F_TIMEZONE_INTERVAL_TIMETZ:
11188 case F_TIMEZONE_TEXT_TIMESTAMP:
11189 case F_TIMEZONE_TEXT_TIMESTAMPTZ:
11190 case F_TIMEZONE_TEXT_TIMETZ:
11191 /* AT TIME ZONE ... note reversed argument order */
11193 get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
11194 (Node *) expr);
11195 appendStringInfoString(buf, " AT TIME ZONE ");
11196 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11197 (Node *) expr);
11199 return true;
11200
11201 case F_TIMEZONE_TIMESTAMP:
11202 case F_TIMEZONE_TIMESTAMPTZ:
11203 case F_TIMEZONE_TIMETZ:
11204 /* AT LOCAL */
11206 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11207 (Node *) expr);
11208 appendStringInfoString(buf, " AT LOCAL)");
11209 return true;
11210
11211 case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
11212 case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
11213 case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
11214 case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
11215 case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
11216 case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
11217 case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
11218 case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
11219 case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
11220 case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
11221 case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
11222 case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
11223 case F_OVERLAPS_TIME_TIME_TIME_TIME:
11224 /* (x1, x2) OVERLAPS (y1, y2) */
11226 get_rule_expr((Node *) linitial(expr->args), context, false);
11228 get_rule_expr((Node *) lsecond(expr->args), context, false);
11229 appendStringInfoString(buf, ") OVERLAPS (");
11230 get_rule_expr((Node *) lthird(expr->args), context, false);
11232 get_rule_expr((Node *) lfourth(expr->args), context, false);
11234 return true;
11235
11236 case F_EXTRACT_TEXT_DATE:
11237 case F_EXTRACT_TEXT_TIME:
11238 case F_EXTRACT_TEXT_TIMETZ:
11239 case F_EXTRACT_TEXT_TIMESTAMP:
11240 case F_EXTRACT_TEXT_TIMESTAMPTZ:
11241 case F_EXTRACT_TEXT_INTERVAL:
11242 /* EXTRACT (x FROM y) */
11243 appendStringInfoString(buf, "EXTRACT(");
11244 {
11245 Const *con = (Const *) linitial(expr->args);
11246
11247 Assert(IsA(con, Const) &&
11248 con->consttype == TEXTOID &&
11249 !con->constisnull);
11251 }
11252 appendStringInfoString(buf, " FROM ");
11253 get_rule_expr((Node *) lsecond(expr->args), context, false);
11255 return true;
11256
11257 case F_IS_NORMALIZED:
11258 /* IS xxx NORMALIZED */
11260 get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11261 (Node *) expr);
11263 if (list_length(expr->args) == 2)
11264 {
11265 Const *con = (Const *) lsecond(expr->args);
11266
11267 Assert(IsA(con, Const) &&
11268 con->consttype == TEXTOID &&
11269 !con->constisnull);
11270 appendStringInfo(buf, " %s",
11271 TextDatumGetCString(con->constvalue));
11272 }
11273 appendStringInfoString(buf, " NORMALIZED)");
11274 return true;
11275
11276 case F_PG_COLLATION_FOR:
11277 /* COLLATION FOR */
11278 appendStringInfoString(buf, "COLLATION FOR (");
11279 get_rule_expr((Node *) linitial(expr->args), context, false);
11281 return true;
11282
11283 case F_NORMALIZE:
11284 /* NORMALIZE() */
11285 appendStringInfoString(buf, "NORMALIZE(");
11286 get_rule_expr((Node *) linitial(expr->args), context, false);
11287 if (list_length(expr->args) == 2)
11288 {
11289 Const *con = (Const *) lsecond(expr->args);
11290
11291 Assert(IsA(con, Const) &&
11292 con->consttype == TEXTOID &&
11293 !con->constisnull);
11294 appendStringInfo(buf, ", %s",
11295 TextDatumGetCString(con->constvalue));
11296 }
11298 return true;
11299
11300 case F_OVERLAY_BIT_BIT_INT4:
11301 case F_OVERLAY_BIT_BIT_INT4_INT4:
11302 case F_OVERLAY_BYTEA_BYTEA_INT4:
11303 case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
11304 case F_OVERLAY_TEXT_TEXT_INT4:
11305 case F_OVERLAY_TEXT_TEXT_INT4_INT4:
11306 /* OVERLAY() */
11307 appendStringInfoString(buf, "OVERLAY(");
11308 get_rule_expr((Node *) linitial(expr->args), context, false);
11309 appendStringInfoString(buf, " PLACING ");
11310 get_rule_expr((Node *) lsecond(expr->args), context, false);
11311 appendStringInfoString(buf, " FROM ");
11312 get_rule_expr((Node *) lthird(expr->args), context, false);
11313 if (list_length(expr->args) == 4)
11314 {
11315 appendStringInfoString(buf, " FOR ");
11316 get_rule_expr((Node *) lfourth(expr->args), context, false);
11317 }
11319 return true;
11320
11321 case F_POSITION_BIT_BIT:
11322 case F_POSITION_BYTEA_BYTEA:
11323 case F_POSITION_TEXT_TEXT:
11324 /* POSITION() ... extra parens since args are b_expr not a_expr */
11325 appendStringInfoString(buf, "POSITION((");
11326 get_rule_expr((Node *) lsecond(expr->args), context, false);
11327 appendStringInfoString(buf, ") IN (");
11328 get_rule_expr((Node *) linitial(expr->args), context, false);
11330 return true;
11331
11332 case F_SUBSTRING_BIT_INT4:
11333 case F_SUBSTRING_BIT_INT4_INT4:
11334 case F_SUBSTRING_BYTEA_INT4:
11335 case F_SUBSTRING_BYTEA_INT4_INT4:
11336 case F_SUBSTRING_TEXT_INT4:
11337 case F_SUBSTRING_TEXT_INT4_INT4:
11338 /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
11339 appendStringInfoString(buf, "SUBSTRING(");
11340 get_rule_expr((Node *) linitial(expr->args), context, false);
11341 appendStringInfoString(buf, " FROM ");
11342 get_rule_expr((Node *) lsecond(expr->args), context, false);
11343 if (list_length(expr->args) == 3)
11344 {
11345 appendStringInfoString(buf, " FOR ");
11346 get_rule_expr((Node *) lthird(expr->args), context, false);
11347 }
11349 return true;
11350
11351 case F_SUBSTRING_TEXT_TEXT_TEXT:
11352 /* SUBSTRING SIMILAR/ESCAPE */
11353 appendStringInfoString(buf, "SUBSTRING(");
11354 get_rule_expr((Node *) linitial(expr->args), context, false);
11355 appendStringInfoString(buf, " SIMILAR ");
11356 get_rule_expr((Node *) lsecond(expr->args), context, false);
11357 appendStringInfoString(buf, " ESCAPE ");
11358 get_rule_expr((Node *) lthird(expr->args), context, false);
11360 return true;
11361
11362 case F_BTRIM_BYTEA_BYTEA:
11363 case F_BTRIM_TEXT:
11364 case F_BTRIM_TEXT_TEXT:
11365 /* TRIM() */
11366 appendStringInfoString(buf, "TRIM(BOTH");
11367 if (list_length(expr->args) == 2)
11368 {
11370 get_rule_expr((Node *) lsecond(expr->args), context, false);
11371 }
11372 appendStringInfoString(buf, " FROM ");
11373 get_rule_expr((Node *) linitial(expr->args), context, false);
11375 return true;
11376
11377 case F_LTRIM_BYTEA_BYTEA:
11378 case F_LTRIM_TEXT:
11379 case F_LTRIM_TEXT_TEXT:
11380 /* TRIM() */
11381 appendStringInfoString(buf, "TRIM(LEADING");
11382 if (list_length(expr->args) == 2)
11383 {
11385 get_rule_expr((Node *) lsecond(expr->args), context, false);
11386 }
11387 appendStringInfoString(buf, " FROM ");
11388 get_rule_expr((Node *) linitial(expr->args), context, false);
11390 return true;
11391
11392 case F_RTRIM_BYTEA_BYTEA:
11393 case F_RTRIM_TEXT:
11394 case F_RTRIM_TEXT_TEXT:
11395 /* TRIM() */
11396 appendStringInfoString(buf, "TRIM(TRAILING");
11397 if (list_length(expr->args) == 2)
11398 {
11400 get_rule_expr((Node *) lsecond(expr->args), context, false);
11401 }
11402 appendStringInfoString(buf, " FROM ");
11403 get_rule_expr((Node *) linitial(expr->args), context, false);
11405 return true;
11406
11407 case F_SYSTEM_USER:
11408 appendStringInfoString(buf, "SYSTEM_USER");
11409 return true;
11410
11411 case F_XMLEXISTS:
11412 /* XMLEXISTS ... extra parens because args are c_expr */
11413 appendStringInfoString(buf, "XMLEXISTS((");
11414 get_rule_expr((Node *) linitial(expr->args), context, false);
11415 appendStringInfoString(buf, ") PASSING (");
11416 get_rule_expr((Node *) lsecond(expr->args), context, false);
11418 return true;
11419 }
11420 return false;
11421}
#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 6940 of file ruleutils.c.

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

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

11799{
11801
11804
11805 if (IsA(ctor->func, Aggref))
11806 get_agg_expr_helper((Aggref *) ctor->func, context,
11807 (Aggref *) ctor->func,
11808 funcname, options.data, is_json_objectagg);
11809 else if (IsA(ctor->func, WindowFunc))
11810 get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
11811 funcname, options.data,
11812 is_json_objectagg);
11813 else
11814 elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
11815 nodeTag(ctor->func));
11816}
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:11060
static void get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
Definition: ruleutils.c:11767

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

9184{
9185 /*
9186 * The order of array elements must correspond to the order of
9187 * JsonBehaviorType members.
9188 */
9189 const char *behavior_names[] =
9190 {
9191 " NULL",
9192 " ERROR",
9193 " EMPTY",
9194 " TRUE",
9195 " FALSE",
9196 " UNKNOWN",
9197 " EMPTY ARRAY",
9198 " EMPTY OBJECT",
9199 " DEFAULT "
9200 };
9201
9202 if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
9203 elog(ERROR, "invalid json behavior type: %d", behavior->btype);
9204
9205 appendStringInfoString(context->buf, behavior_names[behavior->btype]);
9206
9207 if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
9208 get_rule_expr(behavior->expr, context, false);
9209
9210 appendStringInfo(context->buf, " ON %s", on);
9211}
#define lengthof(array)
Definition: c.h:787
@ JSON_BEHAVIOR_DEFAULT
Definition: primnodes.h:1798
Node * expr
Definition: primnodes.h:1816
JsonBehaviorType btype
Definition: primnodes.h:1815

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

11703{
11704 StringInfo buf = context->buf;
11705 const char *funcname;
11706 bool is_json_object;
11707 int curridx;
11708 ListCell *lc;
11709
11710 if (ctor->type == JSCTOR_JSON_OBJECTAGG)
11711 {
11712 get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
11713 return;
11714 }
11715 else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
11716 {
11717 get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
11718 return;
11719 }
11720
11721 switch (ctor->type)
11722 {
11723 case JSCTOR_JSON_OBJECT:
11724 funcname = "JSON_OBJECT";
11725 break;
11726 case JSCTOR_JSON_ARRAY:
11727 funcname = "JSON_ARRAY";
11728 break;
11729 case JSCTOR_JSON_PARSE:
11730 funcname = "JSON";
11731 break;
11732 case JSCTOR_JSON_SCALAR:
11733 funcname = "JSON_SCALAR";
11734 break;
11736 funcname = "JSON_SERIALIZE";
11737 break;
11738 default:
11739 elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
11740 }
11741
11742 appendStringInfo(buf, "%s(", funcname);
11743
11744 is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
11745 foreach(lc, ctor->args)
11746 {
11747 curridx = foreach_current_index(lc);
11748 if (curridx > 0)
11749 {
11750 const char *sep;
11751
11752 sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
11754 }
11755
11756 get_rule_expr((Node *) lfirst(lc), context, true);
11757 }
11758
11761}
@ JSCTOR_JSON_SERIALIZE
Definition: primnodes.h:1721
@ JSCTOR_JSON_ARRAYAGG
Definition: primnodes.h:1718
@ JSCTOR_JSON_PARSE
Definition: primnodes.h:1719
@ JSCTOR_JSON_OBJECT
Definition: primnodes.h:1715
@ JSCTOR_JSON_SCALAR
Definition: primnodes.h:1720
@ JSCTOR_JSON_ARRAY
Definition: primnodes.h:1716
@ JSCTOR_JSON_OBJECTAGG
Definition: primnodes.h:1717
static void get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
Definition: ruleutils.c:11797
JsonConstructorType type
Definition: primnodes.h:1731

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

11768{
11769 if (ctor->absent_on_null)
11770 {
11771 if (ctor->type == JSCTOR_JSON_OBJECT ||
11772 ctor->type == JSCTOR_JSON_OBJECTAGG)
11773 appendStringInfoString(buf, " ABSENT ON NULL");
11774 }
11775 else
11776 {
11777 if (ctor->type == JSCTOR_JSON_ARRAY ||
11778 ctor->type == JSCTOR_JSON_ARRAYAGG)
11779 appendStringInfoString(buf, " NULL ON NULL");
11780 }
11781
11782 if (ctor->unique)
11783 appendStringInfoString(buf, " WITH UNIQUE KEYS");
11784
11785 /*
11786 * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
11787 * support one.
11788 */
11789 if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
11790 get_json_returning(ctor->returning, buf, true);
11791}
static void get_json_returning(JsonReturning *returning, StringInfo buf, bool json_format_by_default)
Definition: ruleutils.c:11681
JsonReturning * returning
Definition: primnodes.h:1735

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

9222{
9223 if (jsexpr->op == JSON_QUERY_OP)
9224 {
9225 if (jsexpr->wrapper == JSW_CONDITIONAL)
9226 appendStringInfoString(context->buf, " WITH CONDITIONAL WRAPPER");
9227 else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
9228 appendStringInfoString(context->buf, " WITH UNCONDITIONAL WRAPPER");
9229 /* The default */
9230 else if (jsexpr->wrapper == JSW_NONE || jsexpr->wrapper == JSW_UNSPEC)
9231 appendStringInfoString(context->buf, " WITHOUT WRAPPER");
9232
9233 if (jsexpr->omit_quotes)
9234 appendStringInfoString(context->buf, " OMIT QUOTES");
9235 /* The default */
9236 else
9237 appendStringInfoString(context->buf, " KEEP QUOTES");
9238 }
9239
9240 if (jsexpr->on_empty && jsexpr->on_empty->btype != default_behavior)
9241 get_json_behavior(jsexpr->on_empty, context, "EMPTY");
9242
9243 if (jsexpr->on_error && jsexpr->on_error->btype != default_behavior)
9244 get_json_behavior(jsexpr->on_error, context, "ERROR");
9245}
@ JSW_UNCONDITIONAL
Definition: primnodes.h:1778
@ JSW_CONDITIONAL
Definition: primnodes.h:1777
@ JSW_UNSPEC
Definition: primnodes.h:1775
@ JSW_NONE
Definition: primnodes.h:1776
@ JSON_QUERY_OP
Definition: primnodes.h:1828
static void get_json_behavior(JsonBehavior *behavior, deparse_context *context, const char *on)
Definition: ruleutils.c:9182
JsonBehavior * on_empty
Definition: primnodes.h:1864
JsonWrapper wrapper
Definition: primnodes.h:1875
JsonExprOp op
Definition: primnodes.h:1842
JsonBehavior * on_error
Definition: primnodes.h:1865
bool omit_quotes
Definition: primnodes.h:1878

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

11657{
11658 if (format->format_type == JS_FORMAT_DEFAULT)
11659 return;
11660
11662 format->format_type == JS_FORMAT_JSONB ?
11663 " FORMAT JSONB" : " FORMAT JSON");
11664
11665 if (format->encoding != JS_ENC_DEFAULT)
11666 {
11667 const char *encoding;
11668
11669 encoding =
11670 format->encoding == JS_ENC_UTF16 ? "UTF16" :
11671 format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
11672
11673 appendStringInfo(buf, " ENCODING %s", encoding);
11674 }
11675}
static char format
int32 encoding
Definition: pg_database.h:41
@ JS_FORMAT_JSONB
Definition: primnodes.h:1665
@ JS_FORMAT_DEFAULT
Definition: primnodes.h:1663
@ JS_ENC_DEFAULT
Definition: primnodes.h:1651
@ JS_ENC_UTF32
Definition: primnodes.h:1654
@ JS_ENC_UTF16
Definition: primnodes.h:1653

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

11645{
11646 if (IsA(path_spec, Const))
11647 get_const_expr((Const *) path_spec, context, -1);
11648 else
11649 get_rule_expr(path_spec, context, showimplicit);
11650}

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

11683{
11684 if (!OidIsValid(returning->typid))
11685 return;
11686
11687 appendStringInfo(buf, " RETURNING %s",
11689 returning->typmod));
11690
11691 if (!json_format_by_default ||
11692 returning->format->format_type !=
11693 (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
11694 get_json_format(returning->format, buf);
11695}
@ JS_FORMAT_JSON
Definition: primnodes.h:1664
static void get_json_format(JsonFormat *format, StringInfo buf)
Definition: ruleutils.c:11656
JsonFormatType format_type
Definition: primnodes.h:1676
JsonFormat * format
Definition: primnodes.h:1688

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

12212{
12213 StringInfo buf = context->buf;
12214 JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
12216
12217 appendStringInfoString(buf, "JSON_TABLE(");
12218
12219 if (PRETTY_INDENT(context))
12220 context->indentLevel += PRETTYINDENT_VAR;
12221
12222 appendContextKeyword(context, "", 0, 0, 0);
12223
12224 get_rule_expr(jexpr->formatted_expr, context, showimplicit);
12225
12227
12228 get_const_expr(root->path->value, context, -1);
12229
12230 appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
12231
12232 if (jexpr->passing_values)
12233 {
12234 ListCell *lc1,
12235 *lc2;
12236 bool needcomma = false;
12237
12239 appendContextKeyword(context, "PASSING ", 0, 0, 0);
12240
12241 if (PRETTY_INDENT(context))
12242 context->indentLevel += PRETTYINDENT_VAR;
12243
12244 forboth(lc1, jexpr->passing_names,
12245 lc2, jexpr->passing_values)
12246 {
12247 if (needcomma)
12249 needcomma = true;
12250
12251 appendContextKeyword(context, "", 0, 0, 0);
12252
12253 get_rule_expr((Node *) lfirst(lc2), context, false);
12254 appendStringInfo(buf, " AS %s",
12255 quote_identifier((lfirst_node(String, lc1))->sval)
12256 );
12257 }
12258
12259 if (PRETTY_INDENT(context))
12260 context->indentLevel -= PRETTYINDENT_VAR;
12261 }
12262
12263 get_json_table_columns(tf, castNode(JsonTablePathScan, tf->plan), context,
12264 showimplicit);
12265
12267 get_json_behavior(jexpr->on_error, context, "ERROR");
12268
12269 if (PRETTY_INDENT(context))
12270 context->indentLevel -= PRETTYINDENT_VAR;
12271
12272 appendContextKeyword(context, ")", 0, 0, 0);
12273}
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
@ JSON_BEHAVIOR_EMPTY_ARRAY
Definition: primnodes.h:1796
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:12105
Node * formatted_expr
Definition: primnodes.h:1848
List * passing_values
Definition: primnodes.h:1861
List * passing_names
Definition: primnodes.h:1860
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 12105 of file ruleutils.c.

12108{
12109 StringInfo buf = context->buf;
12110 ListCell *lc_colname;
12111 ListCell *lc_coltype;
12112 ListCell *lc_coltypmod;
12113 ListCell *lc_colvalexpr;
12114 int colnum = 0;
12115
12117 appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
12118
12119 if (PRETTY_INDENT(context))
12120 context->indentLevel += PRETTYINDENT_VAR;
12121
12122 forfour(lc_colname, tf->colnames,
12123 lc_coltype, tf->coltypes,
12124 lc_coltypmod, tf->coltypmods,
12125 lc_colvalexpr, tf->colvalexprs)
12126 {
12127 char *colname = strVal(lfirst(lc_colname));
12128 JsonExpr *colexpr;
12129 Oid typid;
12130 int32 typmod;
12131 bool ordinality;
12132 JsonBehaviorType default_behavior;
12133
12134 typid = lfirst_oid(lc_coltype);
12135 typmod = lfirst_int(lc_coltypmod);
12136 colexpr = castNode(JsonExpr, lfirst(lc_colvalexpr));
12137
12138 /* Skip columns that don't belong to this scan. */
12139 if (scan->colMin < 0 || colnum < scan->colMin)
12140 {
12141 colnum++;
12142 continue;
12143 }
12144 if (colnum > scan->colMax)
12145 break;
12146
12147 if (colnum > scan->colMin)
12149
12150 colnum++;
12151
12152 ordinality = !colexpr;
12153
12154 appendContextKeyword(context, "", 0, 0, 0);
12155
12156 appendStringInfo(buf, "%s %s", quote_identifier(colname),
12157 ordinality ? "FOR ORDINALITY" :
12158 format_type_with_typemod(typid, typmod));
12159 if (ordinality)
12160 continue;
12161
12162 /*
12163 * Set default_behavior to guide get_json_expr_options() on whether to
12164 * emit the ON ERROR / EMPTY clauses.
12165 */
12166 if (colexpr->op == JSON_EXISTS_OP)
12167 {
12168 appendStringInfoString(buf, " EXISTS");
12169 default_behavior = JSON_BEHAVIOR_FALSE;
12170 }
12171 else
12172 {
12173 if (colexpr->op == JSON_QUERY_OP)
12174 {
12175 char typcategory;
12176 bool typispreferred;
12177
12178 get_type_category_preferred(typid, &typcategory, &typispreferred);
12179
12180 if (typcategory == TYPCATEGORY_STRING)
12182 colexpr->format->format_type == JS_FORMAT_JSONB ?
12183 " FORMAT JSONB" : " FORMAT JSON");
12184 }
12185
12186 default_behavior = JSON_BEHAVIOR_NULL;
12187 }
12188
12189 appendStringInfoString(buf, " PATH ");
12190
12191 get_json_path_spec(colexpr->path_spec, context, showimplicit);
12192
12193 get_json_expr_options(colexpr, context, default_behavior);
12194 }
12195
12196 if (scan->child)
12197 get_json_table_nested_columns(tf, scan->child, context, showimplicit,
12198 scan->colMin >= 0);
12199
12200 if (PRETTY_INDENT(context))
12201 context->indentLevel -= PRETTYINDENT_VAR;
12202
12203 appendContextKeyword(context, ")", 0, 0, 0);
12204}
void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
Definition: lsyscache.c:2877
JsonBehaviorType
Definition: primnodes.h:1789
@ JSON_BEHAVIOR_FALSE
Definition: primnodes.h:1794
@ JSON_BEHAVIOR_NULL
Definition: primnodes.h:1790
@ JSON_EXISTS_OP
Definition: primnodes.h:1827
static void get_json_expr_options(JsonExpr *jsexpr, deparse_context *context, JsonBehaviorType default_behavior)
Definition: ruleutils.c:9220
static void get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11644
static void get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan, deparse_context *context, bool showimplicit, bool needcomma)
Definition: ruleutils.c:12073
JsonFormat * format
Definition: primnodes.h:1851
Node * path_spec
Definition: primnodes.h:1854
JsonTablePlan * child
Definition: primnodes.h:1932

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

12076{
12078 {
12080
12081 if (needcomma)
12082 appendStringInfoChar(context->buf, ',');
12083
12084 appendStringInfoChar(context->buf, ' ');
12085 appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
12086 get_const_expr(scan->path->value, context, -1);
12087 appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
12088 get_json_table_columns(tf, scan, context, showimplicit);
12089 }
12090 else if (IsA(plan, JsonTableSiblingJoin))
12091 {
12093
12094 get_json_table_nested_columns(tf, join->lplan, context, showimplicit,
12095 needcomma);
12096 get_json_table_nested_columns(tf, join->rplan, context, showimplicit,
12097 true);
12098 }
12099}
JsonTablePath * path
Definition: primnodes.h:1923
Const * value
Definition: primnodes.h:1896
JsonTablePlan * rplan
Definition: primnodes.h:1953
JsonTablePlan * lplan
Definition: primnodes.h:1952

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

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

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

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

12892{
12893 HeapTuple ht_opc;
12894 Form_pg_opclass opcrec;
12895 char *opcname;
12896 char *nspname;
12897
12898 ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
12899 if (!HeapTupleIsValid(ht_opc))
12900 elog(ERROR, "cache lookup failed for opclass %u", opclass);
12901 opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
12902
12903 if (!OidIsValid(actual_datatype) ||
12904 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
12905 {
12906 /* Okay, we need the opclass name. Do we need to qualify it? */
12907 opcname = NameStr(opcrec->opcname);
12908 if (OpclassIsVisible(opclass))
12909 appendStringInfo(buf, " %s", quote_identifier(opcname));
12910 else
12911 {
12912 nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
12913 appendStringInfo(buf, " %s.%s",
12914 quote_identifier(nspname),
12915 quote_identifier(opcname));
12916 }
12917 }
12918 ReleaseSysCache(ht_opc);
12919}
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2344
bool OpclassIsVisible(Oid opcid)
Definition: namespace.c:2221
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 10759 of file ruleutils.c.

10760{
10761 StringInfo buf = context->buf;
10762 Oid opno = expr->opno;
10763 List *args = expr->args;
10764
10765 if (!PRETTY_PAREN(context))
10767 if (list_length(args) == 2)
10768 {
10769 /* binary operator */
10770 Node *arg1 = (Node *) linitial(args);
10771 Node *arg2 = (Node *) lsecond(args);
10772
10773 get_rule_expr_paren(arg1, context, true, (Node *) expr);
10774 appendStringInfo(buf, " %s ",
10776 exprType(arg1),
10777 exprType(arg2)));
10778 get_rule_expr_paren(arg2, context, true, (Node *) expr);
10779 }
10780 else
10781 {
10782 /* prefix operator */
10783 Node *arg = (Node *) linitial(args);
10784
10785 appendStringInfo(buf, "%s ",
10787 InvalidOid,
10788 exprType(arg)));
10789 get_rule_expr_paren(arg, context, true, (Node *) expr);
10790 }
10791 if (!PRETTY_PAREN(context))
10793}
static char * generate_operator_name(Oid operid, Oid arg1, Oid arg2)
Definition: ruleutils.c:13393
Oid opno
Definition: primnodes.h:850
List * args
Definition: primnodes.h:868

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

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

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

13708{
13709 deparse_context context;
13711 ListCell *cell;
13712 char *sep;
13713
13714 memset(&context, 0, sizeof(deparse_context));
13715 context.buf = buf;
13716
13718 sep = "";
13719 foreach(cell, bound_datums)
13720 {
13721 PartitionRangeDatum *datum =
13723
13726 appendStringInfoString(buf, "MINVALUE");
13727 else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
13728 appendStringInfoString(buf, "MAXVALUE");
13729 else
13730 {
13731 Const *val = castNode(Const, datum->value);
13732
13733 get_const_expr(val, &context, -1);
13734 }
13735 sep = ", ";
13736 }
13738
13739 return buf->data;
13740}
long val
Definition: informix.c:689
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition: parsenodes.h:954
@ PARTITION_RANGE_DATUM_MINVALUE
Definition: parsenodes.h:952
StringInfo makeStringInfo(void)
Definition: stringinfo.c:72
PartitionRangeDatumKind kind
Definition: parsenodes.h:961

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

13163{
13164 char *relname = get_rel_name(relid);
13165
13166 if (!relname)
13167 elog(ERROR, "cache lookup failed for relation %u", relid);
13168 return relname;
13169}
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095

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

13620{
13621 Datum *options;
13622 int noptions;
13623 int i;
13624
13625 deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
13626 &options, NULL, &noptions);
13627
13628 for (i = 0; i < noptions; i++)
13629 {
13631 char *name;
13632 char *separator;
13633 char *value;
13634
13635 /*
13636 * Each array element should have the form name=value. If the "=" is
13637 * missing for some reason, treat it like an empty value.
13638 */
13639 name = option;
13640 separator = strchr(option, '=');
13641 if (separator)
13642 {
13643 *separator = '\0';
13644 value = separator + 1;
13645 }
13646 else
13647 value = "";
13648
13649 if (i > 0)
13652
13653 /*
13654 * In general we need to quote the value; but to avoid unnecessary
13655 * clutter, do not quote if it is an identifier that would not need
13656 * quoting. (We could also allow numbers, but that is a bit trickier
13657 * than it looks --- for example, are leading zeroes significant? We
13658 * don't want to assume very much here about what custom reloptions
13659 * might mean.)
13660 */
13663 else
13665
13666 pfree(option);
13667 }
13668}
static struct @169 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 6376 of file ruleutils.c.

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

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

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

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

12686{
12688 char *refname = get_rtable_name(varno, context);
12689 deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12690 bool printalias = false;
12691
12692 if (rte->alias != NULL)
12693 {
12694 /* Always print alias if user provided one */
12695 printalias = true;
12696 }
12697 else if (colinfo->printaliases)
12698 {
12699 /* Always print alias if we need to print column aliases */
12700 printalias = true;
12701 }
12702 else if (rte->rtekind == RTE_RELATION)
12703 {
12704 /*
12705 * No need to print alias if it's same as relation name (this would
12706 * normally be the case, but not if set_rtable_names had to resolve a
12707 * conflict).
12708 */
12709 if (strcmp(refname, get_relation_name(rte->relid)) != 0)
12710 printalias = true;
12711 }
12712 else if (rte->rtekind == RTE_FUNCTION)
12713 {
12714 /*
12715 * For a function RTE, always print alias. This covers possible
12716 * renaming of the function and/or instability of the FigureColname
12717 * rules for things that aren't simple functions. Note we'd need to
12718 * force it anyway for the columndef list case.
12719 */
12720 printalias = true;
12721 }
12722 else if (rte->rtekind == RTE_SUBQUERY ||
12723 rte->rtekind == RTE_VALUES)
12724 {
12725 /*
12726 * For a subquery, always print alias. This makes the output
12727 * SQL-spec-compliant, even though we allow such aliases to be omitted
12728 * on input.
12729 */
12730 printalias = true;
12731 }
12732 else if (rte->rtekind == RTE_CTE)
12733 {
12734 /*
12735 * No need to print alias if it's same as CTE name (this would
12736 * normally be the case, but not if set_rtable_names had to resolve a
12737 * conflict).
12738 */
12739 if (strcmp(refname, rte->ctename) != 0)
12740 printalias = true;
12741 }
12742
12743 if (printalias)
12744 appendStringInfo(context->buf, "%s%s",
12745 use_as ? " AS " : " ",
12746 quote_identifier(refname));
12747}
static char * get_relation_name(Oid relid)
Definition: ruleutils.c:13162

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

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

10709{
10710 if (looks_like_function(node))
10711 get_rule_expr(node, context, showimplicit);
10712 else
10713 {
10714 StringInfo buf = context->buf;
10715
10716 appendStringInfoString(buf, "CAST(");
10717 /* no point in showing any top-level implicit cast */
10718 get_rule_expr(node, context, false);
10719 appendStringInfo(buf, " AS %s)",
10721 exprTypmod(node)));
10722 }
10723}
static bool looks_like_function(Node *node)
Definition: ruleutils.c:10730

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

9166{
9167 bool need_paren;
9168
9169 need_paren = PRETTY_PAREN(context) &&
9170 !isSimpleNode(node, parentNode, context->prettyFlags);
9171
9172 if (need_paren)
9173 appendStringInfoChar(context->buf, '(');
9174
9175 get_rule_expr(node, context, showimplicit);
9176
9177 if (need_paren)
9178 appendStringInfoChar(context->buf, ')');
9179}
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
Definition: ruleutils.c:8859

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

10661{
10662 if (node && IsA(node, Var))
10663 (void) get_variable((Var *) node, 0, true, context);
10664 else
10665 get_rule_expr(node, context, showimplicit);
10666}

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

6634{
6635 ListCell *l;
6636 StringInfo buf = context->buf;
6637 bool omit_child_parens = true;
6638 char *sep = "";
6639
6640 switch (gset->kind)
6641 {
6642 case GROUPING_SET_EMPTY:
6644 return;
6645
6647 {
6648 if (!omit_parens || list_length(gset->content) != 1)
6650
6651 foreach(l, gset->content)
6652 {
6653 Index ref = lfirst_int(l);
6654
6656 get_rule_sortgroupclause(ref, targetlist,
6657 false, context);
6658 sep = ", ";
6659 }
6660
6661 if (!omit_parens || list_length(gset->content) != 1)
6663 }
6664 return;
6665
6667 appendStringInfoString(buf, "ROLLUP(");
6668 break;
6669 case GROUPING_SET_CUBE:
6670 appendStringInfoString(buf, "CUBE(");
6671 break;
6672 case GROUPING_SET_SETS:
6673 appendStringInfoString(buf, "GROUPING SETS (");
6674 omit_child_parens = false;
6675 break;
6676 }
6677
6678 foreach(l, gset->content)
6679 {
6681 get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6682 sep = ", ";
6683 }
6684
6686}
@ GROUPING_SET_CUBE
Definition: parsenodes.h:1533
@ GROUPING_SET_SIMPLE
Definition: parsenodes.h:1531
@ GROUPING_SET_ROLLUP
Definition: parsenodes.h:1532
@ GROUPING_SET_SETS
Definition: parsenodes.h:1534
@ GROUPING_SET_EMPTY
Definition: parsenodes.h:1530
List * content
Definition: parsenodes.h:1541

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

10679{
10680 const char *sep;
10681 ListCell *lc;
10682
10683 sep = "";
10684 foreach(lc, lst)
10685 {
10686 Node *e = (Node *) lfirst(lc);
10687
10688 appendStringInfoString(context->buf, sep);
10689 get_rule_expr_toplevel(e, context, showimplicit);
10690 sep = ", ";
10691 }
10692}

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

6694{
6695 StringInfo buf = context->buf;
6696 const char *sep;
6697 ListCell *l;
6698
6699 sep = "";
6700 foreach(l, orderList)
6701 {
6703 Node *sortexpr;
6704 Oid sortcoltype;
6705 TypeCacheEntry *typentry;
6706
6708 sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6709 force_colno, context);
6710 sortcoltype = exprType(sortexpr);
6711 /* See whether operator is default < or > for datatype */
6712 typentry = lookup_type_cache(sortcoltype,
6714 if (srt->sortop == typentry->lt_opr)
6715 {
6716 /* ASC is default, so emit nothing for it */
6717 if (srt->nulls_first)
6718 appendStringInfoString(buf, " NULLS FIRST");
6719 }
6720 else if (srt->sortop == typentry->gt_opr)
6721 {
6722 appendStringInfoString(buf, " DESC");
6723 /* DESC defaults to NULLS FIRST */
6724 if (!srt->nulls_first)
6725 appendStringInfoString(buf, " NULLS LAST");
6726 }
6727 else
6728 {
6729 appendStringInfo(buf, " USING %s",
6731 sortcoltype,
6732 sortcoltype));
6733 /* be specific to eliminate ambiguity */
6734 if (srt->nulls_first)
6735 appendStringInfoString(buf, " NULLS FIRST");
6736 else
6737 appendStringInfoString(buf, " NULLS LAST");
6738 }
6739 sep = ", ";
6740 }
6741}
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 6563 of file ruleutils.c.

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

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

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

6784{
6785 StringInfo buf = context->buf;
6786 bool needspace = false;
6787 const char *sep;
6788 ListCell *l;
6789
6791 if (wc->refname)
6792 {
6794 needspace = true;
6795 }
6796 /* partition clauses are always inherited, so only print if no refname */
6797 if (wc->partitionClause && !wc->refname)
6798 {
6799 if (needspace)
6801 appendStringInfoString(buf, "PARTITION BY ");
6802 sep = "";
6803 foreach(l, wc->partitionClause)
6804 {
6806
6809 false, context);
6810 sep = ", ";
6811 }
6812 needspace = true;
6813 }
6814 /* print ordering clause only if not inherited */
6815 if (wc->orderClause && !wc->copiedOrder)
6816 {
6817 if (needspace)
6819 appendStringInfoString(buf, "ORDER BY ");
6820 get_rule_orderby(wc->orderClause, targetList, false, context);
6821 needspace = true;
6822 }
6823 /* framing clause is never inherited, so print unless it's default */
6825 {
6826 if (needspace)
6829 wc->startOffset, wc->endOffset,
6830 context);
6831 }
6833}
#define FRAMEOPTION_NONDEFAULT
Definition: parsenodes.h:609
static void get_window_frame_options(int frameOptions, Node *startOffset, Node *endOffset, deparse_context *context)
Definition: ruleutils.c:6839
Node * startOffset
Definition: parsenodes.h:1578
List * partitionClause
Definition: parsenodes.h:1574
Node * endOffset
Definition: parsenodes.h:1579
List * orderClause
Definition: parsenodes.h:1576

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

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

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

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

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

8834{
8835 List *args = expr->args;
8836
8837 if (list_length(args) == 2)
8838 {
8839 /* binary operator */
8840 Node *arg1 = (Node *) linitial(args);
8841 Node *arg2 = (Node *) lsecond(args);
8842 const char *op;
8843
8844 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
8845 if (strlen(op) == 1)
8846 return op;
8847 }
8848 return NULL;
8849}

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

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

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

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

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

11850{
11851 StringInfo buf = context->buf;
11852 Query *query = (Query *) (sublink->subselect);
11853 char *opname = NULL;
11854 bool need_paren;
11855
11856 if (sublink->subLinkType == ARRAY_SUBLINK)
11857 appendStringInfoString(buf, "ARRAY(");
11858 else
11860
11861 /*
11862 * Note that we print the name of only the first operator, when there are
11863 * multiple combining operators. This is an approximation that could go
11864 * wrong in various scenarios (operators in different schemas, renamed
11865 * operators, etc) but there is not a whole lot we can do about it, since
11866 * the syntax allows only one operator to be shown.
11867 */
11868 if (sublink->testexpr)
11869 {
11870 if (IsA(sublink->testexpr, OpExpr))
11871 {
11872 /* single combining operator */
11873 OpExpr *opexpr = (OpExpr *) sublink->testexpr;
11874
11875 get_rule_expr(linitial(opexpr->args), context, true);
11876 opname = generate_operator_name(opexpr->opno,
11877 exprType(linitial(opexpr->args)),
11878 exprType(lsecond(opexpr->args)));
11879 }
11880 else if (IsA(sublink->testexpr, BoolExpr))
11881 {
11882 /* multiple combining operators, = or <> cases */
11883 char *sep;
11884 ListCell *l;
11885
11887 sep = "";
11888 foreach(l, ((BoolExpr *) sublink->testexpr)->args)
11889 {
11890 OpExpr *opexpr = lfirst_node(OpExpr, l);
11891
11893 get_rule_expr(linitial(opexpr->args), context, true);
11894 if (!opname)
11895 opname = generate_operator_name(opexpr->opno,
11896 exprType(linitial(opexpr->args)),
11897 exprType(lsecond(opexpr->args)));
11898 sep = ", ";
11899 }
11901 }
11902 else if (IsA(sublink->testexpr, RowCompareExpr))
11903 {
11904 /* multiple combining operators, < <= > >= cases */
11905 RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
11906
11908 get_rule_expr((Node *) rcexpr->largs, context, true);
11909 opname = generate_operator_name(linitial_oid(rcexpr->opnos),
11910 exprType(linitial(rcexpr->largs)),
11911 exprType(linitial(rcexpr->rargs)));
11913 }
11914 else
11915 elog(ERROR, "unrecognized testexpr type: %d",
11916 (int) nodeTag(sublink->testexpr));
11917 }
11918
11919 need_paren = true;
11920
11921 switch (sublink->subLinkType)
11922 {
11923 case EXISTS_SUBLINK:
11924 appendStringInfoString(buf, "EXISTS ");
11925 break;
11926
11927 case ANY_SUBLINK:
11928 if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
11929 appendStringInfoString(buf, " IN ");
11930 else
11931 appendStringInfo(buf, " %s ANY ", opname);
11932 break;
11933
11934 case ALL_SUBLINK:
11935 appendStringInfo(buf, " %s ALL ", opname);
11936 break;
11937
11938 case ROWCOMPARE_SUBLINK:
11939 appendStringInfo(buf, " %s ", opname);
11940 break;
11941
11942 case EXPR_SUBLINK:
11943 case MULTIEXPR_SUBLINK:
11944 case ARRAY_SUBLINK:
11945 need_paren = false;
11946 break;
11947
11948 case CTE_SUBLINK: /* shouldn't occur in a SubLink */
11949 default:
11950 elog(ERROR, "unrecognized sublink type: %d",
11951 (int) sublink->subLinkType);
11952 break;
11953 }
11954
11955 if (need_paren)
11957
11958 get_query_def(query, buf, context->namespaces, NULL, false,
11959 context->prettyFlags, context->wrapColumn,
11960 context->indentLevel);
11961
11962 if (need_paren)
11964 else
11966}

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

12281{
12282 /* XMLTABLE and JSON_TABLE are the only existing implementations. */
12283
12284 if (tf->functype == TFT_XMLTABLE)
12285 get_xmltable(tf, context, showimplicit);
12286 else if (tf->functype == TFT_JSON_TABLE)
12287 get_json_table(tf, context, showimplicit);
12288}
@ 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:11974
static void get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:12211
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 12846 of file ruleutils.c.

12847{
12848 StringInfo buf = context->buf;
12849 Oid argtypes[1];
12850 int nargs;
12851 ListCell *l;
12852
12853 /*
12854 * We should qualify the handler's function name if it wouldn't be
12855 * resolved by lookup in the current search path.
12856 */
12857 argtypes[0] = INTERNALOID;
12858 appendStringInfo(buf, " TABLESAMPLE %s (",
12859 generate_function_name(tablesample->tsmhandler, 1,
12860 NIL, argtypes,
12861 false, NULL, false));
12862
12863 nargs = 0;
12864 foreach(l, tablesample->args)
12865 {
12866 if (nargs++ > 0)
12868 get_rule_expr((Node *) lfirst(l), context, false);
12869 }
12871
12872 if (tablesample->repeatable != NULL)
12873 {
12874 appendStringInfoString(buf, " REPEATABLE (");
12875 get_rule_expr((Node *) tablesample->repeatable, context, false);
12877 }
12878}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

11050{
11051 get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
11052}

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

11063{
11064 StringInfo buf = context->buf;
11065 Oid argtypes[FUNC_MAX_ARGS];
11066 int nargs;
11067 List *argnames;
11068 ListCell *l;
11069
11070 if (list_length(wfunc->args) > FUNC_MAX_ARGS)
11071 ereport(ERROR,
11072 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
11073 errmsg("too many arguments")));
11074 nargs = 0;
11075 argnames = NIL;
11076 foreach(l, wfunc->args)
11077 {
11078 Node *arg = (Node *) lfirst(l);
11079
11080 if (IsA(arg, NamedArgExpr))
11081 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
11082 argtypes[nargs] = exprType(arg);
11083 nargs++;
11084 }
11085
11086 if (!funcname)
11087 funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
11088 argtypes, false, NULL,
11089 context->inGroupBy);
11090
11091 appendStringInfo(buf, "%s(", funcname);
11092
11093 /* winstar can be set only in zero-argument aggregates */
11094 if (wfunc->winstar)
11096 else
11097 {
11098 if (is_json_objectagg)
11099 {
11100 get_rule_expr((Node *) linitial(wfunc->args), context, false);
11102 get_rule_expr((Node *) lsecond(wfunc->args), context, false);
11103 }
11104 else
11105 get_rule_expr((Node *) wfunc->args, context, true);
11106 }
11107
11108 if (options)
11110
11111 if (wfunc->aggfilter != NULL)
11112 {
11113 appendStringInfoString(buf, ") FILTER (WHERE ");
11114 get_rule_expr((Node *) wfunc->aggfilter, context, false);
11115 }
11116
11118
11119 if (wfunc->ignore_nulls == PARSER_IGNORE_NULLS)
11120 appendStringInfoString(buf, "IGNORE NULLS ");
11121
11122 appendStringInfoString(buf, "OVER ");
11123
11124 if (context->windowClause)
11125 {
11126 /* Query-decompilation case: search the windowClause list */
11127 foreach(l, context->windowClause)
11128 {
11129 WindowClause *wc = (WindowClause *) lfirst(l);
11130
11131 if (wc->winref == wfunc->winref)
11132 {
11133 if (wc->name)
11135 else
11136 get_rule_windowspec(wc, context->targetList, context);
11137 break;
11138 }
11139 }
11140 if (l == NULL)
11141 elog(ERROR, "could not find window clause for winref %u",
11142 wfunc->winref);
11143 }
11144 else
11145 {
11146 /*
11147 * In EXPLAIN, search the namespace stack for a matching WindowAgg
11148 * node (probably it's always the first entry), and print winname.
11149 */
11150 foreach(l, context->namespaces)
11151 {
11153
11154 if (dpns->plan && IsA(dpns->plan, WindowAgg))
11155 {
11156 WindowAgg *wagg = (WindowAgg *) dpns->plan;
11157
11158 if (wagg->winref == wfunc->winref)
11159 {
11161 break;
11162 }
11163 }
11164 }
11165 if (l == NULL)
11166 elog(ERROR, "could not find window clause for winref %u",
11167 wfunc->winref);
11168 }
11169}
#define PARSER_IGNORE_NULLS
Definition: primnodes.h:589
char * winname
Definition: plannodes.h:1228
Index winref
Definition: plannodes.h:1231
List * args
Definition: primnodes.h:605
Index winref
Definition: primnodes.h:611
Expr * aggfilter
Definition: primnodes.h:607
int ignore_nulls
Definition: primnodes.h:617
Oid winfnoid
Definition: primnodes.h:597

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(), WindowFunc::ignore_nulls, deparse_context::inGroupBy, IsA, lappend(), lfirst, linitial, list_length(), lsecond, deparse_context::namespaces, NIL, PARSER_IGNORE_NULLS, 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 5766 of file ruleutils.c.

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

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

11975{
11976 StringInfo buf = context->buf;
11977
11978 appendStringInfoString(buf, "XMLTABLE(");
11979
11980 if (tf->ns_uris != NIL)
11981 {
11982 ListCell *lc1,
11983 *lc2;
11984 bool first = true;
11985
11986 appendStringInfoString(buf, "XMLNAMESPACES (");
11987 forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
11988 {
11989 Node *expr = (Node *) lfirst(lc1);
11990 String *ns_node = lfirst_node(String, lc2);
11991
11992 if (!first)
11994 else
11995 first = false;
11996
11997 if (ns_node != NULL)
11998 {
11999 get_rule_expr(expr, context, showimplicit);
12000 appendStringInfo(buf, " AS %s",
12001 quote_identifier(strVal(ns_node)));
12002 }
12003 else
12004 {
12005 appendStringInfoString(buf, "DEFAULT ");
12006 get_rule_expr(expr, context, showimplicit);
12007 }
12008 }
12010 }
12011
12013 get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
12014 appendStringInfoString(buf, ") PASSING (");
12015 get_rule_expr((Node *) tf->docexpr, context, showimplicit);
12017
12018 if (tf->colexprs != NIL)
12019 {
12020 ListCell *l1;
12021 ListCell *l2;
12022 ListCell *l3;
12023 ListCell *l4;
12024 ListCell *l5;
12025 int colnum = 0;
12026
12027 appendStringInfoString(buf, " COLUMNS ");
12028 forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
12029 l4, tf->colexprs, l5, tf->coldefexprs)
12030 {
12031 char *colname = strVal(lfirst(l1));
12032 Oid typid = lfirst_oid(l2);
12033 int32 typmod = lfirst_int(l3);
12034 Node *colexpr = (Node *) lfirst(l4);
12035 Node *coldefexpr = (Node *) lfirst(l5);
12036 bool ordinality = (tf->ordinalitycol == colnum);
12037 bool notnull = bms_is_member(colnum, tf->notnulls);
12038
12039 if (colnum > 0)
12041 colnum++;
12042
12043 appendStringInfo(buf, "%s %s", quote_identifier(colname),
12044 ordinality ? "FOR ORDINALITY" :
12045 format_type_with_typemod(typid, typmod));
12046 if (ordinality)
12047 continue;
12048
12049 if (coldefexpr != NULL)
12050 {
12051 appendStringInfoString(buf, " DEFAULT (");
12052 get_rule_expr((Node *) coldefexpr, context, showimplicit);
12054 }
12055 if (colexpr != NULL)
12056 {
12057 appendStringInfoString(buf, " PATH (");
12058 get_rule_expr((Node *) colexpr, context, showimplicit);
12060 }
12061 if (notnull)
12062 appendStringInfoString(buf, " NOT NULL");
12063 }
12064 }
12065
12067}
#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 4139 of file ruleutils.c.

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

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

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

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

Referenced by pg_get_function_arg_default().

◆ isSimpleNode()

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

Definition at line 8859 of file ruleutils.c.

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

10731{
10732 if (node == NULL)
10733 return false; /* probably shouldn't happen */
10734 switch (nodeTag(node))
10735 {
10736 case T_FuncExpr:
10737 /* OK, unless it's going to deparse as a cast */
10738 return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
10739 ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
10740 case T_NullIfExpr:
10741 case T_CoalesceExpr:
10742 case T_MinMaxExpr:
10743 case T_SQLValueFunction:
10744 case T_XmlExpr:
10745 case T_JsonExpr:
10746 /* these are all accepted by func_expr_common_subexpr */
10747 return true;
10748 default:
10749 break;
10750 }
10751 return false;
10752}

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

4924{
4925 /*
4926 * If the selected name isn't unique, append digits to make it so. For a
4927 * very long input name, we might have to truncate to stay within
4928 * NAMEDATALEN.
4929 */
4930 if (!colname_is_unique(colname, dpns, colinfo))
4931 {
4932 int colnamelen = strlen(colname);
4933 char *modname = (char *) palloc(colnamelen + 16);
4934 int i = 0;
4935
4936 do
4937 {
4938 i++;
4939 for (;;)
4940 {
4941 memcpy(modname, colname, colnamelen);
4942 sprintf(modname + colnamelen, "_%d", i);
4943 if (strlen(modname) < NAMEDATALEN)
4944 break;
4945 /* drop chars from colname to keep all the digits */
4946 colnamelen = pg_mbcliplen(colname, colnamelen,
4947 colnamelen - 1);
4948 }
4949 } while (!colname_is_unique(modname, dpns, colinfo));
4950 colname = modname;
4951 }
4952 return colname;
4953}
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:4847

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

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

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

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

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

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

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

References pg_get_constraintdef_worker().

Referenced by RememberConstraintForRebuilding().

◆ pg_get_constraintdef_ext()

Datum pg_get_constraintdef_ext ( PG_FUNCTION_ARGS  )

Definition at line 2162 of file ruleutils.c.

2163{
2164 Oid constraintId = PG_GETARG_OID(0);
2165 bool pretty = PG_GETARG_BOOL(1);
2166 int prettyFlags;
2167 char *res;
2168
2169 prettyFlags = GET_PRETTY_FLAGS(pretty);
2170
2171 res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2172
2173 if (res == NULL)
2175
2177}
#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 2192 of file ruleutils.c.

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

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

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

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

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

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

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

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

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

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

3179{
3180 Oid funcid = PG_GETARG_OID(0);
3182 HeapTuple proctup;
3183
3184 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3185 if (!HeapTupleIsValid(proctup))
3187
3189
3190 (void) print_function_arguments(&buf, proctup, false, true);
3191
3192 ReleaseSysCache(proctup);
3193
3195}
static int print_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults)
Definition: ruleutils.c:3297

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

3205{
3206 Oid funcid = PG_GETARG_OID(0);
3208 HeapTuple proctup;
3209
3210 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3211 if (!HeapTupleIsValid(proctup))
3213
3215
3216 (void) print_function_arguments(&buf, proctup, false, false);
3217
3218 ReleaseSysCache(proctup);
3219
3221}

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

3230{
3231 Oid funcid = PG_GETARG_OID(0);
3233 HeapTuple proctup;
3234
3235 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3236 if (!HeapTupleIsValid(proctup))
3238
3239 if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3240 {
3241 ReleaseSysCache(proctup);
3243 }
3244
3246
3247 print_function_rettype(&buf, proctup);
3248
3249 ReleaseSysCache(proctup);
3250
3252}
static void print_function_rettype(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3259

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

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

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

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

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:533
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:456
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:1063
void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod, Oid *collid)
Definition: lsyscache.c:1036
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:322
bool amcanorder
Definition: amapi.h:246
Definition: c.h:720
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:727
Definition: c.h:731
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:738

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

2128{
2129 Expr *constr_expr;
2130 List *context;
2131
2132 constr_expr = get_partition_qual_relid(partitionId);
2133 context = deparse_context_for(aliasname, partitionId);
2134
2135 return deparse_expression((Node *) constr_expr, context, true, false);
2136}
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 2095 of file ruleutils.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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
static char * VARDATA_ANY(const void *PTR)
Definition: varatt.h:486

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

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

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:360
#define ViewSelectRuleName
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags, int wrapColumn)
Definition: ruleutils.c:5538
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 5330 of file ruleutils.c.

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

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

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

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

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

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

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

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

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

13029{
13030 StringInfo buf = context->buf;
13031 ListCell *lowlist_item;
13032 ListCell *uplist_item;
13033
13034 lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
13035 foreach(uplist_item, sbsref->refupperindexpr)
13036 {
13038 if (lowlist_item)
13039 {
13040 /* If subexpression is NULL, get_rule_expr prints nothing */
13041 get_rule_expr((Node *) lfirst(lowlist_item), context, false);
13043 lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
13044 }
13045 /* If subexpression is NULL, get_rule_expr prints nothing */
13046 get_rule_expr((Node *) lfirst(uplist_item), context, false);
13048 }
13049}
List * refupperindexpr
Definition: primnodes.h:725
List * reflowerindexpr
Definition: primnodes.h:731

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

12951{
12952 StringInfo buf = context->buf;
12953 CoerceToDomain *cdomain = NULL;
12954
12955 for (;;)
12956 {
12957 if (node == NULL)
12958 break;
12959 if (IsA(node, FieldStore))
12960 {
12961 FieldStore *fstore = (FieldStore *) node;
12962 Oid typrelid;
12963 char *fieldname;
12964
12965 /* lookup tuple type */
12966 typrelid = get_typ_typrelid(fstore->resulttype);
12967 if (!OidIsValid(typrelid))
12968 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
12969 format_type_be(fstore->resulttype));
12970
12971 /*
12972 * Print the field name. There should only be one target field in
12973 * stored rules. There could be more than that in executable
12974 * target lists, but this function cannot be used for that case.
12975 */
12976 Assert(list_length(fstore->fieldnums) == 1);
12977 fieldname = get_attname(typrelid,
12978 linitial_int(fstore->fieldnums), false);
12979 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
12980
12981 /*
12982 * We ignore arg since it should be an uninteresting reference to
12983 * the target column or subcolumn.
12984 */
12985 node = (Node *) linitial(fstore->newvals);
12986 }
12987 else if (IsA(node, SubscriptingRef))
12988 {
12989 SubscriptingRef *sbsref = (SubscriptingRef *) node;
12990
12991 if (sbsref->refassgnexpr == NULL)
12992 break;
12993
12994 printSubscripts(sbsref, context);
12995
12996 /*
12997 * We ignore refexpr since it should be an uninteresting reference
12998 * to the target column or subcolumn.
12999 */
13000 node = (Node *) sbsref->refassgnexpr;
13001 }
13002 else if (IsA(node, CoerceToDomain))
13003 {
13004 cdomain = (CoerceToDomain *) node;
13005 /* If it's an explicit domain coercion, we're done */
13006 if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
13007 break;
13008 /* Tentatively descend past the CoerceToDomain */
13009 node = (Node *) cdomain->arg;
13010 }
13011 else
13012 break;
13013 }
13014
13015 /*
13016 * If we descended past a CoerceToDomain whose argument turned out not to
13017 * be a FieldStore or array assignment, back up to the CoerceToDomain.
13018 * (This is not enough to be fully correct if there are nested implicit
13019 * CoerceToDomains, but such cases shouldn't ever occur.)
13020 */
13021 if (cdomain && node == (Node *) cdomain->arg)
13022 node = (Node *) cdomain;
13023
13024 return node;
13025}
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2898
#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 5309 of file ruleutils.c.

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

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

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

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

13059{
13060 /*
13061 * Can avoid quoting if ident starts with a lowercase letter or underscore
13062 * and contains only lowercase letters, digits, and underscores, *and* is
13063 * not any SQL keyword. Otherwise, supply quotes.
13064 */
13065 int nquotes = 0;
13066 bool safe;
13067 const char *ptr;
13068 char *result;
13069 char *optr;
13070
13071 /*
13072 * would like to use <ctype.h> macros here, but they might yield unwanted
13073 * locale-specific results...
13074 */
13075 safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
13076
13077 for (ptr = ident; *ptr; ptr++)
13078 {
13079 char ch = *ptr;
13080
13081 if ((ch >= 'a' && ch <= 'z') ||
13082 (ch >= '0' && ch <= '9') ||
13083 (ch == '_'))
13084 {
13085 /* okay */
13086 }
13087 else
13088 {
13089 safe = false;
13090 if (ch == '"')
13091 nquotes++;
13092 }
13093 }
13094
13096 safe = false;
13097
13098 if (safe)
13099 {
13100 /*
13101 * Check for keyword. We quote keywords except for unreserved ones.
13102 * (In some cases we could avoid quoting a col_name or type_func_name
13103 * keyword, but it seems much harder than it's worth to tell that.)
13104 *
13105 * Note: ScanKeywordLookup() does case-insensitive comparison, but
13106 * that's fine, since we already know we have all-lower-case.
13107 */
13108 int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
13109
13110 if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
13111 safe = false;
13112 }
13113
13114 if (safe)
13115 return ident; /* no change needed */
13116
13117 result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
13118
13119 optr = result;
13120 *optr++ = '"';
13121 for (ptr = ident; *ptr; ptr++)
13122 {
13123 char ch = *ptr;
13124
13125 if (ch == '"')
13126 *optr++ = '"';
13127 *optr++ = ch;
13128 }
13129 *optr++ = '"';
13130 *optr = '\0';
13131
13132 return result;
13133}
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(), regdatabaseout(), 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 9145 of file ruleutils.c.

9146{
9147 while (str->len > 0 && str->data[str->len - 1] == ' ')
9148 str->data[--(str->len)] = '\0';
9149}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

11823{
11824 const char *valptr;
11825
11826 /*
11827 * We form the string literal according to the prevailing setting of
11828 * standard_conforming_strings; we never use E''. User is responsible for
11829 * making sure result is used correctly.
11830 */
11832 for (valptr = val; *valptr; valptr++)
11833 {
11834 char ch = *valptr;
11835
11839 }
11841}
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1162
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().