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

Go to the source code of this file.

Data Structures

struct  foreign_glob_cxt
 
struct  foreign_loc_cxt
 
struct  deparse_expr_cxt
 

Macros

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

Typedefs

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

Enumerations

enum  FDWCollateState { FDW_COLLATE_NONE , FDW_COLLATE_SAFE , FDW_COLLATE_UNSAFE }
 

Functions

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

Macro Definition Documentation

◆ ADD_REL_QUALIFIER

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

Definition at line 110 of file deparse.c.

◆ REL_ALIAS_PREFIX

#define REL_ALIAS_PREFIX   "r"

Definition at line 108 of file deparse.c.

◆ SUBQUERY_COL_ALIAS_PREFIX

#define SUBQUERY_COL_ALIAS_PREFIX   "c"

Definition at line 113 of file deparse.c.

◆ SUBQUERY_REL_ALIAS_PREFIX

#define SUBQUERY_REL_ALIAS_PREFIX   "s"

Definition at line 112 of file deparse.c.

Typedef Documentation

◆ deparse_expr_cxt

◆ foreign_glob_cxt

◆ foreign_loc_cxt

Enumeration Type Documentation

◆ FDWCollateState

Enumerator
FDW_COLLATE_NONE 
FDW_COLLATE_SAFE 
FDW_COLLATE_UNSAFE 

Definition at line 78 of file deparse.c.

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

Function Documentation

◆ appendAggOrderBy()

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

Definition at line 3747 of file deparse.c.

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

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

Referenced by deparseAggref().

◆ appendConditions()

static void appendConditions ( List exprs,
deparse_expr_cxt context 
)
static

Definition at line 1569 of file deparse.c.

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

References appendStringInfoChar(), appendStringInfoString(), buf, context, deparseExpr(), IsA, lfirst, reset_transmission_modes(), and set_transmission_modes().

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

◆ appendFunctionName()

static void appendFunctionName ( Oid  funcid,
deparse_expr_cxt context 
)
static

Definition at line 4030 of file deparse.c.

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

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

Referenced by deparseAggref(), and deparseFuncExpr().

◆ appendGroupByClause()

static void appendGroupByClause ( List tlist,
deparse_expr_cxt context 
)
static

Definition at line 3860 of file deparse.c.

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

References appendStringInfoString(), Assert, buf, context, deparseSortGroupClause(), Query::groupClause, Query::groupingSets, lfirst, and SortGroupClause::tleSortGroupRef.

Referenced by deparseSelectStmtForRel().

◆ appendLimitClause()

static void appendLimitClause ( deparse_expr_cxt context)
static

Definition at line 4002 of file deparse.c.

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

References appendStringInfoString(), buf, context, deparseExpr(), reset_transmission_modes(), root, and set_transmission_modes().

Referenced by deparseSelectStmtForRel().

◆ appendOrderByClause()

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

Definition at line 3908 of file deparse.c.

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

References appendOrderBySuffix(), appendStringInfoString(), buf, context, deparseExpr(), elog, EquivalenceMember::em_datatype, EquivalenceMember::em_expr, ERROR, exprType(), find_em_for_rel(), find_em_for_rel_target(), get_opfamily_member(), IsA, lfirst, OidIsValid, oprid(), PathKey::pk_nulls_first, PathKey::pk_opfamily, PathKey::pk_strategy, reset_transmission_modes(), and set_transmission_modes().

Referenced by deparseSelectStmtForRel().

◆ appendOrderBySuffix()

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

Definition at line 3776 of file deparse.c.

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

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

Referenced by appendAggOrderBy(), and appendOrderByClause().

◆ appendWhereClause()

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

Definition at line 1606 of file deparse.c.

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

References appendConditions(), appendStringInfoString(), buf, context, lfirst, and NIL.

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

◆ build_tlist_to_deparse()

List* build_tlist_to_deparse ( RelOptInfo foreignrel)

Definition at line 1174 of file deparse.c.

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

References add_to_flat_tlist(), RestrictInfo::clause, PathTarget::exprs, PgFdwRelationInfo::grouped_tlist, if(), IS_UPPER_REL, lfirst_node, PgFdwRelationInfo::local_conds, NIL, pull_var_clause(), PVC_RECURSE_PLACEHOLDERS, and RelOptInfo::reltarget.

Referenced by estimate_path_cost_size(), and postgresGetForeignPlan().

◆ classifyConditions()

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

Definition at line 216 of file deparse.c.

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

References RestrictInfo::clause, is_foreign_expr(), lappend(), lfirst_node, NIL, and root.

Referenced by estimate_path_cost_size(), and postgresGetForeignRelSize().

◆ deparse_type_name()

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

Definition at line 1155 of file deparse.c.

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

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

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

◆ deparseAggref()

static void deparseAggref ( Aggref node,
deparse_expr_cxt context 
)
static

Definition at line 3655 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseAnalyzeInfoSql()

void deparseAnalyzeInfoSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2519 of file deparse.c.

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

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

Referenced by postgresGetAnalyzeInfoForForeignTable().

◆ deparseAnalyzeSizeSql()

void deparseAnalyzeSizeSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2497 of file deparse.c.

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

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

Referenced by postgresAnalyzeForeignTable().

◆ deparseAnalyzeSql()

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

Definition at line 2559 of file deparse.c.

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

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

Referenced by postgresAcquireSampleRowsFunc().

◆ deparseArrayExpr()

static void deparseArrayExpr ( ArrayExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3629 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseBoolExpr()

static void deparseBoolExpr ( BoolExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3508 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseCaseExpr()

static void deparseCaseExpr ( CaseExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3579 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseColumnRef()

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

Definition at line 2679 of file deparse.c.

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

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

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

◆ deparseConst()

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

Definition at line 3018 of file deparse.c.

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

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

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

◆ deparseDeleteSql()

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

Definition at line 2360 of file deparse.c.

2364 {
2365  appendStringInfoString(buf, "DELETE FROM ");
2366  deparseRelation(buf, rel);
2367  appendStringInfoString(buf, " WHERE ctid = $1");
2368 
2369  deparseReturningList(buf, rte, rtindex, rel,
2370  rel->trigdesc && rel->trigdesc->trig_delete_after_row,
2371  NIL, returningList, retrieved_attrs);
2372 }
static void deparseReturningList(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, bool trig_after_row, List *withCheckOptionList, List *returningList, List **retrieved_attrs)
Definition: deparse.c:2440
TriggerDesc * trigdesc
Definition: rel.h:117
bool trig_delete_after_row
Definition: reltrigger.h:67

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

Referenced by postgresPlanForeignModify().

◆ deparseDirectDeleteSql()

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

Definition at line 2389 of file deparse.c.

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

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

Referenced by postgresPlanDirectModify().

◆ deparseDirectUpdateSql()

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

Definition at line 2274 of file deparse.c.

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

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

Referenced by postgresPlanDirectModify().

◆ deparseDistinctExpr()

static void deparseDistinctExpr ( DistinctExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3432 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseExplicitTargetList()

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

Definition at line 1679 of file deparse.c.

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

References appendStringInfoString(), buf, context, deparseExpr(), TargetEntry::expr, i, lappend_int(), lfirst_node, and NIL.

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

◆ deparseExpr()

static void deparseExpr ( Expr node,
deparse_expr_cxt context 
)
static

Definition at line 2882 of file deparse.c.

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

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

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

◆ deparseFromExpr()

static void deparseFromExpr ( List quals,
deparse_expr_cxt context 
)
static

Definition at line 1371 of file deparse.c.

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

References appendStringInfoString(), appendWhereClause(), Assert, bms_membership(), BMS_MULTIPLE, buf, context, deparseFromExprForRel(), IS_JOIN_REL, IS_SIMPLE_REL, IS_UPPER_REL, list_free_deep(), NIL, and RelOptInfo::relids.

Referenced by deparseSelectStmtForRel().

◆ deparseFromExprForRel()

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

Definition at line 1759 of file deparse.c.

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

References appendBinaryStringInfo(), appendConditions(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), appendWhereClause(), Assert, bms_is_member(), buf, context, StringInfoData::data, deparseRangeTblRef(), deparseRelation(), 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, planner_rt_fetch, REL_ALIAS_PREFIX, RangeTblEntry::relid, RelOptInfo::relid, RelOptInfo::relids, root, str, table_close(), and table_open().

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

◆ deparseFuncExpr()

static void deparseFuncExpr ( FuncExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3211 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseInsertSql()

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

Definition at line 2081 of file deparse.c.

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

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

Referenced by postgresBeginForeignInsert(), and postgresPlanForeignModify().

◆ deparseLockingClause()

static void deparseLockingClause ( deparse_expr_cxt context)
static

Definition at line 1479 of file deparse.c.

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

References appendStringInfo(), appendStringInfoString(), bms_is_member(), bms_membership(), BMS_MULTIPLE, bms_next_member(), buf, CMD_DELETE, CMD_UPDATE, context, 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, root, PlanRowMark::strength, and while().

Referenced by deparseSelectStmtForRel().

◆ deparseNullTest()

static void deparseNullTest ( NullTest node,
deparse_expr_cxt context 
)
static

Definition at line 3546 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseOperatorName()

static void deparseOperatorName ( StringInfo  buf,
Form_pg_operator  opform 
)
static

Definition at line 3404 of file deparse.c.

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

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

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

◆ deparseOpExpr()

static void deparseOpExpr ( OpExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3274 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseParam()

static void deparseParam ( Param node,
deparse_expr_cxt context 
)
static

Definition at line 3132 of file deparse.c.

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

References context, equal(), lappend(), lfirst, Param::paramtype, printRemoteParam(), and printRemotePlaceholder().

Referenced by deparseExpr().

◆ deparseRangeTblRef()

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

Definition at line 2006 of file deparse.c.

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

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

Referenced by deparseFromExprForRel().

◆ deparseRelabelType()

static void deparseRelabelType ( RelabelType node,
deparse_expr_cxt context 
)
static

Definition at line 3495 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseRelation()

static void deparseRelation ( StringInfo  buf,
Relation  rel 
)
static

Definition at line 2807 of file deparse.c.

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

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

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

◆ deparseReturningList()

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

Definition at line 2440 of file deparse.c.

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

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

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

◆ deparseScalarArrayOpExpr()

static void deparseScalarArrayOpExpr ( ScalarArrayOpExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3450 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseSelectSql()

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

Definition at line 1313 of file deparse.c.

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

References appendStringInfoString(), PgFdwRelationInfo::attrs_used, buf, context, deparseExplicitTargetList(), deparseSubqueryTargetList(), deparseTargetList(), IS_JOIN_REL, IS_UPPER_REL, NoLock, planner_rt_fetch, RangeTblEntry::relid, RelOptInfo::relid, root, table_close(), and table_open().

Referenced by deparseSelectStmtForRel().

◆ deparseSelectStmtForRel()

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

Definition at line 1231 of file deparse.c.

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

References appendConditions(), appendGroupByClause(), appendLimitClause(), appendOrderByClause(), appendStringInfoString(), Assert, buf, context, deparseFromExpr(), deparseLockingClause(), deparseSelectSql(), IS_JOIN_REL, IS_SIMPLE_REL, IS_UPPER_REL, PgFdwRelationInfo::outerrel, PgFdwRelationInfo::remote_conds, and root.

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

◆ deparseSortGroupClause()

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

Definition at line 4065 of file deparse.c.

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

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

Referenced by appendAggOrderBy(), and appendGroupByClause().

◆ deparseStringLiteral()

void deparseStringLiteral ( StringInfo  buf,
const char *  val 
)

Definition at line 2847 of file deparse.c.

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

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

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

◆ deparseSubqueryTargetList()

static void deparseSubqueryTargetList ( deparse_expr_cxt context)
static

Definition at line 1715 of file deparse.c.

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

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

Referenced by deparseSelectSql().

◆ deparseSubscriptingRef()

static void deparseSubscriptingRef ( SubscriptingRef node,
deparse_expr_cxt context 
)
static

Definition at line 3165 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseTargetList()

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

Definition at line 1403 of file deparse.c.

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

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

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

◆ deparseTruncateSql()

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

Definition at line 2644 of file deparse.c.

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

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

Referenced by postgresExecForeignTruncate().

◆ deparseUpdateSql()

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

Definition at line 2214 of file deparse.c.

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

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

Referenced by postgresPlanForeignModify().

◆ deparseVar()

static void deparseVar ( Var node,
deparse_expr_cxt context 
)
static

Definition at line 2947 of file deparse.c.

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

References appendStringInfo(), bms_is_member(), bms_membership(), BMS_MULTIPLE, context, deparseColumnRef(), equal(), is_subquery_var(), lappend(), lfirst, planner_rt_fetch, printRemoteParam(), printRemotePlaceholder(), SUBQUERY_COL_ALIAS_PREFIX, SUBQUERY_REL_ALIAS_PREFIX, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by deparseExpr().

◆ foreign_expr_walker()

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

Definition at line 310 of file deparse.c.

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

References a, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggorder, AGGSPLIT_SIMPLE, RelabelType::arg, CaseExpr::arg, NullTest::arg, Aggref::args, OpExpr::args, ScalarArrayOpExpr::args, CaseExpr::args, b, bms_is_member(), foreign_loc_cxt::collation, DatumGetObjectId(), CaseExpr::defresult, CaseWhen::expr, TargetEntry::expr, exprType(), FDW_COLLATE_NONE, FDW_COLLATE_SAFE, FDW_COLLATE_UNSAFE, fe(), FirstNormalObjectId, foreign_glob_cxt::foreignrel, get_sortgroupref_tle(), TypeCacheEntry::gt_opr, if(), InvalidOid, is_shippable(), IS_UPPER_REL, IsA, lfirst, lfirst_node, linitial, list_length(), lookup_type_cache(), TypeCacheEntry::lt_opr, nodeTag, OidIsValid, OpExpr::opno, ScalarArrayOpExpr::opno, PARAM_MULTIEXPR, Param::paramkind, SubscriptingRef::refassgnexpr, SubscriptingRef::refexpr, SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, foreign_glob_cxt::relids, CaseWhen::result, SelfItemPointerAttributeNumber, SortGroupClause::sortop, foreign_loc_cxt::state, strip_implicit_coercions(), SortGroupClause::tleSortGroupRef, TYPECACHE_GT_OPR, TYPECACHE_LT_OPR, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by is_foreign_expr().

◆ get_jointype_name()

const char* get_jointype_name ( JoinType  jointype)

Definition at line 1639 of file deparse.c.

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

References elog, ERROR, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, and JOIN_SEMI.

Referenced by deparseFromExprForRel(), and foreign_join_ok().

◆ get_relation_column_alias_ids()

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

Definition at line 4172 of file deparse.c.

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

References elog, ERROR, PathTarget::exprs, i, IsA, lfirst, PgFdwRelationInfo::relation_index, RelOptInfo::reltarget, Var::varattno, and Var::varno.

Referenced by is_subquery_var().

◆ is_foreign_expr()

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

Definition at line 242 of file deparse.c.

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

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

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

◆ is_foreign_param()

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

Definition at line 1080 of file deparse.c.

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

References bms_is_member(), if(), IS_UPPER_REL, nodeTag, PgFdwRelationInfo::outerrel, RelOptInfo::relids, Var::varlevelsup, and Var::varno.

Referenced by foreign_grouping_ok().

◆ is_foreign_pathkey()

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

Definition at line 1121 of file deparse.c.

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

References EquivalenceClass::ec_has_volatile, find_em_for_rel(), if(), is_shippable(), PathKey::pk_opfamily, and root.

Referenced by get_useful_pathkeys_for_relation().

◆ is_subquery_var()

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

Definition at line 4110 of file deparse.c.

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

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

Referenced by deparseVar().

◆ isPlainForeignVar()

static bool isPlainForeignVar ( Expr node,
deparse_expr_cxt context 
)
static

Definition at line 3369 of file deparse.c.

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

References bms_is_member(), COERCE_IMPLICIT_CAST, context, IsA, Var::varlevelsup, and Var::varno.

Referenced by deparseOpExpr().

◆ printRemoteParam()

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

Definition at line 3821 of file deparse.c.

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

References appendStringInfo(), buf, context, and deparse_type_name().

Referenced by deparseParam(), and deparseVar().

◆ printRemotePlaceholder()

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

Definition at line 3847 of file deparse.c.

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

References appendStringInfo(), buf, context, and deparse_type_name().

Referenced by deparseParam(), and deparseVar().

◆ rebuildInsertSql()

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

Definition at line 2154 of file deparse.c.

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

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

Referenced by execute_foreign_modify().