Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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

Go to the source code of this file.

Data Structures

struct  foreign_glob_cxt
 
struct  foreign_loc_cxt
 
struct  deparse_expr_cxt
 

Macros

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

Typedefs

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

Enumerations

enum  FDWCollateState { FDW_COLLATE_NONE , FDW_COLLATE_SAFE , FDW_COLLATE_UNSAFE }
 

Functions

static bool foreign_expr_walker (Node *node, foreign_glob_cxt *glob_cxt, foreign_loc_cxt *outer_cxt, foreign_loc_cxt *case_arg_cxt)
 
static 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 deparseArrayCoerceExpr (ArrayCoerceExpr *node, deparse_expr_cxt *context)
 
static void deparseBoolExpr (BoolExpr *node, deparse_expr_cxt *context)
 
static void deparseNullTest (NullTest *node, deparse_expr_cxt *context)
 
static void deparseCaseExpr (CaseExpr *node, deparse_expr_cxt *context)
 
static void deparseArrayExpr (ArrayExpr *node, deparse_expr_cxt *context)
 
static void printRemoteParam (int paramindex, Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
 
static void printRemotePlaceholder (Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
 
static void deparseSelectSql (List *tlist, bool is_subquery, List **retrieved_attrs, deparse_expr_cxt *context)
 
static void deparseLockingClause (deparse_expr_cxt *context)
 
static void appendOrderByClause (List *pathkeys, bool has_final_sort, deparse_expr_cxt *context)
 
static void appendLimitClause (deparse_expr_cxt *context)
 
static void appendConditions (List *exprs, deparse_expr_cxt *context)
 
static void deparseFromExprForRel (StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool use_alias, Index ignore_rel, List **ignore_conds, List **additional_conds, List **params_list)
 
static void appendWhereClause (List *exprs, List *additional_conds, deparse_expr_cxt *context)
 
static void deparseFromExpr (List *quals, deparse_expr_cxt *context)
 
static void deparseRangeTblRef (StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool make_subquery, Index ignore_rel, List **ignore_conds, List **additional_conds, List **params_list)
 
static void deparseAggref (Aggref *node, deparse_expr_cxt *context)
 
static void appendGroupByClause (List *tlist, deparse_expr_cxt *context)
 
static void appendOrderBySuffix (Oid sortop, Oid sortcoltype, bool nulls_first, deparse_expr_cxt *context)
 
static void appendAggOrderBy (List *orderList, List *targetList, deparse_expr_cxt *context)
 
static void appendFunctionName (Oid funcid, deparse_expr_cxt *context)
 
static NodedeparseSortGroupClause (Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
 
static bool is_subquery_var (Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
 
static void get_relation_column_alias_ids (Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
 
void classifyConditions (PlannerInfo *root, RelOptInfo *baserel, List *input_conds, List **remote_conds, List **local_conds)
 
bool is_foreign_expr (PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
 
bool is_foreign_param (PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
 
bool is_foreign_pathkey (PlannerInfo *root, RelOptInfo *baserel, PathKey *pathkey)
 
Listbuild_tlist_to_deparse (RelOptInfo *foreignrel)
 
void deparseSelectStmtForRel (StringInfo buf, PlannerInfo *root, RelOptInfo *rel, List *tlist, List *remote_conds, List *pathkeys, bool has_final_sort, bool has_limit, bool is_subquery, List **retrieved_attrs, List **params_list)
 
const 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 111 of file deparse.c.

◆ REL_ALIAS_PREFIX

#define REL_ALIAS_PREFIX   "r"

Definition at line 109 of file deparse.c.

◆ SUBQUERY_COL_ALIAS_PREFIX

#define SUBQUERY_COL_ALIAS_PREFIX   "c"

Definition at line 114 of file deparse.c.

◆ SUBQUERY_REL_ALIAS_PREFIX

#define SUBQUERY_REL_ALIAS_PREFIX   "s"

Definition at line 113 of file deparse.c.

Typedef Documentation

◆ deparse_expr_cxt

◆ foreign_glob_cxt

◆ foreign_loc_cxt

Enumeration Type Documentation

◆ FDWCollateState

Enumerator
FDW_COLLATE_NONE 
FDW_COLLATE_SAFE 
FDW_COLLATE_UNSAFE 

Definition at line 79 of file deparse.c.

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

Function Documentation

◆ appendAggOrderBy()

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

Definition at line 3803 of file deparse.c.

3804{
3805 StringInfo buf = context->buf;
3806 ListCell *lc;
3807 bool first = true;
3808
3809 foreach(lc, orderList)
3810 {
3811 SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
3812 Node *sortexpr;
3813
3814 if (!first)
3816 first = false;
3817
3818 /* Deparse the sort expression proper. */
3819 sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
3820 false, context);
3821 /* Add decoration as needed. */
3822 appendOrderBySuffix(srt->sortop, exprType(sortexpr), srt->nulls_first,
3823 context);
3824 }
3825}
static Node * deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
Definition: deparse.c:4121
static void appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first, deparse_expr_cxt *context)
Definition: deparse.c:3832
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:135
Index tleSortGroupRef
Definition: parsenodes.h:1468
StringInfo buf
Definition: deparse.c:105

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

1605{
1606 int nestlevel;
1607 ListCell *lc;
1608 bool is_first = true;
1609 StringInfo buf = context->buf;
1610
1611 /* Make sure any constants in the exprs are printed portably */
1612 nestlevel = set_transmission_modes();
1613
1614 foreach(lc, exprs)
1615 {
1616 Expr *expr = (Expr *) lfirst(lc);
1617
1618 /* Extract clause from RestrictInfo, if required */
1619 if (IsA(expr, RestrictInfo))
1620 expr = ((RestrictInfo *) expr)->clause;
1621
1622 /* Connect expressions with "AND" and parenthesize each condition. */
1623 if (!is_first)
1624 appendStringInfoString(buf, " AND ");
1625
1627 deparseExpr(expr, context);
1629
1630 is_first = false;
1631 }
1632
1633 reset_transmission_modes(nestlevel);
1634}
static void deparseExpr(Expr *node, deparse_expr_cxt *context)
Definition: deparse.c:2917
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
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 4086 of file deparse.c.

4087{
4088 StringInfo buf = context->buf;
4089 HeapTuple proctup;
4090 Form_pg_proc procform;
4091 const char *proname;
4092
4093 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
4094 if (!HeapTupleIsValid(proctup))
4095 elog(ERROR, "cache lookup failed for function %u", funcid);
4096 procform = (Form_pg_proc) GETSTRUCT(proctup);
4097
4098 /* Print schema name only if it's not pg_catalog */
4099 if (procform->pronamespace != PG_CATALOG_NAMESPACE)
4100 {
4101 const char *schemaname;
4102
4103 schemaname = get_namespace_name(procform->pronamespace);
4104 appendStringInfo(buf, "%s.", quote_identifier(schemaname));
4105 }
4106
4107 /* Always print the function name */
4108 proname = NameStr(procform->proname);
4110
4111 ReleaseSysCache(proctup);
4112}
#define NameStr(name)
Definition: c.h:751
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3533
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:262
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:13030
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220

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

3917{
3918 StringInfo buf = context->buf;
3919 Query *query = context->root->parse;
3920 ListCell *lc;
3921 bool first = true;
3922
3923 /* Nothing to be done, if there's no GROUP BY clause in the query. */
3924 if (!query->groupClause)
3925 return;
3926
3927 appendStringInfoString(buf, " GROUP BY ");
3928
3929 /*
3930 * Queries with grouping sets are not pushed down, so we don't expect
3931 * grouping sets here.
3932 */
3933 Assert(!query->groupingSets);
3934
3935 /*
3936 * We intentionally print query->groupClause not processed_groupClause,
3937 * leaving it to the remote planner to get rid of any redundant GROUP BY
3938 * items again. This is necessary in case processed_groupClause reduced
3939 * to empty, and in any case the redundancy situation on the remote might
3940 * be different than what we think here.
3941 */
3942 foreach(lc, query->groupClause)
3943 {
3944 SortGroupClause *grp = (SortGroupClause *) lfirst(lc);
3945
3946 if (!first)
3948 first = false;
3949
3950 deparseSortGroupClause(grp->tleSortGroupRef, tlist, true, context);
3951 }
3952}
Assert(PointerIsAligned(start, uint64))
Query * parse
Definition: pathnodes.h:220
List * groupClause
Definition: parsenodes.h:216
List * groupingSets
Definition: parsenodes.h:220
PlannerInfo * root
Definition: deparse.c:100

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

4059{
4060 PlannerInfo *root = context->root;
4061 StringInfo buf = context->buf;
4062 int nestlevel;
4063
4064 /* Make sure any constants in the exprs are printed portably */
4065 nestlevel = set_transmission_modes();
4066
4067 if (root->parse->limitCount)
4068 {
4069 appendStringInfoString(buf, " LIMIT ");
4070 deparseExpr((Expr *) root->parse->limitCount, context);
4071 }
4072 if (root->parse->limitOffset)
4073 {
4074 appendStringInfoString(buf, " OFFSET ");
4075 deparseExpr((Expr *) root->parse->limitOffset, context);
4076 }
4077
4078 reset_transmission_modes(nestlevel);
4079}
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 3964 of file deparse.c.

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

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_for_cmptype(), IsA, lfirst, OidIsValid, oprid(), PathKey::pk_cmptype, PathKey::pk_nulls_first, PathKey::pk_opfamily, 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 3832 of file deparse.c.

3834{
3835 StringInfo buf = context->buf;
3836 TypeCacheEntry *typentry;
3837
3838 /* See whether operator is default < or > for sort expr's datatype. */
3839 typentry = lookup_type_cache(sortcoltype,
3841
3842 if (sortop == typentry->lt_opr)
3843 appendStringInfoString(buf, " ASC");
3844 else if (sortop == typentry->gt_opr)
3845 appendStringInfoString(buf, " DESC");
3846 else
3847 {
3848 HeapTuple opertup;
3849 Form_pg_operator operform;
3850
3851 appendStringInfoString(buf, " USING ");
3852
3853 /* Append operator name. */
3854 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(sortop));
3855 if (!HeapTupleIsValid(opertup))
3856 elog(ERROR, "cache lookup failed for operator %u", sortop);
3857 operform = (Form_pg_operator) GETSTRUCT(opertup);
3858 deparseOperatorName(buf, operform);
3859 ReleaseSysCache(opertup);
3860 }
3861
3862 if (nulls_first)
3863 appendStringInfoString(buf, " NULLS FIRST");
3864 else
3865 appendStringInfoString(buf, " NULLS LAST");
3866}
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform)
Definition: deparse.c:3442
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:140
#define TYPECACHE_LT_OPR
Definition: typcache.h:139

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

1642{
1643 StringInfo buf = context->buf;
1644 bool need_and = false;
1645 ListCell *lc;
1646
1647 if (exprs != NIL || additional_conds != NIL)
1648 appendStringInfoString(buf, " WHERE ");
1649
1650 /*
1651 * If there are some filters, append them.
1652 */
1653 if (exprs != NIL)
1654 {
1655 appendConditions(exprs, context);
1656 need_and = true;
1657 }
1658
1659 /*
1660 * If there are some EXISTS conditions, coming from SEMI-JOINS, append
1661 * them.
1662 */
1663 foreach(lc, additional_conds)
1664 {
1665 if (need_and)
1666 appendStringInfoString(buf, " AND ");
1667 appendStringInfoString(buf, (char *) lfirst(lc));
1668 need_and = true;
1669 }
1670}
static void appendConditions(List *exprs, deparse_expr_cxt *context)
Definition: deparse.c:1604
#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 1209 of file deparse.c.

1210{
1211 List *tlist = NIL;
1212 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1213 ListCell *lc;
1214
1215 /*
1216 * For an upper relation, we have already built the target list while
1217 * checking shippability, so just return that.
1218 */
1219 if (IS_UPPER_REL(foreignrel))
1220 return fpinfo->grouped_tlist;
1221
1222 /*
1223 * We require columns specified in foreignrel->reltarget->exprs and those
1224 * required for evaluating the local conditions.
1225 */
1226 tlist = add_to_flat_tlist(tlist,
1227 pull_var_clause((Node *) foreignrel->reltarget->exprs,
1229 foreach(lc, fpinfo->local_conds)
1230 {
1232
1233 tlist = add_to_flat_tlist(tlist,
1234 pull_var_clause((Node *) rinfo->clause,
1236 }
1237
1238 return tlist;
1239}
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
#define PVC_RECURSE_PLACEHOLDERS
Definition: optimizer.h:188
#define IS_UPPER_REL(rel)
Definition: pathnodes.h:886
#define lfirst_node(type, lc)
Definition: pg_list.h:176
Definition: pg_list.h:54
List * exprs
Definition: pathnodes.h:1691
struct PathTarget * reltarget
Definition: pathnodes.h:930
Expr * clause
Definition: pathnodes.h:2704
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 218 of file deparse.c.

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

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

1191{
1193
1194 if (!is_builtin(type_oid))
1196
1197 return format_type_extended(type_oid, typemod, flags);
1198}
#define FORMAT_TYPE_TYPEMOD_GIVEN
Definition: builtins.h:124
#define FORMAT_TYPE_FORCE_QUALIFY
Definition: builtins.h:126
uint16 bits16
Definition: c.h:546
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 deparseArrayCoerceExpr(), deparseArrayExpr(), deparseConst(), deparseFuncExpr(), deparseRelabelType(), printRemoteParam(), and printRemotePlaceholder().

◆ deparseAggref()

static void deparseAggref ( Aggref node,
deparse_expr_cxt context 
)
static

Definition at line 3711 of file deparse.c.

3712{
3713 StringInfo buf = context->buf;
3714 bool use_variadic;
3715
3716 /* Only basic, non-split aggregation accepted. */
3717 Assert(node->aggsplit == AGGSPLIT_SIMPLE);
3718
3719 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3720 use_variadic = node->aggvariadic;
3721
3722 /* Find aggregate name from aggfnoid which is a pg_proc entry */
3723 appendFunctionName(node->aggfnoid, context);
3725
3726 /* Add DISTINCT */
3727 appendStringInfoString(buf, (node->aggdistinct != NIL) ? "DISTINCT " : "");
3728
3729 if (AGGKIND_IS_ORDERED_SET(node->aggkind))
3730 {
3731 /* Add WITHIN GROUP (ORDER BY ..) */
3732 ListCell *arg;
3733 bool first = true;
3734
3735 Assert(!node->aggvariadic);
3736 Assert(node->aggorder != NIL);
3737
3738 foreach(arg, node->aggdirectargs)
3739 {
3740 if (!first)
3742 first = false;
3743
3744 deparseExpr((Expr *) lfirst(arg), context);
3745 }
3746
3747 appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
3748 appendAggOrderBy(node->aggorder, node->args, context);
3749 }
3750 else
3751 {
3752 /* aggstar can be set only in zero-argument aggregates */
3753 if (node->aggstar)
3755 else
3756 {
3757 ListCell *arg;
3758 bool first = true;
3759
3760 /* Add all the arguments */
3761 foreach(arg, node->args)
3762 {
3763 TargetEntry *tle = (TargetEntry *) lfirst(arg);
3764 Node *n = (Node *) tle->expr;
3765
3766 if (tle->resjunk)
3767 continue;
3768
3769 if (!first)
3771 first = false;
3772
3773 /* Add VARIADIC */
3774 if (use_variadic && lnext(node->args, arg) == NULL)
3775 appendStringInfoString(buf, "VARIADIC ");
3776
3777 deparseExpr((Expr *) n, context);
3778 }
3779 }
3780
3781 /* Add ORDER BY */
3782 if (node->aggorder != NIL)
3783 {
3784 appendStringInfoString(buf, " ORDER BY ");
3785 appendAggOrderBy(node->aggorder, node->args, context);
3786 }
3787 }
3788
3789 /* Add FILTER (WHERE ..) */
3790 if (node->aggfilter != NULL)
3791 {
3792 appendStringInfoString(buf, ") FILTER (WHERE ");
3793 deparseExpr((Expr *) node->aggfilter, context);
3794 }
3795
3797}
static void appendFunctionName(Oid funcid, deparse_expr_cxt *context)
Definition: deparse.c:4086
static void appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
Definition: deparse.c:3803
@ AGGSPLIT_SIMPLE
Definition: nodes.h:387
void * arg
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
Oid aggfnoid
Definition: primnodes.h:463
List * aggdistinct
Definition: primnodes.h:493
List * aggdirectargs
Definition: primnodes.h:484
List * args
Definition: primnodes.h:487
Expr * aggfilter
Definition: primnodes.h:496
List * aggorder
Definition: primnodes.h:490
Expr * expr
Definition: primnodes.h:2225

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

2555{
2557
2558 /* We'll need the remote relation name as a literal. */
2560 deparseRelation(&relname, rel);
2561
2562 appendStringInfoString(buf, "SELECT reltuples, relkind FROM pg_catalog.pg_class WHERE oid = ");
2564 appendStringInfoString(buf, "::pg_catalog.regclass");
2565}
void deparseStringLiteral(StringInfo buf, const char *val)
Definition: deparse.c:2882
static void deparseRelation(StringInfo buf, Relation rel)
Definition: deparse.c:2842
NameData relname
Definition: pg_class.h:38
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
char data[NAMEDATALEN]
Definition: c.h:747

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

Referenced by postgresGetAnalyzeInfoForForeignTable().

◆ deparseAnalyzeSizeSql()

void deparseAnalyzeSizeSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2532 of file deparse.c.

2533{
2535
2536 /* We'll need the remote relation name as a literal. */
2538 deparseRelation(&relname, rel);
2539
2540 appendStringInfoString(buf, "SELECT pg_catalog.pg_relation_size(");
2542 appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
2543}

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

2597{
2598 Oid relid = RelationGetRelid(rel);
2599 TupleDesc tupdesc = RelationGetDescr(rel);
2600 int i;
2601 char *colname;
2602 List *options;
2603 ListCell *lc;
2604 bool first = true;
2605
2606 *retrieved_attrs = NIL;
2607
2608 appendStringInfoString(buf, "SELECT ");
2609 for (i = 0; i < tupdesc->natts; i++)
2610 {
2611 /* Ignore dropped columns. */
2612 if (TupleDescAttr(tupdesc, i)->attisdropped)
2613 continue;
2614
2615 if (!first)
2617 first = false;
2618
2619 /* Use attribute name or column_name option. */
2620 colname = NameStr(TupleDescAttr(tupdesc, i)->attname);
2621 options = GetForeignColumnOptions(relid, i + 1);
2622
2623 foreach(lc, options)
2624 {
2625 DefElem *def = (DefElem *) lfirst(lc);
2626
2627 if (strcmp(def->defname, "column_name") == 0)
2628 {
2629 colname = defGetString(def);
2630 break;
2631 }
2632 }
2633
2635
2636 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
2637 }
2638
2639 /* Don't generate bad syntax for zero-column relation. */
2640 if (first)
2641 appendStringInfoString(buf, "NULL");
2642
2643 /*
2644 * Construct FROM clause, and perhaps WHERE clause too, depending on the
2645 * selected sampling method.
2646 */
2647 appendStringInfoString(buf, " FROM ");
2648 deparseRelation(buf, rel);
2649
2650 switch (sample_method)
2651 {
2652 case ANALYZE_SAMPLE_OFF:
2653 /* nothing to do here */
2654 break;
2655
2657 appendStringInfo(buf, " WHERE pg_catalog.random() < %f", sample_frac);
2658 break;
2659
2661 appendStringInfo(buf, " TABLESAMPLE SYSTEM(%f)", (100.0 * sample_frac));
2662 break;
2663
2665 appendStringInfo(buf, " TABLESAMPLE BERNOULLI(%f)", (100.0 * sample_frac));
2666 break;
2667
2669 /* should have been resolved into actual method */
2670 elog(ERROR, "unexpected sampling method");
2671 break;
2672 }
2673}
char * defGetString(DefElem *def)
Definition: define.c:35
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition: foreign.c:293
int i
Definition: isn.c:77
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:514
#define RelationGetDescr(relation)
Definition: rel.h:540
char * defname
Definition: parsenodes.h:842
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

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

◆ deparseArrayCoerceExpr()

static void deparseArrayCoerceExpr ( ArrayCoerceExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3546 of file deparse.c.

3547{
3548 deparseExpr(node->arg, context);
3549
3550 /*
3551 * No difference how to deparse explicit cast, but if we omit implicit
3552 * cast in the query, it'll be more user-friendly
3553 */
3554 if (node->coerceformat != COERCE_IMPLICIT_CAST)
3555 appendStringInfo(context->buf, "::%s",
3557 node->resulttypmod));
3558}
static char * deparse_type_name(Oid type_oid, int32 typemod)
Definition: deparse.c:1190
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:755

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

Referenced by deparseExpr().

◆ deparseArrayExpr()

static void deparseArrayExpr ( ArrayExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3685 of file deparse.c.

3686{
3687 StringInfo buf = context->buf;
3688 bool first = true;
3689 ListCell *lc;
3690
3691 appendStringInfoString(buf, "ARRAY[");
3692 foreach(lc, node->elements)
3693 {
3694 if (!first)
3696 deparseExpr(lfirst(lc), context);
3697 first = false;
3698 }
3700
3701 /* If the array is empty, we need an explicit cast to the array type. */
3702 if (node->elements == NIL)
3703 appendStringInfo(buf, "::%s",
3704 deparse_type_name(node->array_typeid, -1));
3705}

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

Referenced by deparseExpr().

◆ deparseBoolExpr()

static void deparseBoolExpr ( BoolExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3564 of file deparse.c.

3565{
3566 StringInfo buf = context->buf;
3567 const char *op = NULL; /* keep compiler quiet */
3568 bool first;
3569 ListCell *lc;
3570
3571 switch (node->boolop)
3572 {
3573 case AND_EXPR:
3574 op = "AND";
3575 break;
3576 case OR_EXPR:
3577 op = "OR";
3578 break;
3579 case NOT_EXPR:
3580 appendStringInfoString(buf, "(NOT ");
3581 deparseExpr(linitial(node->args), context);
3583 return;
3584 }
3585
3587 first = true;
3588 foreach(lc, node->args)
3589 {
3590 if (!first)
3591 appendStringInfo(buf, " %s ", op);
3592 deparseExpr((Expr *) lfirst(lc), context);
3593 first = false;
3594 }
3596}
#define linitial(l)
Definition: pg_list.h:178
@ AND_EXPR
Definition: primnodes.h:950
@ OR_EXPR
Definition: primnodes.h:950
@ NOT_EXPR
Definition: primnodes.h:950
BoolExprType boolop
Definition: primnodes.h:958
List * args
Definition: primnodes.h:959

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

3636{
3637 StringInfo buf = context->buf;
3638 ListCell *lc;
3639
3640 appendStringInfoString(buf, "(CASE");
3641
3642 /* If this is a CASE arg WHEN then emit the arg expression */
3643 if (node->arg != NULL)
3644 {
3646 deparseExpr(node->arg, context);
3647 }
3648
3649 /* Add each condition/result of the CASE clause */
3650 foreach(lc, node->args)
3651 {
3652 CaseWhen *whenclause = (CaseWhen *) lfirst(lc);
3653
3654 /* WHEN */
3655 appendStringInfoString(buf, " WHEN ");
3656 if (node->arg == NULL) /* CASE WHEN */
3657 deparseExpr(whenclause->expr, context);
3658 else /* CASE arg WHEN */
3659 {
3660 /* Ignore the CaseTestExpr and equality operator. */
3661 deparseExpr(lsecond(castNode(OpExpr, whenclause->expr)->args),
3662 context);
3663 }
3664
3665 /* THEN */
3666 appendStringInfoString(buf, " THEN ");
3667 deparseExpr(whenclause->result, context);
3668 }
3669
3670 /* add ELSE if present */
3671 if (node->defresult != NULL)
3672 {
3673 appendStringInfoString(buf, " ELSE ");
3674 deparseExpr(node->defresult, context);
3675 }
3676
3677 /* append END */
3678 appendStringInfoString(buf, " END)");
3679}
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
#define lsecond(l)
Definition: pg_list.h:183
Expr * arg
Definition: primnodes.h:1332
Expr * defresult
Definition: primnodes.h:1334
List * args
Definition: primnodes.h:1333
Expr * result
Definition: primnodes.h:1345
Expr * expr
Definition: primnodes.h:1344

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

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

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

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

2399{
2400 appendStringInfoString(buf, "DELETE FROM ");
2401 deparseRelation(buf, rel);
2402 appendStringInfoString(buf, " WHERE ctid = $1");
2403
2404 deparseReturningList(buf, rte, rtindex, rel,
2406 NIL, returningList, retrieved_attrs);
2407}
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:2475
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 2424 of file deparse.c.

2431{
2432 deparse_expr_cxt context;
2433 List *additional_conds = NIL;
2434
2435 /* Set up context struct for recursion */
2436 context.root = root;
2437 context.foreignrel = foreignrel;
2438 context.scanrel = foreignrel;
2439 context.buf = buf;
2440 context.params_list = params_list;
2441
2442 appendStringInfoString(buf, "DELETE FROM ");
2443 deparseRelation(buf, rel);
2444 if (foreignrel->reloptkind == RELOPT_JOINREL)
2445 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2446
2447 if (foreignrel->reloptkind == RELOPT_JOINREL)
2448 {
2449 List *ignore_conds = NIL;
2450
2451 appendStringInfoString(buf, " USING ");
2452 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2453 &ignore_conds, &additional_conds, params_list);
2454 remote_conds = list_concat(remote_conds, ignore_conds);
2455 }
2456
2457 appendWhereClause(remote_conds, additional_conds, &context);
2458
2459 if (additional_conds != NIL)
2460 list_free_deep(additional_conds);
2461
2462 if (foreignrel->reloptkind == RELOPT_JOINREL)
2463 deparseExplicitTargetList(returningList, true, retrieved_attrs,
2464 &context);
2465 else
2467 rtindex, rel, false,
2468 NIL, returningList, retrieved_attrs);
2469}
#define REL_ALIAS_PREFIX
Definition: deparse.c:109
static void deparseExplicitTargetList(List *tlist, bool is_returning, List **retrieved_attrs, deparse_expr_cxt *context)
Definition: deparse.c:1714
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:1794
static void appendWhereClause(List *exprs, List *additional_conds, deparse_expr_cxt *context)
Definition: deparse.c:1641
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:591
@ RELOPT_JOINREL
Definition: pathnodes.h:865
RelOptKind reloptkind
Definition: pathnodes.h:902
List ** params_list
Definition: deparse.c:106

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

2318{
2319 deparse_expr_cxt context;
2320 int nestlevel;
2321 bool first;
2322 RangeTblEntry *rte = planner_rt_fetch(rtindex, root);
2323 ListCell *lc,
2324 *lc2;
2325 List *additional_conds = NIL;
2326
2327 /* Set up context struct for recursion */
2328 context.root = root;
2329 context.foreignrel = foreignrel;
2330 context.scanrel = foreignrel;
2331 context.buf = buf;
2332 context.params_list = params_list;
2333
2334 appendStringInfoString(buf, "UPDATE ");
2335 deparseRelation(buf, rel);
2336 if (foreignrel->reloptkind == RELOPT_JOINREL)
2337 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2338 appendStringInfoString(buf, " SET ");
2339
2340 /* Make sure any constants in the exprs are printed portably */
2341 nestlevel = set_transmission_modes();
2342
2343 first = true;
2344 forboth(lc, targetlist, lc2, targetAttrs)
2345 {
2347 int attnum = lfirst_int(lc2);
2348
2349 /* update's new-value expressions shouldn't be resjunk */
2350 Assert(!tle->resjunk);
2351
2352 if (!first)
2354 first = false;
2355
2356 deparseColumnRef(buf, rtindex, attnum, rte, false);
2358 deparseExpr((Expr *) tle->expr, &context);
2359 }
2360
2361 reset_transmission_modes(nestlevel);
2362
2363 if (foreignrel->reloptkind == RELOPT_JOINREL)
2364 {
2365 List *ignore_conds = NIL;
2366
2367
2368 appendStringInfoString(buf, " FROM ");
2369 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2370 &ignore_conds, &additional_conds, params_list);
2371 remote_conds = list_concat(remote_conds, ignore_conds);
2372 }
2373
2374 appendWhereClause(remote_conds, additional_conds, &context);
2375
2376 if (additional_conds != NIL)
2377 list_free_deep(additional_conds);
2378
2379 if (foreignrel->reloptkind == RELOPT_JOINREL)
2380 deparseExplicitTargetList(returningList, true, retrieved_attrs,
2381 &context);
2382 else
2383 deparseReturningList(buf, rte, rtindex, rel, false,
2384 NIL, returningList, retrieved_attrs);
2385}
static void deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte, bool qualify_col)
Definition: deparse.c:2714
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 3470 of file deparse.c.

3471{
3472 StringInfo buf = context->buf;
3473
3474 Assert(list_length(node->args) == 2);
3475
3477 deparseExpr(linitial(node->args), context);
3478 appendStringInfoString(buf, " IS DISTINCT FROM ");
3479 deparseExpr(lsecond(node->args), context);
3481}
static int list_length(const List *l)
Definition: pg_list.h:152
List * args
Definition: primnodes.h:855

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

1718{
1719 ListCell *lc;
1720 StringInfo buf = context->buf;
1721 int i = 0;
1722
1723 *retrieved_attrs = NIL;
1724
1725 foreach(lc, tlist)
1726 {
1728
1729 if (i > 0)
1731 else if (is_returning)
1732 appendStringInfoString(buf, " RETURNING ");
1733
1734 deparseExpr((Expr *) tle->expr, context);
1735
1736 *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
1737 i++;
1738 }
1739
1740 if (i == 0 && !is_returning)
1741 appendStringInfoString(buf, "NULL");
1742}

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

2918{
2919 if (node == NULL)
2920 return;
2921
2922 switch (nodeTag(node))
2923 {
2924 case T_Var:
2925 deparseVar((Var *) node, context);
2926 break;
2927 case T_Const:
2928 deparseConst((Const *) node, context, 0);
2929 break;
2930 case T_Param:
2931 deparseParam((Param *) node, context);
2932 break;
2933 case T_SubscriptingRef:
2934 deparseSubscriptingRef((SubscriptingRef *) node, context);
2935 break;
2936 case T_FuncExpr:
2937 deparseFuncExpr((FuncExpr *) node, context);
2938 break;
2939 case T_OpExpr:
2940 deparseOpExpr((OpExpr *) node, context);
2941 break;
2942 case T_DistinctExpr:
2943 deparseDistinctExpr((DistinctExpr *) node, context);
2944 break;
2945 case T_ScalarArrayOpExpr:
2947 break;
2948 case T_RelabelType:
2949 deparseRelabelType((RelabelType *) node, context);
2950 break;
2951 case T_ArrayCoerceExpr:
2952 deparseArrayCoerceExpr((ArrayCoerceExpr *) node, context);
2953 break;
2954 case T_BoolExpr:
2955 deparseBoolExpr((BoolExpr *) node, context);
2956 break;
2957 case T_NullTest:
2958 deparseNullTest((NullTest *) node, context);
2959 break;
2960 case T_CaseExpr:
2961 deparseCaseExpr((CaseExpr *) node, context);
2962 break;
2963 case T_ArrayExpr:
2964 deparseArrayExpr((ArrayExpr *) node, context);
2965 break;
2966 case T_Aggref:
2967 deparseAggref((Aggref *) node, context);
2968 break;
2969 default:
2970 elog(ERROR, "unsupported expression type for deparse: %d",
2971 (int) nodeTag(node));
2972 break;
2973 }
2974}
static void deparseArrayCoerceExpr(ArrayCoerceExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3546
static void deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3635
static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3564
static void deparseAggref(Aggref *node, deparse_expr_cxt *context)
Definition: deparse.c:3711
static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
Definition: deparse.c:3533
static void deparseNullTest(NullTest *node, deparse_expr_cxt *context)
Definition: deparse.c:3602
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3312
static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype)
Definition: deparse.c:3056
static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3470
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3249
static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3685
static void deparseVar(Var *node, deparse_expr_cxt *context)
Definition: deparse.c:2985
static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
Definition: deparse.c:3203
static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3488
static void deparseParam(Param *node, deparse_expr_cxt *context)
Definition: deparse.c:3170
#define nodeTag(nodeptr)
Definition: nodes.h:139
Definition: primnodes.h:262

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

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

◆ deparseFromExpr()

static void deparseFromExpr ( List quals,
deparse_expr_cxt context 
)
static

Definition at line 1406 of file deparse.c.

1407{
1408 StringInfo buf = context->buf;
1409 RelOptInfo *scanrel = context->scanrel;
1410 List *additional_conds = NIL;
1411
1412 /* For upper relations, scanrel must be either a joinrel or a baserel */
1413 Assert(!IS_UPPER_REL(context->foreignrel) ||
1414 IS_JOIN_REL(scanrel) || IS_SIMPLE_REL(scanrel));
1415
1416 /* Construct FROM clause */
1417 appendStringInfoString(buf, " FROM ");
1418 deparseFromExprForRel(buf, context->root, scanrel,
1419 (bms_membership(scanrel->relids) == BMS_MULTIPLE),
1420 (Index) 0, NULL, &additional_conds,
1421 context->params_list);
1422 appendWhereClause(quals, additional_conds, context);
1423 if (additional_conds != NIL)
1424 list_free_deep(additional_conds);
1425}
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:781
@ BMS_MULTIPLE
Definition: bitmapset.h:73
unsigned int Index
Definition: c.h:619
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:876
#define IS_JOIN_REL(rel)
Definition: pathnodes.h:881
Relids relids
Definition: pathnodes.h:908

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

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

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

3250{
3251 StringInfo buf = context->buf;
3252 bool use_variadic;
3253 bool first;
3254 ListCell *arg;
3255
3256 /*
3257 * If the function call came from an implicit coercion, then just show the
3258 * first argument.
3259 */
3260 if (node->funcformat == COERCE_IMPLICIT_CAST)
3261 {
3262 deparseExpr((Expr *) linitial(node->args), context);
3263 return;
3264 }
3265
3266 /*
3267 * If the function call came from a cast, then show the first argument
3268 * plus an explicit cast operation.
3269 */
3270 if (node->funcformat == COERCE_EXPLICIT_CAST)
3271 {
3272 Oid rettype = node->funcresulttype;
3273 int32 coercedTypmod;
3274
3275 /* Get the typmod if this is a length-coercion function */
3276 (void) exprIsLengthCoercion((Node *) node, &coercedTypmod);
3277
3278 deparseExpr((Expr *) linitial(node->args), context);
3279 appendStringInfo(buf, "::%s",
3280 deparse_type_name(rettype, coercedTypmod));
3281 return;
3282 }
3283
3284 /* Check if need to print VARIADIC (cf. ruleutils.c) */
3285 use_variadic = node->funcvariadic;
3286
3287 /*
3288 * Normal function: display as proname(args).
3289 */
3290 appendFunctionName(node->funcid, context);
3292
3293 /* ... and all the arguments */
3294 first = true;
3295 foreach(arg, node->args)
3296 {
3297 if (!first)
3299 if (use_variadic && lnext(node->args, arg) == NULL)
3300 appendStringInfoString(buf, "VARIADIC ");
3301 deparseExpr((Expr *) lfirst(arg), context);
3302 first = false;
3303 }
3305}
int32_t int32
Definition: c.h:534
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:557
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:754
Oid funcid
Definition: primnodes.h:769
List * args
Definition: primnodes.h:787

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

2121{
2122 TupleDesc tupdesc = RelationGetDescr(rel);
2123 AttrNumber pindex;
2124 bool first;
2125 ListCell *lc;
2126
2127 appendStringInfoString(buf, "INSERT INTO ");
2128 deparseRelation(buf, rel);
2129
2130 if (targetAttrs)
2131 {
2133
2134 first = true;
2135 foreach(lc, targetAttrs)
2136 {
2137 int attnum = lfirst_int(lc);
2138
2139 if (!first)
2141 first = false;
2142
2143 deparseColumnRef(buf, rtindex, attnum, rte, false);
2144 }
2145
2146 appendStringInfoString(buf, ") VALUES (");
2147
2148 pindex = 1;
2149 first = true;
2150 foreach(lc, targetAttrs)
2151 {
2152 int attnum = lfirst_int(lc);
2153 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2154
2155 if (!first)
2157 first = false;
2158
2159 if (attr->attgenerated)
2160 appendStringInfoString(buf, "DEFAULT");
2161 else
2162 {
2163 appendStringInfo(buf, "$%d", pindex);
2164 pindex++;
2165 }
2166 }
2167
2169 }
2170 else
2171 appendStringInfoString(buf, " DEFAULT VALUES");
2172 *values_end_len = buf->len;
2173
2174 if (doNothing)
2175 appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
2176
2177 deparseReturningList(buf, rte, rtindex, rel,
2179 withCheckOptionList, returningList, retrieved_attrs);
2180}
int16 AttrNumber
Definition: attnum.h:21
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
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 1514 of file deparse.c.

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

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

3603{
3604 StringInfo buf = context->buf;
3605
3607 deparseExpr(node->arg, context);
3608
3609 /*
3610 * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
3611 * shorter and traditional. If it's a rowtype input but we're applying a
3612 * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
3613 * correct.
3614 */
3615 if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
3616 {
3617 if (node->nulltesttype == IS_NULL)
3618 appendStringInfoString(buf, " IS NULL)");
3619 else
3620 appendStringInfoString(buf, " IS NOT NULL)");
3621 }
3622 else
3623 {
3624 if (node->nulltesttype == IS_NULL)
3625 appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)");
3626 else
3627 appendStringInfoString(buf, " IS DISTINCT FROM NULL)");
3628 }
3629}
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2822
@ IS_NULL
Definition: primnodes.h:1963
NullTestType nulltesttype
Definition: primnodes.h:1970
Expr * arg
Definition: primnodes.h:1969

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

3443{
3444 char *opname;
3445
3446 /* opname is not a SQL identifier, so we should not quote it. */
3447 opname = NameStr(opform->oprname);
3448
3449 /* Print schema name only if it's not pg_catalog */
3450 if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
3451 {
3452 const char *opnspname;
3453
3454 opnspname = get_namespace_name(opform->oprnamespace);
3455 /* Print fully qualified operator name. */
3456 appendStringInfo(buf, "OPERATOR(%s.%s)",
3457 quote_identifier(opnspname), opname);
3458 }
3459 else
3460 {
3461 /* Just print operator name. */
3462 appendStringInfoString(buf, opname);
3463 }
3464}

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

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

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

3171{
3172 if (context->params_list)
3173 {
3174 int pindex = 0;
3175 ListCell *lc;
3176
3177 /* find its index in params_list */
3178 foreach(lc, *context->params_list)
3179 {
3180 pindex++;
3181 if (equal(node, (Node *) lfirst(lc)))
3182 break;
3183 }
3184 if (lc == NULL)
3185 {
3186 /* not in list, so add it */
3187 pindex++;
3188 *context->params_list = lappend(*context->params_list, node);
3189 }
3190
3191 printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
3192 }
3193 else
3194 {
3195 printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
3196 }
3197}
static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3877
static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3903
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
int32 paramtypmod
Definition: primnodes.h:399
Oid paramtype
Definition: primnodes.h:397

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

Referenced by deparseExpr().

◆ deparseRangeTblRef()

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

Definition at line 2041 of file deparse.c.

2044{
2045 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
2046
2047 /* Should only be called in these cases. */
2048 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
2049
2050 Assert(fpinfo->local_conds == NIL);
2051
2052 /* If make_subquery is true, deparse the relation as a subquery. */
2053 if (make_subquery)
2054 {
2055 List *retrieved_attrs;
2056 int ncols;
2057
2058 /*
2059 * The given relation shouldn't contain the target relation, because
2060 * this should only happen for input relations for a full join, and
2061 * such relations can never contain an UPDATE/DELETE target.
2062 */
2063 Assert(ignore_rel == 0 ||
2064 !bms_is_member(ignore_rel, foreignrel->relids));
2065
2066 /* Deparse the subquery representing the relation. */
2068 deparseSelectStmtForRel(buf, root, foreignrel, NIL,
2069 fpinfo->remote_conds, NIL,
2070 false, false, true,
2071 &retrieved_attrs, params_list);
2073
2074 /* Append the relation alias. */
2076 fpinfo->relation_index);
2077
2078 /*
2079 * Append the column aliases if needed. Note that the subquery emits
2080 * expressions specified in the relation's reltarget (see
2081 * deparseSubqueryTargetList).
2082 */
2083 ncols = list_length(foreignrel->reltarget->exprs);
2084 if (ncols > 0)
2085 {
2086 int i;
2087
2089 for (i = 1; i <= ncols; i++)
2090 {
2091 if (i > 1)
2093
2095 }
2097 }
2098 }
2099 else
2100 deparseFromExprForRel(buf, root, foreignrel, true, ignore_rel,
2101 ignore_conds, additional_conds,
2102 params_list);
2103}
#define SUBQUERY_REL_ALIAS_PREFIX
Definition: deparse.c:113
void deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, List *tlist, List *remote_conds, List *pathkeys, bool has_final_sort, bool has_limit, bool is_subquery, List **retrieved_attrs, List **params_list)
Definition: deparse.c:1266
#define SUBQUERY_COL_ALIAS_PREFIX
Definition: deparse.c:114

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

3534{
3535 deparseExpr(node->arg, context);
3536 if (node->relabelformat != COERCE_IMPLICIT_CAST)
3537 appendStringInfo(context->buf, "::%s",
3539 node->resulttypmod));
3540}
Oid resulttype
Definition: primnodes.h:1204
Expr * arg
Definition: primnodes.h:1203

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

2843{
2845 const char *nspname = NULL;
2846 const char *relname = NULL;
2847 ListCell *lc;
2848
2849 /* obtain additional catalog information. */
2851
2852 /*
2853 * Use value of FDW options if any, instead of the name of object itself.
2854 */
2855 foreach(lc, table->options)
2856 {
2857 DefElem *def = (DefElem *) lfirst(lc);
2858
2859 if (strcmp(def->defname, "schema_name") == 0)
2860 nspname = defGetString(def);
2861 else if (strcmp(def->defname, "table_name") == 0)
2862 relname = defGetString(def);
2863 }
2864
2865 /*
2866 * Note: we could skip printing the schema name if it's pg_catalog, but
2867 * that doesn't seem worth the trouble.
2868 */
2869 if (nspname == NULL)
2871 if (relname == NULL)
2873
2874 appendStringInfo(buf, "%s.%s",
2876}
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:255
static const struct lconv_member_info table[]
#define RelationGetRelationName(relation)
Definition: rel.h:548
#define RelationGetNamespace(relation)
Definition: rel.h:555

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

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

◆ deparseReturningList()

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

Definition at line 2475 of file deparse.c.

2481{
2482 Bitmapset *attrs_used = NULL;
2483
2484 if (trig_after_row)
2485 {
2486 /* whole-row reference acquires all non-system columns */
2487 attrs_used =
2489 }
2490
2491 if (withCheckOptionList != NIL)
2492 {
2493 /*
2494 * We need the attrs, non-system and system, mentioned in the local
2495 * query's WITH CHECK OPTION list.
2496 *
2497 * Note: we do this to ensure that WCO constraints will be evaluated
2498 * on the data actually inserted/updated on the remote side, which
2499 * might differ from the data supplied by the core code, for example
2500 * as a result of remote triggers.
2501 */
2502 pull_varattnos((Node *) withCheckOptionList, rtindex,
2503 &attrs_used);
2504 }
2505
2506 if (returningList != NIL)
2507 {
2508 /*
2509 * We need the attrs, non-system and system, mentioned in the local
2510 * query's RETURNING list.
2511 */
2512 pull_varattnos((Node *) returningList, rtindex,
2513 &attrs_used);
2514 }
2515
2516 if (attrs_used != NULL)
2517 deparseTargetList(buf, rte, rtindex, rel, true, attrs_used, false,
2518 retrieved_attrs);
2519 else
2520 *retrieved_attrs = NIL;
2521}
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 3488 of file deparse.c.

3489{
3490 StringInfo buf = context->buf;
3491 HeapTuple tuple;
3492 Form_pg_operator form;
3493 Expr *arg1;
3494 Expr *arg2;
3495
3496 /* Retrieve information about the operator from system catalog. */
3497 tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
3498 if (!HeapTupleIsValid(tuple))
3499 elog(ERROR, "cache lookup failed for operator %u", node->opno);
3500 form = (Form_pg_operator) GETSTRUCT(tuple);
3501
3502 /* Sanity check. */
3503 Assert(list_length(node->args) == 2);
3504
3505 /* Always parenthesize the expression. */
3507
3508 /* Deparse left operand. */
3509 arg1 = linitial(node->args);
3510 deparseExpr(arg1, context);
3512
3513 /* Deparse operator name plus decoration. */
3514 deparseOperatorName(buf, form);
3515 appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
3516
3517 /* Deparse right operand. */
3518 arg2 = lsecond(node->args);
3519 deparseExpr(arg2, context);
3520
3522
3523 /* Always parenthesize the expression. */
3525
3526 ReleaseSysCache(tuple);
3527}

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

1350{
1351 StringInfo buf = context->buf;
1352 RelOptInfo *foreignrel = context->foreignrel;
1353 PlannerInfo *root = context->root;
1354 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1355
1356 /*
1357 * Construct SELECT list
1358 */
1359 appendStringInfoString(buf, "SELECT ");
1360
1361 if (is_subquery)
1362 {
1363 /*
1364 * For a relation that is deparsed as a subquery, emit expressions
1365 * specified in the relation's reltarget. Note that since this is for
1366 * the subquery, no need to care about *retrieved_attrs.
1367 */
1369 }
1370 else if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
1371 {
1372 /*
1373 * For a join or upper relation the input tlist gives the list of
1374 * columns required to be fetched from the foreign server.
1375 */
1376 deparseExplicitTargetList(tlist, false, retrieved_attrs, context);
1377 }
1378 else
1379 {
1380 /*
1381 * For a base relation fpinfo->attrs_used gives the list of columns
1382 * required to be fetched from the foreign server.
1383 */
1384 RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1385
1386 /*
1387 * Core code already has some lock on each rel being planned, so we
1388 * can use NoLock here.
1389 */
1390 Relation rel = table_open(rte->relid, NoLock);
1391
1392 deparseTargetList(buf, rte, foreignrel->relid, rel, false,
1393 fpinfo->attrs_used, false, retrieved_attrs);
1394 table_close(rel, NoLock);
1395 }
1396}
static void deparseSubqueryTargetList(deparse_expr_cxt *context)
Definition: deparse.c:1750
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, 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 1266 of file deparse.c.

1270{
1271 deparse_expr_cxt context;
1272 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1273 List *quals;
1274
1275 /*
1276 * We handle relations for foreign tables, joins between those and upper
1277 * relations.
1278 */
1279 Assert(IS_JOIN_REL(rel) || IS_SIMPLE_REL(rel) || IS_UPPER_REL(rel));
1280
1281 /* Fill portions of context common to upper, join and base relation */
1282 context.buf = buf;
1283 context.root = root;
1284 context.foreignrel = rel;
1285 context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel;
1286 context.params_list = params_list;
1287
1288 /* Construct SELECT clause */
1289 deparseSelectSql(tlist, is_subquery, retrieved_attrs, &context);
1290
1291 /*
1292 * For upper relations, the WHERE clause is built from the remote
1293 * conditions of the underlying scan relation; otherwise, we can use the
1294 * supplied list of remote conditions directly.
1295 */
1296 if (IS_UPPER_REL(rel))
1297 {
1298 PgFdwRelationInfo *ofpinfo;
1299
1300 ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
1301 quals = ofpinfo->remote_conds;
1302 }
1303 else
1304 quals = remote_conds;
1305
1306 /* Construct FROM and WHERE clauses */
1307 deparseFromExpr(quals, &context);
1308
1309 if (IS_UPPER_REL(rel))
1310 {
1311 /* Append GROUP BY clause */
1312 appendGroupByClause(tlist, &context);
1313
1314 /* Append HAVING clause */
1315 if (remote_conds)
1316 {
1317 appendStringInfoString(buf, " HAVING ");
1318 appendConditions(remote_conds, &context);
1319 }
1320 }
1321
1322 /* Add ORDER BY clause if we found any useful pathkeys */
1323 if (pathkeys)
1324 appendOrderByClause(pathkeys, has_final_sort, &context);
1325
1326 /* Add LIMIT clause if necessary */
1327 if (has_limit)
1328 appendLimitClause(&context);
1329
1330 /* Add any necessary FOR UPDATE/SHARE. */
1331 deparseLockingClause(&context);
1332}
static void appendGroupByClause(List *tlist, deparse_expr_cxt *context)
Definition: deparse.c:3916
static void deparseFromExpr(List *quals, deparse_expr_cxt *context)
Definition: deparse.c:1406
static void deparseLockingClause(deparse_expr_cxt *context)
Definition: deparse.c:1514
static void appendOrderByClause(List *pathkeys, bool has_final_sort, deparse_expr_cxt *context)
Definition: deparse.c:3964
static void appendLimitClause(deparse_expr_cxt *context)
Definition: deparse.c:4058
static void deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs, deparse_expr_cxt *context)
Definition: deparse.c:1348

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

4123{
4124 StringInfo buf = context->buf;
4125 TargetEntry *tle;
4126 Expr *expr;
4127
4128 tle = get_sortgroupref_tle(ref, tlist);
4129 expr = tle->expr;
4130
4131 if (force_colno)
4132 {
4133 /* Use column-number form when requested by caller. */
4134 Assert(!tle->resjunk);
4135 appendStringInfo(buf, "%d", tle->resno);
4136 }
4137 else if (expr && IsA(expr, Const))
4138 {
4139 /*
4140 * Force a typecast here so that we don't emit something like "GROUP
4141 * BY 2", which will be misconstrued as a column position rather than
4142 * a constant.
4143 */
4144 deparseConst((Const *) expr, context, 1);
4145 }
4146 else if (!expr || IsA(expr, Var))
4147 deparseExpr(expr, context);
4148 else
4149 {
4150 /* Always parenthesize the expression. */
4152 deparseExpr(expr, context);
4154 }
4155
4156 return (Node *) expr;
4157}
AttrNumber resno
Definition: primnodes.h:2227
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 2882 of file deparse.c.

2883{
2884 const char *valptr;
2885
2886 /*
2887 * Rather than making assumptions about the remote server's value of
2888 * standard_conforming_strings, always use E'foo' syntax if there are any
2889 * backslashes. This will fail on remote servers before 8.1, but those
2890 * are long out of support.
2891 */
2892 if (strchr(val, '\\') != NULL)
2895 for (valptr = val; *valptr; valptr++)
2896 {
2897 char ch = *valptr;
2898
2899 if (SQL_STR_DOUBLE(ch, true))
2902 }
2904}
#define ESCAPE_STRING_SYNTAX
Definition: c.h:1165
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1162
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 1750 of file deparse.c.

1751{
1752 StringInfo buf = context->buf;
1753 RelOptInfo *foreignrel = context->foreignrel;
1754 bool first;
1755 ListCell *lc;
1756
1757 /* Should only be called in these cases. */
1758 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1759
1760 first = true;
1761 foreach(lc, foreignrel->reltarget->exprs)
1762 {
1763 Node *node = (Node *) lfirst(lc);
1764
1765 if (!first)
1767 first = false;
1768
1769 deparseExpr((Expr *) node, context);
1770 }
1771
1772 /* Don't generate bad syntax if no expressions */
1773 if (first)
1774 appendStringInfoString(buf, "NULL");
1775}

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

3204{
3205 StringInfo buf = context->buf;
3206 ListCell *lowlist_item;
3207 ListCell *uplist_item;
3208
3209 /* Always parenthesize the expression. */
3211
3212 /*
3213 * Deparse referenced array expression first. If that expression includes
3214 * a cast, we have to parenthesize to prevent the array subscript from
3215 * being taken as typename decoration. We can avoid that in the typical
3216 * case of subscripting a Var, but otherwise do it.
3217 */
3218 if (IsA(node->refexpr, Var))
3219 deparseExpr(node->refexpr, context);
3220 else
3221 {
3223 deparseExpr(node->refexpr, context);
3225 }
3226
3227 /* Deparse subscript expressions. */
3228 lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
3229 foreach(uplist_item, node->refupperindexpr)
3230 {
3232 if (lowlist_item)
3233 {
3234 deparseExpr(lfirst(lowlist_item), context);
3236 lowlist_item = lnext(node->reflowerindexpr, lowlist_item);
3237 }
3238 deparseExpr(lfirst(uplist_item), context);
3240 }
3241
3243}
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
List * refupperindexpr
Definition: primnodes.h:712
Expr * refexpr
Definition: primnodes.h:720
List * reflowerindexpr
Definition: primnodes.h:718

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

1446{
1447 TupleDesc tupdesc = RelationGetDescr(rel);
1448 bool have_wholerow;
1449 bool first;
1450 int i;
1451
1452 *retrieved_attrs = NIL;
1453
1454 /* If there's a whole-row reference, we'll need all the columns. */
1456 attrs_used);
1457
1458 first = true;
1459 for (i = 1; i <= tupdesc->natts; i++)
1460 {
1461 Form_pg_attribute attr = TupleDescAttr(tupdesc, i - 1);
1462
1463 /* Ignore dropped attributes. */
1464 if (attr->attisdropped)
1465 continue;
1466
1467 if (have_wholerow ||
1469 attrs_used))
1470 {
1471 if (!first)
1473 else if (is_returning)
1474 appendStringInfoString(buf, " RETURNING ");
1475 first = false;
1476
1477 deparseColumnRef(buf, rtindex, i, rte, qualify_col);
1478
1479 *retrieved_attrs = lappend_int(*retrieved_attrs, i);
1480 }
1481 }
1482
1483 /*
1484 * Add ctid if needed. We currently don't support retrieving any other
1485 * system columns.
1486 */
1488 attrs_used))
1489 {
1490 if (!first)
1492 else if (is_returning)
1493 appendStringInfoString(buf, " RETURNING ");
1494 first = false;
1495
1496 if (qualify_col)
1497 ADD_REL_QUALIFIER(buf, rtindex);
1498 appendStringInfoString(buf, "ctid");
1499
1500 *retrieved_attrs = lappend_int(*retrieved_attrs,
1502 }
1503
1504 /* Don't generate bad syntax if no undropped columns */
1505 if (first && !is_returning)
1506 appendStringInfoString(buf, "NULL");
1507}

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

2683{
2684 ListCell *cell;
2685
2686 appendStringInfoString(buf, "TRUNCATE ");
2687
2688 foreach(cell, rels)
2689 {
2690 Relation rel = lfirst(cell);
2691
2692 if (cell != list_head(rels))
2694
2695 deparseRelation(buf, rel);
2696 }
2697
2698 appendStringInfo(buf, " %s IDENTITY",
2699 restart_seqs ? "RESTART" : "CONTINUE");
2700
2701 if (behavior == DROP_RESTRICT)
2702 appendStringInfoString(buf, " RESTRICT");
2703 else if (behavior == DROP_CASCADE)
2704 appendStringInfoString(buf, " CASCADE");
2705}
@ DROP_CASCADE
Definition: parsenodes.h:2398
@ DROP_RESTRICT
Definition: parsenodes.h:2397

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

2254{
2255 TupleDesc tupdesc = RelationGetDescr(rel);
2256 AttrNumber pindex;
2257 bool first;
2258 ListCell *lc;
2259
2260 appendStringInfoString(buf, "UPDATE ");
2261 deparseRelation(buf, rel);
2262 appendStringInfoString(buf, " SET ");
2263
2264 pindex = 2; /* ctid is always the first param */
2265 first = true;
2266 foreach(lc, targetAttrs)
2267 {
2268 int attnum = lfirst_int(lc);
2269 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2270
2271 if (!first)
2273 first = false;
2274
2275 deparseColumnRef(buf, rtindex, attnum, rte, false);
2276 if (attr->attgenerated)
2277 appendStringInfoString(buf, " = DEFAULT");
2278 else
2279 {
2280 appendStringInfo(buf, " = $%d", pindex);
2281 pindex++;
2282 }
2283 }
2284 appendStringInfoString(buf, " WHERE ctid = $1");
2285
2286 deparseReturningList(buf, rte, rtindex, rel,
2288 withCheckOptionList, returningList, retrieved_attrs);
2289}
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 2985 of file deparse.c.

2986{
2987 Relids relids = context->scanrel->relids;
2988 int relno;
2989 int colno;
2990
2991 /* Qualify columns when multiple relations are involved. */
2992 bool qualify_col = (bms_membership(relids) == BMS_MULTIPLE);
2993
2994 /*
2995 * If the Var belongs to the foreign relation that is deparsed as a
2996 * subquery, use the relation and column alias to the Var provided by the
2997 * subquery, instead of the remote name.
2998 */
2999 if (is_subquery_var(node, context->scanrel, &relno, &colno))
3000 {
3001 appendStringInfo(context->buf, "%s%d.%s%d",
3004 return;
3005 }
3006
3007 if (bms_is_member(node->varno, relids) && node->varlevelsup == 0)
3008 deparseColumnRef(context->buf, node->varno, node->varattno,
3009 planner_rt_fetch(node->varno, context->root),
3010 qualify_col);
3011 else
3012 {
3013 /* Treat like a Param */
3014 if (context->params_list)
3015 {
3016 int pindex = 0;
3017 ListCell *lc;
3018
3019 /* find its index in params_list */
3020 foreach(lc, *context->params_list)
3021 {
3022 pindex++;
3023 if (equal(node, (Node *) lfirst(lc)))
3024 break;
3025 }
3026 if (lc == NULL)
3027 {
3028 /* not in list, so add it */
3029 pindex++;
3030 *context->params_list = lappend(*context->params_list, node);
3031 }
3032
3033 printRemoteParam(pindex, node->vartype, node->vartypmod, context);
3034 }
3035 else
3036 {
3037 printRemotePlaceholder(node->vartype, node->vartypmod, context);
3038 }
3039 }
3040}
static bool is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:4166
AttrNumber varattno
Definition: primnodes.h:274
int varno
Definition: primnodes.h:269
Index varlevelsup
Definition: primnodes.h:294

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

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

1675{
1676 switch (jointype)
1677 {
1678 case JOIN_INNER:
1679 return "INNER";
1680
1681 case JOIN_LEFT:
1682 return "LEFT";
1683
1684 case JOIN_RIGHT:
1685 return "RIGHT";
1686
1687 case JOIN_FULL:
1688 return "FULL";
1689
1690 case JOIN_SEMI:
1691 return "SEMI";
1692
1693 default:
1694 /* Shouldn't come here, but protect from buggy code. */
1695 elog(ERROR, "unsupported join type %d", jointype);
1696 }
1697
1698 /* Keep compiler happy */
1699 return NULL;
1700}
@ JOIN_FULL
Definition: nodes.h:305
@ JOIN_RIGHT
Definition: nodes.h:306
@ JOIN_LEFT
Definition: nodes.h:304

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

4230{
4231 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
4232 int i;
4233 ListCell *lc;
4234
4235 /* Get the relation alias ID */
4236 *relno = fpinfo->relation_index;
4237
4238 /* Get the column alias ID */
4239 i = 1;
4240 foreach(lc, foreignrel->reltarget->exprs)
4241 {
4242 Var *tlvar = (Var *) lfirst(lc);
4243
4244 /*
4245 * Match reltarget entries only on varno/varattno. Ideally there
4246 * would be some cross-check on varnullingrels, but it's unclear what
4247 * to do exactly; we don't have enough context to know what that value
4248 * should be.
4249 */
4250 if (IsA(tlvar, Var) &&
4251 tlvar->varno == node->varno &&
4252 tlvar->varattno == node->varattno)
4253 {
4254 *colno = i;
4255 return;
4256 }
4257 i++;
4258 }
4259
4260 /* Shouldn't get here */
4261 elog(ERROR, "unexpected expression in subquery output");
4262}

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

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

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

1118{
1119 if (expr == NULL)
1120 return false;
1121
1122 switch (nodeTag(expr))
1123 {
1124 case T_Var:
1125 {
1126 /* It would have to be sent unless it's a foreign Var */
1127 Var *var = (Var *) expr;
1128 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private);
1129 Relids relids;
1130
1131 if (IS_UPPER_REL(baserel))
1132 relids = fpinfo->outerrel->relids;
1133 else
1134 relids = baserel->relids;
1135
1136 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
1137 return false; /* foreign Var, so not a param */
1138 else
1139 return true; /* it'd have to be a param */
1140 break;
1141 }
1142 case T_Param:
1143 /* Params always have to be sent to the foreign server */
1144 return true;
1145 default:
1146 break;
1147 }
1148 return false;
1149}

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

1159{
1160 EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
1161 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) baserel->fdw_private;
1162
1163 /*
1164 * is_foreign_expr would detect volatile expressions as well, but checking
1165 * ec_has_volatile here saves some cycles.
1166 */
1167 if (pathkey_ec->ec_has_volatile)
1168 return false;
1169
1170 /* can't push down the sort if the pathkey's opfamily is not shippable */
1171 if (!is_shippable(pathkey->pk_opfamily, OperatorFamilyRelationId, fpinfo))
1172 return false;
1173
1174 /* can push if a suitable EC member exists */
1175 return (find_em_for_rel(root, pathkey_ec, baserel) != NULL);
1176}

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

4167{
4168 PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
4169 RelOptInfo *outerrel = fpinfo->outerrel;
4170 RelOptInfo *innerrel = fpinfo->innerrel;
4171
4172 /* Should only be called in these cases. */
4173 Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
4174
4175 /*
4176 * If the given relation isn't a join relation, it doesn't have any lower
4177 * subqueries, so the Var isn't a subquery output column.
4178 */
4179 if (!IS_JOIN_REL(foreignrel))
4180 return false;
4181
4182 /*
4183 * If the Var doesn't belong to any lower subqueries, it isn't a subquery
4184 * output column.
4185 */
4186 if (!bms_is_member(node->varno, fpinfo->lower_subquery_rels))
4187 return false;
4188
4189 if (bms_is_member(node->varno, outerrel->relids))
4190 {
4191 /*
4192 * If outer relation is deparsed as a subquery, the Var is an output
4193 * column of the subquery; get the IDs for the relation/column alias.
4194 */
4195 if (fpinfo->make_outerrel_subquery)
4196 {
4197 get_relation_column_alias_ids(node, outerrel, relno, colno);
4198 return true;
4199 }
4200
4201 /* Otherwise, recurse into the outer relation. */
4202 return is_subquery_var(node, outerrel, relno, colno);
4203 }
4204 else
4205 {
4206 Assert(bms_is_member(node->varno, innerrel->relids));
4207
4208 /*
4209 * If inner relation is deparsed as a subquery, the Var is an output
4210 * column of the subquery; get the IDs for the relation/column alias.
4211 */
4212 if (fpinfo->make_innerrel_subquery)
4213 {
4214 get_relation_column_alias_ids(node, innerrel, relno, colno);
4215 return true;
4216 }
4217
4218 /* Otherwise, recurse into the inner relation. */
4219 return is_subquery_var(node, innerrel, relno, colno);
4220 }
4221}
static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:4228

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

3408{
3409 /*
3410 * We allow the foreign Var to have an implicit RelabelType, mainly so
3411 * that this'll work with varchar columns. Note that deparseRelabelType
3412 * will not print such a cast, so we're not breaking the restriction that
3413 * the expression print as a plain Var. We won't risk it for an implicit
3414 * cast that requires a function, nor for non-implicit RelabelType; such
3415 * cases seem too likely to involve semantics changes compared to what
3416 * would happen on the remote side.
3417 */
3418 if (IsA(node, RelabelType) &&
3419 ((RelabelType *) node)->relabelformat == COERCE_IMPLICIT_CAST)
3420 node = ((RelabelType *) node)->arg;
3421
3422 if (IsA(node, Var))
3423 {
3424 /*
3425 * The Var must be one that'll deparse as a foreign column reference
3426 * (cf. deparseVar).
3427 */
3428 Var *var = (Var *) node;
3429 Relids relids = context->scanrel->relids;
3430
3431 if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
3432 return true;
3433 }
3434
3435 return false;
3436}

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

3879{
3880 StringInfo buf = context->buf;
3881 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3882
3883 appendStringInfo(buf, "$%d::%s", paramindex, ptypename);
3884}

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

3905{
3906 StringInfo buf = context->buf;
3907 char *ptypename = deparse_type_name(paramtype, paramtypmod);
3908
3909 appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
3910}

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

2193{
2194 TupleDesc tupdesc = RelationGetDescr(rel);
2195 int i;
2196 int pindex;
2197 bool first;
2198 ListCell *lc;
2199
2200 /* Make sure the values_end_len is sensible */
2201 Assert((values_end_len > 0) && (values_end_len <= strlen(orig_query)));
2202
2203 /* Copy up to the end of the first record from the original query */
2204 appendBinaryStringInfo(buf, orig_query, values_end_len);
2205
2206 /*
2207 * Add records to VALUES clause (we already have parameters for the first
2208 * row, so start at the right offset).
2209 */
2210 pindex = num_params + 1;
2211 for (i = 0; i < num_rows; i++)
2212 {
2214
2215 first = true;
2216 foreach(lc, target_attrs)
2217 {
2218 int attnum = lfirst_int(lc);
2219 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2220
2221 if (!first)
2223 first = false;
2224
2225 if (attr->attgenerated)
2226 appendStringInfoString(buf, "DEFAULT");
2227 else
2228 {
2229 appendStringInfo(buf, "$%d", pindex);
2230 pindex++;
2231 }
2232 }
2233
2235 }
2236
2237 /* Copy stuff after VALUES clause from the original query */
2238 appendStringInfoString(buf, orig_query + values_end_len);
2239}

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

Referenced by execute_foreign_modify().