PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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_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 char * deparse_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 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 char * get_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 110 of file deparse.c.

◆ REL_ALIAS_PREFIX

#define REL_ALIAS_PREFIX   "r"

Definition at line 108 of file deparse.c.

◆ SUBQUERY_COL_ALIAS_PREFIX

#define SUBQUERY_COL_ALIAS_PREFIX   "c"

Definition at line 113 of file deparse.c.

◆ SUBQUERY_REL_ALIAS_PREFIX

#define SUBQUERY_REL_ALIAS_PREFIX   "s"

Definition at line 112 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 78 of file deparse.c.

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

Function Documentation

◆ appendAggOrderBy()

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

Definition at line 3747 of file deparse.c.

3748{
3749 StringInfo buf = context->buf;
3750 ListCell *lc;
3751 bool first = true;
3752
3753 foreach(lc, orderList)
3754 {
3755 SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
3756 Node *sortexpr;
3757
3758 if (!first)
3760 first = false;
3761
3762 /* Deparse the sort expression proper. */
3763 sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
3764 false, context);
3765 /* Add decoration as needed. */
3766 appendOrderBySuffix(srt->sortop, exprType(sortexpr), srt->nulls_first,
3767 context);
3768 }
3769}
static Node * deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
Definition: deparse.c:4065
static void appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first, deparse_expr_cxt *context)
Definition: deparse.c:3776
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
#define lfirst(lc)
Definition: pg_list.h:172
static char * buf
Definition: pg_test_fsync.c:72
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
Definition: nodes.h:129
Index tleSortGroupRef
Definition: parsenodes.h:1447
StringInfo buf
Definition: deparse.c:104

References appendOrderBySuffix(), appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseSortGroupClause(), exprType(), lfirst, SortGroupClause::nulls_first, SortGroupClause::sortop, and SortGroupClause::tleSortGroupRef.

Referenced by deparseAggref().

◆ appendConditions()

static void appendConditions ( List exprs,
deparse_expr_cxt context 
)
static

Definition at line 1569 of file deparse.c.

1570{
1571 int nestlevel;
1572 ListCell *lc;
1573 bool is_first = true;
1574 StringInfo buf = context->buf;
1575
1576 /* Make sure any constants in the exprs are printed portably */
1577 nestlevel = set_transmission_modes();
1578
1579 foreach(lc, exprs)
1580 {
1581 Expr *expr = (Expr *) lfirst(lc);
1582
1583 /* Extract clause from RestrictInfo, if required */
1584 if (IsA(expr, RestrictInfo))
1585 expr = ((RestrictInfo *) expr)->clause;
1586
1587 /* Connect expressions with "AND" and parenthesize each condition. */
1588 if (!is_first)
1589 appendStringInfoString(buf, " AND ");
1590
1592 deparseExpr(expr, context);
1594
1595 is_first = false;
1596 }
1597
1598 reset_transmission_modes(nestlevel);
1599}
static void deparseExpr(Expr *node, deparse_expr_cxt *context)
Definition: deparse.c:2882
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
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(), 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 4030 of file deparse.c.

4031{
4032 StringInfo buf = context->buf;
4033 HeapTuple proctup;
4034 Form_pg_proc procform;
4035 const char *proname;
4036
4037 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
4038 if (!HeapTupleIsValid(proctup))
4039 elog(ERROR, "cache lookup failed for function %u", funcid);
4040 procform = (Form_pg_proc) GETSTRUCT(proctup);
4041
4042 /* Print schema name only if it's not pg_catalog */
4043 if (procform->pronamespace != PG_CATALOG_NAMESPACE)
4044 {
4045 const char *schemaname;
4046
4047 schemaname = get_namespace_name(procform->pronamespace);
4048 appendStringInfo(buf, "%s.", quote_identifier(schemaname));
4049 }
4050
4051 /* Always print the function name */
4052 proname = NameStr(procform->proname);
4054
4055 ReleaseSysCache(proctup);
4056}
#define NameStr(name)
Definition: c.h:703
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
NameData proname
Definition: pg_proc.h:35
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12940
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References appendStringInfo(), appendStringInfoString(), deparse_expr_cxt::buf, buf, elog, ERROR, 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 3860 of file deparse.c.

3861{
3862 StringInfo buf = context->buf;
3863 Query *query = context->root->parse;
3864 ListCell *lc;
3865 bool first = true;
3866
3867 /* Nothing to be done, if there's no GROUP BY clause in the query. */
3868 if (!query->groupClause)
3869 return;
3870
3871 appendStringInfoString(buf, " GROUP BY ");
3872
3873 /*
3874 * Queries with grouping sets are not pushed down, so we don't expect
3875 * grouping sets here.
3876 */
3877 Assert(!query->groupingSets);
3878
3879 /*
3880 * We intentionally print query->groupClause not processed_groupClause,
3881 * leaving it to the remote planner to get rid of any redundant GROUP BY
3882 * items again. This is necessary in case processed_groupClause reduced
3883 * to empty, and in any case the redundancy situation on the remote might
3884 * be different than what we think here.
3885 */
3886 foreach(lc, query->groupClause)
3887 {
3888 SortGroupClause *grp = (SortGroupClause *) lfirst(lc);
3889
3890 if (!first)
3892 first = false;
3893
3894 deparseSortGroupClause(grp->tleSortGroupRef, tlist, true, context);
3895 }
3896}
#define Assert(condition)
Definition: c.h:815
Query * parse
Definition: pathnodes.h:202
List * groupClause
Definition: parsenodes.h:211
List * groupingSets
Definition: parsenodes.h:214
PlannerInfo * root
Definition: deparse.c:99

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

Referenced by deparseSelectStmtForRel().

◆ appendLimitClause()

static void appendLimitClause ( deparse_expr_cxt context)
static

Definition at line 4002 of file deparse.c.

4003{
4004 PlannerInfo *root = context->root;
4005 StringInfo buf = context->buf;
4006 int nestlevel;
4007
4008 /* Make sure any constants in the exprs are printed portably */
4009 nestlevel = set_transmission_modes();
4010
4011 if (root->parse->limitCount)
4012 {
4013 appendStringInfoString(buf, " LIMIT ");
4014 deparseExpr((Expr *) root->parse->limitCount, context);
4015 }
4016 if (root->parse->limitOffset)
4017 {
4018 appendStringInfoString(buf, " OFFSET ");
4019 deparseExpr((Expr *) root->parse->limitOffset, context);
4020 }
4021
4022 reset_transmission_modes(nestlevel);
4023}
tree ctl root
Definition: radixtree.h:1857

References appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseExpr(), 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 3908 of file deparse.c.

3910{
3911 ListCell *lcell;
3912 int nestlevel;
3913 StringInfo buf = context->buf;
3914 bool gotone = false;
3915
3916 /* Make sure any constants in the exprs are printed portably */
3917 nestlevel = set_transmission_modes();
3918
3919 foreach(lcell, pathkeys)
3920 {
3921 PathKey *pathkey = lfirst(lcell);
3923 Expr *em_expr;
3924 Oid oprid;
3925
3926 if (has_final_sort)
3927 {
3928 /*
3929 * By construction, context->foreignrel is the input relation to
3930 * the final sort.
3931 */
3932 em = find_em_for_rel_target(context->root,
3933 pathkey->pk_eclass,
3934 context->foreignrel);
3935 }
3936 else
3937 em = find_em_for_rel(context->root,
3938 pathkey->pk_eclass,
3939 context->scanrel);
3940
3941 /*
3942 * We don't expect any error here; it would mean that shippability
3943 * wasn't verified earlier. For the same reason, we don't recheck
3944 * shippability of the sort operator.
3945 */
3946 if (em == NULL)
3947 elog(ERROR, "could not find pathkey item to sort");
3948
3949 em_expr = em->em_expr;
3950
3951 /*
3952 * If the member is a Const expression then we needn't add it to the
3953 * ORDER BY clause. This can happen in UNION ALL queries where the
3954 * union child targetlist has a Const. Adding these would be
3955 * wasteful, but also, for INT columns, an integer literal would be
3956 * seen as an ordinal column position rather than a value to sort by.
3957 * deparseConst() does have code to handle this, but it seems less
3958 * effort on all accounts just to skip these for ORDER BY clauses.
3959 */
3960 if (IsA(em_expr, Const))
3961 continue;
3962
3963 if (!gotone)
3964 {
3965 appendStringInfoString(buf, " ORDER BY ");
3966 gotone = true;
3967 }
3968 else
3970
3971 /*
3972 * Lookup the operator corresponding to the strategy in the opclass.
3973 * The datatype used by the opfamily is not necessarily the same as
3974 * the expression type (for array types for example).
3975 */
3977 em->em_datatype,
3978 em->em_datatype,
3979 pathkey->pk_strategy);
3980 if (!OidIsValid(oprid))
3981 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
3982 pathkey->pk_strategy, em->em_datatype, em->em_datatype,
3983 pathkey->pk_opfamily);
3984
3985 deparseExpr(em_expr, context);
3986
3987 /*
3988 * Here we need to use the expression's actual type to discover
3989 * whether the desired operator will be the default or not.
3990 */
3991 appendOrderBySuffix(oprid, exprType((Node *) em_expr),
3992 pathkey->pk_nulls_first, context);
3993
3994 }
3995 reset_transmission_modes(nestlevel);
3996}
#define OidIsValid(objectId)
Definition: c.h:732
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
Oid oprid(Operator op)
Definition: parse_oper.c:238
unsigned int Oid
Definition: postgres_ext.h:32
EquivalenceMember * find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
EquivalenceMember * find_em_for_rel(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
bool pk_nulls_first
Definition: pathnodes.h:1482
int pk_strategy
Definition: pathnodes.h:1481
Oid pk_opfamily
Definition: pathnodes.h:1480
RelOptInfo * foreignrel
Definition: deparse.c:100
RelOptInfo * scanrel
Definition: deparse.c:101

References appendOrderBySuffix(), appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseExpr(), elog, EquivalenceMember::em_datatype, EquivalenceMember::em_expr, ERROR, exprType(), find_em_for_rel(), find_em_for_rel_target(), deparse_expr_cxt::foreignrel, get_opfamily_member(), IsA, lfirst, OidIsValid, oprid(), PathKey::pk_nulls_first, PathKey::pk_opfamily, PathKey::pk_strategy, 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 3776 of file deparse.c.

3778{
3779 StringInfo buf = context->buf;
3780 TypeCacheEntry *typentry;
3781
3782 /* See whether operator is default < or > for sort expr's datatype. */
3783 typentry = lookup_type_cache(sortcoltype,
3785
3786 if (sortop == typentry->lt_opr)
3787 appendStringInfoString(buf, " ASC");
3788 else if (sortop == typentry->gt_opr)
3789 appendStringInfoString(buf, " DESC");
3790 else
3791 {
3792 HeapTuple opertup;
3793 Form_pg_operator operform;
3794
3795 appendStringInfoString(buf, " USING ");
3796
3797 /* Append operator name. */
3798 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(sortop));
3799 if (!HeapTupleIsValid(opertup))
3800 elog(ERROR, "cache lookup failed for operator %u", sortop);
3801 operform = (Form_pg_operator) GETSTRUCT(opertup);
3802 deparseOperatorName(buf, operform);
3803 ReleaseSysCache(opertup);
3804 }
3805
3806 if (nulls_first)
3807 appendStringInfoString(buf, " NULLS FIRST");
3808 else
3809 appendStringInfoString(buf, " NULLS LAST");
3810}
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform)
Definition: deparse.c:3404
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_GT_OPR
Definition: typcache.h:139
#define TYPECACHE_LT_OPR
Definition: typcache.h:138

References appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseOperatorName(), elog, ERROR, 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 1606 of file deparse.c.

1607{
1608 StringInfo buf = context->buf;
1609 bool need_and = false;
1610 ListCell *lc;
1611
1612 if (exprs != NIL || additional_conds != NIL)
1613 appendStringInfoString(buf, " WHERE ");
1614
1615 /*
1616 * If there are some filters, append them.
1617 */
1618 if (exprs != NIL)
1619 {
1620 appendConditions(exprs, context);
1621 need_and = true;
1622 }
1623
1624 /*
1625 * If there are some EXISTS conditions, coming from SEMI-JOINS, append
1626 * them.
1627 */
1628 foreach(lc, additional_conds)
1629 {
1630 if (need_and)
1631 appendStringInfoString(buf, " AND ");
1632 appendStringInfoString(buf, (char *) lfirst(lc));
1633 need_and = true;
1634 }
1635}
static void appendConditions(List *exprs, deparse_expr_cxt *context)
Definition: deparse.c:1569
#define NIL
Definition: pg_list.h:68

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

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

◆ build_tlist_to_deparse()

List * build_tlist_to_deparse ( RelOptInfo foreignrel)

Definition at line 1174 of file deparse.c.

1175{
1176 List *tlist = NIL;
1177 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1178 ListCell *lc;
1179
1180 /*
1181 * For an upper relation, we have already built the target list while
1182 * checking shippability, so just return that.
1183 */
1184 if (IS_UPPER_REL(foreignrel))
1185 return fpinfo->grouped_tlist;
1186
1187 /*
1188 * We require columns specified in foreignrel->reltarget->exprs and those
1189 * required for evaluating the local conditions.
1190 */
1191 tlist = add_to_flat_tlist(tlist,
1192 pull_var_clause((Node *) foreignrel->reltarget->exprs,
1194 foreach(lc, fpinfo->local_conds)
1195 {
1197
1198 tlist = add_to_flat_tlist(tlist,
1199 pull_var_clause((Node *) rinfo->clause,
1201 }
1202
1203 return tlist;
1204}
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
#define PVC_RECURSE_PLACEHOLDERS
Definition: optimizer.h:192
#define IS_UPPER_REL(rel)
Definition: pathnodes.h:849
#define lfirst_node(type, lc)
Definition: pg_list.h:176
Definition: pg_list.h:54
List * exprs
Definition: pathnodes.h:1544
struct PathTarget * reltarget
Definition: pathnodes.h:893
Expr * clause
Definition: pathnodes.h:2575
List * add_to_flat_tlist(List *tlist, List *exprs)
Definition: tlist.c:132
List * pull_var_clause(Node *node, int flags)
Definition: var.c:653

References add_to_flat_tlist(), RestrictInfo::clause, PathTarget::exprs, PgFdwRelationInfo::grouped_tlist, if(), IS_UPPER_REL, lfirst_node, PgFdwRelationInfo::local_conds, 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 216 of file deparse.c.

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

References RestrictInfo::clause, 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 1155 of file deparse.c.

1156{
1158
1159 if (!is_builtin(type_oid))
1161
1162 return format_type_extended(type_oid, typemod, flags);
1163}
#define FORMAT_TYPE_TYPEMOD_GIVEN
Definition: builtins.h:124
#define FORMAT_TYPE_FORCE_QUALIFY
Definition: builtins.h:126
uint16 bits16
Definition: c.h:496
char * format_type_extended(Oid type_oid, int32 typemod, bits16 flags)
Definition: format_type.c:112
bool is_builtin(Oid objectId)
Definition: shippable.c:152

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

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

◆ deparseAggref()

static void deparseAggref ( Aggref node,
deparse_expr_cxt context 
)
static

Definition at line 3655 of file deparse.c.

3656{
3657 StringInfo buf = context->buf;
3658 bool use_variadic;
3659
3660 /* Only basic, non-split aggregation accepted. */
3661 Assert(node->aggsplit == AGGSPLIT_SIMPLE);
3662
3663 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3664 use_variadic = node->aggvariadic;
3665
3666 /* Find aggregate name from aggfnoid which is a pg_proc entry */
3667 appendFunctionName(node->aggfnoid, context);
3669
3670 /* Add DISTINCT */
3671 appendStringInfoString(buf, (node->aggdistinct != NIL) ? "DISTINCT " : "");
3672
3673 if (AGGKIND_IS_ORDERED_SET(node->aggkind))
3674 {
3675 /* Add WITHIN GROUP (ORDER BY ..) */
3676 ListCell *arg;
3677 bool first = true;
3678
3679 Assert(!node->aggvariadic);
3680 Assert(node->aggorder != NIL);
3681
3682 foreach(arg, node->aggdirectargs)
3683 {
3684 if (!first)
3686 first = false;
3687
3688 deparseExpr((Expr *) lfirst(arg), context);
3689 }
3690
3691 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
3692 appendAggOrderBy(node->aggorder, node->args, context);
3693 }
3694 else
3695 {
3696 /* aggstar can be set only in zero-argument aggregates */
3697 if (node->aggstar)
3699 else
3700 {
3701 ListCell *arg;
3702 bool first = true;
3703
3704 /* Add all the arguments */
3705 foreach(arg, node->args)
3706 {
3707 TargetEntry *tle = (TargetEntry *) lfirst(arg);
3708 Node *n = (Node *) tle->expr;
3709
3710 if (tle->resjunk)
3711 continue;
3712
3713 if (!first)
3715 first = false;
3716
3717 /* Add VARIADIC */
3718 if (use_variadic && lnext(node->args, arg) == NULL)
3719 appendStringInfoString(buf, "VARIADIC ");
3720
3721 deparseExpr((Expr *) n, context);
3722 }
3723 }
3724
3725 /* Add ORDER BY */
3726 if (node->aggorder != NIL)
3727 {
3728 appendStringInfoString(buf, " ORDER BY ");
3729 appendAggOrderBy(node->aggorder, node->args, context);
3730 }
3731 }
3732
3733 /* Add FILTER (WHERE ..) */
3734 if (node->aggfilter != NULL)
3735 {
3736 appendStringInfoString(buf, ") FILTER (WHERE ");
3737 deparseExpr((Expr *) node->aggfilter, context);
3738 }
3739
3741}
static void appendFunctionName(Oid funcid, deparse_expr_cxt *context)
Definition: deparse.c:4030
static void appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
Definition: deparse.c:3747
@ AGGSPLIT_SIMPLE
Definition: nodes.h:377
void * arg
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
Oid aggfnoid
Definition: primnodes.h:460
List * aggdistinct
Definition: primnodes.h:490
List * aggdirectargs
Definition: primnodes.h:481
List * args
Definition: primnodes.h:484
Expr * aggfilter
Definition: primnodes.h:493
List * aggorder
Definition: primnodes.h:487
Expr * expr
Definition: primnodes.h:2245

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(), TargetEntry::expr, if(), lfirst, lnext(), and NIL.

Referenced by deparseExpr().

◆ deparseAnalyzeInfoSql()

void deparseAnalyzeInfoSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2519 of file deparse.c.

2520{
2522
2523 /* We'll need the remote relation name as a literal. */
2525 deparseRelation(&relname, rel);
2526
2527 appendStringInfoString(buf, "SELECT reltuples, relkind FROM pg_catalog.pg_class WHERE oid = ");
2529 appendStringInfoString(buf, "::pg_catalog.regclass");
2530}
void deparseStringLiteral(StringInfo buf, const char *val)
Definition: deparse.c:2847
static void deparseRelation(StringInfo buf, Relation rel)
Definition: deparse.c:2807
NameData relname
Definition: pg_class.h:38
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
char data[NAMEDATALEN]
Definition: c.h:699

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

Referenced by postgresGetAnalyzeInfoForForeignTable().

◆ deparseAnalyzeSizeSql()

void deparseAnalyzeSizeSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2497 of file deparse.c.

2498{
2500
2501 /* We'll need the remote relation name as a literal. */
2503 deparseRelation(&relname, rel);
2504
2505 appendStringInfoString(buf, "SELECT pg_catalog.pg_relation_size(");
2507 appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
2508}

References appendStringInfo(), appendStringInfoString(), buf, nameData::data, deparseRelation(), deparseStringLiteral(), 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 2559 of file deparse.c.

2562{
2563 Oid relid = RelationGetRelid(rel);
2564 TupleDesc tupdesc = RelationGetDescr(rel);
2565 int i;
2566 char *colname;
2567 List *options;
2568 ListCell *lc;
2569 bool first = true;
2570
2571 *retrieved_attrs = NIL;
2572
2573 appendStringInfoString(buf, "SELECT ");
2574 for (i = 0; i < tupdesc->natts; i++)
2575 {
2576 /* Ignore dropped columns. */
2577 if (TupleDescAttr(tupdesc, i)->attisdropped)
2578 continue;
2579
2580 if (!first)
2582 first = false;
2583
2584 /* Use attribute name or column_name option. */
2585 colname = NameStr(TupleDescAttr(tupdesc, i)->attname);
2586 options = GetForeignColumnOptions(relid, i + 1);
2587
2588 foreach(lc, options)
2589 {
2590 DefElem *def = (DefElem *) lfirst(lc);
2591
2592 if (strcmp(def->defname, "column_name") == 0)
2593 {
2594 colname = defGetString(def);
2595 break;
2596 }
2597 }
2598
2600
2601 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
2602 }
2603
2604 /* Don't generate bad syntax for zero-column relation. */
2605 if (first)
2606 appendStringInfoString(buf, "NULL");
2607
2608 /*
2609 * Construct FROM clause, and perhaps WHERE clause too, depending on the
2610 * selected sampling method.
2611 */
2612 appendStringInfoString(buf, " FROM ");
2613 deparseRelation(buf, rel);
2614
2615 switch (sample_method)
2616 {
2617 case ANALYZE_SAMPLE_OFF:
2618 /* nothing to do here */
2619 break;
2620
2622 appendStringInfo(buf, " WHERE pg_catalog.random() < %f", sample_frac);
2623 break;
2624
2626 appendStringInfo(buf, " TABLESAMPLE SYSTEM(%f)", (100.0 * sample_frac));
2627 break;
2628
2630 appendStringInfo(buf, " TABLESAMPLE BERNOULLI(%f)", (100.0 * sample_frac));
2631 break;
2632
2634 /* should have been resolved into actual method */
2635 elog(ERROR, "unexpected sampling method");
2636 break;
2637 }
2638}
char * defGetString(DefElem *def)
Definition: define.c:35
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition: foreign.c:292
int i
Definition: isn.c:72
List * lappend_int(List *list, int datum)
Definition: list.c:357
NameData attname
Definition: pg_attribute.h:41
static char ** options
@ ANALYZE_SAMPLE_AUTO
Definition: postgres_fdw.h:148
@ ANALYZE_SAMPLE_OFF
Definition: postgres_fdw.h:147
@ ANALYZE_SAMPLE_BERNOULLI
Definition: postgres_fdw.h:151
@ ANALYZE_SAMPLE_SYSTEM
Definition: postgres_fdw.h:150
@ ANALYZE_SAMPLE_RANDOM
Definition: postgres_fdw.h:149
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
char * defname
Definition: parsenodes.h:826
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:153

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, GetForeignColumnOptions(), i, lappend_int(), lfirst, NameStr, TupleDescData::natts, NIL, options, quote_identifier(), RelationGetDescr, RelationGetRelid, and TupleDescAttr().

Referenced by postgresAcquireSampleRowsFunc().

◆ deparseArrayExpr()

static void deparseArrayExpr ( ArrayExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3629 of file deparse.c.

3630{
3631 StringInfo buf = context->buf;
3632 bool first = true;
3633 ListCell *lc;
3634
3635 appendStringInfoString(buf, "ARRAY[");
3636 foreach(lc, node->elements)
3637 {
3638 if (!first)
3640 deparseExpr(lfirst(lc), context);
3641 first = false;
3642 }
3644
3645 /* If the array is empty, we need an explicit cast to the array type. */
3646 if (node->elements == NIL)
3647 appendStringInfo(buf, "::%s",
3648 deparse_type_name(node->array_typeid, -1));
3649}
static char * deparse_type_name(Oid type_oid, int32 typemod)
Definition: deparse.c:1155
List * elements
Definition: primnodes.h:1396

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

Referenced by deparseExpr().

◆ deparseBoolExpr()

static void deparseBoolExpr ( BoolExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3508 of file deparse.c.

3509{
3510 StringInfo buf = context->buf;
3511 const char *op = NULL; /* keep compiler quiet */
3512 bool first;
3513 ListCell *lc;
3514
3515 switch (node->boolop)
3516 {
3517 case AND_EXPR:
3518 op = "AND";
3519 break;
3520 case OR_EXPR:
3521 op = "OR";
3522 break;
3523 case NOT_EXPR:
3524 appendStringInfoString(buf, "(NOT ");
3525 deparseExpr(linitial(node->args), context);
3527 return;
3528 }
3529
3531 first = true;
3532 foreach(lc, node->args)
3533 {
3534 if (!first)
3535 appendStringInfo(buf, " %s ", op);
3536 deparseExpr((Expr *) lfirst(lc), context);
3537 first = false;
3538 }
3540}
#define linitial(l)
Definition: pg_list.h:178
@ AND_EXPR
Definition: primnodes.h:947
@ OR_EXPR
Definition: primnodes.h:947
@ NOT_EXPR
Definition: primnodes.h:947
BoolExprType boolop
Definition: primnodes.h:955
List * args
Definition: primnodes.h:956

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

Referenced by deparseExpr().

◆ deparseCaseExpr()

static void deparseCaseExpr ( CaseExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3579 of file deparse.c.

3580{
3581 StringInfo buf = context->buf;
3582 ListCell *lc;
3583
3584 appendStringInfoString(buf, "(CASE");
3585
3586 /* If this is a CASE arg WHEN then emit the arg expression */
3587 if (node->arg != NULL)
3588 {
3590 deparseExpr(node->arg, context);
3591 }
3592
3593 /* Add each condition/result of the CASE clause */
3594 foreach(lc, node->args)
3595 {
3596 CaseWhen *whenclause = (CaseWhen *) lfirst(lc);
3597
3598 /* WHEN */
3599 appendStringInfoString(buf, " WHEN ");
3600 if (node->arg == NULL) /* CASE WHEN */
3601 deparseExpr(whenclause->expr, context);
3602 else /* CASE arg WHEN */
3603 {
3604 /* Ignore the CaseTestExpr and equality operator. */
3605 deparseExpr(lsecond(castNode(OpExpr, whenclause->expr)->args),
3606 context);
3607 }
3608
3609 /* THEN */
3610 appendStringInfoString(buf, " THEN ");
3611 deparseExpr(whenclause->result, context);
3612 }
3613
3614 /* add ELSE if present */
3615 if (node->defresult != NULL)
3616 {
3617 appendStringInfoString(buf, " ELSE ");
3618 deparseExpr(node->defresult, context);
3619 }
3620
3621 /* append END */
3622 appendStringInfoString(buf, " END)");
3623}
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
#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, 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 2679 of file deparse.c.

2681{
2682 /* We support fetching the remote side's CTID and OID. */
2683 if (varattno == SelfItemPointerAttributeNumber)
2684 {
2685 if (qualify_col)
2686 ADD_REL_QUALIFIER(buf, varno);
2687 appendStringInfoString(buf, "ctid");
2688 }
2689 else if (varattno < 0)
2690 {
2691 /*
2692 * All other system attributes are fetched as 0, except for table OID,
2693 * which is fetched as the local table OID. However, we must be
2694 * careful; the table could be beneath an outer join, in which case it
2695 * must go to NULL whenever the rest of the row does.
2696 */
2697 Oid fetchval = 0;
2698
2699 if (varattno == TableOidAttributeNumber)
2700 fetchval = rte->relid;
2701
2702 if (qualify_col)
2703 {
2704 appendStringInfoString(buf, "CASE WHEN (");
2705 ADD_REL_QUALIFIER(buf, varno);
2706 appendStringInfo(buf, "*)::text IS NOT NULL THEN %u END", fetchval);
2707 }
2708 else
2709 appendStringInfo(buf, "%u", fetchval);
2710 }
2711 else if (varattno == 0)
2712 {
2713 /* Whole row reference */
2714 Relation rel;
2715 Bitmapset *attrs_used;
2716
2717 /* Required only to be passed down to deparseTargetList(). */
2718 List *retrieved_attrs;
2719
2720 /*
2721 * The lock on the relation will be held by upper callers, so it's
2722 * fine to open it with no lock here.
2723 */
2724 rel = table_open(rte->relid, NoLock);
2725
2726 /*
2727 * The local name of the foreign table can not be recognized by the
2728 * foreign server and the table it references on foreign server might
2729 * have different column ordering or different columns than those
2730 * declared locally. Hence we have to deparse whole-row reference as
2731 * ROW(columns referenced locally). Construct this by deparsing a
2732 * "whole row" attribute.
2733 */
2734 attrs_used = bms_add_member(NULL,
2736
2737 /*
2738 * In case the whole-row reference is under an outer join then it has
2739 * to go NULL whenever the rest of the row goes NULL. Deparsing a join
2740 * query would always involve multiple relations, thus qualify_col
2741 * would be true.
2742 */
2743 if (qualify_col)
2744 {
2745 appendStringInfoString(buf, "CASE WHEN (");
2746 ADD_REL_QUALIFIER(buf, varno);
2747 appendStringInfoString(buf, "*)::text IS NOT NULL THEN ");
2748 }
2749
2750 appendStringInfoString(buf, "ROW(");
2751 deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
2752 &retrieved_attrs);
2754
2755 /* Complete the CASE WHEN statement started above. */
2756 if (qualify_col)
2757 appendStringInfoString(buf, " END");
2758
2759 table_close(rel, NoLock);
2760 bms_free(attrs_used);
2761 }
2762 else
2763 {
2764 char *colname = NULL;
2765 List *options;
2766 ListCell *lc;
2767
2768 /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
2769 Assert(!IS_SPECIAL_VARNO(varno));
2770
2771 /*
2772 * If it's a column of a foreign table, and it has the column_name FDW
2773 * option, use that value.
2774 */
2775 options = GetForeignColumnOptions(rte->relid, varattno);
2776 foreach(lc, options)
2777 {
2778 DefElem *def = (DefElem *) lfirst(lc);
2779
2780 if (strcmp(def->defname, "column_name") == 0)
2781 {
2782 colname = defGetString(def);
2783 break;
2784 }
2785 }
2786
2787 /*
2788 * If it's a column of a regular table or it doesn't have column_name
2789 * FDW option, use attribute name.
2790 */
2791 if (colname == NULL)
2792 colname = get_attname(rte->relid, varattno, false);
2793
2794 if (qualify_col)
2795 ADD_REL_QUALIFIER(buf, varno);
2796
2798 }
2799}
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
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:1403
#define ADD_REL_QUALIFIER(buf, varno)
Definition: deparse.c:110
#define NoLock
Definition: lockdefs.h:34
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:246
#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(), FirstLowInvalidHeapAttributeNumber, get_attname(), GetForeignColumnOptions(), IS_SPECIAL_VARNO, lfirst, NoLock, options, quote_identifier(), RangeTblEntry::relid, 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 3018 of file deparse.c.

3019{
3020 StringInfo buf = context->buf;
3021 Oid typoutput;
3022 bool typIsVarlena;
3023 char *extval;
3024 bool isfloat = false;
3025 bool isstring = false;
3026 bool needlabel;
3027
3028 if (node->constisnull)
3029 {
3030 appendStringInfoString(buf, "NULL");
3031 if (showtype >= 0)
3032 appendStringInfo(buf, "::%s",
3034 node->consttypmod));
3035 return;
3036 }
3037
3039 &typoutput, &typIsVarlena);
3040 extval = OidOutputFunctionCall(typoutput, node->constvalue);
3041
3042 switch (node->consttype)
3043 {
3044 case INT2OID:
3045 case INT4OID:
3046 case INT8OID:
3047 case OIDOID:
3048 case FLOAT4OID:
3049 case FLOAT8OID:
3050 case NUMERICOID:
3051 {
3052 /*
3053 * No need to quote unless it's a special value such as 'NaN'.
3054 * See comments in get_const_expr().
3055 */
3056 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
3057 {
3058 if (extval[0] == '+' || extval[0] == '-')
3059 appendStringInfo(buf, "(%s)", extval);
3060 else
3061 appendStringInfoString(buf, extval);
3062 if (strcspn(extval, "eE.") != strlen(extval))
3063 isfloat = true; /* it looks like a float */
3064 }
3065 else
3066 appendStringInfo(buf, "'%s'", extval);
3067 }
3068 break;
3069 case BITOID:
3070 case VARBITOID:
3071 appendStringInfo(buf, "B'%s'", extval);
3072 break;
3073 case BOOLOID:
3074 if (strcmp(extval, "t") == 0)
3075 appendStringInfoString(buf, "true");
3076 else
3077 appendStringInfoString(buf, "false");
3078 break;
3079 default:
3080 deparseStringLiteral(buf, extval);
3081 isstring = true;
3082 break;
3083 }
3084
3085 pfree(extval);
3086
3087 if (showtype == -1)
3088 return; /* never print type label */
3089
3090 /*
3091 * For showtype == 0, append ::typename unless the constant will be
3092 * implicitly typed as the right type when it is read in.
3093 *
3094 * XXX this code has to be kept in sync with the behavior of the parser,
3095 * especially make_const.
3096 */
3097 switch (node->consttype)
3098 {
3099 case BOOLOID:
3100 case INT4OID:
3101 case UNKNOWNOID:
3102 needlabel = false;
3103 break;
3104 case NUMERICOID:
3105 needlabel = !isfloat || (node->consttypmod >= 0);
3106 break;
3107 default:
3108 if (showtype == -2)
3109 {
3110 /* label unless we printed it as an untyped string */
3111 needlabel = !isstring;
3112 }
3113 else
3114 needlabel = true;
3115 break;
3116 }
3117 if (needlabel || showtype > 0)
3118 appendStringInfo(buf, "::%s",
3120 node->consttypmod));
3121}
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2907
void pfree(void *pointer)
Definition: mcxt.c:1521
Oid consttype
Definition: primnodes.h:328

References appendStringInfo(), appendStringInfoString(), deparse_expr_cxt::buf, buf, Const::consttype, deparse_type_name(), deparseStringLiteral(), 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 2360 of file deparse.c.

2364{
2365 appendStringInfoString(buf, "DELETE FROM ");
2366 deparseRelation(buf, rel);
2367 appendStringInfoString(buf, " WHERE ctid = $1");
2368
2369 deparseReturningList(buf, rte, rtindex, rel,
2371 NIL, returningList, retrieved_attrs);
2372}
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:2440
TriggerDesc * trigdesc
Definition: rel.h:117
bool trig_delete_after_row
Definition: reltrigger.h:67

References appendStringInfoString(), buf, deparseRelation(), deparseReturningList(), 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 2389 of file deparse.c.

2396{
2397 deparse_expr_cxt context;
2398 List *additional_conds = NIL;
2399
2400 /* Set up context struct for recursion */
2401 context.root = root;
2402 context.foreignrel = foreignrel;
2403 context.scanrel = foreignrel;
2404 context.buf = buf;
2405 context.params_list = params_list;
2406
2407 appendStringInfoString(buf, "DELETE FROM ");
2408 deparseRelation(buf, rel);
2409 if (foreignrel->reloptkind == RELOPT_JOINREL)
2410 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2411
2412 if (foreignrel->reloptkind == RELOPT_JOINREL)
2413 {
2414 List *ignore_conds = NIL;
2415
2416 appendStringInfoString(buf, " USING ");
2417 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2418 &ignore_conds, &additional_conds, params_list);
2419 remote_conds = list_concat(remote_conds, ignore_conds);
2420 }
2421
2422 appendWhereClause(remote_conds, additional_conds, &context);
2423
2424 if (additional_conds != NIL)
2425 list_free_deep(additional_conds);
2426
2427 if (foreignrel->reloptkind == RELOPT_JOINREL)
2428 deparseExplicitTargetList(returningList, true, retrieved_attrs,
2429 &context);
2430 else
2432 rtindex, rel, false,
2433 NIL, returningList, retrieved_attrs);
2434}
#define REL_ALIAS_PREFIX
Definition: deparse.c:108
static void deparseExplicitTargetList(List *tlist, bool is_returning, List **retrieved_attrs, deparse_expr_cxt *context)
Definition: deparse.c:1679
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:1759
static void appendWhereClause(List *exprs, List *additional_conds, deparse_expr_cxt *context)
Definition: deparse.c:1606
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:570
@ RELOPT_JOINREL
Definition: pathnodes.h:828
RelOptKind reloptkind
Definition: pathnodes.h:865
List ** params_list
Definition: deparse.c:105

References appendStringInfo(), appendStringInfoString(), appendWhereClause(), deparse_expr_cxt::buf, buf, deparseExplicitTargetList(), deparseFromExprForRel(), deparseRelation(), deparseReturningList(), 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 2274 of file deparse.c.

2283{
2284 deparse_expr_cxt context;
2285 int nestlevel;
2286 bool first;
2287 RangeTblEntry *rte = planner_rt_fetch(rtindex, root);
2288 ListCell *lc,
2289 *lc2;
2290 List *additional_conds = NIL;
2291
2292 /* Set up context struct for recursion */
2293 context.root = root;
2294 context.foreignrel = foreignrel;
2295 context.scanrel = foreignrel;
2296 context.buf = buf;
2297 context.params_list = params_list;
2298
2299 appendStringInfoString(buf, "UPDATE ");
2300 deparseRelation(buf, rel);
2301 if (foreignrel->reloptkind == RELOPT_JOINREL)
2302 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2303 appendStringInfoString(buf, " SET ");
2304
2305 /* Make sure any constants in the exprs are printed portably */
2306 nestlevel = set_transmission_modes();
2307
2308 first = true;
2309 forboth(lc, targetlist, lc2, targetAttrs)
2310 {
2312 int attnum = lfirst_int(lc2);
2313
2314 /* update's new-value expressions shouldn't be resjunk */
2315 Assert(!tle->resjunk);
2316
2317 if (!first)
2319 first = false;
2320
2321 deparseColumnRef(buf, rtindex, attnum, rte, false);
2323 deparseExpr((Expr *) tle->expr, &context);
2324 }
2325
2326 reset_transmission_modes(nestlevel);
2327
2328 if (foreignrel->reloptkind == RELOPT_JOINREL)
2329 {
2330 List *ignore_conds = NIL;
2331
2332
2333 appendStringInfoString(buf, " FROM ");
2334 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2335 &ignore_conds, &additional_conds, params_list);
2336 remote_conds = list_concat(remote_conds, ignore_conds);
2337 }
2338
2339 appendWhereClause(remote_conds, additional_conds, &context);
2340
2341 if (additional_conds != NIL)
2342 list_free_deep(additional_conds);
2343
2344 if (foreignrel->reloptkind == RELOPT_JOINREL)
2345 deparseExplicitTargetList(returningList, true, retrieved_attrs,
2346 &context);
2347 else
2348 deparseReturningList(buf, rte, rtindex, rel, false,
2349 NIL, returningList, retrieved_attrs);
2350}
static void deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte, bool qualify_col)
Definition: deparse.c:2679
int16 attnum
Definition: pg_attribute.h:74
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#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(), TargetEntry::expr, 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 3432 of file deparse.c.

3433{
3434 StringInfo buf = context->buf;
3435
3436 Assert(list_length(node->args) == 2);
3437
3439 deparseExpr(linitial(node->args), context);
3440 appendStringInfoString(buf, " IS DISTINCT FROM ");
3441 deparseExpr(lsecond(node->args), context);
3443}
static int list_length(const List *l)
Definition: pg_list.h:152
List * args
Definition: primnodes.h:852

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 1679 of file deparse.c.

1683{
1684 ListCell *lc;
1685 StringInfo buf = context->buf;
1686 int i = 0;
1687
1688 *retrieved_attrs = NIL;
1689
1690 foreach(lc, tlist)
1691 {
1693
1694 if (i > 0)
1696 else if (is_returning)
1697 appendStringInfoString(buf, " RETURNING ");
1698
1699 deparseExpr((Expr *) tle->expr, context);
1700
1701 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
1702 i++;
1703 }
1704
1705 if (i == 0 && !is_returning)
1706 appendStringInfoString(buf, "NULL");
1707}

References appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseExpr(), TargetEntry::expr, 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 2882 of file deparse.c.

2883{
2884 if (node == NULL)
2885 return;
2886
2887 switch (nodeTag(node))
2888 {
2889 case T_Var:
2890 deparseVar((Var *) node, context);
2891 break;
2892 case T_Const:
2893 deparseConst((Const *) node, context, 0);
2894 break;
2895 case T_Param:
2896 deparseParam((Param *) node, context);
2897 break;
2898 case T_SubscriptingRef:
2899 deparseSubscriptingRef((SubscriptingRef *) node, context);
2900 break;
2901 case T_FuncExpr:
2902 deparseFuncExpr((FuncExpr *) node, context);
2903 break;
2904 case T_OpExpr:
2905 deparseOpExpr((OpExpr *) node, context);
2906 break;
2907 case T_DistinctExpr:
2908 deparseDistinctExpr((DistinctExpr *) node, context);
2909 break;
2910 case T_ScalarArrayOpExpr:
2912 break;
2913 case T_RelabelType:
2914 deparseRelabelType((RelabelType *) node, context);
2915 break;
2916 case T_BoolExpr:
2917 deparseBoolExpr((BoolExpr *) node, context);
2918 break;
2919 case T_NullTest:
2920 deparseNullTest((NullTest *) node, context);
2921 break;
2922 case T_CaseExpr:
2923 deparseCaseExpr((CaseExpr *) node, context);
2924 break;
2925 case T_ArrayExpr:
2926 deparseArrayExpr((ArrayExpr *) node, context);
2927 break;
2928 case T_Aggref:
2929 deparseAggref((Aggref *) node, context);
2930 break;
2931 default:
2932 elog(ERROR, "unsupported expression type for deparse: %d",
2933 (int) nodeTag(node));
2934 break;
2935 }
2936}
static void deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3579
static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3508
static void deparseAggref(Aggref *node, deparse_expr_cxt *context)
Definition: deparse.c:3655
static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
Definition: deparse.c:3495
static void deparseNullTest(NullTest *node, deparse_expr_cxt *context)
Definition: deparse.c:3546
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3274
static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype)
Definition: deparse.c:3018
static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3432
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3211
static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3629
static void deparseVar(Var *node, deparse_expr_cxt *context)
Definition: deparse.c:2947
static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
Definition: deparse.c:3165
static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3450
static void deparseParam(Param *node, deparse_expr_cxt *context)
Definition: deparse.c:3132
#define nodeTag(nodeptr)
Definition: nodes.h:133
Definition: primnodes.h:261

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

Referenced by appendConditions(), appendLimitClause(), appendOrderByClause(), deparseAggref(), 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 1371 of file deparse.c.

1372{
1373 StringInfo buf = context->buf;
1374 RelOptInfo *scanrel = context->scanrel;
1375 List *additional_conds = NIL;
1376
1377 /* For upper relations, scanrel must be either a joinrel or a baserel */
1378 Assert(!IS_UPPER_REL(context->foreignrel) ||
1379 IS_JOIN_REL(scanrel) || IS_SIMPLE_REL(scanrel));
1380
1381 /* Construct FROM clause */
1382 appendStringInfoString(buf, " FROM ");
1383 deparseFromExprForRel(buf, context->root, scanrel,
1384 (bms_membership(scanrel->relids) == BMS_MULTIPLE),
1385 (Index) 0, NULL, &additional_conds,
1386 context->params_list);
1387 appendWhereClause(quals, additional_conds, context);
1388 if (additional_conds != NIL)
1389 list_free_deep(additional_conds);
1390}
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:781
@ BMS_MULTIPLE
Definition: bitmapset.h:73
unsigned int Index
Definition: c.h:571
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:839
#define IS_JOIN_REL(rel)
Definition: pathnodes.h:844
Relids relids
Definition: pathnodes.h:871

References appendStringInfoString(), appendWhereClause(), Assert, bms_membership(), BMS_MULTIPLE, deparse_expr_cxt::buf, buf, deparseFromExprForRel(), 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 1759 of file deparse.c.

1762{
1763 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1764
1765 if (IS_JOIN_REL(foreignrel))
1766 {
1767 StringInfoData join_sql_o;
1768 StringInfoData join_sql_i;
1769 RelOptInfo *outerrel = fpinfo->outerrel;
1770 RelOptInfo *innerrel = fpinfo->innerrel;
1771 bool outerrel_is_target = false;
1772 bool innerrel_is_target = false;
1773 List *additional_conds_i = NIL;
1774 List *additional_conds_o = NIL;
1775
1776 if (ignore_rel > 0 && bms_is_member(ignore_rel, foreignrel->relids))
1777 {
1778 /*
1779 * If this is an inner join, add joinclauses to *ignore_conds and
1780 * set it to empty so that those can be deparsed into the WHERE
1781 * clause. Note that since the target relation can never be
1782 * within the nullable side of an outer join, those could safely
1783 * be pulled up into the WHERE clause (see foreign_join_ok()).
1784 * Note also that since the target relation is only inner-joined
1785 * to any other relation in the query, all conditions in the join
1786 * tree mentioning the target relation could be deparsed into the
1787 * WHERE clause by doing this recursively.
1788 */
1789 if (fpinfo->jointype == JOIN_INNER)
1790 {
1791 *ignore_conds = list_concat(*ignore_conds,
1792 fpinfo->joinclauses);
1793 fpinfo->joinclauses = NIL;
1794 }
1795
1796 /*
1797 * Check if either of the input relations is the target relation.
1798 */
1799 if (outerrel->relid == ignore_rel)
1800 outerrel_is_target = true;
1801 else if (innerrel->relid == ignore_rel)
1802 innerrel_is_target = true;
1803 }
1804
1805 /* Deparse outer relation if not the target relation. */
1806 if (!outerrel_is_target)
1807 {
1808 initStringInfo(&join_sql_o);
1809 deparseRangeTblRef(&join_sql_o, root, outerrel,
1810 fpinfo->make_outerrel_subquery,
1811 ignore_rel, ignore_conds, &additional_conds_o,
1812 params_list);
1813
1814 /*
1815 * If inner relation is the target relation, skip deparsing it.
1816 * Note that since the join of the target relation with any other
1817 * relation in the query is an inner join and can never be within
1818 * the nullable side of an outer join, the join could be
1819 * interchanged with higher-level joins (cf. identity 1 on outer
1820 * join reordering shown in src/backend/optimizer/README), which
1821 * means it's safe to skip the target-relation deparsing here.
1822 */
1823 if (innerrel_is_target)
1824 {
1825 Assert(fpinfo->jointype == JOIN_INNER);
1826 Assert(fpinfo->joinclauses == NIL);
1827 appendBinaryStringInfo(buf, join_sql_o.data, join_sql_o.len);
1828 /* Pass EXISTS conditions to upper level */
1829 if (additional_conds_o != NIL)
1830 {
1831 Assert(*additional_conds == NIL);
1832 *additional_conds = additional_conds_o;
1833 }
1834 return;
1835 }
1836 }
1837
1838 /* Deparse inner relation if not the target relation. */
1839 if (!innerrel_is_target)
1840 {
1841 initStringInfo(&join_sql_i);
1842 deparseRangeTblRef(&join_sql_i, root, innerrel,
1843 fpinfo->make_innerrel_subquery,
1844 ignore_rel, ignore_conds, &additional_conds_i,
1845 params_list);
1846
1847 /*
1848 * SEMI-JOIN is deparsed as the EXISTS subquery. It references
1849 * outer and inner relations, so it should be evaluated as the
1850 * condition in the upper-level WHERE clause. We deparse the
1851 * condition and pass it to upper level callers as an
1852 * additional_conds list. Upper level callers are responsible for
1853 * inserting conditions from the list where appropriate.
1854 */
1855 if (fpinfo->jointype == JOIN_SEMI)
1856 {
1857 deparse_expr_cxt context;
1859
1860 /* Construct deparsed condition from this SEMI-JOIN */
1862 appendStringInfo(&str, "EXISTS (SELECT NULL FROM %s",
1863 join_sql_i.data);
1864
1865 context.buf = &str;
1866 context.foreignrel = foreignrel;
1867 context.scanrel = foreignrel;
1868 context.root = root;
1869 context.params_list = params_list;
1870
1871 /*
1872 * Append SEMI-JOIN clauses and EXISTS conditions from lower
1873 * levels to the current EXISTS subquery
1874 */
1875 appendWhereClause(fpinfo->joinclauses, additional_conds_i, &context);
1876
1877 /*
1878 * EXISTS conditions, coming from lower join levels, have just
1879 * been processed.
1880 */
1881 if (additional_conds_i != NIL)
1882 {
1883 list_free_deep(additional_conds_i);
1884 additional_conds_i = NIL;
1885 }
1886
1887 /* Close parentheses for EXISTS subquery */
1889
1890 *additional_conds = lappend(*additional_conds, str.data);
1891 }
1892
1893 /*
1894 * If outer relation is the target relation, skip deparsing it.
1895 * See the above note about safety.
1896 */
1897 if (outerrel_is_target)
1898 {
1899 Assert(fpinfo->jointype == JOIN_INNER);
1900 Assert(fpinfo->joinclauses == NIL);
1901 appendBinaryStringInfo(buf, join_sql_i.data, join_sql_i.len);
1902 /* Pass EXISTS conditions to the upper call */
1903 if (additional_conds_i != NIL)
1904 {
1905 Assert(*additional_conds == NIL);
1906 *additional_conds = additional_conds_i;
1907 }
1908 return;
1909 }
1910 }
1911
1912 /* Neither of the relations is the target relation. */
1913 Assert(!outerrel_is_target && !innerrel_is_target);
1914
1915 /*
1916 * For semijoin FROM clause is deparsed as an outer relation. An inner
1917 * relation and join clauses are converted to EXISTS condition and
1918 * passed to the upper level.
1919 */
1920 if (fpinfo->jointype == JOIN_SEMI)
1921 {
1922 appendBinaryStringInfo(buf, join_sql_o.data, join_sql_o.len);
1923 }
1924 else
1925 {
1926 /*
1927 * For a join relation FROM clause, entry is deparsed as
1928 *
1929 * ((outer relation) <join type> (inner relation) ON
1930 * (joinclauses))
1931 */
1932 appendStringInfo(buf, "(%s %s JOIN %s ON ", join_sql_o.data,
1933 get_jointype_name(fpinfo->jointype), join_sql_i.data);
1934
1935 /* Append join clause; (TRUE) if no join clause */
1936 if (fpinfo->joinclauses)
1937 {
1938 deparse_expr_cxt context;
1939
1940 context.buf = buf;
1941 context.foreignrel = foreignrel;
1942 context.scanrel = foreignrel;
1943 context.root = root;
1944 context.params_list = params_list;
1945
1947 appendConditions(fpinfo->joinclauses, &context);
1949 }
1950 else
1951 appendStringInfoString(buf, "(TRUE)");
1952
1953 /* End the FROM clause entry. */
1955 }
1956
1957 /*
1958 * Construct additional_conds to be passed to the upper caller from
1959 * current level additional_conds and additional_conds, coming from
1960 * inner and outer rels.
1961 */
1962 if (additional_conds_o != NIL)
1963 {
1964 *additional_conds = list_concat(*additional_conds,
1965 additional_conds_o);
1966 list_free(additional_conds_o);
1967 }
1968
1969 if (additional_conds_i != NIL)
1970 {
1971 *additional_conds = list_concat(*additional_conds,
1972 additional_conds_i);
1973 list_free(additional_conds_i);
1974 }
1975 }
1976 else
1977 {
1978 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1979
1980 /*
1981 * Core code already has some lock on each rel being planned, so we
1982 * can use NoLock here.
1983 */
1984 Relation rel = table_open(rte->relid, NoLock);
1985
1986 deparseRelation(buf, rel);
1987
1988 /*
1989 * Add a unique alias to avoid any conflict in relation names due to
1990 * pulled up subqueries in the query being built for a pushed down
1991 * join.
1992 */
1993 if (use_alias)
1994 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, foreignrel->relid);
1995
1996 table_close(rel, NoLock);
1997 }
1998}
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
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:2006
const char * get_jointype_name(JoinType jointype)
Definition: deparse.c:1639
const char * str
void list_free(List *list)
Definition: list.c:1546
@ JOIN_SEMI
Definition: nodes.h:307
@ JOIN_INNER
Definition: nodes.h:293
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
RelOptInfo * outerrel
Definition: postgres_fdw.h:103
RelOptInfo * innerrel
Definition: postgres_fdw.h:104
Index relid
Definition: pathnodes.h:918

References appendBinaryStringInfo(), appendConditions(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), appendWhereClause(), Assert, bms_is_member(), deparse_expr_cxt::buf, buf, StringInfoData::data, deparseRangeTblRef(), deparseRelation(), deparse_expr_cxt::foreignrel, get_jointype_name(), if(), initStringInfo(), PgFdwRelationInfo::innerrel, IS_JOIN_REL, JOIN_INNER, JOIN_SEMI, PgFdwRelationInfo::joinclauses, PgFdwRelationInfo::jointype, lappend(), StringInfoData::len, list_concat(), list_free(), list_free_deep(), PgFdwRelationInfo::make_innerrel_subquery, PgFdwRelationInfo::make_outerrel_subquery, NIL, NoLock, PgFdwRelationInfo::outerrel, deparse_expr_cxt::params_list, planner_rt_fetch, REL_ALIAS_PREFIX, RangeTblEntry::relid, 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 3211 of file deparse.c.

3212{
3213 StringInfo buf = context->buf;
3214 bool use_variadic;
3215 bool first;
3216 ListCell *arg;
3217
3218 /*
3219 * If the function call came from an implicit coercion, then just show the
3220 * first argument.
3221 */
3222 if (node->funcformat == COERCE_IMPLICIT_CAST)
3223 {
3224 deparseExpr((Expr *) linitial(node->args), context);
3225 return;
3226 }
3227
3228 /*
3229 * If the function call came from a cast, then show the first argument
3230 * plus an explicit cast operation.
3231 */
3232 if (node->funcformat == COERCE_EXPLICIT_CAST)
3233 {
3234 Oid rettype = node->funcresulttype;
3235 int32 coercedTypmod;
3236
3237 /* Get the typmod if this is a length-coercion function */
3238 (void) exprIsLengthCoercion((Node *) node, &coercedTypmod);
3239
3240 deparseExpr((Expr *) linitial(node->args), context);
3241 appendStringInfo(buf, "::%s",
3242 deparse_type_name(rettype, coercedTypmod));
3243 return;
3244 }
3245
3246 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3247 use_variadic = node->funcvariadic;
3248
3249 /*
3250 * Normal function: display as proname(args).
3251 */
3252 appendFunctionName(node->funcid, context);
3254
3255 /* ... and all the arguments */
3256 first = true;
3257 foreach(arg, node->args)
3258 {
3259 if (!first)
3261 if (use_variadic && lnext(node->args, arg) == NULL)
3262 appendStringInfoString(buf, "VARIADIC ");
3263 deparseExpr((Expr *) lfirst(arg), context);
3264 first = false;
3265 }
3267}
int32_t int32
Definition: c.h:484
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:557
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:752
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:751
Oid funcid
Definition: primnodes.h:766
List * args
Definition: primnodes.h:784

References appendFunctionName(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, FuncExpr::args, deparse_expr_cxt::buf, buf, COERCE_EXPLICIT_CAST, COERCE_IMPLICIT_CAST, deparse_type_name(), deparseExpr(), exprIsLengthCoercion(), 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 2081 of file deparse.c.

2086{
2087 TupleDesc tupdesc = RelationGetDescr(rel);
2088 AttrNumber pindex;
2089 bool first;
2090 ListCell *lc;
2091
2092 appendStringInfoString(buf, "INSERT INTO ");
2093 deparseRelation(buf, rel);
2094
2095 if (targetAttrs)
2096 {
2098
2099 first = true;
2100 foreach(lc, targetAttrs)
2101 {
2102 int attnum = lfirst_int(lc);
2103
2104 if (!first)
2106 first = false;
2107
2108 deparseColumnRef(buf, rtindex, attnum, rte, false);
2109 }
2110
2111 appendStringInfoString(buf, ") VALUES (");
2112
2113 pindex = 1;
2114 first = true;
2115 foreach(lc, targetAttrs)
2116 {
2117 int attnum = lfirst_int(lc);
2118 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2119
2120 if (!first)
2122 first = false;
2123
2124 if (attr->attgenerated)
2125 appendStringInfoString(buf, "DEFAULT");
2126 else
2127 {
2128 appendStringInfo(buf, "$%d", pindex);
2129 pindex++;
2130 }
2131 }
2132
2134 }
2135 else
2136 appendStringInfoString(buf, " DEFAULT VALUES");
2137 *values_end_len = buf->len;
2138
2139 if (doNothing)
2140 appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
2141
2142 deparseReturningList(buf, rte, rtindex, rel,
2144 withCheckOptionList, returningList, retrieved_attrs);
2145}
int16 AttrNumber
Definition: attnum.h:21
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
bool trig_insert_after_row
Definition: reltrigger.h:57

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

Referenced by postgresBeginForeignInsert(), and postgresPlanForeignModify().

◆ deparseLockingClause()

static void deparseLockingClause ( deparse_expr_cxt context)
static

Definition at line 1479 of file deparse.c.

1480{
1481 StringInfo buf = context->buf;
1482 PlannerInfo *root = context->root;
1483 RelOptInfo *rel = context->scanrel;
1484 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1485 int relid = -1;
1486
1487 while ((relid = bms_next_member(rel->relids, relid)) >= 0)
1488 {
1489 /*
1490 * Ignore relation if it appears in a lower subquery. Locking clause
1491 * for such a relation is included in the subquery if necessary.
1492 */
1493 if (bms_is_member(relid, fpinfo->lower_subquery_rels))
1494 continue;
1495
1496 /*
1497 * Add FOR UPDATE/SHARE if appropriate. We apply locking during the
1498 * initial row fetch, rather than later on as is done for local
1499 * tables. The extra roundtrips involved in trying to duplicate the
1500 * local semantics exactly don't seem worthwhile (see also comments
1501 * for RowMarkType).
1502 *
1503 * Note: because we actually run the query as a cursor, this assumes
1504 * that DECLARE CURSOR ... FOR UPDATE is supported, which it isn't
1505 * before 8.3.
1506 */
1507 if (bms_is_member(relid, root->all_result_relids) &&
1508 (root->parse->commandType == CMD_UPDATE ||
1509 root->parse->commandType == CMD_DELETE))
1510 {
1511 /* Relation is UPDATE/DELETE target, so use FOR UPDATE */
1512 appendStringInfoString(buf, " FOR UPDATE");
1513
1514 /* Add the relation alias if we are here for a join relation */
1515 if (IS_JOIN_REL(rel))
1516 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1517 }
1518 else
1519 {
1520 PlanRowMark *rc = get_plan_rowmark(root->rowMarks, relid);
1521
1522 if (rc)
1523 {
1524 /*
1525 * Relation is specified as a FOR UPDATE/SHARE target, so
1526 * handle that. (But we could also see LCS_NONE, meaning this
1527 * isn't a target relation after all.)
1528 *
1529 * For now, just ignore any [NO] KEY specification, since (a)
1530 * it's not clear what that means for a remote table that we
1531 * don't have complete information about, and (b) it wouldn't
1532 * work anyway on older remote servers. Likewise, we don't
1533 * worry about NOWAIT.
1534 */
1535 switch (rc->strength)
1536 {
1537 case LCS_NONE:
1538 /* No locking needed */
1539 break;
1540 case LCS_FORKEYSHARE:
1541 case LCS_FORSHARE:
1542 appendStringInfoString(buf, " FOR SHARE");
1543 break;
1544 case LCS_FORNOKEYUPDATE:
1545 case LCS_FORUPDATE:
1546 appendStringInfoString(buf, " FOR UPDATE");
1547 break;
1548 }
1549
1550 /* Add the relation alias if we are here for a join relation */
1551 if (bms_membership(rel->relids) == BMS_MULTIPLE &&
1552 rc->strength != LCS_NONE)
1553 appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1554 }
1555 }
1556 }
1557}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
@ LCS_FORUPDATE
Definition: lockoptions.h:27
@ LCS_NONE
Definition: lockoptions.h:23
@ LCS_FORSHARE
Definition: lockoptions.h:25
@ LCS_FORKEYSHARE
Definition: lockoptions.h:24
@ LCS_FORNOKEYUPDATE
Definition: lockoptions.h:26
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
while(p+4<=pend)
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:509
Relids lower_subquery_rels
Definition: postgres_fdw.h:120
LockClauseStrength strength
Definition: plannodes.h:1387

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

Referenced by deparseSelectStmtForRel().

◆ deparseNullTest()

static void deparseNullTest ( NullTest node,
deparse_expr_cxt context 
)
static

Definition at line 3546 of file deparse.c.

3547{
3548 StringInfo buf = context->buf;
3549
3551 deparseExpr(node->arg, context);
3552
3553 /*
3554 * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
3555 * shorter and traditional. If it's a rowtype input but we're applying a
3556 * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
3557 * correct.
3558 */
3559 if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
3560 {
3561 if (node->nulltesttype == IS_NULL)
3562 appendStringInfoString(buf, " IS NULL)");
3563 else
3564 appendStringInfoString(buf, " IS NOT NULL)");
3565 }
3566 else
3567 {
3568 if (node->nulltesttype == IS_NULL)
3569 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)");
3570 else
3571 appendStringInfoString(buf, " IS DISTINCT FROM NULL)");
3572 }
3573}
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2655
@ IS_NULL
Definition: primnodes.h:1983
NullTestType nulltesttype
Definition: primnodes.h:1990
Expr * arg
Definition: primnodes.h:1989

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 3404 of file deparse.c.

3405{
3406 char *opname;
3407
3408 /* opname is not a SQL identifier, so we should not quote it. */
3409 opname = NameStr(opform->oprname);
3410
3411 /* Print schema name only if it's not pg_catalog */
3412 if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
3413 {
3414 const char *opnspname;
3415
3416 opnspname = get_namespace_name(opform->oprnamespace);
3417 /* Print fully qualified operator name. */
3418 appendStringInfo(buf, "OPERATOR(%s.%s)",
3419 quote_identifier(opnspname), opname);
3420 }
3421 else
3422 {
3423 /* Just print operator name. */
3424 appendStringInfoString(buf, opname);
3425 }
3426}

References appendStringInfo(), appendStringInfoString(), buf, 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 3274 of file deparse.c.

3275{
3276 StringInfo buf = context->buf;
3277 HeapTuple tuple;
3278 Form_pg_operator form;
3279 Expr *right;
3280 bool canSuppressRightConstCast = false;
3281 char oprkind;
3282
3283 /* Retrieve information about the operator from system catalog. */
3284 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
3285 if (!HeapTupleIsValid(tuple))
3286 elog(ERROR, "cache lookup failed for operator %u", node->opno);
3287 form = (Form_pg_operator) GETSTRUCT(tuple);
3288 oprkind = form->oprkind;
3289
3290 /* Sanity check. */
3291 Assert((oprkind == 'l' && list_length(node->args) == 1) ||
3292 (oprkind == 'b' && list_length(node->args) == 2));
3293
3294 right = llast(node->args);
3295
3296 /* Always parenthesize the expression. */
3298
3299 /* Deparse left operand, if any. */
3300 if (oprkind == 'b')
3301 {
3302 Expr *left = linitial(node->args);
3303 Oid leftType = exprType((Node *) left);
3304 Oid rightType = exprType((Node *) right);
3305 bool canSuppressLeftConstCast = false;
3306
3307 /*
3308 * When considering a binary operator, if one operand is a Const that
3309 * can be printed as a bare string literal or NULL (i.e., it will look
3310 * like type UNKNOWN to the remote parser), the Const normally
3311 * receives an explicit cast to the operator's input type. However,
3312 * in Const-to-Var comparisons where both operands are of the same
3313 * type, we prefer to suppress the explicit cast, leaving the Const's
3314 * type resolution up to the remote parser. The remote's resolution
3315 * heuristic will assume that an unknown input type being compared to
3316 * a known input type is of that known type as well.
3317 *
3318 * This hack allows some cases to succeed where a remote column is
3319 * declared with a different type in the local (foreign) table. By
3320 * emitting "foreigncol = 'foo'" not "foreigncol = 'foo'::text" or the
3321 * like, we allow the remote parser to pick an "=" operator that's
3322 * compatible with whatever type the remote column really is, such as
3323 * an enum.
3324 *
3325 * We allow cast suppression to happen only when the other operand is
3326 * a plain foreign Var. Although the remote's unknown-type heuristic
3327 * would apply to other cases just as well, we would be taking a
3328 * bigger risk that the inferred type is something unexpected. With
3329 * this restriction, if anything goes wrong it's the user's fault for
3330 * not declaring the local column with the same type as the remote
3331 * column.
3332 */
3333 if (leftType == rightType)
3334 {
3335 if (IsA(left, Const))
3336 canSuppressLeftConstCast = isPlainForeignVar(right, context);
3337 else if (IsA(right, Const))
3338 canSuppressRightConstCast = isPlainForeignVar(left, context);
3339 }
3340
3341 if (canSuppressLeftConstCast)
3342 deparseConst((Const *) left, context, -2);
3343 else
3344 deparseExpr(left, context);
3345
3347 }
3348
3349 /* Deparse operator name. */
3350 deparseOperatorName(buf, form);
3351
3352 /* Deparse right operand. */
3354
3355 if (canSuppressRightConstCast)
3356 deparseConst((Const *) right, context, -2);
3357 else
3358 deparseExpr(right, context);
3359
3361
3362 ReleaseSysCache(tuple);
3363}
static bool isPlainForeignVar(Expr *node, deparse_expr_cxt *context)
Definition: deparse.c:3369
#define llast(l)
Definition: pg_list.h:198
Oid opno
Definition: primnodes.h:834

References appendStringInfoChar(), OpExpr::args, Assert, deparse_expr_cxt::buf, buf, deparseConst(), deparseExpr(), deparseOperatorName(), elog, ERROR, exprType(), 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 3132 of file deparse.c.

3133{
3134 if (context->params_list)
3135 {
3136 int pindex = 0;
3137 ListCell *lc;
3138
3139 /* find its index in params_list */
3140 foreach(lc, *context->params_list)
3141 {
3142 pindex++;
3143 if (equal(node, (Node *) lfirst(lc)))
3144 break;
3145 }
3146 if (lc == NULL)
3147 {
3148 /* not in list, so add it */
3149 pindex++;
3150 *context->params_list = lappend(*context->params_list, node);
3151 }
3152
3153 printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
3154 }
3155 else
3156 {
3157 printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
3158 }
3159}
static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3821
static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3847
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
Oid paramtype
Definition: primnodes.h:394

References equal(), lappend(), lfirst, deparse_expr_cxt::params_list, Param::paramtype, 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 2006 of file deparse.c.

2009{
2010 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
2011
2012 /* Should only be called in these cases. */
2013 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
2014
2015 Assert(fpinfo->local_conds == NIL);
2016
2017 /* If make_subquery is true, deparse the relation as a subquery. */
2018 if (make_subquery)
2019 {
2020 List *retrieved_attrs;
2021 int ncols;
2022
2023 /*
2024 * The given relation shouldn't contain the target relation, because
2025 * this should only happen for input relations for a full join, and
2026 * such relations can never contain an UPDATE/DELETE target.
2027 */
2028 Assert(ignore_rel == 0 ||
2029 !bms_is_member(ignore_rel, foreignrel->relids));
2030
2031 /* Deparse the subquery representing the relation. */
2033 deparseSelectStmtForRel(buf, root, foreignrel, NIL,
2034 fpinfo->remote_conds, NIL,
2035 false, false, true,
2036 &retrieved_attrs, params_list);
2038
2039 /* Append the relation alias. */
2041 fpinfo->relation_index);
2042
2043 /*
2044 * Append the column aliases if needed. Note that the subquery emits
2045 * expressions specified in the relation's reltarget (see
2046 * deparseSubqueryTargetList).
2047 */
2048 ncols = list_length(foreignrel->reltarget->exprs);
2049 if (ncols > 0)
2050 {
2051 int i;
2052
2054 for (i = 1; i <= ncols; i++)
2055 {
2056 if (i > 1)
2058
2060 }
2062 }
2063 }
2064 else
2065 deparseFromExprForRel(buf, root, foreignrel, true, ignore_rel,
2066 ignore_conds, additional_conds,
2067 params_list);
2068}
#define SUBQUERY_REL_ALIAS_PREFIX
Definition: deparse.c:112
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:1231
#define SUBQUERY_COL_ALIAS_PREFIX
Definition: deparse.c:113

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, bms_is_member(), buf, deparseFromExprForRel(), deparseSelectStmtForRel(), PathTarget::exprs, i, IS_JOIN_REL, IS_SIMPLE_REL, list_length(), PgFdwRelationInfo::local_conds, NIL, PgFdwRelationInfo::relation_index, RelOptInfo::relids, RelOptInfo::reltarget, PgFdwRelationInfo::remote_conds, 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 3495 of file deparse.c.

3496{
3497 deparseExpr(node->arg, context);
3498 if (node->relabelformat != COERCE_IMPLICIT_CAST)
3499 appendStringInfo(context->buf, "::%s",
3501 node->resulttypmod));
3502}
Oid resulttype
Definition: primnodes.h:1201
Expr * arg
Definition: primnodes.h:1200

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 2807 of file deparse.c.

2808{
2809 ForeignTable *table;
2810 const char *nspname = NULL;
2811 const char *relname = NULL;
2812 ListCell *lc;
2813
2814 /* obtain additional catalog information. */
2815 table = GetForeignTable(RelationGetRelid(rel));
2816
2817 /*
2818 * Use value of FDW options if any, instead of the name of object itself.
2819 */
2820 foreach(lc, table->options)
2821 {
2822 DefElem *def = (DefElem *) lfirst(lc);
2823
2824 if (strcmp(def->defname, "schema_name") == 0)
2825 nspname = defGetString(def);
2826 else if (strcmp(def->defname, "table_name") == 0)
2827 relname = defGetString(def);
2828 }
2829
2830 /*
2831 * Note: we could skip printing the schema name if it's pg_catalog, but
2832 * that doesn't seem worth the trouble.
2833 */
2834 if (nspname == NULL)
2836 if (relname == NULL)
2838
2839 appendStringInfo(buf, "%s.%s",
2841}
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:254
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
List * options
Definition: foreign.h:57

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

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 2440 of file deparse.c.

2446{
2447 Bitmapset *attrs_used = NULL;
2448
2449 if (trig_after_row)
2450 {
2451 /* whole-row reference acquires all non-system columns */
2452 attrs_used =
2454 }
2455
2456 if (withCheckOptionList != NIL)
2457 {
2458 /*
2459 * We need the attrs, non-system and system, mentioned in the local
2460 * query's WITH CHECK OPTION list.
2461 *
2462 * Note: we do this to ensure that WCO constraints will be evaluated
2463 * on the data actually inserted/updated on the remote side, which
2464 * might differ from the data supplied by the core code, for example
2465 * as a result of remote triggers.
2466 */
2467 pull_varattnos((Node *) withCheckOptionList, rtindex,
2468 &attrs_used);
2469 }
2470
2471 if (returningList != NIL)
2472 {
2473 /*
2474 * We need the attrs, non-system and system, mentioned in the local
2475 * query's RETURNING list.
2476 */
2477 pull_varattnos((Node *) returningList, rtindex,
2478 &attrs_used);
2479 }
2480
2481 if (attrs_used != NULL)
2482 deparseTargetList(buf, rte, rtindex, rel, true, attrs_used, false,
2483 retrieved_attrs);
2484 else
2485 *retrieved_attrs = NIL;
2486}
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296

References bms_make_singleton(), buf, deparseTargetList(), 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 3450 of file deparse.c.

3451{
3452 StringInfo buf = context->buf;
3453 HeapTuple tuple;
3454 Form_pg_operator form;
3455 Expr *arg1;
3456 Expr *arg2;
3457
3458 /* Retrieve information about the operator from system catalog. */
3459 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
3460 if (!HeapTupleIsValid(tuple))
3461 elog(ERROR, "cache lookup failed for operator %u", node->opno);
3462 form = (Form_pg_operator) GETSTRUCT(tuple);
3463
3464 /* Sanity check. */
3465 Assert(list_length(node->args) == 2);
3466
3467 /* Always parenthesize the expression. */
3469
3470 /* Deparse left operand. */
3471 arg1 = linitial(node->args);
3472 deparseExpr(arg1, context);
3474
3475 /* Deparse operator name plus decoration. */
3476 deparseOperatorName(buf, form);
3477 appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
3478
3479 /* Deparse right operand. */
3480 arg2 = lsecond(node->args);
3481 deparseExpr(arg2, context);
3482
3484
3485 /* Always parenthesize the expression. */
3487
3488 ReleaseSysCache(tuple);
3489}

References appendStringInfo(), appendStringInfoChar(), ScalarArrayOpExpr::args, Assert, deparse_expr_cxt::buf, buf, deparseExpr(), deparseOperatorName(), elog, ERROR, 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 1313 of file deparse.c.

1315{
1316 StringInfo buf = context->buf;
1317 RelOptInfo *foreignrel = context->foreignrel;
1318 PlannerInfo *root = context->root;
1319 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1320
1321 /*
1322 * Construct SELECT list
1323 */
1324 appendStringInfoString(buf, "SELECT ");
1325
1326 if (is_subquery)
1327 {
1328 /*
1329 * For a relation that is deparsed as a subquery, emit expressions
1330 * specified in the relation's reltarget. Note that since this is for
1331 * the subquery, no need to care about *retrieved_attrs.
1332 */
1334 }
1335 else if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
1336 {
1337 /*
1338 * For a join or upper relation the input tlist gives the list of
1339 * columns required to be fetched from the foreign server.
1340 */
1341 deparseExplicitTargetList(tlist, false, retrieved_attrs, context);
1342 }
1343 else
1344 {
1345 /*
1346 * For a base relation fpinfo->attrs_used gives the list of columns
1347 * required to be fetched from the foreign server.
1348 */
1349 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1350
1351 /*
1352 * Core code already has some lock on each rel being planned, so we
1353 * can use NoLock here.
1354 */
1355 Relation rel = table_open(rte->relid, NoLock);
1356
1357 deparseTargetList(buf, rte, foreignrel->relid, rel, false,
1358 fpinfo->attrs_used, false, retrieved_attrs);
1359 table_close(rel, NoLock);
1360 }
1361}
static void deparseSubqueryTargetList(deparse_expr_cxt *context)
Definition: deparse.c:1715
Bitmapset * attrs_used
Definition: postgres_fdw.h:50

References appendStringInfoString(), PgFdwRelationInfo::attrs_used, deparse_expr_cxt::buf, buf, deparseExplicitTargetList(), deparseSubqueryTargetList(), deparseTargetList(), deparse_expr_cxt::foreignrel, IS_JOIN_REL, IS_UPPER_REL, NoLock, planner_rt_fetch, RangeTblEntry::relid, 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 1231 of file deparse.c.

1235{
1236 deparse_expr_cxt context;
1237 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1238 List *quals;
1239
1240 /*
1241 * We handle relations for foreign tables, joins between those and upper
1242 * relations.
1243 */
1244 Assert(IS_JOIN_REL(rel) || IS_SIMPLE_REL(rel) || IS_UPPER_REL(rel));
1245
1246 /* Fill portions of context common to upper, join and base relation */
1247 context.buf = buf;
1248 context.root = root;
1249 context.foreignrel = rel;
1250 context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel;
1251 context.params_list = params_list;
1252
1253 /* Construct SELECT clause */
1254 deparseSelectSql(tlist, is_subquery, retrieved_attrs, &context);
1255
1256 /*
1257 * For upper relations, the WHERE clause is built from the remote
1258 * conditions of the underlying scan relation; otherwise, we can use the
1259 * supplied list of remote conditions directly.
1260 */
1261 if (IS_UPPER_REL(rel))
1262 {
1263 PgFdwRelationInfo *ofpinfo;
1264
1265 ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
1266 quals = ofpinfo->remote_conds;
1267 }
1268 else
1269 quals = remote_conds;
1270
1271 /* Construct FROM and WHERE clauses */
1272 deparseFromExpr(quals, &context);
1273
1274 if (IS_UPPER_REL(rel))
1275 {
1276 /* Append GROUP BY clause */
1277 appendGroupByClause(tlist, &context);
1278
1279 /* Append HAVING clause */
1280 if (remote_conds)
1281 {
1282 appendStringInfoString(buf, " HAVING ");
1283 appendConditions(remote_conds, &context);
1284 }
1285 }
1286
1287 /* Add ORDER BY clause if we found any useful pathkeys */
1288 if (pathkeys)
1289 appendOrderByClause(pathkeys, has_final_sort, &context);
1290
1291 /* Add LIMIT clause if necessary */
1292 if (has_limit)
1293 appendLimitClause(&context);
1294
1295 /* Add any necessary FOR UPDATE/SHARE. */
1296 deparseLockingClause(&context);
1297}
static void appendGroupByClause(List *tlist, deparse_expr_cxt *context)
Definition: deparse.c:3860
static void deparseFromExpr(List *quals, deparse_expr_cxt *context)
Definition: deparse.c:1371
static void deparseLockingClause(deparse_expr_cxt *context)
Definition: deparse.c:1479
static void appendOrderByClause(List *pathkeys, bool has_final_sort, deparse_expr_cxt *context)
Definition: deparse.c:3908
static void appendLimitClause(deparse_expr_cxt *context)
Definition: deparse.c:4002
static void deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs, deparse_expr_cxt *context)
Definition: deparse.c:1313

References appendConditions(), appendGroupByClause(), appendLimitClause(), appendOrderByClause(), appendStringInfoString(), Assert, deparse_expr_cxt::buf, buf, deparseFromExpr(), deparseLockingClause(), deparseSelectSql(), deparse_expr_cxt::foreignrel, IS_JOIN_REL, IS_SIMPLE_REL, IS_UPPER_REL, PgFdwRelationInfo::outerrel, deparse_expr_cxt::params_list, PgFdwRelationInfo::remote_conds, 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 4065 of file deparse.c.

4067{
4068 StringInfo buf = context->buf;
4069 TargetEntry *tle;
4070 Expr *expr;
4071
4072 tle = get_sortgroupref_tle(ref, tlist);
4073 expr = tle->expr;
4074
4075 if (force_colno)
4076 {
4077 /* Use column-number form when requested by caller. */
4078 Assert(!tle->resjunk);
4079 appendStringInfo(buf, "%d", tle->resno);
4080 }
4081 else if (expr && IsA(expr, Const))
4082 {
4083 /*
4084 * Force a typecast here so that we don't emit something like "GROUP
4085 * BY 2", which will be misconstrued as a column position rather than
4086 * a constant.
4087 */
4088 deparseConst((Const *) expr, context, 1);
4089 }
4090 else if (!expr || IsA(expr, Var))
4091 deparseExpr(expr, context);
4092 else
4093 {
4094 /* Always parenthesize the expression. */
4096 deparseExpr(expr, context);
4098 }
4099
4100 return (Node *) expr;
4101}
AttrNumber resno
Definition: primnodes.h:2247
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition: tlist.c:345

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

Referenced by appendAggOrderBy(), and appendGroupByClause().

◆ deparseStringLiteral()

void deparseStringLiteral ( StringInfo  buf,
const char *  val 
)

Definition at line 2847 of file deparse.c.

2848{
2849 const char *valptr;
2850
2851 /*
2852 * Rather than making assumptions about the remote server's value of
2853 * standard_conforming_strings, always use E'foo' syntax if there are any
2854 * backslashes. This will fail on remote servers before 8.1, but those
2855 * are long out of support.
2856 */
2857 if (strchr(val, '\\') != NULL)
2860 for (valptr = val; *valptr; valptr++)
2861 {
2862 char ch = *valptr;
2863
2864 if (SQL_STR_DOUBLE(ch, true))
2867 }
2869}
#define ESCAPE_STRING_SYNTAX
Definition: c.h:1123
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1120
long val
Definition: informix.c:689

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

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

◆ deparseSubqueryTargetList()

static void deparseSubqueryTargetList ( deparse_expr_cxt context)
static

Definition at line 1715 of file deparse.c.

1716{
1717 StringInfo buf = context->buf;
1718 RelOptInfo *foreignrel = context->foreignrel;
1719 bool first;
1720 ListCell *lc;
1721
1722 /* Should only be called in these cases. */
1723 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1724
1725 first = true;
1726 foreach(lc, foreignrel->reltarget->exprs)
1727 {
1728 Node *node = (Node *) lfirst(lc);
1729
1730 if (!first)
1732 first = false;
1733
1734 deparseExpr((Expr *) node, context);
1735 }
1736
1737 /* Don't generate bad syntax if no expressions */
1738 if (first)
1739 appendStringInfoString(buf, "NULL");
1740}

References appendStringInfoString(), Assert, deparse_expr_cxt::buf, buf, deparseExpr(), PathTarget::exprs, 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 3165 of file deparse.c.

3166{
3167 StringInfo buf = context->buf;
3168 ListCell *lowlist_item;
3169 ListCell *uplist_item;
3170
3171 /* Always parenthesize the expression. */
3173
3174 /*
3175 * Deparse referenced array expression first. If that expression includes
3176 * a cast, we have to parenthesize to prevent the array subscript from
3177 * being taken as typename decoration. We can avoid that in the typical
3178 * case of subscripting a Var, but otherwise do it.
3179 */
3180 if (IsA(node->refexpr, Var))
3181 deparseExpr(node->refexpr, context);
3182 else
3183 {
3185 deparseExpr(node->refexpr, context);
3187 }
3188
3189 /* Deparse subscript expressions. */
3190 lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
3191 foreach(uplist_item, node->refupperindexpr)
3192 {
3194 if (lowlist_item)
3195 {
3196 deparseExpr(lfirst(lowlist_item), context);
3198 lowlist_item = lnext(node->reflowerindexpr, lowlist_item);
3199 }
3200 deparseExpr(lfirst(uplist_item), context);
3202 }
3203
3205}
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
List * refupperindexpr
Definition: primnodes.h:709
Expr * refexpr
Definition: primnodes.h:717
List * reflowerindexpr
Definition: primnodes.h:715

References appendStringInfoChar(), deparse_expr_cxt::buf, buf, deparseExpr(), 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 1403 of file deparse.c.

1411{
1412 TupleDesc tupdesc = RelationGetDescr(rel);
1413 bool have_wholerow;
1414 bool first;
1415 int i;
1416
1417 *retrieved_attrs = NIL;
1418
1419 /* If there's a whole-row reference, we'll need all the columns. */
1421 attrs_used);
1422
1423 first = true;
1424 for (i = 1; i <= tupdesc->natts; i++)
1425 {
1426 Form_pg_attribute attr = TupleDescAttr(tupdesc, i - 1);
1427
1428 /* Ignore dropped attributes. */
1429 if (attr->attisdropped)
1430 continue;
1431
1432 if (have_wholerow ||
1434 attrs_used))
1435 {
1436 if (!first)
1438 else if (is_returning)
1439 appendStringInfoString(buf, " RETURNING ");
1440 first = false;
1441
1442 deparseColumnRef(buf, rtindex, i, rte, qualify_col);
1443
1444 *retrieved_attrs = lappend_int(*retrieved_attrs, i);
1445 }
1446 }
1447
1448 /*
1449 * Add ctid if needed. We currently don't support retrieving any other
1450 * system columns.
1451 */
1453 attrs_used))
1454 {
1455 if (!first)
1457 else if (is_returning)
1458 appendStringInfoString(buf, " RETURNING ");
1459 first = false;
1460
1461 if (qualify_col)
1462 ADD_REL_QUALIFIER(buf, rtindex);
1463 appendStringInfoString(buf, "ctid");
1464
1465 *retrieved_attrs = lappend_int(*retrieved_attrs,
1467 }
1468
1469 /* Don't generate bad syntax if no undropped columns */
1470 if (first && !is_returning)
1471 appendStringInfoString(buf, "NULL");
1472}

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

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

◆ deparseTruncateSql()

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

Definition at line 2644 of file deparse.c.

2648{
2649 ListCell *cell;
2650
2651 appendStringInfoString(buf, "TRUNCATE ");
2652
2653 foreach(cell, rels)
2654 {
2655 Relation rel = lfirst(cell);
2656
2657 if (cell != list_head(rels))
2659
2660 deparseRelation(buf, rel);
2661 }
2662
2663 appendStringInfo(buf, " %s IDENTITY",
2664 restart_seqs ? "RESTART" : "CONTINUE");
2665
2666 if (behavior == DROP_RESTRICT)
2667 appendStringInfoString(buf, " RESTRICT");
2668 else if (behavior == DROP_CASCADE)
2669 appendStringInfoString(buf, " CASCADE");
2670}
@ DROP_CASCADE
Definition: parsenodes.h:2386
@ DROP_RESTRICT
Definition: parsenodes.h:2385

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 2214 of file deparse.c.

2219{
2220 TupleDesc tupdesc = RelationGetDescr(rel);
2221 AttrNumber pindex;
2222 bool first;
2223 ListCell *lc;
2224
2225 appendStringInfoString(buf, "UPDATE ");
2226 deparseRelation(buf, rel);
2227 appendStringInfoString(buf, " SET ");
2228
2229 pindex = 2; /* ctid is always the first param */
2230 first = true;
2231 foreach(lc, targetAttrs)
2232 {
2233 int attnum = lfirst_int(lc);
2234 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2235
2236 if (!first)
2238 first = false;
2239
2240 deparseColumnRef(buf, rtindex, attnum, rte, false);
2241 if (attr->attgenerated)
2242 appendStringInfoString(buf, " = DEFAULT");
2243 else
2244 {
2245 appendStringInfo(buf, " = $%d", pindex);
2246 pindex++;
2247 }
2248 }
2249 appendStringInfoString(buf, " WHERE ctid = $1");
2250
2251 deparseReturningList(buf, rte, rtindex, rel,
2253 withCheckOptionList, returningList, retrieved_attrs);
2254}
bool trig_update_after_row
Definition: reltrigger.h:62

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

Referenced by postgresPlanForeignModify().

◆ deparseVar()

static void deparseVar ( Var node,
deparse_expr_cxt context 
)
static

Definition at line 2947 of file deparse.c.

2948{
2949 Relids relids = context->scanrel->relids;
2950 int relno;
2951 int colno;
2952
2953 /* Qualify columns when multiple relations are involved. */
2954 bool qualify_col = (bms_membership(relids) == BMS_MULTIPLE);
2955
2956 /*
2957 * If the Var belongs to the foreign relation that is deparsed as a
2958 * subquery, use the relation and column alias to the Var provided by the
2959 * subquery, instead of the remote name.
2960 */
2961 if (is_subquery_var(node, context->scanrel, &relno, &colno))
2962 {
2963 appendStringInfo(context->buf, "%s%d.%s%d",
2966 return;
2967 }
2968
2969 if (bms_is_member(node->varno, relids) && node->varlevelsup == 0)
2970 deparseColumnRef(context->buf, node->varno, node->varattno,
2971 planner_rt_fetch(node->varno, context->root),
2972 qualify_col);
2973 else
2974 {
2975 /* Treat like a Param */
2976 if (context->params_list)
2977 {
2978 int pindex = 0;
2979 ListCell *lc;
2980
2981 /* find its index in params_list */
2982 foreach(lc, *context->params_list)
2983 {
2984 pindex++;
2985 if (equal(node, (Node *) lfirst(lc)))
2986 break;
2987 }
2988 if (lc == NULL)
2989 {
2990 /* not in list, so add it */
2991 pindex++;
2992 *context->params_list = lappend(*context->params_list, node);
2993 }
2994
2995 printRemoteParam(pindex, node->vartype, node->vartypmod, context);
2996 }
2997 else
2998 {
2999 printRemotePlaceholder(node->vartype, node->vartypmod, context);
3000 }
3001 }
3002}
static bool is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:4110
AttrNumber varattno
Definition: primnodes.h:273
int varno
Definition: primnodes.h:268
Index varlevelsup
Definition: primnodes.h:293

References appendStringInfo(), bms_is_member(), bms_membership(), BMS_MULTIPLE, deparse_expr_cxt::buf, deparseColumnRef(), equal(), 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 310 of file deparse.c.

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

References a, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggorder, AGGSPLIT_SIMPLE, RelabelType::arg, CaseExpr::arg, NullTest::arg, Aggref::args, OpExpr::args, ScalarArrayOpExpr::args, CaseExpr::args, b, bms_is_member(), foreign_loc_cxt::collation, DatumGetObjectId(), CaseExpr::defresult, CaseWhen::expr, TargetEntry::expr, exprType(), FDW_COLLATE_NONE, FDW_COLLATE_SAFE, FDW_COLLATE_UNSAFE, fe(), FirstNormalObjectId, foreign_expr_walker(), foreign_glob_cxt::foreignrel, get_sortgroupref_tle(), TypeCacheEntry::gt_opr, if(), InvalidOid, is_shippable(), IS_UPPER_REL, IsA, lfirst, lfirst_node, linitial, list_length(), lookup_type_cache(), TypeCacheEntry::lt_opr, nodeTag, OidIsValid, OpExpr::opno, ScalarArrayOpExpr::opno, PARAM_MULTIEXPR, Param::paramkind, SubscriptingRef::refassgnexpr, SubscriptingRef::refexpr, SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, foreign_glob_cxt::relids, CaseWhen::result, SelfItemPointerAttributeNumber, SortGroupClause::sortop, foreign_loc_cxt::state, strip_implicit_coercions(), SortGroupClause::tleSortGroupRef, 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 1639 of file deparse.c.

1640{
1641 switch (jointype)
1642 {
1643 case JOIN_INNER:
1644 return "INNER";
1645
1646 case JOIN_LEFT:
1647 return "LEFT";
1648
1649 case JOIN_RIGHT:
1650 return "RIGHT";
1651
1652 case JOIN_FULL:
1653 return "FULL";
1654
1655 case JOIN_SEMI:
1656 return "SEMI";
1657
1658 default:
1659 /* Shouldn't come here, but protect from buggy code. */
1660 elog(ERROR, "unsupported join type %d", jointype);
1661 }
1662
1663 /* Keep compiler happy */
1664 return NULL;
1665}
@ JOIN_FULL
Definition: nodes.h:295
@ JOIN_RIGHT
Definition: nodes.h:296
@ JOIN_LEFT
Definition: nodes.h:294

References elog, ERROR, 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 4172 of file deparse.c.

4174{
4175 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
4176 int i;
4177 ListCell *lc;
4178
4179 /* Get the relation alias ID */
4180 *relno = fpinfo->relation_index;
4181
4182 /* Get the column alias ID */
4183 i = 1;
4184 foreach(lc, foreignrel->reltarget->exprs)
4185 {
4186 Var *tlvar = (Var *) lfirst(lc);
4187
4188 /*
4189 * Match reltarget entries only on varno/varattno. Ideally there
4190 * would be some cross-check on varnullingrels, but it's unclear what
4191 * to do exactly; we don't have enough context to know what that value
4192 * should be.
4193 */
4194 if (IsA(tlvar, Var) &&
4195 tlvar->varno == node->varno &&
4196 tlvar->varattno == node->varattno)
4197 {
4198 *colno = i;
4199 return;
4200 }
4201 i++;
4202 }
4203
4204 /* Shouldn't get here */
4205 elog(ERROR, "unexpected expression in subquery output");
4206}

References elog, ERROR, PathTarget::exprs, i, IsA, lfirst, PgFdwRelationInfo::relation_index, 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 242 of file deparse.c.

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

References foreign_loc_cxt::collation, contain_mutable_functions(), FDW_COLLATE_NONE, FDW_COLLATE_UNSAFE, foreign_expr_walker(), foreign_glob_cxt::foreignrel, if(), InvalidOid, IS_UPPER_REL, PgFdwRelationInfo::outerrel, foreign_glob_cxt::relids, RelOptInfo::relids, foreign_glob_cxt::root, root, and foreign_loc_cxt::state.

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 1080 of file deparse.c.

1083{
1084 if (expr == NULL)
1085 return false;
1086
1087 switch (nodeTag(expr))
1088 {
1089 case T_Var:
1090 {
1091 /* It would have to be sent unless it's a foreign Var */
1092 Var *var = (Var *) expr;
1093 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private);
1094 Relids relids;
1095
1096 if (IS_UPPER_REL(baserel))
1097 relids = fpinfo->outerrel->relids;
1098 else
1099 relids = baserel->relids;
1100
1101 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
1102 return false; /* foreign Var, so not a param */
1103 else
1104 return true; /* it'd have to be a param */
1105 break;
1106 }
1107 case T_Param:
1108 /* Params always have to be sent to the foreign server */
1109 return true;
1110 default:
1111 break;
1112 }
1113 return false;
1114}

References bms_is_member(), if(), IS_UPPER_REL, nodeTag, PgFdwRelationInfo::outerrel, RelOptInfo::relids, 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 1121 of file deparse.c.

1124{
1125 EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
1126 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) baserel->fdw_private;
1127
1128 /*
1129 * is_foreign_expr would detect volatile expressions as well, but checking
1130 * ec_has_volatile here saves some cycles.
1131 */
1132 if (pathkey_ec->ec_has_volatile)
1133 return false;
1134
1135 /* can't push down the sort if the pathkey's opfamily is not shippable */
1136 if (!is_shippable(pathkey->pk_opfamily, OperatorFamilyRelationId, fpinfo))
1137 return false;
1138
1139 /* can push if a suitable EC member exists */
1140 return (find_em_for_rel(root, pathkey_ec, baserel) != NULL);
1141}

References EquivalenceClass::ec_has_volatile, find_em_for_rel(), if(), is_shippable(), PathKey::pk_opfamily, 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 4110 of file deparse.c.

4111{
4112 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
4113 RelOptInfo *outerrel = fpinfo->outerrel;
4114 RelOptInfo *innerrel = fpinfo->innerrel;
4115
4116 /* Should only be called in these cases. */
4117 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
4118
4119 /*
4120 * If the given relation isn't a join relation, it doesn't have any lower
4121 * subqueries, so the Var isn't a subquery output column.
4122 */
4123 if (!IS_JOIN_REL(foreignrel))
4124 return false;
4125
4126 /*
4127 * If the Var doesn't belong to any lower subqueries, it isn't a subquery
4128 * output column.
4129 */
4130 if (!bms_is_member(node->varno, fpinfo->lower_subquery_rels))
4131 return false;
4132
4133 if (bms_is_member(node->varno, outerrel->relids))
4134 {
4135 /*
4136 * If outer relation is deparsed as a subquery, the Var is an output
4137 * column of the subquery; get the IDs for the relation/column alias.
4138 */
4139 if (fpinfo->make_outerrel_subquery)
4140 {
4141 get_relation_column_alias_ids(node, outerrel, relno, colno);
4142 return true;
4143 }
4144
4145 /* Otherwise, recurse into the outer relation. */
4146 return is_subquery_var(node, outerrel, relno, colno);
4147 }
4148 else
4149 {
4150 Assert(bms_is_member(node->varno, innerrel->relids));
4151
4152 /*
4153 * If inner relation is deparsed as a subquery, the Var is an output
4154 * column of the subquery; get the IDs for the relation/column alias.
4155 */
4156 if (fpinfo->make_innerrel_subquery)
4157 {
4158 get_relation_column_alias_ids(node, innerrel, relno, colno);
4159 return true;
4160 }
4161
4162 /* Otherwise, recurse into the inner relation. */
4163 return is_subquery_var(node, innerrel, relno, colno);
4164 }
4165}
static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:4172

References Assert, bms_is_member(), get_relation_column_alias_ids(), PgFdwRelationInfo::innerrel, IS_JOIN_REL, IS_SIMPLE_REL, is_subquery_var(), PgFdwRelationInfo::lower_subquery_rels, PgFdwRelationInfo::make_innerrel_subquery, PgFdwRelationInfo::make_outerrel_subquery, PgFdwRelationInfo::outerrel, and Var::varno.

Referenced by deparseVar(), and is_subquery_var().

◆ isPlainForeignVar()

static bool isPlainForeignVar ( Expr node,
deparse_expr_cxt context 
)
static

Definition at line 3369 of file deparse.c.

3370{
3371 /*
3372 * We allow the foreign Var to have an implicit RelabelType, mainly so
3373 * that this'll work with varchar columns. Note that deparseRelabelType
3374 * will not print such a cast, so we're not breaking the restriction that
3375 * the expression print as a plain Var. We won't risk it for an implicit
3376 * cast that requires a function, nor for non-implicit RelabelType; such
3377 * cases seem too likely to involve semantics changes compared to what
3378 * would happen on the remote side.
3379 */
3380 if (IsA(node, RelabelType) &&
3381 ((RelabelType *) node)->relabelformat == COERCE_IMPLICIT_CAST)
3382 node = ((RelabelType *) node)->arg;
3383
3384 if (IsA(node, Var))
3385 {
3386 /*
3387 * The Var must be one that'll deparse as a foreign column reference
3388 * (cf. deparseVar).
3389 */
3390 Var *var = (Var *) node;
3391 Relids relids = context->scanrel->relids;
3392
3393 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
3394 return true;
3395 }
3396
3397 return false;
3398}

References bms_is_member(), COERCE_IMPLICIT_CAST, 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 3821 of file deparse.c.

3823{
3824 StringInfo buf = context->buf;
3825 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3826
3827 appendStringInfo(buf, "$%d::%s", paramindex, ptypename);
3828}

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

Referenced by deparseParam(), and deparseVar().

◆ printRemotePlaceholder()

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

Definition at line 3847 of file deparse.c.

3849{
3850 StringInfo buf = context->buf;
3851 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3852
3853 appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
3854}

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

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 2154 of file deparse.c.

2158{
2159 TupleDesc tupdesc = RelationGetDescr(rel);
2160 int i;
2161 int pindex;
2162 bool first;
2163 ListCell *lc;
2164
2165 /* Make sure the values_end_len is sensible */
2166 Assert((values_end_len > 0) && (values_end_len <= strlen(orig_query)));
2167
2168 /* Copy up to the end of the first record from the original query */
2169 appendBinaryStringInfo(buf, orig_query, values_end_len);
2170
2171 /*
2172 * Add records to VALUES clause (we already have parameters for the first
2173 * row, so start at the right offset).
2174 */
2175 pindex = num_params + 1;
2176 for (i = 0; i < num_rows; i++)
2177 {
2179
2180 first = true;
2181 foreach(lc, target_attrs)
2182 {
2183 int attnum = lfirst_int(lc);
2184 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2185
2186 if (!first)
2188 first = false;
2189
2190 if (attr->attgenerated)
2191 appendStringInfoString(buf, "DEFAULT");
2192 else
2193 {
2194 appendStringInfo(buf, "$%d", pindex);
2195 pindex++;
2196 }
2197 }
2198
2200 }
2201
2202 /* Copy stuff after VALUES clause from the original query */
2203 appendStringInfoString(buf, orig_query + values_end_len);
2204}

References appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert, attnum, buf, i, lfirst_int, RelationGetDescr, and TupleDescAttr().

Referenced by execute_foreign_modify().