PostgreSQL Source Code git master
Loading...
Searching...
No Matches
deparse.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_dict.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "nodes/nodeFuncs.h"
#include "nodes/plannodes.h"
#include "optimizer/optimizer.h"
#include "optimizer/prep.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
#include "postgres_fdw.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for deparse.c:

Go to the source code of this file.

Data Structures

struct  foreign_glob_cxt
 
struct  foreign_loc_cxt
 
struct  deparse_expr_cxt
 

Macros

#define REL_ALIAS_PREFIX   "r"
 
#define ADD_REL_QUALIFIER(buf, varno)    appendStringInfo((buf), "%s%d.", REL_ALIAS_PREFIX, (varno))
 
#define SUBQUERY_REL_ALIAS_PREFIX   "s"
 
#define SUBQUERY_COL_ALIAS_PREFIX   "c"
 

Typedefs

typedef struct foreign_glob_cxt foreign_glob_cxt
 
typedef struct foreign_loc_cxt foreign_loc_cxt
 
typedef struct deparse_expr_cxt deparse_expr_cxt
 

Enumerations

enum  FDWCollateState { FDW_COLLATE_NONE , FDW_COLLATE_SAFE , FDW_COLLATE_UNSAFE }
 

Functions

static bool foreign_expr_walker (Node *node, foreign_glob_cxt *glob_cxt, foreign_loc_cxt *outer_cxt, foreign_loc_cxt *case_arg_cxt)
 
static chardeparse_type_name (Oid type_oid, int32 typemod)
 
static void deparseTargetList (StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, bool is_returning, Bitmapset *attrs_used, bool qualify_col, List **retrieved_attrs)
 
static void deparseExplicitTargetList (List *tlist, bool is_returning, List **retrieved_attrs, deparse_expr_cxt *context)
 
static void deparseSubqueryTargetList (deparse_expr_cxt *context)
 
static void deparseReturningList (StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, bool trig_after_row, List *withCheckOptionList, List *returningList, List **retrieved_attrs)
 
static void deparseColumnRef (StringInfo buf, int varno, int varattno, RangeTblEntry *rte, bool qualify_col)
 
static void deparseRelation (StringInfo buf, Relation rel)
 
static void deparseExpr (Expr *node, deparse_expr_cxt *context)
 
static void deparseVar (Var *node, deparse_expr_cxt *context)
 
static void deparseConst (Const *node, deparse_expr_cxt *context, int showtype)
 
static void deparseParam (Param *node, deparse_expr_cxt *context)
 
static void deparseSubscriptingRef (SubscriptingRef *node, deparse_expr_cxt *context)
 
static void deparseFuncExpr (FuncExpr *node, deparse_expr_cxt *context)
 
static void deparseOpExpr (OpExpr *node, deparse_expr_cxt *context)
 
static bool isPlainForeignVar (Expr *node, deparse_expr_cxt *context)
 
static void deparseOperatorName (StringInfo buf, Form_pg_operator opform)
 
static void deparseDistinctExpr (DistinctExpr *node, deparse_expr_cxt *context)
 
static void deparseScalarArrayOpExpr (ScalarArrayOpExpr *node, deparse_expr_cxt *context)
 
static void deparseRelabelType (RelabelType *node, deparse_expr_cxt *context)
 
static void deparseArrayCoerceExpr (ArrayCoerceExpr *node, deparse_expr_cxt *context)
 
static void deparseBoolExpr (BoolExpr *node, deparse_expr_cxt *context)
 
static void deparseNullTest (NullTest *node, deparse_expr_cxt *context)
 
static void deparseCaseExpr (CaseExpr *node, deparse_expr_cxt *context)
 
static void deparseArrayExpr (ArrayExpr *node, deparse_expr_cxt *context)
 
static void printRemoteParam (int paramindex, Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
 
static void printRemotePlaceholder (Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
 
static void deparseSelectSql (List *tlist, bool is_subquery, List **retrieved_attrs, deparse_expr_cxt *context)
 
static void deparseLockingClause (deparse_expr_cxt *context)
 
static void appendOrderByClause (List *pathkeys, bool has_final_sort, deparse_expr_cxt *context)
 
static void appendLimitClause (deparse_expr_cxt *context)
 
static void appendConditions (List *exprs, deparse_expr_cxt *context)
 
static void deparseFromExprForRel (StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool use_alias, Index ignore_rel, List **ignore_conds, List **additional_conds, List **params_list)
 
static void appendWhereClause (List *exprs, List *additional_conds, deparse_expr_cxt *context)
 
static void deparseFromExpr (List *quals, deparse_expr_cxt *context)
 
static void deparseRangeTblRef (StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool make_subquery, Index ignore_rel, List **ignore_conds, List **additional_conds, List **params_list)
 
static void deparseAggref (Aggref *node, deparse_expr_cxt *context)
 
static void appendGroupByClause (List *tlist, deparse_expr_cxt *context)
 
static void appendOrderBySuffix (Oid sortop, Oid sortcoltype, bool nulls_first, deparse_expr_cxt *context)
 
static void appendAggOrderBy (List *orderList, List *targetList, deparse_expr_cxt *context)
 
static void appendFunctionName (Oid funcid, deparse_expr_cxt *context)
 
static NodedeparseSortGroupClause (Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
 
static bool is_subquery_var (Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
 
static void get_relation_column_alias_ids (Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
 
void classifyConditions (PlannerInfo *root, RelOptInfo *baserel, List *input_conds, List **remote_conds, List **local_conds)
 
bool is_foreign_expr (PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
 
bool is_foreign_param (PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
 
bool is_foreign_pathkey (PlannerInfo *root, RelOptInfo *baserel, PathKey *pathkey)
 
Listbuild_tlist_to_deparse (RelOptInfo *foreignrel)
 
void deparseSelectStmtForRel (StringInfo buf, PlannerInfo *root, RelOptInfo *rel, List *tlist, List *remote_conds, List *pathkeys, bool has_final_sort, bool has_limit, bool is_subquery, List **retrieved_attrs, List **params_list)
 
const charget_jointype_name (JoinType jointype)
 
void deparseInsertSql (StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs, bool doNothing, List *withCheckOptionList, List *returningList, List **retrieved_attrs, int *values_end_len)
 
void rebuildInsertSql (StringInfo buf, Relation rel, char *orig_query, List *target_attrs, int values_end_len, int num_params, int num_rows)
 
void deparseUpdateSql (StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs, List *withCheckOptionList, List *returningList, List **retrieved_attrs)
 
void deparseDirectUpdateSql (StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, RelOptInfo *foreignrel, List *targetlist, List *targetAttrs, List *remote_conds, List **params_list, List *returningList, List **retrieved_attrs)
 
void deparseDeleteSql (StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *returningList, List **retrieved_attrs)
 
void deparseDirectDeleteSql (StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, RelOptInfo *foreignrel, List *remote_conds, List **params_list, List *returningList, List **retrieved_attrs)
 
void deparseAnalyzeSizeSql (StringInfo buf, Relation rel)
 
void deparseAnalyzeInfoSql (StringInfo buf, Relation rel)
 
void deparseAnalyzeSql (StringInfo buf, Relation rel, PgFdwSamplingMethod sample_method, double sample_frac, List **retrieved_attrs)
 
void deparseTruncateSql (StringInfo buf, List *rels, DropBehavior behavior, bool restart_seqs)
 
void deparseStringLiteral (StringInfo buf, const char *val)
 

Macro Definition Documentation

◆ ADD_REL_QUALIFIER

#define ADD_REL_QUALIFIER (   buf,
  varno 
)     appendStringInfo((buf), "%s%d.", REL_ALIAS_PREFIX, (varno))

Definition at line 111 of file deparse.c.

◆ REL_ALIAS_PREFIX

#define REL_ALIAS_PREFIX   "r"

Definition at line 109 of file deparse.c.

◆ SUBQUERY_COL_ALIAS_PREFIX

#define SUBQUERY_COL_ALIAS_PREFIX   "c"

Definition at line 114 of file deparse.c.

◆ SUBQUERY_REL_ALIAS_PREFIX

#define SUBQUERY_REL_ALIAS_PREFIX   "s"

Definition at line 113 of file deparse.c.

Typedef Documentation

◆ deparse_expr_cxt

◆ foreign_glob_cxt

◆ foreign_loc_cxt

Enumeration Type Documentation

◆ FDWCollateState

Enumerator
FDW_COLLATE_NONE 
FDW_COLLATE_SAFE 
FDW_COLLATE_UNSAFE 

Definition at line 79 of file deparse.c.

80{
81 FDW_COLLATE_NONE, /* expression is of a noncollatable type, or
82 * it has default collation that is not
83 * traceable to a foreign Var */
84 FDW_COLLATE_SAFE, /* collation derives from a foreign Var */
85 FDW_COLLATE_UNSAFE, /* collation is non-default and derives from
86 * something other than a foreign Var */
FDWCollateState
Definition deparse.c:80
@ FDW_COLLATE_SAFE
Definition deparse.c:84
@ FDW_COLLATE_UNSAFE
Definition deparse.c:85
@ FDW_COLLATE_NONE
Definition deparse.c:81

Function Documentation

◆ appendAggOrderBy()

static void appendAggOrderBy ( List orderList,
List targetList,
deparse_expr_cxt context 
)
static

Definition at line 3821 of file deparse.c.

3822{
3823 StringInfo buf = context->buf;
3824 ListCell *lc;
3825 bool first = true;
3826
3827 foreach(lc, orderList)
3828 {
3830 Node *sortexpr;
3831
3832 if (!first)
3834 first = false;
3835
3836 /* Deparse the sort expression proper. */
3837 sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
3838 false, context);
3839 /* Add decoration as needed. */
3840 appendOrderBySuffix(srt->sortop, exprType(sortexpr), srt->nulls_first,
3841 context);
3842 }
3843}
static Node * deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
Definition deparse.c:4139
static void appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first, deparse_expr_cxt *context)
Definition deparse.c:3850
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
#define lfirst(lc)
Definition pg_list.h:172
static char buf[DEFAULT_XLOG_SEG_SIZE]
static int fb(int x)
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
Definition nodes.h:133
StringInfo buf
Definition deparse.c:105

References appendOrderBySuffix(), appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseSortGroupClause(), exprType(), fb(), and lfirst.

Referenced by deparseAggref().

◆ appendConditions()

static void appendConditions ( List exprs,
deparse_expr_cxt context 
)
static

Definition at line 1622 of file deparse.c.

1623{
1624 int nestlevel;
1625 ListCell *lc;
1626 bool is_first = true;
1627 StringInfo buf = context->buf;
1628
1629 /* Make sure any constants in the exprs are printed portably */
1631
1632 foreach(lc, exprs)
1633 {
1634 Expr *expr = (Expr *) lfirst(lc);
1635
1636 /* Extract clause from RestrictInfo, if required */
1637 if (IsA(expr, RestrictInfo))
1638 expr = ((RestrictInfo *) expr)->clause;
1639
1640 /* Connect expressions with "AND" and parenthesize each condition. */
1641 if (!is_first)
1642 appendStringInfoString(buf, " AND ");
1643
1645 deparseExpr(expr, context);
1647
1648 is_first = false;
1649 }
1650
1652}
static void deparseExpr(Expr *node, deparse_expr_cxt *context)
Definition deparse.c:2935
#define IsA(nodeptr, _type_)
Definition nodes.h:162
void reset_transmission_modes(int nestlevel)
int set_transmission_modes(void)
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242

References appendStringInfoChar(), appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseExpr(), fb(), IsA, lfirst, reset_transmission_modes(), and set_transmission_modes().

Referenced by appendWhereClause(), deparseFromExprForRel(), and deparseSelectStmtForRel().

◆ appendFunctionName()

static void appendFunctionName ( Oid  funcid,
deparse_expr_cxt context 
)
static

Definition at line 4104 of file deparse.c.

4105{
4106 StringInfo buf = context->buf;
4109 const char *proname;
4110
4113 elog(ERROR, "cache lookup failed for function %u", funcid);
4115
4116 /* Print schema name only if it's not pg_catalog */
4117 if (procform->pronamespace != PG_CATALOG_NAMESPACE)
4118 {
4119 const char *schemaname;
4120
4121 schemaname = get_namespace_name(procform->pronamespace);
4122 appendStringInfo(buf, "%s.", quote_identifier(schemaname));
4123 }
4124
4125 /* Always print the function name */
4126 proname = NameStr(procform->proname);
4128
4130}
#define NameStr(name)
Definition c.h:894
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
END_CATALOG_STRUCT typedef FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:140
NameData proname
Definition pg_proc.h:37
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
const char * quote_identifier(const char *ident)
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221

References appendStringInfo(), appendStringInfoString(), deparse_expr_cxt::buf, buf, elog, ERROR, fb(), Form_pg_proc, get_namespace_name(), GETSTRUCT(), HeapTupleIsValid, NameStr, ObjectIdGetDatum(), proname, quote_identifier(), ReleaseSysCache(), and SearchSysCache1().

Referenced by deparseAggref(), and deparseFuncExpr().

◆ appendGroupByClause()

static void appendGroupByClause ( List tlist,
deparse_expr_cxt context 
)
static

Definition at line 3934 of file deparse.c.

3935{
3936 StringInfo buf = context->buf;
3937 Query *query = context->root->parse;
3938 ListCell *lc;
3939 bool first = true;
3940
3941 /* Nothing to be done, if there's no GROUP BY clause in the query. */
3942 if (!query->groupClause)
3943 return;
3944
3945 appendStringInfoString(buf, " GROUP BY ");
3946
3947 /*
3948 * Queries with grouping sets are not pushed down, so we don't expect
3949 * grouping sets here.
3950 */
3951 Assert(!query->groupingSets);
3952
3953 /*
3954 * We intentionally print query->groupClause not processed_groupClause,
3955 * leaving it to the remote planner to get rid of any redundant GROUP BY
3956 * items again. This is necessary in case processed_groupClause reduced
3957 * to empty, and in any case the redundancy situation on the remote might
3958 * be different than what we think here.
3959 */
3960 foreach(lc, query->groupClause)
3961 {
3963
3964 if (!first)
3966 first = false;
3967
3968 deparseSortGroupClause(grp->tleSortGroupRef, tlist, true, context);
3969 }
3970}
#define Assert(condition)
Definition c.h:1002
Query * parse
Definition pathnodes.h:309
List * groupClause
Definition parsenodes.h:221
List * groupingSets
Definition parsenodes.h:224
PlannerInfo * root
Definition deparse.c:100

References appendStringInfoString(), Assert, deparse_expr_cxt::buf, buf, deparseSortGroupClause(), fb(), Query::groupClause, Query::groupingSets, lfirst, PlannerInfo::parse, and deparse_expr_cxt::root.

Referenced by deparseSelectStmtForRel().

◆ appendLimitClause()

static void appendLimitClause ( deparse_expr_cxt context)
static

Definition at line 4076 of file deparse.c.

4077{
4078 PlannerInfo *root = context->root;
4079 StringInfo buf = context->buf;
4080 int nestlevel;
4081
4082 /* Make sure any constants in the exprs are printed portably */
4084
4085 if (root->parse->limitCount)
4086 {
4087 appendStringInfoString(buf, " LIMIT ");
4088 deparseExpr((Expr *) root->parse->limitCount, context);
4089 }
4090 if (root->parse->limitOffset)
4091 {
4092 appendStringInfoString(buf, " OFFSET ");
4093 deparseExpr((Expr *) root->parse->limitOffset, context);
4094 }
4095
4097}
tree ctl root
Definition radixtree.h:1857

References appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseExpr(), fb(), reset_transmission_modes(), deparse_expr_cxt::root, root, and set_transmission_modes().

Referenced by deparseSelectStmtForRel().

◆ appendOrderByClause()

static void appendOrderByClause ( List pathkeys,
bool  has_final_sort,
deparse_expr_cxt context 
)
static

Definition at line 3982 of file deparse.c.

3984{
3985 ListCell *lcell;
3986 int nestlevel;
3987 StringInfo buf = context->buf;
3988 bool gotone = false;
3989
3990 /* Make sure any constants in the exprs are printed portably */
3992
3993 foreach(lcell, pathkeys)
3994 {
3997 Expr *em_expr;
3998 Oid oprid;
3999
4000 if (has_final_sort)
4001 {
4002 /*
4003 * By construction, context->foreignrel is the input relation to
4004 * the final sort.
4005 */
4006 em = find_em_for_rel_target(context->root,
4007 pathkey->pk_eclass,
4008 context->foreignrel);
4009 }
4010 else
4011 em = find_em_for_rel(context->root,
4012 pathkey->pk_eclass,
4013 context->scanrel);
4014
4015 /*
4016 * We don't expect any error here; it would mean that shippability
4017 * wasn't verified earlier. For the same reason, we don't recheck
4018 * shippability of the sort operator.
4019 */
4020 if (em == NULL)
4021 elog(ERROR, "could not find pathkey item to sort");
4022
4023 em_expr = em->em_expr;
4024
4025 /*
4026 * If the member is a Const expression then we needn't add it to the
4027 * ORDER BY clause. This can happen in UNION ALL queries where the
4028 * union child targetlist has a Const. Adding these would be
4029 * wasteful, but also, for INT columns, an integer literal would be
4030 * seen as an ordinal column position rather than a value to sort by.
4031 * deparseConst() does have code to handle this, but it seems less
4032 * effort on all accounts just to skip these for ORDER BY clauses.
4033 */
4034 if (IsA(em_expr, Const))
4035 continue;
4036
4037 if (!gotone)
4038 {
4039 appendStringInfoString(buf, " ORDER BY ");
4040 gotone = true;
4041 }
4042 else
4044
4045 /*
4046 * Lookup the operator corresponding to the compare type in the
4047 * opclass. The datatype used by the opfamily is not necessarily the
4048 * same as the expression type (for array types for example).
4049 */
4051 em->em_datatype,
4052 em->em_datatype,
4053 pathkey->pk_cmptype);
4054 if (!OidIsValid(oprid))
4055 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
4056 pathkey->pk_cmptype, em->em_datatype, em->em_datatype,
4057 pathkey->pk_opfamily);
4058
4059 deparseExpr(em_expr, context);
4060
4061 /*
4062 * Here we need to use the expression's actual type to discover
4063 * whether the desired operator will be the default or not.
4064 */
4065 appendOrderBySuffix(oprid, exprType((Node *) em_expr),
4066 pathkey->pk_nulls_first, context);
4067
4068 }
4070}
#define OidIsValid(objectId)
Definition c.h:917
Oid get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, CompareType cmptype)
Definition lsyscache.c:199
Oid oprid(Operator op)
Definition parse_oper.c:241
unsigned int Oid
EquivalenceMember * find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
EquivalenceMember * find_em_for_rel(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
RelOptInfo * foreignrel
Definition deparse.c:101
RelOptInfo * scanrel
Definition deparse.c:102

References appendOrderBySuffix(), appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseExpr(), elog, ERROR, exprType(), fb(), find_em_for_rel(), find_em_for_rel_target(), deparse_expr_cxt::foreignrel, get_opfamily_member_for_cmptype(), IsA, lfirst, OidIsValid, oprid(), reset_transmission_modes(), deparse_expr_cxt::root, deparse_expr_cxt::scanrel, and set_transmission_modes().

Referenced by deparseSelectStmtForRel().

◆ appendOrderBySuffix()

static void appendOrderBySuffix ( Oid  sortop,
Oid  sortcoltype,
bool  nulls_first,
deparse_expr_cxt context 
)
static

Definition at line 3850 of file deparse.c.

3852{
3853 StringInfo buf = context->buf;
3854 TypeCacheEntry *typentry;
3855
3856 /* See whether operator is default < or > for sort expr's datatype. */
3857 typentry = lookup_type_cache(sortcoltype,
3859
3860 if (sortop == typentry->lt_opr)
3861 appendStringInfoString(buf, " ASC");
3862 else if (sortop == typentry->gt_opr)
3863 appendStringInfoString(buf, " DESC");
3864 else
3865 {
3868
3869 appendStringInfoString(buf, " USING ");
3870
3871 /* Append operator name. */
3874 elog(ERROR, "cache lookup failed for operator %u", sortop);
3878 }
3879
3880 if (nulls_first)
3881 appendStringInfoString(buf, " NULLS FIRST");
3882 else
3883 appendStringInfoString(buf, " NULLS LAST");
3884}
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform)
Definition deparse.c:3460
END_CATALOG_STRUCT typedef FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:87
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#define TYPECACHE_GT_OPR
Definition typcache.h:140
#define TYPECACHE_LT_OPR
Definition typcache.h:139

References appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseOperatorName(), elog, ERROR, fb(), Form_pg_operator, GETSTRUCT(), TypeCacheEntry::gt_opr, HeapTupleIsValid, lookup_type_cache(), TypeCacheEntry::lt_opr, ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache1(), TYPECACHE_GT_OPR, and TYPECACHE_LT_OPR.

Referenced by appendAggOrderBy(), and appendOrderByClause().

◆ appendWhereClause()

static void appendWhereClause ( List exprs,
List additional_conds,
deparse_expr_cxt context 
)
static

Definition at line 1659 of file deparse.c.

1660{
1661 StringInfo buf = context->buf;
1662 bool need_and = false;
1663 ListCell *lc;
1664
1665 if (exprs != NIL || additional_conds != NIL)
1666 appendStringInfoString(buf, " WHERE ");
1667
1668 /*
1669 * If there are some filters, append them.
1670 */
1671 if (exprs != NIL)
1672 {
1673 appendConditions(exprs, context);
1674 need_and = true;
1675 }
1676
1677 /*
1678 * If there are some EXISTS conditions, coming from SEMI-JOINS, append
1679 * them.
1680 */
1681 foreach(lc, additional_conds)
1682 {
1683 if (need_and)
1684 appendStringInfoString(buf, " AND ");
1685 appendStringInfoString(buf, (char *) lfirst(lc));
1686 need_and = true;
1687 }
1688}
static void appendConditions(List *exprs, deparse_expr_cxt *context)
Definition deparse.c:1622
#define NIL
Definition pg_list.h:68

References appendConditions(), appendStringInfoString(), deparse_expr_cxt::buf, buf, fb(), lfirst, and NIL.

Referenced by deparseDirectDeleteSql(), deparseDirectUpdateSql(), deparseFromExpr(), and deparseFromExprForRel().

◆ build_tlist_to_deparse()

List * build_tlist_to_deparse ( RelOptInfo foreignrel)

Definition at line 1229 of file deparse.c.

1230{
1231 List *tlist = NIL;
1232 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1233 ListCell *lc;
1234
1235 /*
1236 * For an upper relation, we have already built the target list while
1237 * checking shippability, so just return that.
1238 */
1239 if (IS_UPPER_REL(foreignrel))
1240 return fpinfo->grouped_tlist;
1241
1242 /*
1243 * We require columns specified in foreignrel->reltarget->exprs and those
1244 * required for evaluating the local conditions.
1245 */
1246 tlist = add_to_flat_tlist(tlist,
1247 pull_var_clause((Node *) foreignrel->reltarget->exprs,
1249 foreach(lc, fpinfo->local_conds)
1250 {
1252
1253 tlist = add_to_flat_tlist(tlist,
1254 pull_var_clause((Node *) rinfo->clause,
1256 }
1257
1258 return tlist;
1259}
#define PVC_RECURSE_PLACEHOLDERS
Definition optimizer.h:202
#define IS_UPPER_REL(rel)
Definition pathnodes.h:999
#define lfirst_node(type, lc)
Definition pg_list.h:176
Definition pg_list.h:54
List * exprs
Definition pathnodes.h:1878
struct PathTarget * reltarget
Definition pathnodes.h:1045
Expr * clause
Definition pathnodes.h:2901
List * add_to_flat_tlist(List *tlist, List *exprs)
Definition tlist.c:141
List * pull_var_clause(Node *node, int flags)
Definition var.c:653

References add_to_flat_tlist(), RestrictInfo::clause, PathTarget::exprs, fb(), IS_UPPER_REL, lfirst_node, NIL, pull_var_clause(), PVC_RECURSE_PLACEHOLDERS, and RelOptInfo::reltarget.

Referenced by estimate_path_cost_size(), and postgresGetForeignPlan().

◆ classifyConditions()

void classifyConditions ( PlannerInfo root,
RelOptInfo baserel,
List input_conds,
List **  remote_conds,
List **  local_conds 
)

Definition at line 218 of file deparse.c.

223{
224 ListCell *lc;
225
226 *remote_conds = NIL;
227 *local_conds = NIL;
228
229 foreach(lc, input_conds)
230 {
232
233 if (is_foreign_expr(root, baserel, ri->clause))
234 *remote_conds = lappend(*remote_conds, ri);
235 else
236 *local_conds = lappend(*local_conds, ri);
237 }
238}
bool is_foreign_expr(PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
Definition deparse.c:244
List * lappend(List *list, void *datum)
Definition list.c:339

References fb(), is_foreign_expr(), lappend(), lfirst_node, NIL, and root.

Referenced by estimate_path_cost_size(), and postgresGetForeignRelSize().

◆ deparse_type_name()

static char * deparse_type_name ( Oid  type_oid,
int32  typemod 
)
static

Definition at line 1210 of file deparse.c.

1211{
1213
1214 if (!is_builtin(type_oid))
1216
1217 return format_type_extended(type_oid, typemod, flags);
1218}
#define FORMAT_TYPE_TYPEMOD_GIVEN
Definition builtins.h:125
#define FORMAT_TYPE_FORCE_QUALIFY
Definition builtins.h:127
uint16_t uint16
Definition c.h:682
char * format_type_extended(Oid type_oid, int32 typemod, uint16 flags)
bool is_builtin(Oid objectId)
Definition shippable.c:153

References fb(), format_type_extended(), FORMAT_TYPE_FORCE_QUALIFY, FORMAT_TYPE_TYPEMOD_GIVEN, and is_builtin().

Referenced by deparseArrayCoerceExpr(), deparseArrayExpr(), deparseConst(), deparseFuncExpr(), deparseRelabelType(), printRemoteParam(), and printRemotePlaceholder().

◆ deparseAggref()

static void deparseAggref ( Aggref node,
deparse_expr_cxt context 
)
static

Definition at line 3729 of file deparse.c.

3730{
3731 StringInfo buf = context->buf;
3732 bool use_variadic;
3733
3734 /* Only basic, non-split aggregation accepted. */
3735 Assert(node->aggsplit == AGGSPLIT_SIMPLE);
3736
3737 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3738 use_variadic = node->aggvariadic;
3739
3740 /* Find aggregate name from aggfnoid which is a pg_proc entry */
3741 appendFunctionName(node->aggfnoid, context);
3743
3744 /* Add DISTINCT */
3745 appendStringInfoString(buf, (node->aggdistinct != NIL) ? "DISTINCT " : "");
3746
3747 if (AGGKIND_IS_ORDERED_SET(node->aggkind))
3748 {
3749 /* Add WITHIN GROUP (ORDER BY ..) */
3750 ListCell *arg;
3751 bool first = true;
3752
3753 Assert(!node->aggvariadic);
3754 Assert(node->aggorder != NIL);
3755
3756 foreach(arg, node->aggdirectargs)
3757 {
3758 if (!first)
3760 first = false;
3761
3762 deparseExpr((Expr *) lfirst(arg), context);
3763 }
3764
3765 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
3766 appendAggOrderBy(node->aggorder, node->args, context);
3767 }
3768 else
3769 {
3770 /* aggstar can be set only in zero-argument aggregates */
3771 if (node->aggstar)
3773 else
3774 {
3775 ListCell *arg;
3776 bool first = true;
3777
3778 /* Add all the arguments */
3779 foreach(arg, node->args)
3780 {
3782 Node *n = (Node *) tle->expr;
3783
3784 if (tle->resjunk)
3785 continue;
3786
3787 if (!first)
3789 first = false;
3790
3791 /* Add VARIADIC */
3792 if (use_variadic && lnext(node->args, arg) == NULL)
3793 appendStringInfoString(buf, "VARIADIC ");
3794
3795 deparseExpr((Expr *) n, context);
3796 }
3797 }
3798
3799 /* Add ORDER BY */
3800 if (node->aggorder != NIL)
3801 {
3802 appendStringInfoString(buf, " ORDER BY ");
3803 appendAggOrderBy(node->aggorder, node->args, context);
3804 }
3805 }
3806
3807 /* Add FILTER (WHERE ..) */
3808 if (node->aggfilter != NULL)
3809 {
3810 appendStringInfoString(buf, ") FILTER (WHERE ");
3811 deparseExpr((Expr *) node->aggfilter, context);
3812 }
3813
3815}
static void appendFunctionName(Oid funcid, deparse_expr_cxt *context)
Definition deparse.c:4104
static void appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
Definition deparse.c:3821
Datum arg
Definition elog.c:1323
@ AGGSPLIT_SIMPLE
Definition nodes.h:385
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:375
Oid aggfnoid
Definition primnodes.h:461
List * aggdistinct
Definition primnodes.h:491
List * aggdirectargs
Definition primnodes.h:482
List * args
Definition primnodes.h:485
Expr * aggfilter
Definition primnodes.h:494
List * aggorder
Definition primnodes.h:488

References Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggorder, AGGSPLIT_SIMPLE, appendAggOrderBy(), appendFunctionName(), appendStringInfoChar(), appendStringInfoString(), arg, Aggref::args, Assert, deparse_expr_cxt::buf, buf, deparseExpr(), fb(), lfirst, lnext(), and NIL.

Referenced by deparseExpr().

◆ deparseAnalyzeInfoSql()

void deparseAnalyzeInfoSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2572 of file deparse.c.

2573{
2575
2576 /* We'll need the remote relation name as a literal. */
2578 deparseRelation(&relname, rel);
2579
2580 appendStringInfoString(buf, "SELECT relpages, reltuples, relkind FROM pg_catalog.pg_class WHERE oid = ");
2582 appendStringInfoString(buf, "::pg_catalog.regclass");
2583}
void deparseStringLiteral(StringInfo buf, const char *val)
Definition deparse.c:2900
static void deparseRelation(StringInfo buf, Relation rel)
Definition deparse.c:2860
NameData relname
Definition pg_class.h:40
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
char data[NAMEDATALEN]
Definition c.h:890

References appendStringInfoString(), buf, nameData::data, deparseRelation(), deparseStringLiteral(), initStringInfo(), and relname.

Referenced by fetch_relstats(), and postgresGetAnalyzeInfoForForeignTable().

◆ deparseAnalyzeSizeSql()

void deparseAnalyzeSizeSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2550 of file deparse.c.

2551{
2553
2554 /* We'll need the remote relation name as a literal. */
2556 deparseRelation(&relname, rel);
2557
2558 appendStringInfoString(buf, "SELECT pg_catalog.pg_relation_size(");
2560 appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
2561}

References appendStringInfo(), appendStringInfoString(), buf, nameData::data, deparseRelation(), deparseStringLiteral(), fb(), initStringInfo(), and relname.

Referenced by postgresAnalyzeForeignTable().

◆ deparseAnalyzeSql()

void deparseAnalyzeSql ( StringInfo  buf,
Relation  rel,
PgFdwSamplingMethod  sample_method,
double  sample_frac,
List **  retrieved_attrs 
)

Definition at line 2612 of file deparse.c.

2615{
2616 Oid relid = RelationGetRelid(rel);
2617 TupleDesc tupdesc = RelationGetDescr(rel);
2618 int i;
2619 char *colname;
2620 List *options;
2621 ListCell *lc;
2622 bool first = true;
2623
2624 *retrieved_attrs = NIL;
2625
2626 appendStringInfoString(buf, "SELECT ");
2627 for (i = 0; i < tupdesc->natts; i++)
2628 {
2629 /* Ignore dropped columns. */
2630 if (TupleDescAttr(tupdesc, i)->attisdropped)
2631 continue;
2632
2633 if (!first)
2635 first = false;
2636
2637 /* Use attribute name or column_name option. */
2638 colname = NameStr(TupleDescAttr(tupdesc, i)->attname);
2639 options = GetForeignColumnOptions(relid, i + 1);
2640
2641 foreach(lc, options)
2642 {
2643 DefElem *def = (DefElem *) lfirst(lc);
2644
2645 if (strcmp(def->defname, "column_name") == 0)
2646 {
2647 colname = defGetString(def);
2648 break;
2649 }
2650 }
2651
2653
2654 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
2655 }
2656
2657 /* Don't generate bad syntax for zero-column relation. */
2658 if (first)
2659 appendStringInfoString(buf, "NULL");
2660
2661 /*
2662 * Construct FROM clause, and perhaps WHERE clause too, depending on the
2663 * selected sampling method.
2664 */
2665 appendStringInfoString(buf, " FROM ");
2666 deparseRelation(buf, rel);
2667
2668 switch (sample_method)
2669 {
2670 case ANALYZE_SAMPLE_OFF:
2671 /* nothing to do here */
2672 break;
2673
2675 appendStringInfo(buf, " WHERE pg_catalog.random() < %f", sample_frac);
2676 break;
2677
2679 appendStringInfo(buf, " TABLESAMPLE SYSTEM(%f)", (100.0 * sample_frac));
2680 break;
2681
2683 appendStringInfo(buf, " TABLESAMPLE BERNOULLI(%f)", (100.0 * sample_frac));
2684 break;
2685
2687 /* should have been resolved into actual method */
2688 elog(ERROR, "unexpected sampling method");
2689 break;
2690 }
2691}
char * defGetString(DefElem *def)
Definition define.c:34
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition foreign.c:324
int i
Definition isn.c:77
List * lappend_int(List *list, int datum)
Definition list.c:357
NameData attname
@ ANALYZE_SAMPLE_AUTO
@ ANALYZE_SAMPLE_OFF
@ ANALYZE_SAMPLE_BERNOULLI
@ ANALYZE_SAMPLE_SYSTEM
@ ANALYZE_SAMPLE_RANDOM
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetDescr(relation)
Definition rel.h:542
char * defname
Definition parsenodes.h:862
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178

References ANALYZE_SAMPLE_AUTO, ANALYZE_SAMPLE_BERNOULLI, ANALYZE_SAMPLE_OFF, ANALYZE_SAMPLE_RANDOM, ANALYZE_SAMPLE_SYSTEM, appendStringInfo(), appendStringInfoString(), attname, buf, defGetString(), DefElem::defname, deparseRelation(), elog, ERROR, fb(), GetForeignColumnOptions(), i, lappend_int(), lfirst, NameStr, TupleDescData::natts, NIL, quote_identifier(), RelationGetDescr, RelationGetRelid, and TupleDescAttr().

Referenced by postgresAcquireSampleRowsFunc().

◆ deparseArrayCoerceExpr()

static void deparseArrayCoerceExpr ( ArrayCoerceExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3564 of file deparse.c.

3565{
3566 deparseExpr(node->arg, context);
3567
3568 /*
3569 * No difference how to deparse explicit cast, but if we omit implicit
3570 * cast in the query, it'll be more user-friendly
3571 */
3572 if (node->coerceformat != COERCE_IMPLICIT_CAST)
3573 appendStringInfo(context->buf, "::%s",
3575 node->resulttypmod));
3576}
static char * deparse_type_name(Oid type_oid, int32 typemod)
Definition deparse.c:1210
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:759

References appendStringInfo(), ArrayCoerceExpr::arg, deparse_expr_cxt::buf, COERCE_IMPLICIT_CAST, deparse_type_name(), deparseExpr(), and ArrayCoerceExpr::resulttype.

Referenced by deparseExpr().

◆ deparseArrayExpr()

static void deparseArrayExpr ( ArrayExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3703 of file deparse.c.

3704{
3705 StringInfo buf = context->buf;
3706 bool first = true;
3707 ListCell *lc;
3708
3709 appendStringInfoString(buf, "ARRAY[");
3710 foreach(lc, node->elements)
3711 {
3712 if (!first)
3714 deparseExpr(lfirst(lc), context);
3715 first = false;
3716 }
3718
3719 /* If the array is empty, we need an explicit cast to the array type. */
3720 if (node->elements == NIL)
3721 appendStringInfo(buf, "::%s",
3722 deparse_type_name(node->array_typeid, -1));
3723}

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), deparse_expr_cxt::buf, buf, deparse_type_name(), deparseExpr(), fb(), lfirst, and NIL.

Referenced by deparseExpr().

◆ deparseBoolExpr()

static void deparseBoolExpr ( BoolExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3582 of file deparse.c.

3583{
3584 StringInfo buf = context->buf;
3585 const char *op = NULL; /* keep compiler quiet */
3586 bool first;
3587 ListCell *lc;
3588
3589 switch (node->boolop)
3590 {
3591 case AND_EXPR:
3592 op = "AND";
3593 break;
3594 case OR_EXPR:
3595 op = "OR";
3596 break;
3597 case NOT_EXPR:
3598 appendStringInfoString(buf, "(NOT ");
3599 deparseExpr(linitial(node->args), context);
3601 return;
3602 }
3603
3605 first = true;
3606 foreach(lc, node->args)
3607 {
3608 if (!first)
3609 appendStringInfo(buf, " %s ", op);
3610 deparseExpr((Expr *) lfirst(lc), context);
3611 first = false;
3612 }
3614}
#define linitial(l)
Definition pg_list.h:178
@ AND_EXPR
Definition primnodes.h:945
@ OR_EXPR
Definition primnodes.h:945
@ NOT_EXPR
Definition primnodes.h:945
BoolExprType boolop
Definition primnodes.h:953
List * args
Definition primnodes.h:954

References AND_EXPR, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), BoolExpr::args, BoolExpr::boolop, deparse_expr_cxt::buf, buf, deparseExpr(), fb(), lfirst, linitial, NOT_EXPR, and OR_EXPR.

Referenced by deparseExpr().

◆ deparseCaseExpr()

static void deparseCaseExpr ( CaseExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3653 of file deparse.c.

3654{
3655 StringInfo buf = context->buf;
3656 ListCell *lc;
3657
3658 appendStringInfoString(buf, "(CASE");
3659
3660 /* If this is a CASE arg WHEN then emit the arg expression */
3661 if (node->arg != NULL)
3662 {
3664 deparseExpr(node->arg, context);
3665 }
3666
3667 /* Add each condition/result of the CASE clause */
3668 foreach(lc, node->args)
3669 {
3670 CaseWhen *whenclause = (CaseWhen *) lfirst(lc);
3671
3672 /* WHEN */
3673 appendStringInfoString(buf, " WHEN ");
3674 if (node->arg == NULL) /* CASE WHEN */
3675 deparseExpr(whenclause->expr, context);
3676 else /* CASE arg WHEN */
3677 {
3678 /* Ignore the CaseTestExpr and equality operator. */
3679 deparseExpr(lsecond(castNode(OpExpr, whenclause->expr)->args),
3680 context);
3681 }
3682
3683 /* THEN */
3684 appendStringInfoString(buf, " THEN ");
3685 deparseExpr(whenclause->result, context);
3686 }
3687
3688 /* add ELSE if present */
3689 if (node->defresult != NULL)
3690 {
3691 appendStringInfoString(buf, " ELSE ");
3692 deparseExpr(node->defresult, context);
3693 }
3694
3695 /* append END */
3696 appendStringInfoString(buf, " END)");
3697}
#define castNode(_type_, nodeptr)
Definition nodes.h:180
#define lsecond(l)
Definition pg_list.h:183
Expr * arg
Definition primnodes.h:1329
Expr * defresult
Definition primnodes.h:1331
List * args
Definition primnodes.h:1330
Expr * result
Definition primnodes.h:1342
Expr * expr
Definition primnodes.h:1341

References appendStringInfoChar(), appendStringInfoString(), CaseExpr::arg, CaseExpr::args, deparse_expr_cxt::buf, buf, castNode, CaseExpr::defresult, deparseExpr(), CaseWhen::expr, fb(), lfirst, lsecond, and CaseWhen::result.

Referenced by deparseExpr().

◆ deparseColumnRef()

static void deparseColumnRef ( StringInfo  buf,
int  varno,
int  varattno,
RangeTblEntry rte,
bool  qualify_col 
)
static

Definition at line 2732 of file deparse.c.

2734{
2735 /* We support fetching the remote side's CTID and OID. */
2736 if (varattno == SelfItemPointerAttributeNumber)
2737 {
2738 if (qualify_col)
2739 ADD_REL_QUALIFIER(buf, varno);
2740 appendStringInfoString(buf, "ctid");
2741 }
2742 else if (varattno < 0)
2743 {
2744 /*
2745 * All other system attributes are fetched as 0, except for table OID,
2746 * which is fetched as the local table OID. However, we must be
2747 * careful; the table could be beneath an outer join, in which case it
2748 * must go to NULL whenever the rest of the row does.
2749 */
2750 Oid fetchval = 0;
2751
2752 if (varattno == TableOidAttributeNumber)
2753 fetchval = rte->relid;
2754
2755 if (qualify_col)
2756 {
2757 appendStringInfoString(buf, "CASE WHEN (");
2758 ADD_REL_QUALIFIER(buf, varno);
2759 appendStringInfo(buf, "*)::text IS NOT NULL THEN %u END", fetchval);
2760 }
2761 else
2763 }
2764 else if (varattno == 0)
2765 {
2766 /* Whole row reference */
2767 Relation rel;
2768 Bitmapset *attrs_used;
2769
2770 /* Required only to be passed down to deparseTargetList(). */
2771 List *retrieved_attrs;
2772
2773 /*
2774 * The lock on the relation will be held by upper callers, so it's
2775 * fine to open it with no lock here.
2776 */
2777 rel = table_open(rte->relid, NoLock);
2778
2779 /*
2780 * The local name of the foreign table can not be recognized by the
2781 * foreign server and the table it references on foreign server might
2782 * have different column ordering or different columns than those
2783 * declared locally. Hence we have to deparse whole-row reference as
2784 * ROW(columns referenced locally). Construct this by deparsing a
2785 * "whole row" attribute.
2786 */
2787 attrs_used = bms_add_member(NULL,
2789
2790 /*
2791 * In case the whole-row reference is under an outer join then it has
2792 * to go NULL whenever the rest of the row goes NULL. Deparsing a join
2793 * query would always involve multiple relations, thus qualify_col
2794 * would be true.
2795 */
2796 if (qualify_col)
2797 {
2798 appendStringInfoString(buf, "CASE WHEN (");
2799 ADD_REL_QUALIFIER(buf, varno);
2800 appendStringInfoString(buf, "*)::text IS NOT NULL THEN ");
2801 }
2802
2803 appendStringInfoString(buf, "ROW(");
2804 deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
2805 &retrieved_attrs);
2807
2808 /* Complete the CASE WHEN statement started above. */
2809 if (qualify_col)
2810 appendStringInfoString(buf, " END");
2811
2812 table_close(rel, NoLock);
2813 bms_free(attrs_used);
2814 }
2815 else
2816 {
2817 char *colname = NULL;
2818 List *options;
2819 ListCell *lc;
2820
2821 /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
2822 Assert(!IS_SPECIAL_VARNO(varno));
2823
2824 /*
2825 * If it's a column of a foreign table, and it has the column_name FDW
2826 * option, use that value.
2827 */
2828 options = GetForeignColumnOptions(rte->relid, varattno);
2829 foreach(lc, options)
2830 {
2831 DefElem *def = (DefElem *) lfirst(lc);
2832
2833 if (strcmp(def->defname, "column_name") == 0)
2834 {
2835 colname = defGetString(def);
2836 break;
2837 }
2838 }
2839
2840 /*
2841 * If it's a column of a regular table or it doesn't have column_name
2842 * FDW option, use attribute name.
2843 */
2844 if (colname == NULL)
2845 colname = get_attname(rte->relid, varattno, false);
2846
2847 if (qualify_col)
2848 ADD_REL_QUALIFIER(buf, varno);
2849
2851 }
2852}
void bms_free(Bitmapset *a)
Definition bitmapset.c:240
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:934
static void deparseTargetList(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, bool is_returning, Bitmapset *attrs_used, bool qualify_col, List **retrieved_attrs)
Definition deparse.c:1458
#define ADD_REL_QUALIFIER(buf, varno)
Definition deparse.c:111
#define NoLock
Definition lockdefs.h:34
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:1053
#define IS_SPECIAL_VARNO(varno)
Definition primnodes.h:248
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
#define TableOidAttributeNumber
Definition sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition sysattr.h:21
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40

References ADD_REL_QUALIFIER, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, bms_add_member(), bms_free(), buf, defGetString(), DefElem::defname, deparseTargetList(), fb(), FirstLowInvalidHeapAttributeNumber, get_attname(), GetForeignColumnOptions(), IS_SPECIAL_VARNO, lfirst, NoLock, quote_identifier(), SelfItemPointerAttributeNumber, table_close(), table_open(), and TableOidAttributeNumber.

Referenced by deparseDirectUpdateSql(), deparseInsertSql(), deparseTargetList(), deparseUpdateSql(), and deparseVar().

◆ deparseConst()

static void deparseConst ( Const node,
deparse_expr_cxt context,
int  showtype 
)
static

Definition at line 3074 of file deparse.c.

3075{
3076 StringInfo buf = context->buf;
3077 Oid typoutput;
3078 bool typIsVarlena;
3079 char *extval;
3080 bool isfloat = false;
3081 bool isstring = false;
3082 bool needlabel;
3083
3084 if (node->constisnull)
3085 {
3086 appendStringInfoString(buf, "NULL");
3087 if (showtype >= 0)
3088 appendStringInfo(buf, "::%s",
3090 node->consttypmod));
3091 return;
3092 }
3093
3095 &typoutput, &typIsVarlena);
3096 extval = OidOutputFunctionCall(typoutput, node->constvalue);
3097
3098 switch (node->consttype)
3099 {
3100 case INT2OID:
3101 case INT4OID:
3102 case INT8OID:
3103 case OIDOID:
3104 case FLOAT4OID:
3105 case FLOAT8OID:
3106 case NUMERICOID:
3107 {
3108 /*
3109 * No need to quote unless it's a special value such as 'NaN'.
3110 * See comments in get_const_expr().
3111 */
3112 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
3113 {
3114 if (extval[0] == '+' || extval[0] == '-')
3115 appendStringInfo(buf, "(%s)", extval);
3116 else
3118 if (strcspn(extval, "eE.") != strlen(extval))
3119 isfloat = true; /* it looks like a float */
3120 }
3121 else
3122 appendStringInfo(buf, "'%s'", extval);
3123 }
3124 break;
3125 case BITOID:
3126 case VARBITOID:
3127 appendStringInfo(buf, "B'%s'", extval);
3128 break;
3129 case BOOLOID:
3130 if (strcmp(extval, "t") == 0)
3131 appendStringInfoString(buf, "true");
3132 else
3133 appendStringInfoString(buf, "false");
3134 break;
3135 default:
3137 isstring = true;
3138 break;
3139 }
3140
3141 pfree(extval);
3142
3143 if (showtype == -1)
3144 return; /* never print type label */
3145
3146 /*
3147 * For showtype == 0, append ::typename unless the constant will be
3148 * implicitly typed as the right type when it is read in.
3149 *
3150 * XXX this code has to be kept in sync with the behavior of the parser,
3151 * especially make_const.
3152 */
3153 switch (node->consttype)
3154 {
3155 case BOOLOID:
3156 case INT4OID:
3157 case UNKNOWNOID:
3158 needlabel = false;
3159 break;
3160 case NUMERICOID:
3161 needlabel = !isfloat || (node->consttypmod >= 0);
3162 break;
3163 default:
3164 if (showtype == -2)
3165 {
3166 /* label unless we printed it as an untyped string */
3168 }
3169 else
3170 needlabel = true;
3171 break;
3172 }
3173 if (needlabel || showtype > 0)
3174 appendStringInfo(buf, "::%s",
3176 node->consttypmod));
3177}
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition fmgr.c:1764
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3223
void pfree(void *pointer)
Definition mcxt.c:1619
Oid consttype
Definition primnodes.h:333

References appendStringInfo(), appendStringInfoString(), deparse_expr_cxt::buf, buf, Const::consttype, deparse_type_name(), deparseStringLiteral(), fb(), getTypeOutputInfo(), OidOutputFunctionCall(), and pfree().

Referenced by deparseExpr(), deparseOpExpr(), and deparseSortGroupClause().

◆ deparseDeleteSql()

void deparseDeleteSql ( StringInfo  buf,
RangeTblEntry rte,
Index  rtindex,
Relation  rel,
List returningList,
List **  retrieved_attrs 
)

Definition at line 2413 of file deparse.c.

2417{
2418 appendStringInfoString(buf, "DELETE FROM ");
2419 deparseRelation(buf, rel);
2420 appendStringInfoString(buf, " WHERE ctid = $1");
2421
2422 deparseReturningList(buf, rte, rtindex, rel,
2424 NIL, returningList, retrieved_attrs);
2425}
static void deparseReturningList(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, bool trig_after_row, List *withCheckOptionList, List *returningList, List **retrieved_attrs)
Definition deparse.c:2493
TriggerDesc * trigdesc
Definition rel.h:117
bool trig_delete_after_row
Definition reltrigger.h:67

References appendStringInfoString(), buf, deparseRelation(), deparseReturningList(), fb(), NIL, TriggerDesc::trig_delete_after_row, and RelationData::trigdesc.

Referenced by postgresPlanForeignModify().

◆ deparseDirectDeleteSql()

void deparseDirectDeleteSql ( StringInfo  buf,
PlannerInfo root,
Index  rtindex,
Relation  rel,
RelOptInfo foreignrel,
List remote_conds,
List **  params_list,
List returningList,
List **  retrieved_attrs 
)

Definition at line 2442 of file deparse.c.

2449{
2450 deparse_expr_cxt context;
2452
2453 /* Set up context struct for recursion */
2454 context.root = root;
2455 context.foreignrel = foreignrel;
2456 context.scanrel = foreignrel;
2457 context.buf = buf;
2458 context.params_list = params_list;
2459
2460 appendStringInfoString(buf, "DELETE FROM ");
2461 deparseRelation(buf, rel);
2462 if (foreignrel->reloptkind == RELOPT_JOINREL)
2463 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2464
2465 if (foreignrel->reloptkind == RELOPT_JOINREL)
2466 {
2468
2469 appendStringInfoString(buf, " USING ");
2470 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2471 &ignore_conds, &additional_conds, params_list);
2472 remote_conds = list_concat(remote_conds, ignore_conds);
2473 }
2474
2475 appendWhereClause(remote_conds, additional_conds, &context);
2476
2477 if (additional_conds != NIL)
2479
2480 if (foreignrel->reloptkind == RELOPT_JOINREL)
2481 deparseExplicitTargetList(returningList, true, retrieved_attrs,
2482 &context);
2483 else
2485 rtindex, rel, false,
2486 NIL, returningList, retrieved_attrs);
2487}
#define REL_ALIAS_PREFIX
Definition deparse.c:109
static void deparseExplicitTargetList(List *tlist, bool is_returning, List **retrieved_attrs, deparse_expr_cxt *context)
Definition deparse.c:1732
static void deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool use_alias, Index ignore_rel, List **ignore_conds, List **additional_conds, List **params_list)
Definition deparse.c:1812
static void appendWhereClause(List *exprs, List *additional_conds, deparse_expr_cxt *context)
Definition deparse.c:1659
List * list_concat(List *list1, const List *list2)
Definition list.c:561
void list_free_deep(List *list)
Definition list.c:1560
#define planner_rt_fetch(rti, root)
Definition pathnodes.h:704
@ RELOPT_JOINREL
Definition pathnodes.h:978
RelOptKind reloptkind
Definition pathnodes.h:1015
List ** params_list
Definition deparse.c:106

References appendStringInfo(), appendStringInfoString(), appendWhereClause(), deparse_expr_cxt::buf, buf, deparseExplicitTargetList(), deparseFromExprForRel(), deparseRelation(), deparseReturningList(), fb(), deparse_expr_cxt::foreignrel, list_concat(), list_free_deep(), NIL, deparse_expr_cxt::params_list, planner_rt_fetch, REL_ALIAS_PREFIX, RELOPT_JOINREL, RelOptInfo::reloptkind, deparse_expr_cxt::root, root, and deparse_expr_cxt::scanrel.

Referenced by postgresPlanDirectModify().

◆ deparseDirectUpdateSql()

void deparseDirectUpdateSql ( StringInfo  buf,
PlannerInfo root,
Index  rtindex,
Relation  rel,
RelOptInfo foreignrel,
List targetlist,
List targetAttrs,
List remote_conds,
List **  params_list,
List returningList,
List **  retrieved_attrs 
)

Definition at line 2327 of file deparse.c.

2336{
2337 deparse_expr_cxt context;
2338 int nestlevel;
2339 bool first;
2341 ListCell *lc,
2342 *lc2;
2344
2345 /* Set up context struct for recursion */
2346 context.root = root;
2347 context.foreignrel = foreignrel;
2348 context.scanrel = foreignrel;
2349 context.buf = buf;
2350 context.params_list = params_list;
2351
2352 appendStringInfoString(buf, "UPDATE ");
2353 deparseRelation(buf, rel);
2354 if (foreignrel->reloptkind == RELOPT_JOINREL)
2355 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2356 appendStringInfoString(buf, " SET ");
2357
2358 /* Make sure any constants in the exprs are printed portably */
2360
2361 first = true;
2362 forboth(lc, targetlist, lc2, targetAttrs)
2363 {
2365 int attnum = lfirst_int(lc2);
2366
2367 /* update's new-value expressions shouldn't be resjunk */
2368 Assert(!tle->resjunk);
2369
2370 if (!first)
2372 first = false;
2373
2374 deparseColumnRef(buf, rtindex, attnum, rte, false);
2376 deparseExpr((Expr *) tle->expr, &context);
2377 }
2378
2380
2381 if (foreignrel->reloptkind == RELOPT_JOINREL)
2382 {
2384
2385
2386 appendStringInfoString(buf, " FROM ");
2387 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2388 &ignore_conds, &additional_conds, params_list);
2389 remote_conds = list_concat(remote_conds, ignore_conds);
2390 }
2391
2392 appendWhereClause(remote_conds, additional_conds, &context);
2393
2394 if (additional_conds != NIL)
2396
2397 if (foreignrel->reloptkind == RELOPT_JOINREL)
2398 deparseExplicitTargetList(returningList, true, retrieved_attrs,
2399 &context);
2400 else
2401 deparseReturningList(buf, rte, rtindex, rel, false,
2402 NIL, returningList, retrieved_attrs);
2403}
static void deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte, bool qualify_col)
Definition deparse.c:2732
int16 attnum
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:550
#define lfirst_int(lc)
Definition pg_list.h:173

References appendStringInfo(), appendStringInfoString(), appendWhereClause(), Assert, attnum, deparse_expr_cxt::buf, buf, deparseColumnRef(), deparseExplicitTargetList(), deparseExpr(), deparseFromExprForRel(), deparseRelation(), deparseReturningList(), fb(), forboth, deparse_expr_cxt::foreignrel, lfirst_int, lfirst_node, list_concat(), list_free_deep(), NIL, deparse_expr_cxt::params_list, planner_rt_fetch, REL_ALIAS_PREFIX, RELOPT_JOINREL, RelOptInfo::reloptkind, reset_transmission_modes(), deparse_expr_cxt::root, root, deparse_expr_cxt::scanrel, and set_transmission_modes().

Referenced by postgresPlanDirectModify().

◆ deparseDistinctExpr()

static void deparseDistinctExpr ( DistinctExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3488 of file deparse.c.

3489{
3490 StringInfo buf = context->buf;
3491
3492 Assert(list_length(node->args) == 2);
3493
3495 deparseExpr(linitial(node->args), context);
3496 appendStringInfoString(buf, " IS DISTINCT FROM ");
3497 deparseExpr(lsecond(node->args), context);
3499}
static int list_length(const List *l)
Definition pg_list.h:152
List * args
Definition primnodes.h:853

References appendStringInfoChar(), appendStringInfoString(), OpExpr::args, Assert, deparse_expr_cxt::buf, buf, deparseExpr(), linitial, list_length(), and lsecond.

Referenced by deparseExpr().

◆ deparseExplicitTargetList()

static void deparseExplicitTargetList ( List tlist,
bool  is_returning,
List **  retrieved_attrs,
deparse_expr_cxt context 
)
static

Definition at line 1732 of file deparse.c.

1736{
1737 ListCell *lc;
1738 StringInfo buf = context->buf;
1739 int i = 0;
1740
1741 *retrieved_attrs = NIL;
1742
1743 foreach(lc, tlist)
1744 {
1746
1747 if (i > 0)
1749 else if (is_returning)
1750 appendStringInfoString(buf, " RETURNING ");
1751
1752 deparseExpr((Expr *) tle->expr, context);
1753
1754 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
1755 i++;
1756 }
1757
1758 if (i == 0 && !is_returning)
1759 appendStringInfoString(buf, "NULL");
1760}

References appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseExpr(), fb(), i, lappend_int(), lfirst_node, and NIL.

Referenced by deparseDirectDeleteSql(), deparseDirectUpdateSql(), and deparseSelectSql().

◆ deparseExpr()

static void deparseExpr ( Expr node,
deparse_expr_cxt context 
)
static

Definition at line 2935 of file deparse.c.

2936{
2937 if (node == NULL)
2938 return;
2939
2940 switch (nodeTag(node))
2941 {
2942 case T_Var:
2943 deparseVar((Var *) node, context);
2944 break;
2945 case T_Const:
2946 deparseConst((Const *) node, context, 0);
2947 break;
2948 case T_Param:
2949 deparseParam((Param *) node, context);
2950 break;
2951 case T_SubscriptingRef:
2952 deparseSubscriptingRef((SubscriptingRef *) node, context);
2953 break;
2954 case T_FuncExpr:
2955 deparseFuncExpr((FuncExpr *) node, context);
2956 break;
2957 case T_OpExpr:
2958 deparseOpExpr((OpExpr *) node, context);
2959 break;
2960 case T_DistinctExpr:
2961 deparseDistinctExpr((DistinctExpr *) node, context);
2962 break;
2965 break;
2966 case T_RelabelType:
2967 deparseRelabelType((RelabelType *) node, context);
2968 break;
2969 case T_ArrayCoerceExpr:
2970 deparseArrayCoerceExpr((ArrayCoerceExpr *) node, context);
2971 break;
2972 case T_BoolExpr:
2973 deparseBoolExpr((BoolExpr *) node, context);
2974 break;
2975 case T_NullTest:
2976 deparseNullTest((NullTest *) node, context);
2977 break;
2978 case T_CaseExpr:
2979 deparseCaseExpr((CaseExpr *) node, context);
2980 break;
2981 case T_ArrayExpr:
2982 deparseArrayExpr((ArrayExpr *) node, context);
2983 break;
2984 case T_Aggref:
2985 deparseAggref((Aggref *) node, context);
2986 break;
2987 default:
2988 elog(ERROR, "unsupported expression type for deparse: %d",
2989 (int) nodeTag(node));
2990 break;
2991 }
2992}
static void deparseArrayCoerceExpr(ArrayCoerceExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3564
static void deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3653
static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3582
static void deparseAggref(Aggref *node, deparse_expr_cxt *context)
Definition deparse.c:3729
static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
Definition deparse.c:3551
static void deparseNullTest(NullTest *node, deparse_expr_cxt *context)
Definition deparse.c:3620
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3330
static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype)
Definition deparse.c:3074
static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3488
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3267
static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3703
static void deparseVar(Var *node, deparse_expr_cxt *context)
Definition deparse.c:3003
static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
Definition deparse.c:3221
static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
Definition deparse.c:3506
static void deparseParam(Param *node, deparse_expr_cxt *context)
Definition deparse.c:3188
#define nodeTag(nodeptr)
Definition nodes.h:137

References deparseAggref(), deparseArrayCoerceExpr(), deparseArrayExpr(), deparseBoolExpr(), deparseCaseExpr(), deparseConst(), deparseDistinctExpr(), deparseFuncExpr(), deparseNullTest(), deparseOpExpr(), deparseParam(), deparseRelabelType(), deparseScalarArrayOpExpr(), deparseSubscriptingRef(), deparseVar(), elog, ERROR, fb(), and nodeTag.

Referenced by appendConditions(), appendLimitClause(), appendOrderByClause(), deparseAggref(), deparseArrayCoerceExpr(), deparseArrayExpr(), deparseBoolExpr(), deparseCaseExpr(), deparseDirectUpdateSql(), deparseDistinctExpr(), deparseExplicitTargetList(), deparseFuncExpr(), deparseNullTest(), deparseOpExpr(), deparseRelabelType(), deparseScalarArrayOpExpr(), deparseSortGroupClause(), deparseSubqueryTargetList(), and deparseSubscriptingRef().

◆ deparseFromExpr()

static void deparseFromExpr ( List quals,
deparse_expr_cxt context 
)
static

Definition at line 1426 of file deparse.c.

1427{
1428 StringInfo buf = context->buf;
1429 RelOptInfo *scanrel = context->scanrel;
1431
1432 /* For upper relations, scanrel must be either a joinrel or a baserel */
1433 Assert(!IS_UPPER_REL(context->foreignrel) ||
1434 IS_JOIN_REL(scanrel) || IS_SIMPLE_REL(scanrel));
1435
1436 /* Construct FROM clause */
1437 appendStringInfoString(buf, " FROM ");
1438 deparseFromExprForRel(buf, context->root, scanrel,
1439 (bms_membership(scanrel->relids) == BMS_MULTIPLE),
1441 context->params_list);
1442 appendWhereClause(quals, additional_conds, context);
1443 if (additional_conds != NIL)
1445}
BMS_Membership bms_membership(const Bitmapset *a)
Definition bitmapset.c:900
@ BMS_MULTIPLE
Definition bitmapset.h:73
unsigned int Index
Definition c.h:757
#define IS_SIMPLE_REL(rel)
Definition pathnodes.h:989
#define IS_JOIN_REL(rel)
Definition pathnodes.h:994
Relids relids
Definition pathnodes.h:1021

References appendStringInfoString(), appendWhereClause(), Assert, bms_membership(), BMS_MULTIPLE, deparse_expr_cxt::buf, buf, deparseFromExprForRel(), fb(), deparse_expr_cxt::foreignrel, IS_JOIN_REL, IS_SIMPLE_REL, IS_UPPER_REL, list_free_deep(), NIL, deparse_expr_cxt::params_list, RelOptInfo::relids, deparse_expr_cxt::root, and deparse_expr_cxt::scanrel.

Referenced by deparseSelectStmtForRel().

◆ deparseFromExprForRel()

static void deparseFromExprForRel ( StringInfo  buf,
PlannerInfo root,
RelOptInfo foreignrel,
bool  use_alias,
Index  ignore_rel,
List **  ignore_conds,
List **  additional_conds,
List **  params_list 
)
static

Definition at line 1812 of file deparse.c.

1815{
1816 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1817
1818 if (IS_JOIN_REL(foreignrel))
1819 {
1822 RelOptInfo *outerrel = fpinfo->outerrel;
1823 RelOptInfo *innerrel = fpinfo->innerrel;
1824 bool outerrel_is_target = false;
1825 bool innerrel_is_target = false;
1828
1829 if (ignore_rel > 0 && bms_is_member(ignore_rel, foreignrel->relids))
1830 {
1831 /*
1832 * If this is an inner join, add joinclauses to *ignore_conds and
1833 * set it to empty so that those can be deparsed into the WHERE
1834 * clause. Note that since the target relation can never be
1835 * within the nullable side of an outer join, those could safely
1836 * be pulled up into the WHERE clause (see foreign_join_ok()).
1837 * Note also that since the target relation is only inner-joined
1838 * to any other relation in the query, all conditions in the join
1839 * tree mentioning the target relation could be deparsed into the
1840 * WHERE clause by doing this recursively.
1841 */
1842 if (fpinfo->jointype == JOIN_INNER)
1843 {
1845 fpinfo->joinclauses);
1846 fpinfo->joinclauses = NIL;
1847 }
1848
1849 /*
1850 * Check if either of the input relations is the target relation.
1851 */
1852 if (outerrel->relid == ignore_rel)
1853 outerrel_is_target = true;
1854 else if (innerrel->relid == ignore_rel)
1855 innerrel_is_target = true;
1856 }
1857
1858 /* Deparse outer relation if not the target relation. */
1859 if (!outerrel_is_target)
1860 {
1863 fpinfo->make_outerrel_subquery,
1865 params_list);
1866
1867 /*
1868 * If inner relation is the target relation, skip deparsing it.
1869 * Note that since the join of the target relation with any other
1870 * relation in the query is an inner join and can never be within
1871 * the nullable side of an outer join, the join could be
1872 * interchanged with higher-level joins (cf. identity 1 on outer
1873 * join reordering shown in src/backend/optimizer/README), which
1874 * means it's safe to skip the target-relation deparsing here.
1875 */
1877 {
1878 Assert(fpinfo->jointype == JOIN_INNER);
1879 Assert(fpinfo->joinclauses == NIL);
1881 /* Pass EXISTS conditions to upper level */
1882 if (additional_conds_o != NIL)
1883 {
1886 }
1887 return;
1888 }
1889 }
1890
1891 /* Deparse inner relation if not the target relation. */
1892 if (!innerrel_is_target)
1893 {
1896 fpinfo->make_innerrel_subquery,
1898 params_list);
1899
1900 /*
1901 * SEMI-JOIN is deparsed as the EXISTS subquery. It references
1902 * outer and inner relations, so it should be evaluated as the
1903 * condition in the upper-level WHERE clause. We deparse the
1904 * condition and pass it to upper level callers as an
1905 * additional_conds list. Upper level callers are responsible for
1906 * inserting conditions from the list where appropriate.
1907 */
1908 if (fpinfo->jointype == JOIN_SEMI)
1909 {
1910 deparse_expr_cxt context;
1912
1913 /* Construct deparsed condition from this SEMI-JOIN */
1915 appendStringInfo(&str, "EXISTS (SELECT NULL FROM %s",
1916 join_sql_i.data);
1917
1918 context.buf = &str;
1919 context.foreignrel = foreignrel;
1920 context.scanrel = foreignrel;
1921 context.root = root;
1922 context.params_list = params_list;
1923
1924 /*
1925 * Append SEMI-JOIN clauses and EXISTS conditions from lower
1926 * levels to the current EXISTS subquery
1927 */
1928 appendWhereClause(fpinfo->joinclauses, additional_conds_i, &context);
1929
1930 /*
1931 * EXISTS conditions, coming from lower join levels, have just
1932 * been processed.
1933 */
1934 if (additional_conds_i != NIL)
1935 {
1938 }
1939
1940 /* Close parentheses for EXISTS subquery */
1942
1944 }
1945
1946 /*
1947 * If outer relation is the target relation, skip deparsing it.
1948 * See the above note about safety.
1949 */
1951 {
1952 Assert(fpinfo->jointype == JOIN_INNER);
1953 Assert(fpinfo->joinclauses == NIL);
1955 /* Pass EXISTS conditions to the upper call */
1956 if (additional_conds_i != NIL)
1957 {
1960 }
1961 return;
1962 }
1963 }
1964
1965 /* Neither of the relations is the target relation. */
1967
1968 /*
1969 * For semijoin FROM clause is deparsed as an outer relation. An inner
1970 * relation and join clauses are converted to EXISTS condition and
1971 * passed to the upper level.
1972 */
1973 if (fpinfo->jointype == JOIN_SEMI)
1974 {
1976 }
1977 else
1978 {
1979 /*
1980 * For a join relation FROM clause, entry is deparsed as
1981 *
1982 * ((outer relation) <join type> (inner relation) ON
1983 * (joinclauses))
1984 */
1985 appendStringInfo(buf, "(%s %s JOIN %s ON ", join_sql_o.data,
1986 get_jointype_name(fpinfo->jointype), join_sql_i.data);
1987
1988 /* Append join clause; (TRUE) if no join clause */
1989 if (fpinfo->joinclauses)
1990 {
1991 deparse_expr_cxt context;
1992
1993 context.buf = buf;
1994 context.foreignrel = foreignrel;
1995 context.scanrel = foreignrel;
1996 context.root = root;
1997 context.params_list = params_list;
1998
2000 appendConditions(fpinfo->joinclauses, &context);
2002 }
2003 else
2004 appendStringInfoString(buf, "(TRUE)");
2005
2006 /* End the FROM clause entry. */
2008 }
2009
2010 /*
2011 * Construct additional_conds to be passed to the upper caller from
2012 * current level additional_conds and additional_conds, coming from
2013 * inner and outer rels.
2014 */
2015 if (additional_conds_o != NIL)
2016 {
2020 }
2021
2022 if (additional_conds_i != NIL)
2023 {
2027 }
2028 }
2029 else
2030 {
2031 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
2032
2033 /*
2034 * Core code already has some lock on each rel being planned, so we
2035 * can use NoLock here.
2036 */
2037 Relation rel = table_open(rte->relid, NoLock);
2038
2039 deparseRelation(buf, rel);
2040
2041 /*
2042 * Add a unique alias to avoid any conflict in relation names due to
2043 * pulled up subqueries in the query being built for a pushed down
2044 * join.
2045 */
2046 if (use_alias)
2047 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, foreignrel->relid);
2048
2049 table_close(rel, NoLock);
2050 }
2051}
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:645
static void deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool make_subquery, Index ignore_rel, List **ignore_conds, List **additional_conds, List **params_list)
Definition deparse.c:2059
const char * get_jointype_name(JoinType jointype)
Definition deparse.c:1692
const char * str
void list_free(List *list)
Definition list.c:1546
@ JOIN_SEMI
Definition nodes.h:315
@ JOIN_INNER
Definition nodes.h:301
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition stringinfo.c:281
Index relid
Definition pathnodes.h:1069

References appendBinaryStringInfo(), appendConditions(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), appendWhereClause(), Assert, bms_is_member(), deparse_expr_cxt::buf, buf, deparseRangeTblRef(), deparseRelation(), fb(), deparse_expr_cxt::foreignrel, get_jointype_name(), initStringInfo(), IS_JOIN_REL, JOIN_INNER, JOIN_SEMI, lappend(), list_concat(), list_free(), list_free_deep(), NIL, NoLock, deparse_expr_cxt::params_list, planner_rt_fetch, REL_ALIAS_PREFIX, RelOptInfo::relid, RelOptInfo::relids, deparse_expr_cxt::root, root, deparse_expr_cxt::scanrel, str, table_close(), and table_open().

Referenced by deparseDirectDeleteSql(), deparseDirectUpdateSql(), deparseFromExpr(), and deparseRangeTblRef().

◆ deparseFuncExpr()

static void deparseFuncExpr ( FuncExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3267 of file deparse.c.

3268{
3269 StringInfo buf = context->buf;
3270 bool use_variadic;
3271 bool first;
3272 ListCell *arg;
3273
3274 /*
3275 * If the function call came from an implicit coercion, then just show the
3276 * first argument.
3277 */
3278 if (node->funcformat == COERCE_IMPLICIT_CAST)
3279 {
3280 deparseExpr((Expr *) linitial(node->args), context);
3281 return;
3282 }
3283
3284 /*
3285 * If the function call came from a cast, then show the first argument
3286 * plus an explicit cast operation.
3287 */
3288 if (node->funcformat == COERCE_EXPLICIT_CAST)
3289 {
3290 Oid rettype = node->funcresulttype;
3292
3293 /* Get the typmod if this is a length-coercion function */
3295
3296 deparseExpr((Expr *) linitial(node->args), context);
3297 appendStringInfo(buf, "::%s",
3299 return;
3300 }
3301
3302 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3303 use_variadic = node->funcvariadic;
3304
3305 /*
3306 * Normal function: display as proname(args).
3307 */
3308 appendFunctionName(node->funcid, context);
3310
3311 /* ... and all the arguments */
3312 first = true;
3313 foreach(arg, node->args)
3314 {
3315 if (!first)
3317 if (use_variadic && lnext(node->args, arg) == NULL)
3318 appendStringInfoString(buf, "VARIADIC ");
3319 deparseExpr((Expr *) lfirst(arg), context);
3320 first = false;
3321 }
3323}
int32_t int32
Definition c.h:679
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition nodeFuncs.c:562
@ COERCE_EXPLICIT_CAST
Definition primnodes.h:758
Oid funcid
Definition primnodes.h:770
List * args
Definition primnodes.h:788

References appendFunctionName(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, FuncExpr::args, deparse_expr_cxt::buf, buf, COERCE_EXPLICIT_CAST, COERCE_IMPLICIT_CAST, deparse_type_name(), deparseExpr(), exprIsLengthCoercion(), fb(), FuncExpr::funcid, lfirst, linitial, and lnext().

Referenced by deparseExpr().

◆ deparseInsertSql()

void deparseInsertSql ( StringInfo  buf,
RangeTblEntry rte,
Index  rtindex,
Relation  rel,
List targetAttrs,
bool  doNothing,
List withCheckOptionList,
List returningList,
List **  retrieved_attrs,
int values_end_len 
)

Definition at line 2134 of file deparse.c.

2139{
2140 TupleDesc tupdesc = RelationGetDescr(rel);
2142 bool first;
2143 ListCell *lc;
2144
2145 appendStringInfoString(buf, "INSERT INTO ");
2146 deparseRelation(buf, rel);
2147
2148 if (targetAttrs)
2149 {
2151
2152 first = true;
2153 foreach(lc, targetAttrs)
2154 {
2155 int attnum = lfirst_int(lc);
2156
2157 if (!first)
2159 first = false;
2160
2161 deparseColumnRef(buf, rtindex, attnum, rte, false);
2162 }
2163
2164 appendStringInfoString(buf, ") VALUES (");
2165
2166 pindex = 1;
2167 first = true;
2168 foreach(lc, targetAttrs)
2169 {
2170 int attnum = lfirst_int(lc);
2171 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
2172
2173 if (!first)
2175 first = false;
2176
2177 if (attr->attgenerated)
2178 appendStringInfoString(buf, "DEFAULT");
2179 else
2180 {
2181 appendStringInfo(buf, "$%d", pindex);
2182 pindex++;
2183 }
2184 }
2185
2187 }
2188 else
2189 appendStringInfoString(buf, " DEFAULT VALUES");
2190 *values_end_len = buf->len;
2191
2192 if (doNothing)
2193 appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
2194
2195 deparseReturningList(buf, rte, rtindex, rel,
2197 withCheckOptionList, returningList, retrieved_attrs);
2198}
int16 AttrNumber
Definition attnum.h:21
bool attgenerated
Definition tupdesc.h:79
bool trig_insert_after_row
Definition reltrigger.h:57
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:195

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), CompactAttribute::attgenerated, attnum, buf, deparseColumnRef(), deparseRelation(), deparseReturningList(), fb(), lfirst_int, RelationGetDescr, TriggerDesc::trig_insert_after_row, RelationData::trigdesc, and TupleDescCompactAttr().

Referenced by postgresBeginForeignInsert(), and postgresPlanForeignModify().

◆ deparseLockingClause()

static void deparseLockingClause ( deparse_expr_cxt context)
static

Definition at line 1532 of file deparse.c.

1533{
1534 StringInfo buf = context->buf;
1535 PlannerInfo *root = context->root;
1536 RelOptInfo *rel = context->scanrel;
1537 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1538 int relid = -1;
1539
1540 while ((relid = bms_next_member(rel->relids, relid)) >= 0)
1541 {
1542 /*
1543 * Ignore relation if it appears in a lower subquery. Locking clause
1544 * for such a relation is included in the subquery if necessary.
1545 */
1546 if (bms_is_member(relid, fpinfo->lower_subquery_rels))
1547 continue;
1548
1549 /*
1550 * Add FOR UPDATE/SHARE if appropriate. We apply locking during the
1551 * initial row fetch, rather than later on as is done for local
1552 * tables. The extra roundtrips involved in trying to duplicate the
1553 * local semantics exactly don't seem worthwhile (see also comments
1554 * for RowMarkType).
1555 *
1556 * Note: because we actually run the query as a cursor, this assumes
1557 * that DECLARE CURSOR ... FOR UPDATE is supported, which it isn't
1558 * before 8.3.
1559 */
1560 if (bms_is_member(relid, root->all_result_relids) &&
1561 (root->parse->commandType == CMD_UPDATE ||
1562 root->parse->commandType == CMD_DELETE))
1563 {
1564 /* Relation is UPDATE/DELETE target, so use FOR UPDATE */
1565 appendStringInfoString(buf, " FOR UPDATE");
1566
1567 /* Add the relation alias if we are here for a join relation */
1568 if (IS_JOIN_REL(rel))
1569 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1570 }
1571 else
1572 {
1573 PlanRowMark *rc = get_plan_rowmark(root->rowMarks, relid);
1574
1575 if (rc)
1576 {
1577 /*
1578 * Relation is specified as a FOR UPDATE/SHARE target, so
1579 * handle that. (But we could also see LCS_NONE, meaning this
1580 * isn't a target relation after all.)
1581 *
1582 * For now, just ignore any [NO] KEY specification, since (a)
1583 * it's not clear what that means for a remote table that we
1584 * don't have complete information about, and (b) it wouldn't
1585 * work anyway on older remote servers. Likewise, we don't
1586 * worry about NOWAIT.
1587 */
1588 switch (rc->strength)
1589 {
1590 case LCS_NONE:
1591 /* No locking needed */
1592 break;
1593 case LCS_FORKEYSHARE:
1594 case LCS_FORSHARE:
1595 appendStringInfoString(buf, " FOR SHARE");
1596 break;
1597 case LCS_FORNOKEYUPDATE:
1598 case LCS_FORUPDATE:
1599 appendStringInfoString(buf, " FOR UPDATE");
1600 break;
1601 }
1602
1603 /* Add the relation alias if we are here for a join relation */
1604 if (bms_membership(rel->relids) == BMS_MULTIPLE &&
1605 rc->strength != LCS_NONE)
1606 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1607 }
1608 }
1609 }
1610}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1425
@ LCS_FORUPDATE
Definition lockoptions.h:28
@ LCS_NONE
Definition lockoptions.h:23
@ LCS_FORSHARE
Definition lockoptions.h:26
@ LCS_FORKEYSHARE
Definition lockoptions.h:25
@ LCS_FORNOKEYUPDATE
Definition lockoptions.h:27
@ CMD_DELETE
Definition nodes.h:276
@ CMD_UPDATE
Definition nodes.h:274
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition preptlist.c:528
LockClauseStrength strength
Definition plannodes.h:1623

References appendStringInfo(), appendStringInfoString(), bms_is_member(), bms_membership(), BMS_MULTIPLE, bms_next_member(), deparse_expr_cxt::buf, buf, CMD_DELETE, CMD_UPDATE, fb(), get_plan_rowmark(), IS_JOIN_REL, LCS_FORKEYSHARE, LCS_FORNOKEYUPDATE, LCS_FORSHARE, LCS_FORUPDATE, LCS_NONE, REL_ALIAS_PREFIX, RelOptInfo::relids, deparse_expr_cxt::root, root, deparse_expr_cxt::scanrel, and PlanRowMark::strength.

Referenced by deparseSelectStmtForRel().

◆ deparseNullTest()

static void deparseNullTest ( NullTest node,
deparse_expr_cxt context 
)
static

Definition at line 3620 of file deparse.c.

3621{
3622 StringInfo buf = context->buf;
3623
3625 deparseExpr(node->arg, context);
3626
3627 /*
3628 * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
3629 * shorter and traditional. If it's a rowtype input but we're applying a
3630 * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
3631 * correct.
3632 */
3633 if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
3634 {
3635 if (node->nulltesttype == IS_NULL)
3636 appendStringInfoString(buf, " IS NULL)");
3637 else
3638 appendStringInfoString(buf, " IS NOT NULL)");
3639 }
3640 else
3641 {
3642 if (node->nulltesttype == IS_NULL)
3643 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)");
3644 else
3645 appendStringInfoString(buf, " IS DISTINCT FROM NULL)");
3646 }
3647}
bool type_is_rowtype(Oid typid)
Definition lsyscache.c:2971
@ IS_NULL
Definition primnodes.h:1975
NullTestType nulltesttype
Definition primnodes.h:1982
Expr * arg
Definition primnodes.h:1981

References appendStringInfoChar(), appendStringInfoString(), NullTest::arg, deparse_expr_cxt::buf, buf, deparseExpr(), exprType(), IS_NULL, NullTest::nulltesttype, and type_is_rowtype().

Referenced by deparseExpr().

◆ deparseOperatorName()

static void deparseOperatorName ( StringInfo  buf,
Form_pg_operator  opform 
)
static

Definition at line 3460 of file deparse.c.

3461{
3462 char *opname;
3463
3464 /* opname is not a SQL identifier, so we should not quote it. */
3465 opname = NameStr(opform->oprname);
3466
3467 /* Print schema name only if it's not pg_catalog */
3468 if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
3469 {
3470 const char *opnspname;
3471
3472 opnspname = get_namespace_name(opform->oprnamespace);
3473 /* Print fully qualified operator name. */
3474 appendStringInfo(buf, "OPERATOR(%s.%s)",
3476 }
3477 else
3478 {
3479 /* Just print operator name. */
3481 }
3482}

References appendStringInfo(), appendStringInfoString(), buf, fb(), get_namespace_name(), NameStr, and quote_identifier().

Referenced by appendOrderBySuffix(), deparseOpExpr(), and deparseScalarArrayOpExpr().

◆ deparseOpExpr()

static void deparseOpExpr ( OpExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3330 of file deparse.c.

3331{
3332 StringInfo buf = context->buf;
3333 HeapTuple tuple;
3335 Expr *right;
3336 bool canSuppressRightConstCast = false;
3337 char oprkind;
3338
3339 /* Retrieve information about the operator from system catalog. */
3341 if (!HeapTupleIsValid(tuple))
3342 elog(ERROR, "cache lookup failed for operator %u", node->opno);
3343 form = (Form_pg_operator) GETSTRUCT(tuple);
3344 oprkind = form->oprkind;
3345
3346 /* Sanity check. */
3347 Assert((oprkind == 'l' && list_length(node->args) == 1) ||
3348 (oprkind == 'b' && list_length(node->args) == 2));
3349
3350 right = llast(node->args);
3351
3352 /* Always parenthesize the expression. */
3354
3355 /* Deparse left operand, if any. */
3356 if (oprkind == 'b')
3357 {
3358 Expr *left = linitial(node->args);
3359 Oid leftType = exprType((Node *) left);
3360 Oid rightType = exprType((Node *) right);
3361 bool canSuppressLeftConstCast = false;
3362
3363 /*
3364 * When considering a binary operator, if one operand is a Const that
3365 * can be printed as a bare string literal or NULL (i.e., it will look
3366 * like type UNKNOWN to the remote parser), the Const normally
3367 * receives an explicit cast to the operator's input type. However,
3368 * in Const-to-Var comparisons where both operands are of the same
3369 * type, we prefer to suppress the explicit cast, leaving the Const's
3370 * type resolution up to the remote parser. The remote's resolution
3371 * heuristic will assume that an unknown input type being compared to
3372 * a known input type is of that known type as well.
3373 *
3374 * This hack allows some cases to succeed where a remote column is
3375 * declared with a different type in the local (foreign) table. By
3376 * emitting "foreigncol = 'foo'" not "foreigncol = 'foo'::text" or the
3377 * like, we allow the remote parser to pick an "=" operator that's
3378 * compatible with whatever type the remote column really is, such as
3379 * an enum.
3380 *
3381 * We allow cast suppression to happen only when the other operand is
3382 * a plain foreign Var. Although the remote's unknown-type heuristic
3383 * would apply to other cases just as well, we would be taking a
3384 * bigger risk that the inferred type is something unexpected. With
3385 * this restriction, if anything goes wrong it's the user's fault for
3386 * not declaring the local column with the same type as the remote
3387 * column.
3388 */
3389 if (leftType == rightType)
3390 {
3391 if (IsA(left, Const))
3393 else if (IsA(right, Const))
3395 }
3396
3398 deparseConst((Const *) left, context, -2);
3399 else
3400 deparseExpr(left, context);
3401
3403 }
3404
3405 /* Deparse operator name. */
3407
3408 /* Deparse right operand. */
3410
3412 deparseConst((Const *) right, context, -2);
3413 else
3414 deparseExpr(right, context);
3415
3417
3418 ReleaseSysCache(tuple);
3419}
static bool isPlainForeignVar(Expr *node, deparse_expr_cxt *context)
Definition deparse.c:3425
#define llast(l)
Definition pg_list.h:198
Oid opno
Definition primnodes.h:835

References appendStringInfoChar(), OpExpr::args, Assert, deparse_expr_cxt::buf, buf, deparseConst(), deparseExpr(), deparseOperatorName(), elog, ERROR, exprType(), fb(), Form_pg_operator, GETSTRUCT(), HeapTupleIsValid, IsA, isPlainForeignVar(), linitial, list_length(), llast, ObjectIdGetDatum(), OpExpr::opno, ReleaseSysCache(), and SearchSysCache1().

Referenced by deparseExpr().

◆ deparseParam()

static void deparseParam ( Param node,
deparse_expr_cxt context 
)
static

Definition at line 3188 of file deparse.c.

3189{
3190 if (context->params_list)
3191 {
3192 int pindex = 0;
3193 ListCell *lc;
3194
3195 /* find its index in params_list */
3196 foreach(lc, *context->params_list)
3197 {
3198 pindex++;
3199 if (equal(node, (Node *) lfirst(lc)))
3200 break;
3201 }
3202 if (lc == NULL)
3203 {
3204 /* not in list, so add it */
3205 pindex++;
3206 *context->params_list = lappend(*context->params_list, node);
3207 }
3208
3209 printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
3210 }
3211 else
3212 {
3213 printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
3214 }
3215}
static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition deparse.c:3895
static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition deparse.c:3921
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
int32 paramtypmod
Definition primnodes.h:400
Oid paramtype
Definition primnodes.h:398

References equal(), fb(), lappend(), lfirst, deparse_expr_cxt::params_list, Param::paramtype, Param::paramtypmod, printRemoteParam(), and printRemotePlaceholder().

Referenced by deparseExpr().

◆ deparseRangeTblRef()

static void deparseRangeTblRef ( StringInfo  buf,
PlannerInfo root,
RelOptInfo foreignrel,
bool  make_subquery,
Index  ignore_rel,
List **  ignore_conds,
List **  additional_conds,
List **  params_list 
)
static

Definition at line 2059 of file deparse.c.

2062{
2063 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
2064
2065 /* Should only be called in these cases. */
2066 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
2067
2068 Assert(fpinfo->local_conds == NIL);
2069
2070 /* If make_subquery is true, deparse the relation as a subquery. */
2071 if (make_subquery)
2072 {
2073 List *retrieved_attrs;
2074 int ncols;
2075
2076 /*
2077 * The given relation shouldn't contain the target relation, because
2078 * this should only happen for input relations for a full join, and
2079 * such relations can never contain an UPDATE/DELETE target.
2080 */
2081 Assert(ignore_rel == 0 ||
2082 !bms_is_member(ignore_rel, foreignrel->relids));
2083
2084 /* Deparse the subquery representing the relation. */
2086 deparseSelectStmtForRel(buf, root, foreignrel, NIL,
2087 fpinfo->remote_conds, NIL,
2088 false, false, true,
2089 &retrieved_attrs, params_list);
2091
2092 /* Append the relation alias. */
2094 fpinfo->relation_index);
2095
2096 /*
2097 * Append the column aliases if needed. Note that the subquery emits
2098 * expressions specified in the relation's reltarget (see
2099 * deparseSubqueryTargetList).
2100 */
2101 ncols = list_length(foreignrel->reltarget->exprs);
2102 if (ncols > 0)
2103 {
2104 int i;
2105
2107 for (i = 1; i <= ncols; i++)
2108 {
2109 if (i > 1)
2111
2113 }
2115 }
2116 }
2117 else
2118 deparseFromExprForRel(buf, root, foreignrel, true, ignore_rel,
2120 params_list);
2121}
#define SUBQUERY_REL_ALIAS_PREFIX
Definition deparse.c:113
void deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, List *tlist, List *remote_conds, List *pathkeys, bool has_final_sort, bool has_limit, bool is_subquery, List **retrieved_attrs, List **params_list)
Definition deparse.c:1286
#define SUBQUERY_COL_ALIAS_PREFIX
Definition deparse.c:114

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, bms_is_member(), buf, deparseFromExprForRel(), deparseSelectStmtForRel(), PathTarget::exprs, fb(), i, IS_JOIN_REL, IS_SIMPLE_REL, list_length(), NIL, RelOptInfo::relids, RelOptInfo::reltarget, root, SUBQUERY_COL_ALIAS_PREFIX, and SUBQUERY_REL_ALIAS_PREFIX.

Referenced by deparseFromExprForRel().

◆ deparseRelabelType()

static void deparseRelabelType ( RelabelType node,
deparse_expr_cxt context 
)
static

Definition at line 3551 of file deparse.c.

3552{
3553 deparseExpr(node->arg, context);
3554 if (node->relabelformat != COERCE_IMPLICIT_CAST)
3555 appendStringInfo(context->buf, "::%s",
3557 node->resulttypmod));
3558}

References appendStringInfo(), RelabelType::arg, deparse_expr_cxt::buf, COERCE_IMPLICIT_CAST, deparse_type_name(), deparseExpr(), and RelabelType::resulttype.

Referenced by deparseExpr().

◆ deparseRelation()

static void deparseRelation ( StringInfo  buf,
Relation  rel 
)
static

Definition at line 2860 of file deparse.c.

2861{
2863 const char *nspname = NULL;
2864 const char *relname = NULL;
2865 ListCell *lc;
2866
2867 /* obtain additional catalog information. */
2869
2870 /*
2871 * Use value of FDW options if any, instead of the name of object itself.
2872 */
2873 foreach(lc, table->options)
2874 {
2875 DefElem *def = (DefElem *) lfirst(lc);
2876
2877 if (strcmp(def->defname, "schema_name") == 0)
2878 nspname = defGetString(def);
2879 else if (strcmp(def->defname, "table_name") == 0)
2880 relname = defGetString(def);
2881 }
2882
2883 /*
2884 * Note: we could skip printing the schema name if it's pg_catalog, but
2885 * that doesn't seem worth the trouble.
2886 */
2887 if (nspname == NULL)
2889 if (relname == NULL)
2891
2892 appendStringInfo(buf, "%s.%s",
2894}
ForeignTable * GetForeignTable(Oid relid)
Definition foreign.c:286
static const struct lconv_member_info table[]
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationGetNamespace(relation)
Definition rel.h:557

References appendStringInfo(), buf, defGetString(), DefElem::defname, fb(), get_namespace_name(), GetForeignTable(), lfirst, quote_identifier(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, relname, and table.

Referenced by deparseAnalyzeInfoSql(), deparseAnalyzeSizeSql(), deparseAnalyzeSql(), deparseDeleteSql(), deparseDirectDeleteSql(), deparseDirectUpdateSql(), deparseFromExprForRel(), deparseInsertSql(), deparseTruncateSql(), and deparseUpdateSql().

◆ deparseReturningList()

static void deparseReturningList ( StringInfo  buf,
RangeTblEntry rte,
Index  rtindex,
Relation  rel,
bool  trig_after_row,
List withCheckOptionList,
List returningList,
List **  retrieved_attrs 
)
static

Definition at line 2493 of file deparse.c.

2499{
2500 Bitmapset *attrs_used = NULL;
2501
2502 if (trig_after_row)
2503 {
2504 /* whole-row reference acquires all non-system columns */
2505 attrs_used =
2507 }
2508
2509 if (withCheckOptionList != NIL)
2510 {
2511 /*
2512 * We need the attrs, non-system and system, mentioned in the local
2513 * query's WITH CHECK OPTION list.
2514 *
2515 * Note: we do this to ensure that WCO constraints will be evaluated
2516 * on the data actually inserted/updated on the remote side, which
2517 * might differ from the data supplied by the core code, for example
2518 * as a result of remote triggers.
2519 */
2521 &attrs_used);
2522 }
2523
2524 if (returningList != NIL)
2525 {
2526 /*
2527 * We need the attrs, non-system and system, mentioned in the local
2528 * query's RETURNING list.
2529 */
2530 pull_varattnos((Node *) returningList, rtindex,
2531 &attrs_used);
2532 }
2533
2534 if (attrs_used != NULL)
2535 deparseTargetList(buf, rte, rtindex, rel, true, attrs_used, false,
2536 retrieved_attrs);
2537 else
2538 *retrieved_attrs = NIL;
2539}
Bitmapset * bms_make_singleton(int x)
Definition bitmapset.c:217
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition var.c:296

References bms_make_singleton(), buf, deparseTargetList(), fb(), FirstLowInvalidHeapAttributeNumber, NIL, and pull_varattnos().

Referenced by deparseDeleteSql(), deparseDirectDeleteSql(), deparseDirectUpdateSql(), deparseInsertSql(), and deparseUpdateSql().

◆ deparseScalarArrayOpExpr()

static void deparseScalarArrayOpExpr ( ScalarArrayOpExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3506 of file deparse.c.

3507{
3508 StringInfo buf = context->buf;
3509 HeapTuple tuple;
3511 Expr *arg1;
3512 Expr *arg2;
3513
3514 /* Retrieve information about the operator from system catalog. */
3516 if (!HeapTupleIsValid(tuple))
3517 elog(ERROR, "cache lookup failed for operator %u", node->opno);
3518 form = (Form_pg_operator) GETSTRUCT(tuple);
3519
3520 /* Sanity check. */
3521 Assert(list_length(node->args) == 2);
3522
3523 /* Always parenthesize the expression. */
3525
3526 /* Deparse left operand. */
3527 arg1 = linitial(node->args);
3528 deparseExpr(arg1, context);
3530
3531 /* Deparse operator name plus decoration. */
3533 appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
3534
3535 /* Deparse right operand. */
3536 arg2 = lsecond(node->args);
3537 deparseExpr(arg2, context);
3538
3540
3541 /* Always parenthesize the expression. */
3543
3544 ReleaseSysCache(tuple);
3545}

References appendStringInfo(), appendStringInfoChar(), ScalarArrayOpExpr::args, Assert, deparse_expr_cxt::buf, buf, deparseExpr(), deparseOperatorName(), elog, ERROR, fb(), Form_pg_operator, GETSTRUCT(), HeapTupleIsValid, linitial, list_length(), lsecond, ObjectIdGetDatum(), ScalarArrayOpExpr::opno, ReleaseSysCache(), SearchSysCache1(), and ScalarArrayOpExpr::useOr.

Referenced by deparseExpr().

◆ deparseSelectSql()

static void deparseSelectSql ( List tlist,
bool  is_subquery,
List **  retrieved_attrs,
deparse_expr_cxt context 
)
static

Definition at line 1368 of file deparse.c.

1370{
1371 StringInfo buf = context->buf;
1372 RelOptInfo *foreignrel = context->foreignrel;
1373 PlannerInfo *root = context->root;
1374 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1375
1376 /*
1377 * Construct SELECT list
1378 */
1379 appendStringInfoString(buf, "SELECT ");
1380
1381 if (is_subquery)
1382 {
1383 /*
1384 * For a relation that is deparsed as a subquery, emit expressions
1385 * specified in the relation's reltarget. Note that since this is for
1386 * the subquery, no need to care about *retrieved_attrs.
1387 */
1389 }
1390 else if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
1391 {
1392 /*
1393 * For a join or upper relation the input tlist gives the list of
1394 * columns required to be fetched from the foreign server.
1395 */
1396 deparseExplicitTargetList(tlist, false, retrieved_attrs, context);
1397 }
1398 else
1399 {
1400 /*
1401 * For a base relation fpinfo->attrs_used gives the list of columns
1402 * required to be fetched from the foreign server.
1403 */
1404 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1405
1406 /*
1407 * Core code already has some lock on each rel being planned, so we
1408 * can use NoLock here.
1409 */
1410 Relation rel = table_open(rte->relid, NoLock);
1411
1412 deparseTargetList(buf, rte, foreignrel->relid, rel, false,
1413 fpinfo->attrs_used, false, retrieved_attrs);
1414 table_close(rel, NoLock);
1415 }
1416}
static void deparseSubqueryTargetList(deparse_expr_cxt *context)
Definition deparse.c:1768

References appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseExplicitTargetList(), deparseSubqueryTargetList(), deparseTargetList(), fb(), deparse_expr_cxt::foreignrel, IS_JOIN_REL, IS_UPPER_REL, NoLock, planner_rt_fetch, RelOptInfo::relid, deparse_expr_cxt::root, root, table_close(), and table_open().

Referenced by deparseSelectStmtForRel().

◆ deparseSelectStmtForRel()

void deparseSelectStmtForRel ( StringInfo  buf,
PlannerInfo root,
RelOptInfo rel,
List tlist,
List remote_conds,
List pathkeys,
bool  has_final_sort,
bool  has_limit,
bool  is_subquery,
List **  retrieved_attrs,
List **  params_list 
)

Definition at line 1286 of file deparse.c.

1290{
1291 deparse_expr_cxt context;
1292 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1293 List *quals;
1294
1295 /*
1296 * We handle relations for foreign tables, joins between those and upper
1297 * relations.
1298 */
1299 Assert(IS_JOIN_REL(rel) || IS_SIMPLE_REL(rel) || IS_UPPER_REL(rel));
1300
1301 /* Fill portions of context common to upper, join and base relation */
1302 context.buf = buf;
1303 context.root = root;
1304 context.foreignrel = rel;
1305 context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel;
1306 context.params_list = params_list;
1307
1308 /* Construct SELECT clause */
1309 deparseSelectSql(tlist, is_subquery, retrieved_attrs, &context);
1310
1311 /*
1312 * For upper relations, the WHERE clause is built from the remote
1313 * conditions of the underlying scan relation; otherwise, we can use the
1314 * supplied list of remote conditions directly.
1315 */
1316 if (IS_UPPER_REL(rel))
1317 {
1319
1320 ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
1321 quals = ofpinfo->remote_conds;
1322 }
1323 else
1324 quals = remote_conds;
1325
1326 /* Construct FROM and WHERE clauses */
1327 deparseFromExpr(quals, &context);
1328
1329 if (IS_UPPER_REL(rel))
1330 {
1331 /* Append GROUP BY clause */
1332 appendGroupByClause(tlist, &context);
1333
1334 /* Append HAVING clause */
1335 if (remote_conds)
1336 {
1337 appendStringInfoString(buf, " HAVING ");
1338 appendConditions(remote_conds, &context);
1339 }
1340 }
1341
1342 /* Add ORDER BY clause if we found any useful pathkeys */
1343 if (pathkeys)
1344 appendOrderByClause(pathkeys, has_final_sort, &context);
1345
1346 /* Add LIMIT clause if necessary */
1347 if (has_limit)
1348 appendLimitClause(&context);
1349
1350 /* Add any necessary FOR UPDATE/SHARE. */
1351 deparseLockingClause(&context);
1352}
static void appendGroupByClause(List *tlist, deparse_expr_cxt *context)
Definition deparse.c:3934
static void deparseFromExpr(List *quals, deparse_expr_cxt *context)
Definition deparse.c:1426
static void deparseLockingClause(deparse_expr_cxt *context)
Definition deparse.c:1532
static void appendOrderByClause(List *pathkeys, bool has_final_sort, deparse_expr_cxt *context)
Definition deparse.c:3982
static void appendLimitClause(deparse_expr_cxt *context)
Definition deparse.c:4076
static void deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs, deparse_expr_cxt *context)
Definition deparse.c:1368
RelOptInfo * outerrel

References appendConditions(), appendGroupByClause(), appendLimitClause(), appendOrderByClause(), appendStringInfoString(), Assert, deparse_expr_cxt::buf, buf, deparseFromExpr(), deparseLockingClause(), deparseSelectSql(), fb(), deparse_expr_cxt::foreignrel, IS_JOIN_REL, IS_SIMPLE_REL, IS_UPPER_REL, PgFdwRelationInfo::outerrel, deparse_expr_cxt::params_list, deparse_expr_cxt::root, root, and deparse_expr_cxt::scanrel.

Referenced by deparseRangeTblRef(), estimate_path_cost_size(), and postgresGetForeignPlan().

◆ deparseSortGroupClause()

static Node * deparseSortGroupClause ( Index  ref,
List tlist,
bool  force_colno,
deparse_expr_cxt context 
)
static

Definition at line 4139 of file deparse.c.

4141{
4142 StringInfo buf = context->buf;
4144 Expr *expr;
4145
4146 tle = get_sortgroupref_tle(ref, tlist);
4147 expr = tle->expr;
4148
4149 if (force_colno)
4150 {
4151 /* Use column-number form when requested by caller. */
4152 Assert(!tle->resjunk);
4153 appendStringInfo(buf, "%d", tle->resno);
4154 }
4155 else if (expr && IsA(expr, Const))
4156 {
4157 /*
4158 * Force a typecast here so that we don't emit something like "GROUP
4159 * BY 2", which will be misconstrued as a column position rather than
4160 * a constant.
4161 */
4162 deparseConst((Const *) expr, context, 1);
4163 }
4164 else if (!expr || IsA(expr, Var))
4165 deparseExpr(expr, context);
4166 else
4167 {
4168 /* Always parenthesize the expression. */
4170 deparseExpr(expr, context);
4172 }
4173
4174 return (Node *) expr;
4175}
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition tlist.c:354

References appendStringInfo(), appendStringInfoChar(), Assert, deparse_expr_cxt::buf, buf, deparseConst(), deparseExpr(), fb(), get_sortgroupref_tle(), and IsA.

Referenced by appendAggOrderBy(), and appendGroupByClause().

◆ deparseStringLiteral()

void deparseStringLiteral ( StringInfo  buf,
const char val 
)

Definition at line 2900 of file deparse.c.

2901{
2902 const char *valptr;
2903
2904 /*
2905 * Rather than making assumptions about the remote server's value of
2906 * standard_conforming_strings, always use E'foo' syntax if there are any
2907 * backslashes. This will fail on remote servers before 8.1, but those
2908 * are long out of support.
2909 */
2910 if (strchr(val, '\\') != NULL)
2913 for (valptr = val; *valptr; valptr++)
2914 {
2915 char ch = *valptr;
2916
2917 if (SQL_STR_DOUBLE(ch, true))
2920 }
2922}
#define ESCAPE_STRING_SYNTAX
Definition c.h:1295
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition c.h:1292
long val
Definition informix.c:689

References appendStringInfoChar(), buf, ESCAPE_STRING_SYNTAX, fb(), SQL_STR_DOUBLE, and val.

Referenced by build_remattrmap(), deparseAnalyzeInfoSql(), deparseAnalyzeSizeSql(), deparseConst(), fetch_attstats(), and postgresImportForeignSchema().

◆ deparseSubqueryTargetList()

static void deparseSubqueryTargetList ( deparse_expr_cxt context)
static

Definition at line 1768 of file deparse.c.

1769{
1770 StringInfo buf = context->buf;
1771 RelOptInfo *foreignrel = context->foreignrel;
1772 bool first;
1773 ListCell *lc;
1774
1775 /* Should only be called in these cases. */
1776 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1777
1778 first = true;
1779 foreach(lc, foreignrel->reltarget->exprs)
1780 {
1781 Node *node = (Node *) lfirst(lc);
1782
1783 if (!first)
1785 first = false;
1786
1787 deparseExpr((Expr *) node, context);
1788 }
1789
1790 /* Don't generate bad syntax if no expressions */
1791 if (first)
1792 appendStringInfoString(buf, "NULL");
1793}

References appendStringInfoString(), Assert, deparse_expr_cxt::buf, buf, deparseExpr(), PathTarget::exprs, fb(), deparse_expr_cxt::foreignrel, IS_JOIN_REL, IS_SIMPLE_REL, lfirst, and RelOptInfo::reltarget.

Referenced by deparseSelectSql().

◆ deparseSubscriptingRef()

static void deparseSubscriptingRef ( SubscriptingRef node,
deparse_expr_cxt context 
)
static

Definition at line 3221 of file deparse.c.

3222{
3223 StringInfo buf = context->buf;
3226
3227 /* Always parenthesize the expression. */
3229
3230 /*
3231 * Deparse referenced array expression first. If that expression includes
3232 * a cast, we have to parenthesize to prevent the array subscript from
3233 * being taken as typename decoration. We can avoid that in the typical
3234 * case of subscripting a Var, but otherwise do it.
3235 */
3236 if (IsA(node->refexpr, Var))
3237 deparseExpr(node->refexpr, context);
3238 else
3239 {
3241 deparseExpr(node->refexpr, context);
3243 }
3244
3245 /* Deparse subscript expressions. */
3246 lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
3247 foreach(uplist_item, node->refupperindexpr)
3248 {
3250 if (lowlist_item)
3251 {
3252 deparseExpr(lfirst(lowlist_item), context);
3255 }
3256 deparseExpr(lfirst(uplist_item), context);
3258 }
3259
3261}
static ListCell * list_head(const List *l)
Definition pg_list.h:128
List * refupperindexpr
Definition primnodes.h:716
List * reflowerindexpr
Definition primnodes.h:722

References appendStringInfoChar(), deparse_expr_cxt::buf, buf, deparseExpr(), fb(), IsA, lfirst, list_head(), lnext(), SubscriptingRef::refexpr, SubscriptingRef::reflowerindexpr, and SubscriptingRef::refupperindexpr.

Referenced by deparseExpr().

◆ deparseTargetList()

static void deparseTargetList ( StringInfo  buf,
RangeTblEntry rte,
Index  rtindex,
Relation  rel,
bool  is_returning,
Bitmapset attrs_used,
bool  qualify_col,
List **  retrieved_attrs 
)
static

Definition at line 1458 of file deparse.c.

1466{
1467 TupleDesc tupdesc = RelationGetDescr(rel);
1468 bool have_wholerow;
1469 bool first;
1470 int i;
1471
1472 *retrieved_attrs = NIL;
1473
1474 /* If there's a whole-row reference, we'll need all the columns. */
1476 attrs_used);
1477
1478 first = true;
1479 for (i = 1; i <= tupdesc->natts; i++)
1480 {
1481 /* Ignore dropped attributes. */
1482 if (TupleDescCompactAttr(tupdesc, i - 1)->attisdropped)
1483 continue;
1484
1485 if (have_wholerow ||
1487 attrs_used))
1488 {
1489 if (!first)
1491 else if (is_returning)
1492 appendStringInfoString(buf, " RETURNING ");
1493 first = false;
1494
1495 deparseColumnRef(buf, rtindex, i, rte, qualify_col);
1496
1497 *retrieved_attrs = lappend_int(*retrieved_attrs, i);
1498 }
1499 }
1500
1501 /*
1502 * Add ctid if needed. We currently don't support retrieving any other
1503 * system columns.
1504 */
1506 attrs_used))
1507 {
1508 if (!first)
1510 else if (is_returning)
1511 appendStringInfoString(buf, " RETURNING ");
1512 first = false;
1513
1514 if (qualify_col)
1515 ADD_REL_QUALIFIER(buf, rtindex);
1516 appendStringInfoString(buf, "ctid");
1517
1518 *retrieved_attrs = lappend_int(*retrieved_attrs,
1520 }
1521
1522 /* Don't generate bad syntax if no undropped columns */
1523 if (first && !is_returning)
1524 appendStringInfoString(buf, "NULL");
1525}

References ADD_REL_QUALIFIER, appendStringInfoString(), bms_is_member(), buf, deparseColumnRef(), fb(), FirstLowInvalidHeapAttributeNumber, i, lappend_int(), TupleDescData::natts, NIL, RelationGetDescr, SelfItemPointerAttributeNumber, and TupleDescCompactAttr().

Referenced by deparseColumnRef(), deparseReturningList(), and deparseSelectSql().

◆ deparseTruncateSql()

void deparseTruncateSql ( StringInfo  buf,
List rels,
DropBehavior  behavior,
bool  restart_seqs 
)

Definition at line 2697 of file deparse.c.

2701{
2702 ListCell *cell;
2703
2704 appendStringInfoString(buf, "TRUNCATE ");
2705
2706 foreach(cell, rels)
2707 {
2708 Relation rel = lfirst(cell);
2709
2710 if (cell != list_head(rels))
2712
2713 deparseRelation(buf, rel);
2714 }
2715
2716 appendStringInfo(buf, " %s IDENTITY",
2717 restart_seqs ? "RESTART" : "CONTINUE");
2718
2719 if (behavior == DROP_RESTRICT)
2720 appendStringInfoString(buf, " RESTRICT");
2721 else if (behavior == DROP_CASCADE)
2722 appendStringInfoString(buf, " CASCADE");
2723}
@ DROP_CASCADE
@ DROP_RESTRICT

References appendStringInfo(), appendStringInfoString(), buf, deparseRelation(), DROP_CASCADE, DROP_RESTRICT, lfirst, and list_head().

Referenced by postgresExecForeignTruncate().

◆ deparseUpdateSql()

void deparseUpdateSql ( StringInfo  buf,
RangeTblEntry rte,
Index  rtindex,
Relation  rel,
List targetAttrs,
List withCheckOptionList,
List returningList,
List **  retrieved_attrs 
)

Definition at line 2267 of file deparse.c.

2272{
2273 TupleDesc tupdesc = RelationGetDescr(rel);
2275 bool first;
2276 ListCell *lc;
2277
2278 appendStringInfoString(buf, "UPDATE ");
2279 deparseRelation(buf, rel);
2280 appendStringInfoString(buf, " SET ");
2281
2282 pindex = 2; /* ctid is always the first param */
2283 first = true;
2284 foreach(lc, targetAttrs)
2285 {
2286 int attnum = lfirst_int(lc);
2287 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
2288
2289 if (!first)
2291 first = false;
2292
2293 deparseColumnRef(buf, rtindex, attnum, rte, false);
2294 if (attr->attgenerated)
2295 appendStringInfoString(buf, " = DEFAULT");
2296 else
2297 {
2298 appendStringInfo(buf, " = $%d", pindex);
2299 pindex++;
2300 }
2301 }
2302 appendStringInfoString(buf, " WHERE ctid = $1");
2303
2304 deparseReturningList(buf, rte, rtindex, rel,
2306 withCheckOptionList, returningList, retrieved_attrs);
2307}
bool trig_update_after_row
Definition reltrigger.h:62

References appendStringInfo(), appendStringInfoString(), CompactAttribute::attgenerated, attnum, buf, deparseColumnRef(), deparseRelation(), deparseReturningList(), fb(), lfirst_int, RelationGetDescr, TriggerDesc::trig_update_after_row, RelationData::trigdesc, and TupleDescCompactAttr().

Referenced by postgresPlanForeignModify().

◆ deparseVar()

static void deparseVar ( Var node,
deparse_expr_cxt context 
)
static

Definition at line 3003 of file deparse.c.

3004{
3005 Relids relids = context->scanrel->relids;
3006 int relno;
3007 int colno;
3008
3009 /* Qualify columns when multiple relations are involved. */
3010 bool qualify_col = (bms_membership(relids) == BMS_MULTIPLE);
3011
3012 /*
3013 * If the Var belongs to the foreign relation that is deparsed as a
3014 * subquery, use the relation and column alias to the Var provided by the
3015 * subquery, instead of the remote name.
3016 */
3017 if (is_subquery_var(node, context->scanrel, &relno, &colno))
3018 {
3019 appendStringInfo(context->buf, "%s%d.%s%d",
3022 return;
3023 }
3024
3025 if (bms_is_member(node->varno, relids) && node->varlevelsup == 0)
3026 deparseColumnRef(context->buf, node->varno, node->varattno,
3027 planner_rt_fetch(node->varno, context->root),
3028 qualify_col);
3029 else
3030 {
3031 /* Treat like a Param */
3032 if (context->params_list)
3033 {
3034 int pindex = 0;
3035 ListCell *lc;
3036
3037 /* find its index in params_list */
3038 foreach(lc, *context->params_list)
3039 {
3040 pindex++;
3041 if (equal(node, (Node *) lfirst(lc)))
3042 break;
3043 }
3044 if (lc == NULL)
3045 {
3046 /* not in list, so add it */
3047 pindex++;
3048 *context->params_list = lappend(*context->params_list, node);
3049 }
3050
3051 printRemoteParam(pindex, node->vartype, node->vartypmod, context);
3052 }
3053 else
3054 {
3055 printRemotePlaceholder(node->vartype, node->vartypmod, context);
3056 }
3057 }
3058}
static bool is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition deparse.c:4184
AttrNumber varattno
Definition primnodes.h:275
int varno
Definition primnodes.h:270
Index varlevelsup
Definition primnodes.h:295

References appendStringInfo(), bms_is_member(), bms_membership(), BMS_MULTIPLE, deparse_expr_cxt::buf, deparseColumnRef(), equal(), fb(), is_subquery_var(), lappend(), lfirst, deparse_expr_cxt::params_list, planner_rt_fetch, printRemoteParam(), printRemotePlaceholder(), RelOptInfo::relids, deparse_expr_cxt::root, deparse_expr_cxt::scanrel, SUBQUERY_COL_ALIAS_PREFIX, SUBQUERY_REL_ALIAS_PREFIX, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by deparseExpr().

◆ foreign_expr_walker()

static bool foreign_expr_walker ( Node node,
foreign_glob_cxt glob_cxt,
foreign_loc_cxt outer_cxt,
foreign_loc_cxt case_arg_cxt 
)
static

Definition at line 312 of file deparse.c.

316{
317 bool check_type = true;
320 Oid collation;
322
323 /* Need do nothing for empty subexpressions */
324 if (node == NULL)
325 return true;
326
327 /* May need server info from baserel's fdw_private struct */
328 fpinfo = (PgFdwRelationInfo *) (glob_cxt->foreignrel->fdw_private);
329
330 /* Set up inner_cxt for possible recursion to child nodes */
331 inner_cxt.collation = InvalidOid;
333
334 switch (nodeTag(node))
335 {
336 case T_Var:
337 {
338 Var *var = (Var *) node;
339
340 /*
341 * If the Var is from the foreign table, we consider its
342 * collation (if any) safe to use. If it is from another
343 * table, we treat its collation the same way as we would a
344 * Param's collation, ie it's not safe for it to have a
345 * non-default collation.
346 */
347 if (bms_is_member(var->varno, glob_cxt->relids) &&
348 var->varlevelsup == 0)
349 {
350 /* Var belongs to foreign table */
351
352 /*
353 * System columns other than ctid should not be sent to
354 * the remote, since we don't make any effort to ensure
355 * that local and remote values match (tableoid, in
356 * particular, almost certainly doesn't match).
357 */
358 if (var->varattno < 0 &&
360 return false;
361
362 /* Else check the collation */
363 collation = var->varcollid;
365 }
366 else
367 {
368 /* Var belongs to some other table */
369 collation = var->varcollid;
370 if (collation == InvalidOid ||
371 collation == DEFAULT_COLLATION_OID)
372 {
373 /*
374 * It's noncollatable, or it's safe to combine with a
375 * collatable foreign Var, so set state to NONE.
376 */
378 }
379 else
380 {
381 /*
382 * Do not fail right away, since the Var might appear
383 * in a collation-insensitive context.
384 */
386 }
387 }
388 }
389 break;
390 case T_Const:
391 {
392 Const *c = (Const *) node;
393
394 /*
395 * Constants of regproc and related types can't be shipped
396 * unless the referenced object is shippable. But NULL's ok.
397 * (See also the related code in dependency.c.)
398 */
399 if (!c->constisnull)
400 {
401 switch (c->consttype)
402 {
403 case REGPROCOID:
404 case REGPROCEDUREOID:
405 if (!is_shippable(DatumGetObjectId(c->constvalue),
407 return false;
408 break;
409 case REGOPEROID:
410 case REGOPERATOROID:
411 if (!is_shippable(DatumGetObjectId(c->constvalue),
413 return false;
414 break;
415 case REGCLASSOID:
416 if (!is_shippable(DatumGetObjectId(c->constvalue),
418 return false;
419 break;
420 case REGTYPEOID:
421 if (!is_shippable(DatumGetObjectId(c->constvalue),
423 return false;
424 break;
425 case REGCOLLATIONOID:
426 if (!is_shippable(DatumGetObjectId(c->constvalue),
428 return false;
429 break;
430 case REGCONFIGOID:
431
432 /*
433 * For text search objects only, we weaken the
434 * normal shippability criterion to allow all OIDs
435 * below FirstNormalObjectId. Without this, none
436 * of the initdb-installed TS configurations would
437 * be shippable, which would be quite annoying.
438 */
439 if (DatumGetObjectId(c->constvalue) >= FirstNormalObjectId &&
440 !is_shippable(DatumGetObjectId(c->constvalue),
442 return false;
443 break;
444 case REGDICTIONARYOID:
445 if (DatumGetObjectId(c->constvalue) >= FirstNormalObjectId &&
446 !is_shippable(DatumGetObjectId(c->constvalue),
448 return false;
449 break;
450 case REGNAMESPACEOID:
451 if (!is_shippable(DatumGetObjectId(c->constvalue),
453 return false;
454 break;
455 case REGROLEOID:
456 if (!is_shippable(DatumGetObjectId(c->constvalue),
458 return false;
459 break;
460 case REGDATABASEOID:
461 if (!is_shippable(DatumGetObjectId(c->constvalue),
463 return false;
464 break;
465 }
466 }
467
468 /*
469 * If the constant has nondefault collation, either it's of a
470 * non-builtin type, or it reflects folding of a CollateExpr.
471 * It's unsafe to send to the remote unless it's used in a
472 * non-collation-sensitive context.
473 */
474 collation = c->constcollid;
475 if (collation == InvalidOid ||
476 collation == DEFAULT_COLLATION_OID)
478 else
480 }
481 break;
482 case T_Param:
483 {
484 Param *p = (Param *) node;
485
486 /*
487 * If it's a MULTIEXPR Param, punt. We can't tell from here
488 * whether the referenced sublink/subplan contains any remote
489 * Vars; if it does, handling that is too complicated to
490 * consider supporting at present. Fortunately, MULTIEXPR
491 * Params are not reduced to plain PARAM_EXEC until the end of
492 * planning, so we can easily detect this case. (Normal
493 * PARAM_EXEC Params are safe to ship because their values
494 * come from somewhere else in the plan tree; but a MULTIEXPR
495 * references a sub-select elsewhere in the same targetlist,
496 * so we'd be on the hook to evaluate it somehow if we wanted
497 * to handle such cases as direct foreign updates.)
498 */
499 if (p->paramkind == PARAM_MULTIEXPR)
500 return false;
501
502 /*
503 * Collation rule is same as for Consts and non-foreign Vars.
504 */
505 collation = p->paramcollid;
506 if (collation == InvalidOid ||
507 collation == DEFAULT_COLLATION_OID)
509 else
511 }
512 break;
514 {
516
517 /* Assignment should not be in restrictions. */
518 if (sr->refassgnexpr != NULL)
519 return false;
520
521 /*
522 * Recurse into the remaining subexpressions. The container
523 * subscripts will not affect collation of the SubscriptingRef
524 * result, so do those first and reset inner_cxt afterwards.
525 */
526 if (!foreign_expr_walker((Node *) sr->refupperindexpr,
528 return false;
529 inner_cxt.collation = InvalidOid;
531 if (!foreign_expr_walker((Node *) sr->reflowerindexpr,
533 return false;
534 inner_cxt.collation = InvalidOid;
536 if (!foreign_expr_walker((Node *) sr->refexpr,
538 return false;
539
540 /*
541 * Container subscripting typically yields same collation as
542 * refexpr's, but in case it doesn't, use same logic as for
543 * function nodes.
544 */
545 collation = sr->refcollid;
546 if (collation == InvalidOid)
548 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
549 collation == inner_cxt.collation)
551 else if (collation == DEFAULT_COLLATION_OID)
553 else
555 }
556 break;
557 case T_FuncExpr:
558 {
559 FuncExpr *fe = (FuncExpr *) node;
560
561 /*
562 * If function used by the expression is not shippable, it
563 * can't be sent to remote because it might have incompatible
564 * semantics on remote side.
565 */
567 return false;
568
569 /*
570 * Recurse to input subexpressions.
571 */
572 if (!foreign_expr_walker((Node *) fe->args,
574 return false;
575
576 /*
577 * If function's input collation is not derived from a foreign
578 * Var, it can't be sent to remote.
579 */
580 if (fe->inputcollid == InvalidOid)
581 /* OK, inputs are all noncollatable */ ;
582 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
583 fe->inputcollid != inner_cxt.collation)
584 return false;
585
586 /*
587 * Detect whether node is introducing a collation not derived
588 * from a foreign Var. (If so, we just mark it unsafe for now
589 * rather than immediately returning false, since the parent
590 * node might not care.)
591 */
592 collation = fe->funccollid;
593 if (collation == InvalidOid)
595 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
596 collation == inner_cxt.collation)
598 else if (collation == DEFAULT_COLLATION_OID)
600 else
602 }
603 break;
604 case T_OpExpr:
605 case T_DistinctExpr: /* struct-equivalent to OpExpr */
606 {
607 OpExpr *oe = (OpExpr *) node;
608
609 /*
610 * Similarly, only shippable operators can be sent to remote.
611 * (If the operator is shippable, we assume its underlying
612 * function is too.)
613 */
615 return false;
616
617 /*
618 * Recurse to input subexpressions.
619 */
620 if (!foreign_expr_walker((Node *) oe->args,
622 return false;
623
624 /*
625 * If operator's input collation is not derived from a foreign
626 * Var, it can't be sent to remote.
627 */
628 if (oe->inputcollid == InvalidOid)
629 /* OK, inputs are all noncollatable */ ;
630 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
631 oe->inputcollid != inner_cxt.collation)
632 return false;
633
634 /* Result-collation handling is same as for functions */
635 collation = oe->opcollid;
636 if (collation == InvalidOid)
638 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
639 collation == inner_cxt.collation)
641 else if (collation == DEFAULT_COLLATION_OID)
643 else
645 }
646 break;
648 {
650
651 /*
652 * Again, only shippable operators can be sent to remote.
653 */
655 return false;
656
657 /*
658 * Recurse to input subexpressions.
659 */
660 if (!foreign_expr_walker((Node *) oe->args,
662 return false;
663
664 /*
665 * If operator's input collation is not derived from a foreign
666 * Var, it can't be sent to remote.
667 */
668 if (oe->inputcollid == InvalidOid)
669 /* OK, inputs are all noncollatable */ ;
670 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
671 oe->inputcollid != inner_cxt.collation)
672 return false;
673
674 /* Output is always boolean and so noncollatable. */
675 collation = InvalidOid;
677 }
678 break;
679 case T_RelabelType:
680 {
681 RelabelType *r = (RelabelType *) node;
682
683 /*
684 * Recurse to input subexpression.
685 */
686 if (!foreign_expr_walker((Node *) r->arg,
688 return false;
689
690 /*
691 * RelabelType must not introduce a collation not derived from
692 * an input foreign Var (same logic as for a real function).
693 */
694 collation = r->resultcollid;
695 if (collation == InvalidOid)
697 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
698 collation == inner_cxt.collation)
700 else if (collation == DEFAULT_COLLATION_OID)
702 else
704 }
705 break;
707 {
709
710 /*
711 * Push down only when the per-element coercion is a plain
712 * relabeling, that is, elemexpr is a RelabelType or a bare
713 * CaseTestExpr. Any other element coercion -- a cast
714 * function, an I/O conversion (CoerceViaIO), or a domain
715 * coercion -- is kept local. We ship only a bare
716 * "arg::resulttype" cast (nothing at all for an
717 * implicit-format coercion), so a non-relabeling conversion
718 * would be re-resolved against the remote server's catalogs
719 * and session state and could silently change the result.
720 * This matches the handling of the scalar coercions for the
721 * I/O and domain cases (never shipped); an element cast
722 * function is kept local too, which is more conservative than
723 * the scalar case (a scalar cast function is shipped when it
724 * is shippable).
725 */
726 if (!IsA(e->elemexpr, RelabelType) &&
727 !IsA(e->elemexpr, CaseTestExpr))
728 return false;
729
730 /*
731 * Recurse to input subexpression.
732 */
733 if (!foreign_expr_walker((Node *) e->arg,
735 return false;
736
737 /*
738 * T_ArrayCoerceExpr must not introduce a collation not
739 * derived from an input foreign Var (same logic as for a
740 * function).
741 */
742 collation = e->resultcollid;
743 if (collation == InvalidOid)
745 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
746 collation == inner_cxt.collation)
748 else if (collation == DEFAULT_COLLATION_OID)
750 else
752 }
753 break;
754 case T_BoolExpr:
755 {
756 BoolExpr *b = (BoolExpr *) node;
757
758 /*
759 * Recurse to input subexpressions.
760 */
761 if (!foreign_expr_walker((Node *) b->args,
763 return false;
764
765 /* Output is always boolean and so noncollatable. */
766 collation = InvalidOid;
768 }
769 break;
770 case T_NullTest:
771 {
772 NullTest *nt = (NullTest *) node;
773
774 /*
775 * Recurse to input subexpressions.
776 */
777 if (!foreign_expr_walker((Node *) nt->arg,
779 return false;
780
781 /* Output is always boolean and so noncollatable. */
782 collation = InvalidOid;
784 }
785 break;
786 case T_CaseExpr:
787 {
788 CaseExpr *ce = (CaseExpr *) node;
790 foreign_loc_cxt tmp_cxt;
791 ListCell *lc;
792
793 /*
794 * Recurse to CASE's arg expression, if any. Its collation
795 * has to be saved aside for use while examining CaseTestExprs
796 * within the WHEN expressions.
797 */
798 arg_cxt.collation = InvalidOid;
800 if (ce->arg)
801 {
802 if (!foreign_expr_walker((Node *) ce->arg,
804 return false;
805 }
806
807 /* Examine the CaseWhen subexpressions. */
808 foreach(lc, ce->args)
809 {
811
812 if (ce->arg)
813 {
814 /*
815 * In a CASE-with-arg, the parser should have produced
816 * WHEN clauses of the form "CaseTestExpr = RHS",
817 * possibly with an implicit coercion inserted above
818 * the CaseTestExpr. However in an expression that's
819 * been through the optimizer, the WHEN clause could
820 * be almost anything (since the equality operator
821 * could have been expanded into an inline function).
822 * In such cases forbid pushdown, because
823 * deparseCaseExpr can't handle it.
824 */
825 Node *whenExpr = (Node *) cw->expr;
826 List *opArgs;
827
828 if (!IsA(whenExpr, OpExpr))
829 return false;
830
831 opArgs = ((OpExpr *) whenExpr)->args;
832 if (list_length(opArgs) != 2 ||
835 return false;
836 }
837
838 /*
839 * Recurse to WHEN expression, passing down the arg info.
840 * Its collation doesn't affect the result (really, it
841 * should be boolean and thus not have a collation).
842 */
843 tmp_cxt.collation = InvalidOid;
844 tmp_cxt.state = FDW_COLLATE_NONE;
845 if (!foreign_expr_walker((Node *) cw->expr,
846 glob_cxt, &tmp_cxt, &arg_cxt))
847 return false;
848
849 /* Recurse to THEN expression. */
850 if (!foreign_expr_walker((Node *) cw->result,
852 return false;
853 }
854
855 /* Recurse to ELSE expression. */
856 if (!foreign_expr_walker((Node *) ce->defresult,
858 return false;
859
860 /*
861 * Detect whether node is introducing a collation not derived
862 * from a foreign Var. (If so, we just mark it unsafe for now
863 * rather than immediately returning false, since the parent
864 * node might not care.) This is the same as for function
865 * nodes, except that the input collation is derived from only
866 * the THEN and ELSE subexpressions.
867 */
868 collation = ce->casecollid;
869 if (collation == InvalidOid)
871 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
872 collation == inner_cxt.collation)
874 else if (collation == DEFAULT_COLLATION_OID)
876 else
878 }
879 break;
880 case T_CaseTestExpr:
881 {
882 CaseTestExpr *c = (CaseTestExpr *) node;
883
884 /* Punt if we seem not to be inside a CASE arg WHEN. */
885 if (!case_arg_cxt)
886 return false;
887
888 /*
889 * Otherwise, any nondefault collation attached to the
890 * CaseTestExpr node must be derived from foreign Var(s) in
891 * the CASE arg.
892 */
893 collation = c->collation;
894 if (collation == InvalidOid)
896 else if (case_arg_cxt->state == FDW_COLLATE_SAFE &&
897 collation == case_arg_cxt->collation)
899 else if (collation == DEFAULT_COLLATION_OID)
901 else
903 }
904 break;
905 case T_ArrayExpr:
906 {
907 ArrayExpr *a = (ArrayExpr *) node;
908
909 /*
910 * Recurse to input subexpressions.
911 */
912 if (!foreign_expr_walker((Node *) a->elements,
914 return false;
915
916 /*
917 * ArrayExpr must not introduce a collation not derived from
918 * an input foreign Var (same logic as for a function).
919 */
920 collation = a->array_collid;
921 if (collation == InvalidOid)
923 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
924 collation == inner_cxt.collation)
926 else if (collation == DEFAULT_COLLATION_OID)
928 else
930 }
931 break;
932 case T_List:
933 {
934 List *l = (List *) node;
935 ListCell *lc;
936
937 /*
938 * Recurse to component subexpressions.
939 */
940 foreach(lc, l)
941 {
944 return false;
945 }
946
947 /*
948 * When processing a list, collation state just bubbles up
949 * from the list elements.
950 */
951 collation = inner_cxt.collation;
952 state = inner_cxt.state;
953
954 /* Don't apply exprType() to the list. */
955 check_type = false;
956 }
957 break;
958 case T_Aggref:
959 {
960 Aggref *agg = (Aggref *) node;
961 ListCell *lc;
962
963 /* Not safe to pushdown when not in grouping context */
964 if (!IS_UPPER_REL(glob_cxt->foreignrel))
965 return false;
966
967 /* Only non-split aggregates are pushable. */
968 if (agg->aggsplit != AGGSPLIT_SIMPLE)
969 return false;
970
971 /* As usual, it must be shippable. */
972 if (!is_shippable(agg->aggfnoid, ProcedureRelationId, fpinfo))
973 return false;
974
975 /*
976 * Recurse to input args. aggdirectargs, aggorder and
977 * aggdistinct are all present in args, so no need to check
978 * their shippability explicitly.
979 */
980 foreach(lc, agg->args)
981 {
982 Node *n = (Node *) lfirst(lc);
983
984 /* If TargetEntry, extract the expression from it */
985 if (IsA(n, TargetEntry))
986 {
987 TargetEntry *tle = (TargetEntry *) n;
988
989 n = (Node *) tle->expr;
990 }
991
992 if (!foreign_expr_walker(n,
994 return false;
995 }
996
997 /*
998 * For aggorder elements, check whether the sort operator, if
999 * specified, is shippable or not.
1000 */
1001 if (agg->aggorder)
1002 {
1003 foreach(lc, agg->aggorder)
1004 {
1007 TypeCacheEntry *typentry;
1009
1010 tle = get_sortgroupref_tle(srt->tleSortGroupRef,
1011 agg->args);
1012 sortcoltype = exprType((Node *) tle->expr);
1013 typentry = lookup_type_cache(sortcoltype,
1015 /* Check shippability of non-default sort operator. */
1016 if (srt->sortop != typentry->lt_opr &&
1017 srt->sortop != typentry->gt_opr &&
1019 fpinfo))
1020 return false;
1021 }
1022 }
1023
1024 /* Check aggregate filter */
1025 if (!foreign_expr_walker((Node *) agg->aggfilter,
1027 return false;
1028
1029 /*
1030 * If aggregate's input collation is not derived from a
1031 * foreign Var, it can't be sent to remote.
1032 */
1033 if (agg->inputcollid == InvalidOid)
1034 /* OK, inputs are all noncollatable */ ;
1035 else if (inner_cxt.state != FDW_COLLATE_SAFE ||
1036 agg->inputcollid != inner_cxt.collation)
1037 return false;
1038
1039 /*
1040 * Detect whether node is introducing a collation not derived
1041 * from a foreign Var. (If so, we just mark it unsafe for now
1042 * rather than immediately returning false, since the parent
1043 * node might not care.)
1044 */
1045 collation = agg->aggcollid;
1046 if (collation == InvalidOid)
1048 else if (inner_cxt.state == FDW_COLLATE_SAFE &&
1049 collation == inner_cxt.collation)
1051 else if (collation == DEFAULT_COLLATION_OID)
1053 else
1055 }
1056 break;
1057 default:
1058
1059 /*
1060 * If it's anything else, assume it's unsafe. This list can be
1061 * expanded later, but don't forget to add deparse support below.
1062 */
1063 return false;
1064 }
1065
1066 /*
1067 * If result type of given expression is not shippable, it can't be sent
1068 * to remote because it might have incompatible semantics on remote side.
1069 */
1071 return false;
1072
1073 /*
1074 * Now, merge my collation information into my parent's state.
1075 */
1076 if (state > outer_cxt->state)
1077 {
1078 /* Override previous parent state */
1079 outer_cxt->collation = collation;
1080 outer_cxt->state = state;
1081 }
1082 else if (state == outer_cxt->state)
1083 {
1084 /* Merge, or detect error if there's a collation conflict */
1085 switch (state)
1086 {
1087 case FDW_COLLATE_NONE:
1088 /* Nothing + nothing is still nothing */
1089 break;
1090 case FDW_COLLATE_SAFE:
1091 if (collation != outer_cxt->collation)
1092 {
1093 /*
1094 * Non-default collation always beats default.
1095 */
1096 if (outer_cxt->collation == DEFAULT_COLLATION_OID)
1097 {
1098 /* Override previous parent state */
1099 outer_cxt->collation = collation;
1100 }
1101 else if (collation != DEFAULT_COLLATION_OID)
1102 {
1103 /*
1104 * Conflict; show state as indeterminate. We don't
1105 * want to "return false" right away, since parent
1106 * node might not care about collation.
1107 */
1109 }
1110 }
1111 break;
1112 case FDW_COLLATE_UNSAFE:
1113 /* We're still conflicted ... */
1114 break;
1115 }
1116 }
1117
1118 /* It looks OK */
1119 return true;
1120}
static bool foreign_expr_walker(Node *node, foreign_glob_cxt *glob_cxt, foreign_loc_cxt *outer_cxt, foreign_loc_cxt *case_arg_cxt)
Definition deparse.c:312
int b
Definition isn.c:74
int a
Definition isn.c:73
Node * strip_implicit_coercions(Node *node)
Definition nodeFuncs.c:710
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
#define InvalidOid
bool is_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo)
Definition shippable.c:163
char * c
e
static int fe(enum e x)
@ PARAM_MULTIEXPR
Definition primnodes.h:388
ParamKind paramkind
Definition primnodes.h:396
Oid paramcollid
Definition primnodes.h:402
FDWCollateState state
Definition deparse.c:92
#define FirstNormalObjectId
Definition transam.h:197

References a, AGGSPLIT_SIMPLE, RelabelType::arg, b, bms_is_member(), foreign_loc_cxt::collation, DatumGetObjectId(), exprType(), fb(), FDW_COLLATE_NONE, FDW_COLLATE_SAFE, FDW_COLLATE_UNSAFE, fe(), FirstNormalObjectId, foreign_expr_walker(), get_sortgroupref_tle(), TypeCacheEntry::gt_opr, InvalidOid, is_shippable(), IS_UPPER_REL, IsA, lfirst, lfirst_node, linitial, list_length(), lookup_type_cache(), TypeCacheEntry::lt_opr, nodeTag, OidIsValid, PARAM_MULTIEXPR, Param::paramcollid, Param::paramkind, SelfItemPointerAttributeNumber, foreign_loc_cxt::state, strip_implicit_coercions(), TYPECACHE_GT_OPR, TYPECACHE_LT_OPR, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by foreign_expr_walker(), and is_foreign_expr().

◆ get_jointype_name()

const char * get_jointype_name ( JoinType  jointype)

Definition at line 1692 of file deparse.c.

1693{
1694 switch (jointype)
1695 {
1696 case JOIN_INNER:
1697 return "INNER";
1698
1699 case JOIN_LEFT:
1700 return "LEFT";
1701
1702 case JOIN_RIGHT:
1703 return "RIGHT";
1704
1705 case JOIN_FULL:
1706 return "FULL";
1707
1708 case JOIN_SEMI:
1709 return "SEMI";
1710
1711 default:
1712 /* Shouldn't come here, but protect from buggy code. */
1713 elog(ERROR, "unsupported join type %d", jointype);
1714 }
1715
1716 /* Keep compiler happy */
1717 return NULL;
1718}
@ JOIN_FULL
Definition nodes.h:303
@ JOIN_RIGHT
Definition nodes.h:304
@ JOIN_LEFT
Definition nodes.h:302

References elog, ERROR, fb(), JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, and JOIN_SEMI.

Referenced by deparseFromExprForRel(), and foreign_join_ok().

◆ get_relation_column_alias_ids()

static void get_relation_column_alias_ids ( Var node,
RelOptInfo foreignrel,
int relno,
int colno 
)
static

Definition at line 4246 of file deparse.c.

4248{
4249 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
4250 int i;
4251 ListCell *lc;
4252
4253 /* Get the relation alias ID */
4254 *relno = fpinfo->relation_index;
4255
4256 /* Get the column alias ID */
4257 i = 1;
4258 foreach(lc, foreignrel->reltarget->exprs)
4259 {
4260 Var *tlvar = (Var *) lfirst(lc);
4261
4262 /*
4263 * Match reltarget entries only on varno/varattno. Ideally there
4264 * would be some cross-check on varnullingrels, but it's unclear what
4265 * to do exactly; we don't have enough context to know what that value
4266 * should be.
4267 */
4268 if (IsA(tlvar, Var) &&
4269 tlvar->varno == node->varno &&
4270 tlvar->varattno == node->varattno)
4271 {
4272 *colno = i;
4273 return;
4274 }
4275 i++;
4276 }
4277
4278 /* Shouldn't get here */
4279 elog(ERROR, "unexpected expression in subquery output");
4280}

References elog, ERROR, PathTarget::exprs, fb(), i, IsA, lfirst, RelOptInfo::reltarget, Var::varattno, and Var::varno.

Referenced by is_subquery_var().

◆ is_foreign_expr()

bool is_foreign_expr ( PlannerInfo root,
RelOptInfo baserel,
Expr expr 
)

Definition at line 244 of file deparse.c.

247{
251
252 /*
253 * Check that the expression consists of nodes that are safe to execute
254 * remotely.
255 */
256 glob_cxt.root = root;
257 glob_cxt.foreignrel = baserel;
258
259 /*
260 * For an upper relation, use relids from its underneath scan relation,
261 * because the upperrel's own relids currently aren't set to anything
262 * meaningful by the core code. For other relation, use their own relids.
263 */
265 glob_cxt.relids = fpinfo->outerrel->relids;
266 else
267 glob_cxt.relids = baserel->relids;
268 loc_cxt.collation = InvalidOid;
270 if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt, NULL))
271 return false;
272
273 /*
274 * If the expression has a valid collation that does not arise from a
275 * foreign var, the expression can not be sent over.
276 */
277 if (loc_cxt.state == FDW_COLLATE_UNSAFE)
278 return false;
279
280 /*
281 * An expression which includes any mutable functions can't be sent over
282 * because its result is not stable. For example, sending now() remote
283 * side could cause confusion from clock offsets. Future versions might
284 * be able to make this choice with more granularity. (We check this last
285 * because it requires a lot of expensive catalog lookups.)
286 */
287 if (contain_mutable_functions((Node *) expr))
288 return false;
289
290 /* OK to evaluate on the remote server */
291 return true;
292}
bool contain_mutable_functions(Node *clause)
Definition clauses.c:399

References contain_mutable_functions(), fb(), FDW_COLLATE_NONE, FDW_COLLATE_UNSAFE, foreign_expr_walker(), InvalidOid, IS_UPPER_REL, PgFdwRelationInfo::outerrel, RelOptInfo::relids, and root.

Referenced by add_foreign_final_paths(), classifyConditions(), find_em_for_rel(), find_em_for_rel_target(), foreign_grouping_ok(), foreign_join_ok(), postgresGetForeignPaths(), postgresGetForeignPlan(), and postgresPlanDirectModify().

◆ is_foreign_param()

bool is_foreign_param ( PlannerInfo root,
RelOptInfo baserel,
Expr expr 
)

Definition at line 1135 of file deparse.c.

1138{
1139 if (expr == NULL)
1140 return false;
1141
1142 switch (nodeTag(expr))
1143 {
1144 case T_Var:
1145 {
1146 /* It would have to be sent unless it's a foreign Var */
1147 Var *var = (Var *) expr;
1148 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private);
1149 Relids relids;
1150
1151 if (IS_UPPER_REL(baserel))
1152 relids = fpinfo->outerrel->relids;
1153 else
1154 relids = baserel->relids;
1155
1156 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
1157 return false; /* foreign Var, so not a param */
1158 else
1159 return true; /* it'd have to be a param */
1160 break;
1161 }
1162 case T_Param:
1163 /* Params always have to be sent to the foreign server */
1164 return true;
1165 default:
1166 break;
1167 }
1168 return false;
1169}

References bms_is_member(), fb(), IS_UPPER_REL, nodeTag, Var::varlevelsup, and Var::varno.

Referenced by foreign_grouping_ok().

◆ is_foreign_pathkey()

bool is_foreign_pathkey ( PlannerInfo root,
RelOptInfo baserel,
PathKey pathkey 
)

Definition at line 1176 of file deparse.c.

1179{
1180 EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
1182
1183 /*
1184 * is_foreign_expr would detect volatile expressions as well, but checking
1185 * ec_has_volatile here saves some cycles.
1186 */
1187 if (pathkey_ec->ec_has_volatile)
1188 return false;
1189
1190 /* can't push down the sort if the pathkey's opfamily is not shippable */
1192 return false;
1193
1194 /* can push if a suitable EC member exists */
1196}

References fb(), find_em_for_rel(), is_shippable(), and root.

Referenced by get_useful_pathkeys_for_relation().

◆ is_subquery_var()

static bool is_subquery_var ( Var node,
RelOptInfo foreignrel,
int relno,
int colno 
)
static

Definition at line 4184 of file deparse.c.

4185{
4186 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
4187 RelOptInfo *outerrel = fpinfo->outerrel;
4188 RelOptInfo *innerrel = fpinfo->innerrel;
4189
4190 /* Should only be called in these cases. */
4191 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
4192
4193 /*
4194 * If the given relation isn't a join relation, it doesn't have any lower
4195 * subqueries, so the Var isn't a subquery output column.
4196 */
4197 if (!IS_JOIN_REL(foreignrel))
4198 return false;
4199
4200 /*
4201 * If the Var doesn't belong to any lower subqueries, it isn't a subquery
4202 * output column.
4203 */
4204 if (!bms_is_member(node->varno, fpinfo->lower_subquery_rels))
4205 return false;
4206
4207 if (bms_is_member(node->varno, outerrel->relids))
4208 {
4209 /*
4210 * If outer relation is deparsed as a subquery, the Var is an output
4211 * column of the subquery; get the IDs for the relation/column alias.
4212 */
4213 if (fpinfo->make_outerrel_subquery)
4214 {
4215 get_relation_column_alias_ids(node, outerrel, relno, colno);
4216 return true;
4217 }
4218
4219 /* Otherwise, recurse into the outer relation. */
4220 return is_subquery_var(node, outerrel, relno, colno);
4221 }
4222 else
4223 {
4224 Assert(bms_is_member(node->varno, innerrel->relids));
4225
4226 /*
4227 * If inner relation is deparsed as a subquery, the Var is an output
4228 * column of the subquery; get the IDs for the relation/column alias.
4229 */
4230 if (fpinfo->make_innerrel_subquery)
4231 {
4232 get_relation_column_alias_ids(node, innerrel, relno, colno);
4233 return true;
4234 }
4235
4236 /* Otherwise, recurse into the inner relation. */
4237 return is_subquery_var(node, innerrel, relno, colno);
4238 }
4239}
static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition deparse.c:4246

References Assert, bms_is_member(), fb(), get_relation_column_alias_ids(), IS_JOIN_REL, IS_SIMPLE_REL, is_subquery_var(), RelOptInfo::relids, and Var::varno.

Referenced by deparseVar(), and is_subquery_var().

◆ isPlainForeignVar()

static bool isPlainForeignVar ( Expr node,
deparse_expr_cxt context 
)
static

Definition at line 3425 of file deparse.c.

3426{
3427 /*
3428 * We allow the foreign Var to have an implicit RelabelType, mainly so
3429 * that this'll work with varchar columns. Note that deparseRelabelType
3430 * will not print such a cast, so we're not breaking the restriction that
3431 * the expression print as a plain Var. We won't risk it for an implicit
3432 * cast that requires a function, nor for non-implicit RelabelType; such
3433 * cases seem too likely to involve semantics changes compared to what
3434 * would happen on the remote side.
3435 */
3436 if (IsA(node, RelabelType) &&
3438 node = ((RelabelType *) node)->arg;
3439
3440 if (IsA(node, Var))
3441 {
3442 /*
3443 * The Var must be one that'll deparse as a foreign column reference
3444 * (cf. deparseVar).
3445 */
3446 Var *var = (Var *) node;
3447 Relids relids = context->scanrel->relids;
3448
3449 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
3450 return true;
3451 }
3452
3453 return false;
3454}

References bms_is_member(), COERCE_IMPLICIT_CAST, fb(), IsA, RelOptInfo::relids, deparse_expr_cxt::scanrel, Var::varlevelsup, and Var::varno.

Referenced by deparseOpExpr().

◆ printRemoteParam()

static void printRemoteParam ( int  paramindex,
Oid  paramtype,
int32  paramtypmod,
deparse_expr_cxt context 
)
static

Definition at line 3895 of file deparse.c.

3897{
3898 StringInfo buf = context->buf;
3899 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3900
3902}

References appendStringInfo(), deparse_expr_cxt::buf, buf, deparse_type_name(), and fb().

Referenced by deparseParam(), and deparseVar().

◆ printRemotePlaceholder()

static void printRemotePlaceholder ( Oid  paramtype,
int32  paramtypmod,
deparse_expr_cxt context 
)
static

Definition at line 3921 of file deparse.c.

3923{
3924 StringInfo buf = context->buf;
3925 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3926
3927 appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
3928}

References appendStringInfo(), deparse_expr_cxt::buf, buf, deparse_type_name(), and fb().

Referenced by deparseParam(), and deparseVar().

◆ rebuildInsertSql()

void rebuildInsertSql ( StringInfo  buf,
Relation  rel,
char orig_query,
List target_attrs,
int  values_end_len,
int  num_params,
int  num_rows 
)

Definition at line 2207 of file deparse.c.

2211{
2212 TupleDesc tupdesc = RelationGetDescr(rel);
2213 int i;
2214 int pindex;
2215 bool first;
2216 ListCell *lc;
2217
2218 /* Make sure the values_end_len is sensible */
2219 Assert((values_end_len > 0) && (values_end_len <= strlen(orig_query)));
2220
2221 /* Copy up to the end of the first record from the original query */
2223
2224 /*
2225 * Add records to VALUES clause (we already have parameters for the first
2226 * row, so start at the right offset).
2227 */
2228 pindex = num_params + 1;
2229 for (i = 0; i < num_rows; i++)
2230 {
2232
2233 first = true;
2234 foreach(lc, target_attrs)
2235 {
2236 int attnum = lfirst_int(lc);
2237 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
2238
2239 if (!first)
2241 first = false;
2242
2243 if (attr->attgenerated)
2244 appendStringInfoString(buf, "DEFAULT");
2245 else
2246 {
2247 appendStringInfo(buf, "$%d", pindex);
2248 pindex++;
2249 }
2250 }
2251
2253 }
2254
2255 /* Copy stuff after VALUES clause from the original query */
2257}

References appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, CompactAttribute::attgenerated, attnum, buf, fb(), i, lfirst_int, RelationGetDescr, and TupleDescCompactAttr().

Referenced by execute_foreign_modify().