PostgreSQL Source Code  git master
deparse.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_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/makefuncs.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 "commands/tablecmds.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 **params_list)
 
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 **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 112 of file deparse.c.

◆ REL_ALIAS_PREFIX

#define REL_ALIAS_PREFIX   "r"

Definition at line 110 of file deparse.c.

◆ SUBQUERY_COL_ALIAS_PREFIX

#define SUBQUERY_COL_ALIAS_PREFIX   "c"

Definition at line 115 of file deparse.c.

◆ SUBQUERY_REL_ALIAS_PREFIX

#define SUBQUERY_REL_ALIAS_PREFIX   "s"

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

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

Function Documentation

◆ appendAggOrderBy()

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

Definition at line 3607 of file deparse.c.

3608 {
3609  StringInfo buf = context->buf;
3610  ListCell *lc;
3611  bool first = true;
3612 
3613  foreach(lc, orderList)
3614  {
3615  SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
3616  Node *sortexpr;
3617 
3618  if (!first)
3619  appendStringInfoString(buf, ", ");
3620  first = false;
3621 
3622  /* Deparse the sort expression proper. */
3623  sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
3624  false, context);
3625  /* Add decoration as needed. */
3626  appendOrderBySuffix(srt->sortop, exprType(sortexpr), srt->nulls_first,
3627  context);
3628  }
3629 }
static Node * deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
Definition: deparse.c:3908
static void appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first, deparse_expr_cxt *context)
Definition: deparse.c:3636
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
#define lfirst(lc)
Definition: pg_list.h:172
static char * buf
Definition: pg_test_fsync.c:67
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
Definition: nodes.h:129
Index tleSortGroupRef
Definition: parsenodes.h:1392
StringInfo buf
Definition: deparse.c:106

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

Referenced by deparseAggref().

◆ appendConditions()

static void appendConditions ( List exprs,
deparse_expr_cxt context 
)
static

Definition at line 1569 of file deparse.c.

1570 {
1571  int nestlevel;
1572  ListCell *lc;
1573  bool is_first = true;
1574  StringInfo buf = context->buf;
1575 
1576  /* Make sure any constants in the exprs are printed portably */
1577  nestlevel = set_transmission_modes();
1578 
1579  foreach(lc, exprs)
1580  {
1581  Expr *expr = (Expr *) lfirst(lc);
1582 
1583  /* Extract clause from RestrictInfo, if required */
1584  if (IsA(expr, RestrictInfo))
1585  expr = ((RestrictInfo *) expr)->clause;
1586 
1587  /* Connect expressions with "AND" and parenthesize each condition. */
1588  if (!is_first)
1589  appendStringInfoString(buf, " AND ");
1590 
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:2742
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
void reset_transmission_modes(int nestlevel)
int set_transmission_modes(void)
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188

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

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

◆ appendFunctionName()

static void appendFunctionName ( Oid  funcid,
deparse_expr_cxt context 
)
static

Definition at line 3873 of file deparse.c.

3874 {
3875  StringInfo buf = context->buf;
3876  HeapTuple proctup;
3877  Form_pg_proc procform;
3878  const char *proname;
3879 
3880  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3881  if (!HeapTupleIsValid(proctup))
3882  elog(ERROR, "cache lookup failed for function %u", funcid);
3883  procform = (Form_pg_proc) GETSTRUCT(proctup);
3884 
3885  /* Print schema name only if it's not pg_catalog */
3886  if (procform->pronamespace != PG_CATALOG_NAMESPACE)
3887  {
3888  const char *schemaname;
3889 
3890  schemaname = get_namespace_name(procform->pronamespace);
3891  appendStringInfo(buf, "%s.", quote_identifier(schemaname));
3892  }
3893 
3894  /* Always print the function name */
3895  proname = NameStr(procform->proname);
3897 
3898  ReleaseSysCache(proctup);
3899 }
#define NameStr(name)
Definition: c.h:735
#define ERROR
Definition: elog.h:39
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3348
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:11965
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
@ PROCOID
Definition: syscache.h:79

References appendStringInfo(), appendStringInfoString(), deparse_expr_cxt::buf, buf, elog(), ERROR, get_namespace_name(), GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), PROCOID, 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 3720 of file deparse.c.

3721 {
3722  StringInfo buf = context->buf;
3723  Query *query = context->root->parse;
3724  ListCell *lc;
3725  bool first = true;
3726 
3727  /* Nothing to be done, if there's no GROUP BY clause in the query. */
3728  if (!query->groupClause)
3729  return;
3730 
3731  appendStringInfoString(buf, " GROUP BY ");
3732 
3733  /*
3734  * Queries with grouping sets are not pushed down, so we don't expect
3735  * grouping sets here.
3736  */
3737  Assert(!query->groupingSets);
3738 
3739  /*
3740  * We intentionally print query->groupClause not processed_groupClause,
3741  * leaving it to the remote planner to get rid of any redundant GROUP BY
3742  * items again. This is necessary in case processed_groupClause reduced
3743  * to empty, and in any case the redundancy situation on the remote might
3744  * be different than what we think here.
3745  */
3746  foreach(lc, query->groupClause)
3747  {
3748  SortGroupClause *grp = (SortGroupClause *) lfirst(lc);
3749 
3750  if (!first)
3751  appendStringInfoString(buf, ", ");
3752  first = false;
3753 
3754  deparseSortGroupClause(grp->tleSortGroupRef, tlist, true, context);
3755  }
3756 }
Assert(fmt[strlen(fmt) - 1] !='\n')
Query * parse
Definition: pathnodes.h:199
List * groupClause
Definition: parsenodes.h:197
List * groupingSets
Definition: parsenodes.h:200
PlannerInfo * root
Definition: deparse.c:101

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

Referenced by deparseSelectStmtForRel().

◆ appendLimitClause()

static void appendLimitClause ( deparse_expr_cxt context)
static

Definition at line 3845 of file deparse.c.

3846 {
3847  PlannerInfo *root = context->root;
3848  StringInfo buf = context->buf;
3849  int nestlevel;
3850 
3851  /* Make sure any constants in the exprs are printed portably */
3852  nestlevel = set_transmission_modes();
3853 
3854  if (root->parse->limitCount)
3855  {
3856  appendStringInfoString(buf, " LIMIT ");
3857  deparseExpr((Expr *) root->parse->limitCount, context);
3858  }
3859  if (root->parse->limitOffset)
3860  {
3861  appendStringInfoString(buf, " OFFSET ");
3862  deparseExpr((Expr *) root->parse->limitOffset, context);
3863  }
3864 
3865  reset_transmission_modes(nestlevel);
3866 }
Node * limitCount
Definition: parsenodes.h:211
Node * limitOffset
Definition: parsenodes.h:210

References appendStringInfoString(), deparse_expr_cxt::buf, buf, deparseExpr(), Query::limitCount, Query::limitOffset, PlannerInfo::parse, reset_transmission_modes(), deparse_expr_cxt::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 3768 of file deparse.c.

3770 {
3771  ListCell *lcell;
3772  int nestlevel;
3773  const char *delim = " ";
3774  StringInfo buf = context->buf;
3775 
3776  /* Make sure any constants in the exprs are printed portably */
3777  nestlevel = set_transmission_modes();
3778 
3779  appendStringInfoString(buf, " ORDER BY");
3780  foreach(lcell, pathkeys)
3781  {
3782  PathKey *pathkey = lfirst(lcell);
3783  EquivalenceMember *em;
3784  Expr *em_expr;
3785  Oid oprid;
3786 
3787  if (has_final_sort)
3788  {
3789  /*
3790  * By construction, context->foreignrel is the input relation to
3791  * the final sort.
3792  */
3793  em = find_em_for_rel_target(context->root,
3794  pathkey->pk_eclass,
3795  context->foreignrel);
3796  }
3797  else
3798  em = find_em_for_rel(context->root,
3799  pathkey->pk_eclass,
3800  context->scanrel);
3801 
3802  /*
3803  * We don't expect any error here; it would mean that shippability
3804  * wasn't verified earlier. For the same reason, we don't recheck
3805  * shippability of the sort operator.
3806  */
3807  if (em == NULL)
3808  elog(ERROR, "could not find pathkey item to sort");
3809 
3810  em_expr = em->em_expr;
3811 
3812  /*
3813  * Lookup the operator corresponding to the strategy in the opclass.
3814  * The datatype used by the opfamily is not necessarily the same as
3815  * the expression type (for array types for example).
3816  */
3818  em->em_datatype,
3819  em->em_datatype,
3820  pathkey->pk_strategy);
3821  if (!OidIsValid(oprid))
3822  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
3823  pathkey->pk_strategy, em->em_datatype, em->em_datatype,
3824  pathkey->pk_opfamily);
3825 
3826  appendStringInfoString(buf, delim);
3827  deparseExpr(em_expr, context);
3828 
3829  /*
3830  * Here we need to use the expression's actual type to discover
3831  * whether the desired operator will be the default or not.
3832  */
3833  appendOrderBySuffix(oprid, exprType((Node *) em_expr),
3834  pathkey->pk_nulls_first, context);
3835 
3836  delim = ", ";
3837  }
3838  reset_transmission_modes(nestlevel);
3839 }
#define OidIsValid(objectId)
Definition: c.h:764
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:165
Oid oprid(Operator op)
Definition: parse_oper.c:250
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:1456
int pk_strategy
Definition: pathnodes.h:1455
Oid pk_opfamily
Definition: pathnodes.h:1454
RelOptInfo * foreignrel
Definition: deparse.c:102
RelOptInfo * scanrel
Definition: deparse.c:103

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

Referenced by deparseSelectStmtForRel().

◆ appendOrderBySuffix()

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

Definition at line 3636 of file deparse.c.

3638 {
3639  StringInfo buf = context->buf;
3640  TypeCacheEntry *typentry;
3641 
3642  /* See whether operator is default < or > for sort expr's datatype. */
3643  typentry = lookup_type_cache(sortcoltype,
3645 
3646  if (sortop == typentry->lt_opr)
3647  appendStringInfoString(buf, " ASC");
3648  else if (sortop == typentry->gt_opr)
3649  appendStringInfoString(buf, " DESC");
3650  else
3651  {
3652  HeapTuple opertup;
3653  Form_pg_operator operform;
3654 
3655  appendStringInfoString(buf, " USING ");
3656 
3657  /* Append operator name. */
3658  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(sortop));
3659  if (!HeapTupleIsValid(opertup))
3660  elog(ERROR, "cache lookup failed for operator %u", sortop);
3661  operform = (Form_pg_operator) GETSTRUCT(opertup);
3662  deparseOperatorName(buf, operform);
3663  ReleaseSysCache(opertup);
3664  }
3665 
3666  if (nulls_first)
3667  appendStringInfoString(buf, " NULLS FIRST");
3668  else
3669  appendStringInfoString(buf, " NULLS LAST");
3670 }
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform)
Definition: deparse.c:3264
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
@ OPEROID
Definition: syscache.h:72
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:344
#define TYPECACHE_GT_OPR
Definition: typcache.h:138
#define TYPECACHE_LT_OPR
Definition: typcache.h:137

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

Referenced by appendAggOrderBy(), and appendOrderByClause().

◆ build_tlist_to_deparse()

List* build_tlist_to_deparse ( RelOptInfo foreignrel)

Definition at line 1172 of file deparse.c.

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

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

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

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

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

1154 {
1156 
1157  if (!is_builtin(type_oid))
1158  flags |= FORMAT_TYPE_FORCE_QUALIFY;
1159 
1160  return format_type_extended(type_oid, typemod, flags);
1161 }
#define FORMAT_TYPE_TYPEMOD_GIVEN
Definition: builtins.h:121
#define FORMAT_TYPE_FORCE_QUALIFY
Definition: builtins.h:123
uint16 bits16
Definition: c.h:503
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 3515 of file deparse.c.

3516 {
3517  StringInfo buf = context->buf;
3518  bool use_variadic;
3519 
3520  /* Only basic, non-split aggregation accepted. */
3521  Assert(node->aggsplit == AGGSPLIT_SIMPLE);
3522 
3523  /* Check if need to print VARIADIC (cf. ruleutils.c) */
3524  use_variadic = node->aggvariadic;
3525 
3526  /* Find aggregate name from aggfnoid which is a pg_proc entry */
3527  appendFunctionName(node->aggfnoid, context);
3528  appendStringInfoChar(buf, '(');
3529 
3530  /* Add DISTINCT */
3531  appendStringInfoString(buf, (node->aggdistinct != NIL) ? "DISTINCT " : "");
3532 
3533  if (AGGKIND_IS_ORDERED_SET(node->aggkind))
3534  {
3535  /* Add WITHIN GROUP (ORDER BY ..) */
3536  ListCell *arg;
3537  bool first = true;
3538 
3539  Assert(!node->aggvariadic);
3540  Assert(node->aggorder != NIL);
3541 
3542  foreach(arg, node->aggdirectargs)
3543  {
3544  if (!first)
3545  appendStringInfoString(buf, ", ");
3546  first = false;
3547 
3548  deparseExpr((Expr *) lfirst(arg), context);
3549  }
3550 
3551  appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
3552  appendAggOrderBy(node->aggorder, node->args, context);
3553  }
3554  else
3555  {
3556  /* aggstar can be set only in zero-argument aggregates */
3557  if (node->aggstar)
3558  appendStringInfoChar(buf, '*');
3559  else
3560  {
3561  ListCell *arg;
3562  bool first = true;
3563 
3564  /* Add all the arguments */
3565  foreach(arg, node->args)
3566  {
3567  TargetEntry *tle = (TargetEntry *) lfirst(arg);
3568  Node *n = (Node *) tle->expr;
3569 
3570  if (tle->resjunk)
3571  continue;
3572 
3573  if (!first)
3574  appendStringInfoString(buf, ", ");
3575  first = false;
3576 
3577  /* Add VARIADIC */
3578  if (use_variadic && lnext(node->args, arg) == NULL)
3579  appendStringInfoString(buf, "VARIADIC ");
3580 
3581  deparseExpr((Expr *) n, context);
3582  }
3583  }
3584 
3585  /* Add ORDER BY */
3586  if (node->aggorder != NIL)
3587  {
3588  appendStringInfoString(buf, " ORDER BY ");
3589  appendAggOrderBy(node->aggorder, node->args, context);
3590  }
3591  }
3592 
3593  /* Add FILTER (WHERE ..) */
3594  if (node->aggfilter != NULL)
3595  {
3596  appendStringInfoString(buf, ") FILTER (WHERE ");
3597  deparseExpr((Expr *) node->aggfilter, context);
3598  }
3599 
3600  appendStringInfoChar(buf, ')');
3601 }
static void appendFunctionName(Oid funcid, deparse_expr_cxt *context)
Definition: deparse.c:3873
static void appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
Definition: deparse.c:3607
@ AGGSPLIT_SIMPLE
Definition: nodes.h:387
void * arg
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
Oid aggfnoid
Definition: primnodes.h:422
List * aggdistinct
Definition: primnodes.h:452
List * aggdirectargs
Definition: primnodes.h:443
List * args
Definition: primnodes.h:446
Expr * aggfilter
Definition: primnodes.h:455
List * aggorder
Definition: primnodes.h:449
Expr * expr
Definition: primnodes.h:1895

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

Referenced by deparseExpr().

◆ deparseAnalyzeInfoSql()

void deparseAnalyzeInfoSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2379 of file deparse.c.

2380 {
2382 
2383  /* We'll need the remote relation name as a literal. */
2385  deparseRelation(&relname, rel);
2386 
2387  appendStringInfoString(buf, "SELECT reltuples, relkind FROM pg_catalog.pg_class WHERE oid = ");
2389  appendStringInfoString(buf, "::pg_catalog.regclass");
2390 }
void deparseStringLiteral(StringInfo buf, const char *val)
Definition: deparse.c:2707
static void deparseRelation(StringInfo buf, Relation rel)
Definition: deparse.c:2667
NameData relname
Definition: pg_class.h:38
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
char data[NAMEDATALEN]
Definition: c.h:731

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

Referenced by postgresGetAnalyzeInfoForForeignTable().

◆ deparseAnalyzeSizeSql()

void deparseAnalyzeSizeSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2357 of file deparse.c.

2358 {
2360 
2361  /* We'll need the remote relation name as a literal. */
2363  deparseRelation(&relname, rel);
2364 
2365  appendStringInfoString(buf, "SELECT pg_catalog.pg_relation_size(");
2367  appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
2368 }

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

2422 {
2423  Oid relid = RelationGetRelid(rel);
2424  TupleDesc tupdesc = RelationGetDescr(rel);
2425  int i;
2426  char *colname;
2427  List *options;
2428  ListCell *lc;
2429  bool first = true;
2430 
2431  *retrieved_attrs = NIL;
2432 
2433  appendStringInfoString(buf, "SELECT ");
2434  for (i = 0; i < tupdesc->natts; i++)
2435  {
2436  /* Ignore dropped columns. */
2437  if (TupleDescAttr(tupdesc, i)->attisdropped)
2438  continue;
2439 
2440  if (!first)
2441  appendStringInfoString(buf, ", ");
2442  first = false;
2443 
2444  /* Use attribute name or column_name option. */
2445  colname = NameStr(TupleDescAttr(tupdesc, i)->attname);
2446  options = GetForeignColumnOptions(relid, i + 1);
2447 
2448  foreach(lc, options)
2449  {
2450  DefElem *def = (DefElem *) lfirst(lc);
2451 
2452  if (strcmp(def->defname, "column_name") == 0)
2453  {
2454  colname = defGetString(def);
2455  break;
2456  }
2457  }
2458 
2460 
2461  *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
2462  }
2463 
2464  /* Don't generate bad syntax for zero-column relation. */
2465  if (first)
2466  appendStringInfoString(buf, "NULL");
2467 
2468  /*
2469  * Construct FROM clause, and perhaps WHERE clause too, depending on the
2470  * selected sampling method.
2471  */
2472  appendStringInfoString(buf, " FROM ");
2473  deparseRelation(buf, rel);
2474 
2475  switch (sample_method)
2476  {
2477  case ANALYZE_SAMPLE_OFF:
2478  /* nothing to do here */
2479  break;
2480 
2481  case ANALYZE_SAMPLE_RANDOM:
2482  appendStringInfo(buf, " WHERE pg_catalog.random() < %f", sample_frac);
2483  break;
2484 
2485  case ANALYZE_SAMPLE_SYSTEM:
2486  appendStringInfo(buf, " TABLESAMPLE SYSTEM(%f)", (100.0 * sample_frac));
2487  break;
2488 
2490  appendStringInfo(buf, " TABLESAMPLE BERNOULLI(%f)", (100.0 * sample_frac));
2491  break;
2492 
2493  case ANALYZE_SAMPLE_AUTO:
2494  /* should have been resolved into actual method */
2495  elog(ERROR, "unexpected sampling method");
2496  break;
2497  }
2498 }
char * defGetString(DefElem *def)
Definition: define.c:49
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition: foreign.c:288
int i
Definition: isn.c:73
List * lappend_int(List *list, int datum)
Definition: list.c:356
NameData attname
Definition: pg_attribute.h:41
static char ** options
@ ANALYZE_SAMPLE_AUTO
Definition: postgres_fdw.h:143
@ ANALYZE_SAMPLE_OFF
Definition: postgres_fdw.h:142
@ ANALYZE_SAMPLE_BERNOULLI
Definition: postgres_fdw.h:146
@ ANALYZE_SAMPLE_SYSTEM
Definition: postgres_fdw.h:145
@ ANALYZE_SAMPLE_RANDOM
Definition: postgres_fdw.h:144
#define RelationGetRelid(relation)
Definition: rel.h:504
#define RelationGetDescr(relation)
Definition: rel.h:530
char * defname
Definition: parsenodes.h:809
#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 3489 of file deparse.c.

3490 {
3491  StringInfo buf = context->buf;
3492  bool first = true;
3493  ListCell *lc;
3494 
3495  appendStringInfoString(buf, "ARRAY[");
3496  foreach(lc, node->elements)
3497  {
3498  if (!first)
3499  appendStringInfoString(buf, ", ");
3500  deparseExpr(lfirst(lc), context);
3501  first = false;
3502  }
3503  appendStringInfoChar(buf, ']');
3504 
3505  /* If the array is empty, we need an explicit cast to the array type. */
3506  if (node->elements == NIL)
3507  appendStringInfo(buf, "::%s",
3508  deparse_type_name(node->array_typeid, -1));
3509 }
static char * deparse_type_name(Oid type_oid, int32 typemod)
Definition: deparse.c:1153
List * elements
Definition: primnodes.h:1307

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

Referenced by deparseExpr().

◆ deparseBoolExpr()

static void deparseBoolExpr ( BoolExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3368 of file deparse.c.

3369 {
3370  StringInfo buf = context->buf;
3371  const char *op = NULL; /* keep compiler quiet */
3372  bool first;
3373  ListCell *lc;
3374 
3375  switch (node->boolop)
3376  {
3377  case AND_EXPR:
3378  op = "AND";
3379  break;
3380  case OR_EXPR:
3381  op = "OR";
3382  break;
3383  case NOT_EXPR:
3384  appendStringInfoString(buf, "(NOT ");
3385  deparseExpr(linitial(node->args), context);
3386  appendStringInfoChar(buf, ')');
3387  return;
3388  }
3389 
3390  appendStringInfoChar(buf, '(');
3391  first = true;
3392  foreach(lc, node->args)
3393  {
3394  if (!first)
3395  appendStringInfo(buf, " %s ", op);
3396  deparseExpr((Expr *) lfirst(lc), context);
3397  first = false;
3398  }
3399  appendStringInfoChar(buf, ')');
3400 }
#define linitial(l)
Definition: pg_list.h:178
@ AND_EXPR
Definition: primnodes.h:858
@ OR_EXPR
Definition: primnodes.h:858
@ NOT_EXPR
Definition: primnodes.h:858
BoolExprType boolop
Definition: primnodes.h:866
List * args
Definition: primnodes.h:867

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

Referenced by deparseExpr().

◆ deparseCaseExpr()

static void deparseCaseExpr ( CaseExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3439 of file deparse.c.

3440 {
3441  StringInfo buf = context->buf;
3442  ListCell *lc;
3443 
3444  appendStringInfoString(buf, "(CASE");
3445 
3446  /* If this is a CASE arg WHEN then emit the arg expression */
3447  if (node->arg != NULL)
3448  {
3449  appendStringInfoChar(buf, ' ');
3450  deparseExpr(node->arg, context);
3451  }
3452 
3453  /* Add each condition/result of the CASE clause */
3454  foreach(lc, node->args)
3455  {
3456  CaseWhen *whenclause = (CaseWhen *) lfirst(lc);
3457 
3458  /* WHEN */
3459  appendStringInfoString(buf, " WHEN ");
3460  if (node->arg == NULL) /* CASE WHEN */
3461  deparseExpr(whenclause->expr, context);
3462  else /* CASE arg WHEN */
3463  {
3464  /* Ignore the CaseTestExpr and equality operator. */
3465  deparseExpr(lsecond(castNode(OpExpr, whenclause->expr)->args),
3466  context);
3467  }
3468 
3469  /* THEN */
3470  appendStringInfoString(buf, " THEN ");
3471  deparseExpr(whenclause->result, context);
3472  }
3473 
3474  /* add ELSE if present */
3475  if (node->defresult != NULL)
3476  {
3477  appendStringInfoString(buf, " ELSE ");
3478  deparseExpr(node->defresult, context);
3479  }
3480 
3481  /* append END */
3482  appendStringInfoString(buf, " END)");
3483 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
#define lsecond(l)
Definition: pg_list.h:183
Expr * arg
Definition: primnodes.h:1240
Expr * defresult
Definition: primnodes.h:1242
List * args
Definition: primnodes.h:1241
Expr * result
Definition: primnodes.h:1253
Expr * expr
Definition: primnodes.h:1252

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

Referenced by deparseExpr().

◆ deparseColumnRef()

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

Definition at line 2539 of file deparse.c.

2541 {
2542  /* We support fetching the remote side's CTID and OID. */
2543  if (varattno == SelfItemPointerAttributeNumber)
2544  {
2545  if (qualify_col)
2546  ADD_REL_QUALIFIER(buf, varno);
2547  appendStringInfoString(buf, "ctid");
2548  }
2549  else if (varattno < 0)
2550  {
2551  /*
2552  * All other system attributes are fetched as 0, except for table OID,
2553  * which is fetched as the local table OID. However, we must be
2554  * careful; the table could be beneath an outer join, in which case it
2555  * must go to NULL whenever the rest of the row does.
2556  */
2557  Oid fetchval = 0;
2558 
2559  if (varattno == TableOidAttributeNumber)
2560  fetchval = rte->relid;
2561 
2562  if (qualify_col)
2563  {
2564  appendStringInfoString(buf, "CASE WHEN (");
2565  ADD_REL_QUALIFIER(buf, varno);
2566  appendStringInfo(buf, "*)::text IS NOT NULL THEN %u END", fetchval);
2567  }
2568  else
2569  appendStringInfo(buf, "%u", fetchval);
2570  }
2571  else if (varattno == 0)
2572  {
2573  /* Whole row reference */
2574  Relation rel;
2575  Bitmapset *attrs_used;
2576 
2577  /* Required only to be passed down to deparseTargetList(). */
2578  List *retrieved_attrs;
2579 
2580  /*
2581  * The lock on the relation will be held by upper callers, so it's
2582  * fine to open it with no lock here.
2583  */
2584  rel = table_open(rte->relid, NoLock);
2585 
2586  /*
2587  * The local name of the foreign table can not be recognized by the
2588  * foreign server and the table it references on foreign server might
2589  * have different column ordering or different columns than those
2590  * declared locally. Hence we have to deparse whole-row reference as
2591  * ROW(columns referenced locally). Construct this by deparsing a
2592  * "whole row" attribute.
2593  */
2594  attrs_used = bms_add_member(NULL,
2596 
2597  /*
2598  * In case the whole-row reference is under an outer join then it has
2599  * to go NULL whenever the rest of the row goes NULL. Deparsing a join
2600  * query would always involve multiple relations, thus qualify_col
2601  * would be true.
2602  */
2603  if (qualify_col)
2604  {
2605  appendStringInfoString(buf, "CASE WHEN (");
2606  ADD_REL_QUALIFIER(buf, varno);
2607  appendStringInfoString(buf, "*)::text IS NOT NULL THEN ");
2608  }
2609 
2610  appendStringInfoString(buf, "ROW(");
2611  deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
2612  &retrieved_attrs);
2613  appendStringInfoChar(buf, ')');
2614 
2615  /* Complete the CASE WHEN statement started above. */
2616  if (qualify_col)
2617  appendStringInfoString(buf, " END");
2618 
2619  table_close(rel, NoLock);
2620  bms_free(attrs_used);
2621  }
2622  else
2623  {
2624  char *colname = NULL;
2625  List *options;
2626  ListCell *lc;
2627 
2628  /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
2629  Assert(!IS_SPECIAL_VARNO(varno));
2630 
2631  /*
2632  * If it's a column of a foreign table, and it has the column_name FDW
2633  * option, use that value.
2634  */
2635  options = GetForeignColumnOptions(rte->relid, varattno);
2636  foreach(lc, options)
2637  {
2638  DefElem *def = (DefElem *) lfirst(lc);
2639 
2640  if (strcmp(def->defname, "column_name") == 0)
2641  {
2642  colname = defGetString(def);
2643  break;
2644  }
2645  }
2646 
2647  /*
2648  * If it's a column of a regular table or it doesn't have column_name
2649  * FDW option, use attribute name.
2650  */
2651  if (colname == NULL)
2652  colname = get_attname(rte->relid, varattno, false);
2653 
2654  if (qualify_col)
2655  ADD_REL_QUALIFIER(buf, varno);
2656 
2658  }
2659 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:194
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:753
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:112
#define NoLock
Definition: lockdefs.h:34
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:826
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:219
#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 2878 of file deparse.c.

2879 {
2880  StringInfo buf = context->buf;
2881  Oid typoutput;
2882  bool typIsVarlena;
2883  char *extval;
2884  bool isfloat = false;
2885  bool isstring = false;
2886  bool needlabel;
2887 
2888  if (node->constisnull)
2889  {
2890  appendStringInfoString(buf, "NULL");
2891  if (showtype >= 0)
2892  appendStringInfo(buf, "::%s",
2894  node->consttypmod));
2895  return;
2896  }
2897 
2899  &typoutput, &typIsVarlena);
2900  extval = OidOutputFunctionCall(typoutput, node->constvalue);
2901 
2902  switch (node->consttype)
2903  {
2904  case INT2OID:
2905  case INT4OID:
2906  case INT8OID:
2907  case OIDOID:
2908  case FLOAT4OID:
2909  case FLOAT8OID:
2910  case NUMERICOID:
2911  {
2912  /*
2913  * No need to quote unless it's a special value such as 'NaN'.
2914  * See comments in get_const_expr().
2915  */
2916  if (strspn(extval, "0123456789+-eE.") == strlen(extval))
2917  {
2918  if (extval[0] == '+' || extval[0] == '-')
2919  appendStringInfo(buf, "(%s)", extval);
2920  else
2921  appendStringInfoString(buf, extval);
2922  if (strcspn(extval, "eE.") != strlen(extval))
2923  isfloat = true; /* it looks like a float */
2924  }
2925  else
2926  appendStringInfo(buf, "'%s'", extval);
2927  }
2928  break;
2929  case BITOID:
2930  case VARBITOID:
2931  appendStringInfo(buf, "B'%s'", extval);
2932  break;
2933  case BOOLOID:
2934  if (strcmp(extval, "t") == 0)
2935  appendStringInfoString(buf, "true");
2936  else
2937  appendStringInfoString(buf, "false");
2938  break;
2939  default:
2940  deparseStringLiteral(buf, extval);
2941  isstring = true;
2942  break;
2943  }
2944 
2945  pfree(extval);
2946 
2947  if (showtype == -1)
2948  return; /* never print type label */
2949 
2950  /*
2951  * For showtype == 0, append ::typename unless the constant will be
2952  * implicitly typed as the right type when it is read in.
2953  *
2954  * XXX this code has to be kept in sync with the behavior of the parser,
2955  * especially make_const.
2956  */
2957  switch (node->consttype)
2958  {
2959  case BOOLOID:
2960  case INT4OID:
2961  case UNKNOWNOID:
2962  needlabel = false;
2963  break;
2964  case NUMERICOID:
2965  needlabel = !isfloat || (node->consttypmod >= 0);
2966  break;
2967  default:
2968  if (showtype == -2)
2969  {
2970  /* label unless we printed it as an untyped string */
2971  needlabel = !isstring;
2972  }
2973  else
2974  needlabel = true;
2975  break;
2976  }
2977  if (needlabel || showtype > 0)
2978  appendStringInfo(buf, "::%s",
2980  node->consttypmod));
2981 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1746
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2889
void pfree(void *pointer)
Definition: mcxt.c:1456
Oid consttype
Definition: primnodes.h:290

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

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

◆ deparseDeleteSql()

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

Definition at line 2220 of file deparse.c.

2224 {
2225  appendStringInfoString(buf, "DELETE FROM ");
2226  deparseRelation(buf, rel);
2227  appendStringInfoString(buf, " WHERE ctid = $1");
2228 
2229  deparseReturningList(buf, rte, rtindex, rel,
2230  rel->trigdesc && rel->trigdesc->trig_delete_after_row,
2231  NIL, returningList, retrieved_attrs);
2232 }
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:2300
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 2249 of file deparse.c.

2256 {
2257  deparse_expr_cxt context;
2258 
2259  /* Set up context struct for recursion */
2260  context.root = root;
2261  context.foreignrel = foreignrel;
2262  context.scanrel = foreignrel;
2263  context.buf = buf;
2264  context.params_list = params_list;
2265 
2266  appendStringInfoString(buf, "DELETE FROM ");
2267  deparseRelation(buf, rel);
2268  if (foreignrel->reloptkind == RELOPT_JOINREL)
2269  appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2270 
2271  if (foreignrel->reloptkind == RELOPT_JOINREL)
2272  {
2273  List *ignore_conds = NIL;
2274 
2275  appendStringInfoString(buf, " USING ");
2276  deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2277  &ignore_conds, params_list);
2278  remote_conds = list_concat(remote_conds, ignore_conds);
2279  }
2280 
2281  if (remote_conds)
2282  {
2283  appendStringInfoString(buf, " WHERE ");
2284  appendConditions(remote_conds, &context);
2285  }
2286 
2287  if (foreignrel->reloptkind == RELOPT_JOINREL)
2288  deparseExplicitTargetList(returningList, true, retrieved_attrs,
2289  &context);
2290  else
2291  deparseReturningList(buf, planner_rt_fetch(rtindex, root),
2292  rtindex, rel, false,
2293  NIL, returningList, retrieved_attrs);
2294 }
#define REL_ALIAS_PREFIX
Definition: deparse.c:110
static void appendConditions(List *exprs, deparse_expr_cxt *context)
Definition: deparse.c:1569
static void deparseExplicitTargetList(List *tlist, bool is_returning, List **retrieved_attrs, deparse_expr_cxt *context)
Definition: deparse.c:1640
static void deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool use_alias, Index ignore_rel, List **ignore_conds, List **params_list)
Definition: deparse.c:1717
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:555
@ RELOPT_JOINREL
Definition: pathnodes.h:813
RelOptKind reloptkind
Definition: pathnodes.h:850
List ** params_list
Definition: deparse.c:107

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

Referenced by postgresPlanDirectModify().

◆ deparseDirectUpdateSql()

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

Definition at line 2135 of file deparse.c.

2144 {
2145  deparse_expr_cxt context;
2146  int nestlevel;
2147  bool first;
2148  RangeTblEntry *rte = planner_rt_fetch(rtindex, root);
2149  ListCell *lc,
2150  *lc2;
2151 
2152  /* Set up context struct for recursion */
2153  context.root = root;
2154  context.foreignrel = foreignrel;
2155  context.scanrel = foreignrel;
2156  context.buf = buf;
2157  context.params_list = params_list;
2158 
2159  appendStringInfoString(buf, "UPDATE ");
2160  deparseRelation(buf, rel);
2161  if (foreignrel->reloptkind == RELOPT_JOINREL)
2162  appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2163  appendStringInfoString(buf, " SET ");
2164 
2165  /* Make sure any constants in the exprs are printed portably */
2166  nestlevel = set_transmission_modes();
2167 
2168  first = true;
2169  forboth(lc, targetlist, lc2, targetAttrs)
2170  {
2171  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2172  int attnum = lfirst_int(lc2);
2173 
2174  /* update's new-value expressions shouldn't be resjunk */
2175  Assert(!tle->resjunk);
2176 
2177  if (!first)
2178  appendStringInfoString(buf, ", ");
2179  first = false;
2180 
2181  deparseColumnRef(buf, rtindex, attnum, rte, false);
2182  appendStringInfoString(buf, " = ");
2183  deparseExpr((Expr *) tle->expr, &context);
2184  }
2185 
2186  reset_transmission_modes(nestlevel);
2187 
2188  if (foreignrel->reloptkind == RELOPT_JOINREL)
2189  {
2190  List *ignore_conds = NIL;
2191 
2192  appendStringInfoString(buf, " FROM ");
2193  deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2194  &ignore_conds, params_list);
2195  remote_conds = list_concat(remote_conds, ignore_conds);
2196  }
2197 
2198  if (remote_conds)
2199  {
2200  appendStringInfoString(buf, " WHERE ");
2201  appendConditions(remote_conds, &context);
2202  }
2203 
2204  if (foreignrel->reloptkind == RELOPT_JOINREL)
2205  deparseExplicitTargetList(returningList, true, retrieved_attrs,
2206  &context);
2207  else
2208  deparseReturningList(buf, rte, rtindex, rel, false,
2209  NIL, returningList, retrieved_attrs);
2210 }
static void deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte, bool qualify_col)
Definition: deparse.c:2539
int16 attnum
Definition: pg_attribute.h:74
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
#define lfirst_int(lc)
Definition: pg_list.h:173

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

Referenced by postgresPlanDirectModify().

◆ deparseDistinctExpr()

static void deparseDistinctExpr ( DistinctExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3292 of file deparse.c.

3293 {
3294  StringInfo buf = context->buf;
3295 
3296  Assert(list_length(node->args) == 2);
3297 
3298  appendStringInfoChar(buf, '(');
3299  deparseExpr(linitial(node->args), context);
3300  appendStringInfoString(buf, " IS DISTINCT FROM ");
3301  deparseExpr(lsecond(node->args), context);
3302  appendStringInfoChar(buf, ')');
3303 }
static int list_length(const List *l)
Definition: pg_list.h:152
List * args
Definition: primnodes.h:763

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

Referenced by deparseExpr().

◆ deparseExplicitTargetList()

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

Definition at line 1640 of file deparse.c.

1644 {
1645  ListCell *lc;
1646  StringInfo buf = context->buf;
1647  int i = 0;
1648 
1649  *retrieved_attrs = NIL;
1650 
1651  foreach(lc, tlist)
1652  {
1653  TargetEntry *tle = lfirst_node(TargetEntry, lc);
1654 
1655  if (i > 0)
1656  appendStringInfoString(buf, ", ");
1657  else if (is_returning)
1658  appendStringInfoString(buf, " RETURNING ");
1659 
1660  deparseExpr((Expr *) tle->expr, context);
1661 
1662  *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
1663  i++;
1664  }
1665 
1666  if (i == 0 && !is_returning)
1667  appendStringInfoString(buf, "NULL");
1668 }

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

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

◆ deparseExpr()

static void deparseExpr ( Expr node,
deparse_expr_cxt context 
)
static

Definition at line 2742 of file deparse.c.

2743 {
2744  if (node == NULL)
2745  return;
2746 
2747  switch (nodeTag(node))
2748  {
2749  case T_Var:
2750  deparseVar((Var *) node, context);
2751  break;
2752  case T_Const:
2753  deparseConst((Const *) node, context, 0);
2754  break;
2755  case T_Param:
2756  deparseParam((Param *) node, context);
2757  break;
2758  case T_SubscriptingRef:
2759  deparseSubscriptingRef((SubscriptingRef *) node, context);
2760  break;
2761  case T_FuncExpr:
2762  deparseFuncExpr((FuncExpr *) node, context);
2763  break;
2764  case T_OpExpr:
2765  deparseOpExpr((OpExpr *) node, context);
2766  break;
2767  case T_DistinctExpr:
2768  deparseDistinctExpr((DistinctExpr *) node, context);
2769  break;
2770  case T_ScalarArrayOpExpr:
2771  deparseScalarArrayOpExpr((ScalarArrayOpExpr *) node, context);
2772  break;
2773  case T_RelabelType:
2774  deparseRelabelType((RelabelType *) node, context);
2775  break;
2776  case T_BoolExpr:
2777  deparseBoolExpr((BoolExpr *) node, context);
2778  break;
2779  case T_NullTest:
2780  deparseNullTest((NullTest *) node, context);
2781  break;
2782  case T_CaseExpr:
2783  deparseCaseExpr((CaseExpr *) node, context);
2784  break;
2785  case T_ArrayExpr:
2786  deparseArrayExpr((ArrayExpr *) node, context);
2787  break;
2788  case T_Aggref:
2789  deparseAggref((Aggref *) node, context);
2790  break;
2791  default:
2792  elog(ERROR, "unsupported expression type for deparse: %d",
2793  (int) nodeTag(node));
2794  break;
2795  }
2796 }
static void deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3439
static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3368
static void deparseAggref(Aggref *node, deparse_expr_cxt *context)
Definition: deparse.c:3515
static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
Definition: deparse.c:3355
static void deparseNullTest(NullTest *node, deparse_expr_cxt *context)
Definition: deparse.c:3406
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3134
static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype)
Definition: deparse.c:2878
static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3292
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3071
static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3489
static void deparseVar(Var *node, deparse_expr_cxt *context)
Definition: deparse.c:2807
static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
Definition: deparse.c:3025
static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3310
static void deparseParam(Param *node, deparse_expr_cxt *context)
Definition: deparse.c:2992
#define nodeTag(nodeptr)
Definition: nodes.h:133
Definition: primnodes.h:226

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

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

◆ deparseFromExpr()

static void deparseFromExpr ( List quals,
deparse_expr_cxt context 
)
static

Definition at line 1369 of file deparse.c.

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

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

Referenced by deparseSelectStmtForRel().

◆ deparseFromExprForRel()

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

Definition at line 1717 of file deparse.c.

1720 {
1721  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1722 
1723  if (IS_JOIN_REL(foreignrel))
1724  {
1725  StringInfoData join_sql_o;
1726  StringInfoData join_sql_i;
1727  RelOptInfo *outerrel = fpinfo->outerrel;
1728  RelOptInfo *innerrel = fpinfo->innerrel;
1729  bool outerrel_is_target = false;
1730  bool innerrel_is_target = false;
1731 
1732  if (ignore_rel > 0 && bms_is_member(ignore_rel, foreignrel->relids))
1733  {
1734  /*
1735  * If this is an inner join, add joinclauses to *ignore_conds and
1736  * set it to empty so that those can be deparsed into the WHERE
1737  * clause. Note that since the target relation can never be
1738  * within the nullable side of an outer join, those could safely
1739  * be pulled up into the WHERE clause (see foreign_join_ok()).
1740  * Note also that since the target relation is only inner-joined
1741  * to any other relation in the query, all conditions in the join
1742  * tree mentioning the target relation could be deparsed into the
1743  * WHERE clause by doing this recursively.
1744  */
1745  if (fpinfo->jointype == JOIN_INNER)
1746  {
1747  *ignore_conds = list_concat(*ignore_conds,
1748  fpinfo->joinclauses);
1749  fpinfo->joinclauses = NIL;
1750  }
1751 
1752  /*
1753  * Check if either of the input relations is the target relation.
1754  */
1755  if (outerrel->relid == ignore_rel)
1756  outerrel_is_target = true;
1757  else if (innerrel->relid == ignore_rel)
1758  innerrel_is_target = true;
1759  }
1760 
1761  /* Deparse outer relation if not the target relation. */
1762  if (!outerrel_is_target)
1763  {
1764  initStringInfo(&join_sql_o);
1765  deparseRangeTblRef(&join_sql_o, root, outerrel,
1766  fpinfo->make_outerrel_subquery,
1767  ignore_rel, ignore_conds, params_list);
1768 
1769  /*
1770  * If inner relation is the target relation, skip deparsing it.
1771  * Note that since the join of the target relation with any other
1772  * relation in the query is an inner join and can never be within
1773  * the nullable side of an outer join, the join could be
1774  * interchanged with higher-level joins (cf. identity 1 on outer
1775  * join reordering shown in src/backend/optimizer/README), which
1776  * means it's safe to skip the target-relation deparsing here.
1777  */
1778  if (innerrel_is_target)
1779  {
1780  Assert(fpinfo->jointype == JOIN_INNER);
1781  Assert(fpinfo->joinclauses == NIL);
1782  appendBinaryStringInfo(buf, join_sql_o.data, join_sql_o.len);
1783  return;
1784  }
1785  }
1786 
1787  /* Deparse inner relation if not the target relation. */
1788  if (!innerrel_is_target)
1789  {
1790  initStringInfo(&join_sql_i);
1791  deparseRangeTblRef(&join_sql_i, root, innerrel,
1792  fpinfo->make_innerrel_subquery,
1793  ignore_rel, ignore_conds, params_list);
1794 
1795  /*
1796  * If outer relation is the target relation, skip deparsing it.
1797  * See the above note about safety.
1798  */
1799  if (outerrel_is_target)
1800  {
1801  Assert(fpinfo->jointype == JOIN_INNER);
1802  Assert(fpinfo->joinclauses == NIL);
1803  appendBinaryStringInfo(buf, join_sql_i.data, join_sql_i.len);
1804  return;
1805  }
1806  }
1807 
1808  /* Neither of the relations is the target relation. */
1809  Assert(!outerrel_is_target && !innerrel_is_target);
1810 
1811  /*
1812  * For a join relation FROM clause entry is deparsed as
1813  *
1814  * ((outer relation) <join type> (inner relation) ON (joinclauses))
1815  */
1816  appendStringInfo(buf, "(%s %s JOIN %s ON ", join_sql_o.data,
1817  get_jointype_name(fpinfo->jointype), join_sql_i.data);
1818 
1819  /* Append join clause; (TRUE) if no join clause */
1820  if (fpinfo->joinclauses)
1821  {
1822  deparse_expr_cxt context;
1823 
1824  context.buf = buf;
1825  context.foreignrel = foreignrel;
1826  context.scanrel = foreignrel;
1827  context.root = root;
1828  context.params_list = params_list;
1829 
1830  appendStringInfoChar(buf, '(');
1831  appendConditions(fpinfo->joinclauses, &context);
1832  appendStringInfoChar(buf, ')');
1833  }
1834  else
1835  appendStringInfoString(buf, "(TRUE)");
1836 
1837  /* End the FROM clause entry. */
1838  appendStringInfoChar(buf, ')');
1839  }
1840  else
1841  {
1842  RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1843 
1844  /*
1845  * Core code already has some lock on each rel being planned, so we
1846  * can use NoLock here.
1847  */
1848  Relation rel = table_open(rte->relid, NoLock);
1849 
1850  deparseRelation(buf, rel);
1851 
1852  /*
1853  * Add a unique alias to avoid any conflict in relation names due to
1854  * pulled up subqueries in the query being built for a pushed down
1855  * join.
1856  */
1857  if (use_alias)
1858  appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, foreignrel->relid);
1859 
1860  table_close(rel, NoLock);
1861  }
1862 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:460
static void deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool make_subquery, Index ignore_rel, List **ignore_conds, List **params_list)
Definition: deparse.c:1868
const char * get_jointype_name(JoinType jointype)
Definition: deparse.c:1603
@ JOIN_INNER
Definition: nodes.h:304
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:227
RelOptInfo * outerrel
Definition: postgres_fdw.h:102
RelOptInfo * innerrel
Definition: postgres_fdw.h:103
Index relid
Definition: pathnodes.h:903

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

3072 {
3073  StringInfo buf = context->buf;
3074  bool use_variadic;
3075  bool first;
3076  ListCell *arg;
3077 
3078  /*
3079  * If the function call came from an implicit coercion, then just show the
3080  * first argument.
3081  */
3082  if (node->funcformat == COERCE_IMPLICIT_CAST)
3083  {
3084  deparseExpr((Expr *) linitial(node->args), context);
3085  return;
3086  }
3087 
3088  /*
3089  * If the function call came from a cast, then show the first argument
3090  * plus an explicit cast operation.
3091  */
3092  if (node->funcformat == COERCE_EXPLICIT_CAST)
3093  {
3094  Oid rettype = node->funcresulttype;
3095  int32 coercedTypmod;
3096 
3097  /* Get the typmod if this is a length-coercion function */
3098  (void) exprIsLengthCoercion((Node *) node, &coercedTypmod);
3099 
3100  deparseExpr((Expr *) linitial(node->args), context);
3101  appendStringInfo(buf, "::%s",
3102  deparse_type_name(rettype, coercedTypmod));
3103  return;
3104  }
3105 
3106  /* Check if need to print VARIADIC (cf. ruleutils.c) */
3107  use_variadic = node->funcvariadic;
3108 
3109  /*
3110  * Normal function: display as proname(args).
3111  */
3112  appendFunctionName(node->funcid, context);
3113  appendStringInfoChar(buf, '(');
3114 
3115  /* ... and all the arguments */
3116  first = true;
3117  foreach(arg, node->args)
3118  {
3119  if (!first)
3120  appendStringInfoString(buf, ", ");
3121  if (use_variadic && lnext(node->args, arg) == NULL)
3122  appendStringInfoString(buf, "VARIADIC ");
3123  deparseExpr((Expr *) lfirst(arg), context);
3124  first = false;
3125  }
3126  appendStringInfoChar(buf, ')');
3127 }
signed int int32
Definition: c.h:483
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:522
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:663
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:662
Oid funcid
Definition: primnodes.h:677
List * args
Definition: primnodes.h:695

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

Referenced by deparseExpr().

◆ deparseInsertSql()

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

Definition at line 1942 of file deparse.c.

1947 {
1948  TupleDesc tupdesc = RelationGetDescr(rel);
1949  AttrNumber pindex;
1950  bool first;
1951  ListCell *lc;
1952 
1953  appendStringInfoString(buf, "INSERT INTO ");
1954  deparseRelation(buf, rel);
1955 
1956  if (targetAttrs)
1957  {
1958  appendStringInfoChar(buf, '(');
1959 
1960  first = true;
1961  foreach(lc, targetAttrs)
1962  {
1963  int attnum = lfirst_int(lc);
1964 
1965  if (!first)
1966  appendStringInfoString(buf, ", ");
1967  first = false;
1968 
1969  deparseColumnRef(buf, rtindex, attnum, rte, false);
1970  }
1971 
1972  appendStringInfoString(buf, ") VALUES (");
1973 
1974  pindex = 1;
1975  first = true;
1976  foreach(lc, targetAttrs)
1977  {
1978  int attnum = lfirst_int(lc);
1979  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
1980 
1981  if (!first)
1982  appendStringInfoString(buf, ", ");
1983  first = false;
1984 
1985  if (attr->attgenerated)
1986  appendStringInfoString(buf, "DEFAULT");
1987  else
1988  {
1989  appendStringInfo(buf, "$%d", pindex);
1990  pindex++;
1991  }
1992  }
1993 
1994  appendStringInfoChar(buf, ')');
1995  }
1996  else
1997  appendStringInfoString(buf, " DEFAULT VALUES");
1998  *values_end_len = buf->len;
1999 
2000  if (doNothing)
2001  appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
2002 
2003  deparseReturningList(buf, rte, rtindex, rel,
2004  rel->trigdesc && rel->trigdesc->trig_insert_after_row,
2005  withCheckOptionList, returningList, retrieved_attrs);
2006 }
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:1106
@ 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:279
@ CMD_UPDATE
Definition: nodes.h:277
while(p+4<=pend)
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:485
Relids lower_subquery_rels
Definition: postgres_fdw.h:119
LockClauseStrength strength
Definition: plannodes.h:1385
List * rowMarks
Definition: pathnodes.h:368
Relids all_result_relids
Definition: pathnodes.h:351
CmdType commandType
Definition: parsenodes.h:127

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

Referenced by deparseSelectStmtForRel().

◆ deparseNullTest()

static void deparseNullTest ( NullTest node,
deparse_expr_cxt context 
)
static

Definition at line 3406 of file deparse.c.

3407 {
3408  StringInfo buf = context->buf;
3409 
3410  appendStringInfoChar(buf, '(');
3411  deparseExpr(node->arg, context);
3412 
3413  /*
3414  * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
3415  * shorter and traditional. If it's a rowtype input but we're applying a
3416  * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
3417  * correct.
3418  */
3419  if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
3420  {
3421  if (node->nulltesttype == IS_NULL)
3422  appendStringInfoString(buf, " IS NULL)");
3423  else
3424  appendStringInfoString(buf, " IS NOT NULL)");
3425  }
3426  else
3427  {
3428  if (node->nulltesttype == IS_NULL)
3429  appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)");
3430  else
3431  appendStringInfoString(buf, " IS DISTINCT FROM NULL)");
3432  }
3433 }
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2637
@ IS_NULL
Definition: primnodes.h:1686
NullTestType nulltesttype
Definition: primnodes.h:1693
Expr * arg
Definition: primnodes.h:1692

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

Referenced by deparseExpr().

◆ deparseOperatorName()

static void deparseOperatorName ( StringInfo  buf,
Form_pg_operator  opform 
)
static

Definition at line 3264 of file deparse.c.

3265 {
3266  char *opname;
3267 
3268  /* opname is not a SQL identifier, so we should not quote it. */
3269  opname = NameStr(opform->oprname);
3270 
3271  /* Print schema name only if it's not pg_catalog */
3272  if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
3273  {
3274  const char *opnspname;
3275 
3276  opnspname = get_namespace_name(opform->oprnamespace);
3277  /* Print fully qualified operator name. */
3278  appendStringInfo(buf, "OPERATOR(%s.%s)",
3279  quote_identifier(opnspname), opname);
3280  }
3281  else
3282  {
3283  /* Just print operator name. */
3284  appendStringInfoString(buf, opname);
3285  }
3286 }

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

3135 {
3136  StringInfo buf = context->buf;
3137  HeapTuple tuple;
3138  Form_pg_operator form;
3139  Expr *right;
3140  bool canSuppressRightConstCast = false;
3141  char oprkind;
3142 
3143  /* Retrieve information about the operator from system catalog. */
3144  tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
3145  if (!HeapTupleIsValid(tuple))
3146  elog(ERROR, "cache lookup failed for operator %u", node->opno);
3147  form = (Form_pg_operator) GETSTRUCT(tuple);
3148  oprkind = form->oprkind;
3149 
3150  /* Sanity check. */
3151  Assert((oprkind == 'l' && list_length(node->args) == 1) ||
3152  (oprkind == 'b' && list_length(node->args) == 2));
3153 
3154  right = llast(node->args);
3155 
3156  /* Always parenthesize the expression. */
3157  appendStringInfoChar(buf, '(');
3158 
3159  /* Deparse left operand, if any. */
3160  if (oprkind == 'b')
3161  {
3162  Expr *left = linitial(node->args);
3163  Oid leftType = exprType((Node *) left);
3164  Oid rightType = exprType((Node *) right);
3165  bool canSuppressLeftConstCast = false;
3166 
3167  /*
3168  * When considering a binary operator, if one operand is a Const that
3169  * can be printed as a bare string literal or NULL (i.e., it will look
3170  * like type UNKNOWN to the remote parser), the Const normally
3171  * receives an explicit cast to the operator's input type. However,
3172  * in Const-to-Var comparisons where both operands are of the same
3173  * type, we prefer to suppress the explicit cast, leaving the Const's
3174  * type resolution up to the remote parser. The remote's resolution
3175  * heuristic will assume that an unknown input type being compared to
3176  * a known input type is of that known type as well.
3177  *
3178  * This hack allows some cases to succeed where a remote column is
3179  * declared with a different type in the local (foreign) table. By
3180  * emitting "foreigncol = 'foo'" not "foreigncol = 'foo'::text" or the
3181  * like, we allow the remote parser to pick an "=" operator that's
3182  * compatible with whatever type the remote column really is, such as
3183  * an enum.
3184  *
3185  * We allow cast suppression to happen only when the other operand is
3186  * a plain foreign Var. Although the remote's unknown-type heuristic
3187  * would apply to other cases just as well, we would be taking a
3188  * bigger risk that the inferred type is something unexpected. With
3189  * this restriction, if anything goes wrong it's the user's fault for
3190  * not declaring the local column with the same type as the remote
3191  * column.
3192  */
3193  if (leftType == rightType)
3194  {
3195  if (IsA(left, Const))
3196  canSuppressLeftConstCast = isPlainForeignVar(right, context);
3197  else if (IsA(right, Const))
3198  canSuppressRightConstCast = isPlainForeignVar(left, context);
3199  }
3200 
3201  if (canSuppressLeftConstCast)
3202  deparseConst((Const *) left, context, -2);
3203  else
3204  deparseExpr(left, context);
3205 
3206  appendStringInfoChar(buf, ' ');
3207  }
3208 
3209  /* Deparse operator name. */
3210  deparseOperatorName(buf, form);
3211 
3212  /* Deparse right operand. */
3213  appendStringInfoChar(buf, ' ');
3214 
3215  if (canSuppressRightConstCast)
3216  deparseConst((Const *) right, context, -2);
3217  else
3218  deparseExpr(right, context);
3219 
3220  appendStringInfoChar(buf, ')');
3221 
3222  ReleaseSysCache(tuple);
3223 }
static bool isPlainForeignVar(Expr *node, deparse_expr_cxt *context)
Definition: deparse.c:3229
#define llast(l)
Definition: pg_list.h:198
Oid opno
Definition: primnodes.h:745

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

Referenced by deparseExpr().

◆ deparseParam()

static void deparseParam ( Param node,
deparse_expr_cxt context 
)
static

Definition at line 2992 of file deparse.c.

2993 {
2994  if (context->params_list)
2995  {
2996  int pindex = 0;
2997  ListCell *lc;
2998 
2999  /* find its index in params_list */
3000  foreach(lc, *context->params_list)
3001  {
3002  pindex++;
3003  if (equal(node, (Node *) lfirst(lc)))
3004  break;
3005  }
3006  if (lc == NULL)
3007  {
3008  /* not in list, so add it */
3009  pindex++;
3010  *context->params_list = lappend(*context->params_list, node);
3011  }
3012 
3013  printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
3014  }
3015  else
3016  {
3017  printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
3018  }
3019 }
static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3681
static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3707
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
Oid paramtype
Definition: primnodes.h:356

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

Referenced by deparseExpr().

◆ deparseRangeTblRef()

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

Definition at line 1868 of file deparse.c.

1871 {
1872  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1873 
1874  /* Should only be called in these cases. */
1875  Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1876 
1877  Assert(fpinfo->local_conds == NIL);
1878 
1879  /* If make_subquery is true, deparse the relation as a subquery. */
1880  if (make_subquery)
1881  {
1882  List *retrieved_attrs;
1883  int ncols;
1884 
1885  /*
1886  * The given relation shouldn't contain the target relation, because
1887  * this should only happen for input relations for a full join, and
1888  * such relations can never contain an UPDATE/DELETE target.
1889  */
1890  Assert(ignore_rel == 0 ||
1891  !bms_is_member(ignore_rel, foreignrel->relids));
1892 
1893  /* Deparse the subquery representing the relation. */
1894  appendStringInfoChar(buf, '(');
1895  deparseSelectStmtForRel(buf, root, foreignrel, NIL,
1896  fpinfo->remote_conds, NIL,
1897  false, false, true,
1898  &retrieved_attrs, params_list);
1899  appendStringInfoChar(buf, ')');
1900 
1901  /* Append the relation alias. */
1903  fpinfo->relation_index);
1904 
1905  /*
1906  * Append the column aliases if needed. Note that the subquery emits
1907  * expressions specified in the relation's reltarget (see
1908  * deparseSubqueryTargetList).
1909  */
1910  ncols = list_length(foreignrel->reltarget->exprs);
1911  if (ncols > 0)
1912  {
1913  int i;
1914 
1915  appendStringInfoChar(buf, '(');
1916  for (i = 1; i <= ncols; i++)
1917  {
1918  if (i > 1)
1919  appendStringInfoString(buf, ", ");
1920 
1922  }
1923  appendStringInfoChar(buf, ')');
1924  }
1925  }
1926  else
1927  deparseFromExprForRel(buf, root, foreignrel, true, ignore_rel,
1928  ignore_conds, params_list);
1929 }
#define SUBQUERY_REL_ALIAS_PREFIX
Definition: deparse.c:114
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:1229
#define SUBQUERY_COL_ALIAS_PREFIX
Definition: deparse.c:115

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

3356 {
3357  deparseExpr(node->arg, context);
3358  if (node->relabelformat != COERCE_IMPLICIT_CAST)
3359  appendStringInfo(context->buf, "::%s",
3361  node->resulttypmod));
3362 }
Oid resulttype
Definition: primnodes.h:1112
Expr * arg
Definition: primnodes.h:1111

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

Referenced by deparseExpr().

◆ deparseRelation()

static void deparseRelation ( StringInfo  buf,
Relation  rel 
)
static

Definition at line 2667 of file deparse.c.

2668 {
2669  ForeignTable *table;
2670  const char *nspname = NULL;
2671  const char *relname = NULL;
2672  ListCell *lc;
2673 
2674  /* obtain additional catalog information. */
2675  table = GetForeignTable(RelationGetRelid(rel));
2676 
2677  /*
2678  * Use value of FDW options if any, instead of the name of object itself.
2679  */
2680  foreach(lc, table->options)
2681  {
2682  DefElem *def = (DefElem *) lfirst(lc);
2683 
2684  if (strcmp(def->defname, "schema_name") == 0)
2685  nspname = defGetString(def);
2686  else if (strcmp(def->defname, "table_name") == 0)
2687  relname = defGetString(def);
2688  }
2689 
2690  /*
2691  * Note: we could skip printing the schema name if it's pg_catalog, but
2692  * that doesn't seem worth the trouble.
2693  */
2694  if (nspname == NULL)
2695  nspname = get_namespace_name(RelationGetNamespace(rel));
2696  if (relname == NULL)
2698 
2699  appendStringInfo(buf, "%s.%s",
2701 }
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:250
#define RelationGetRelationName(relation)
Definition: rel.h:538
#define RelationGetNamespace(relation)
Definition: rel.h:545
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 2300 of file deparse.c.

2306 {
2307  Bitmapset *attrs_used = NULL;
2308 
2309  if (trig_after_row)
2310  {
2311  /* whole-row reference acquires all non-system columns */
2312  attrs_used =
2314  }
2315 
2316  if (withCheckOptionList != NIL)
2317  {
2318  /*
2319  * We need the attrs, non-system and system, mentioned in the local
2320  * query's WITH CHECK OPTION list.
2321  *
2322  * Note: we do this to ensure that WCO constraints will be evaluated
2323  * on the data actually inserted/updated on the remote side, which
2324  * might differ from the data supplied by the core code, for example
2325  * as a result of remote triggers.
2326  */
2327  pull_varattnos((Node *) withCheckOptionList, rtindex,
2328  &attrs_used);
2329  }
2330 
2331  if (returningList != NIL)
2332  {
2333  /*
2334  * We need the attrs, non-system and system, mentioned in the local
2335  * query's RETURNING list.
2336  */
2337  pull_varattnos((Node *) returningList, rtindex,
2338  &attrs_used);
2339  }
2340 
2341  if (attrs_used != NULL)
2342  deparseTargetList(buf, rte, rtindex, rel, true, attrs_used, false,
2343  retrieved_attrs);
2344  else
2345  *retrieved_attrs = NIL;
2346 }
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:171
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:291

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

3311 {
3312  StringInfo buf = context->buf;
3313  HeapTuple tuple;
3314  Form_pg_operator form;
3315  Expr *arg1;
3316  Expr *arg2;
3317 
3318  /* Retrieve information about the operator from system catalog. */
3319  tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
3320  if (!HeapTupleIsValid(tuple))
3321  elog(ERROR, "cache lookup failed for operator %u", node->opno);
3322  form = (Form_pg_operator) GETSTRUCT(tuple);
3323 
3324  /* Sanity check. */
3325  Assert(list_length(node->args) == 2);
3326 
3327  /* Always parenthesize the expression. */
3328  appendStringInfoChar(buf, '(');
3329 
3330  /* Deparse left operand. */
3331  arg1 = linitial(node->args);
3332  deparseExpr(arg1, context);
3333  appendStringInfoChar(buf, ' ');
3334 
3335  /* Deparse operator name plus decoration. */
3336  deparseOperatorName(buf, form);
3337  appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
3338 
3339  /* Deparse right operand. */
3340  arg2 = lsecond(node->args);
3341  deparseExpr(arg2, context);
3342 
3343  appendStringInfoChar(buf, ')');
3344 
3345  /* Always parenthesize the expression. */
3346  appendStringInfoChar(buf, ')');
3347 
3348  ReleaseSysCache(tuple);
3349 }

References appendStringInfo(), appendStringInfoChar(), ScalarArrayOpExpr::args, Assert(), deparse_expr_cxt::buf, buf, deparseExpr(), deparseOperatorName(), elog(), ERROR, GETSTRUCT, HeapTupleIsValid, linitial, list_length(), lsecond, ObjectIdGetDatum(), OPEROID, 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 1311 of file deparse.c.

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

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

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

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

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

◆ deparseSortGroupClause()

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

Definition at line 3908 of file deparse.c.

3910 {
3911  StringInfo buf = context->buf;
3912  TargetEntry *tle;
3913  Expr *expr;
3914 
3915  tle = get_sortgroupref_tle(ref, tlist);
3916  expr = tle->expr;
3917 
3918  if (force_colno)
3919  {
3920  /* Use column-number form when requested by caller. */
3921  Assert(!tle->resjunk);
3922  appendStringInfo(buf, "%d", tle->resno);
3923  }
3924  else if (expr && IsA(expr, Const))
3925  {
3926  /*
3927  * Force a typecast here so that we don't emit something like "GROUP
3928  * BY 2", which will be misconstrued as a column position rather than
3929  * a constant.
3930  */
3931  deparseConst((Const *) expr, context, 1);
3932  }
3933  else if (!expr || IsA(expr, Var))
3934  deparseExpr(expr, context);
3935  else
3936  {
3937  /* Always parenthesize the expression. */
3938  appendStringInfoChar(buf, '(');
3939  deparseExpr(expr, context);
3940  appendStringInfoChar(buf, ')');
3941  }
3942 
3943  return (Node *) expr;
3944 }
AttrNumber resno
Definition: primnodes.h:1897
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition: tlist.c:345

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

Referenced by appendAggOrderBy(), and appendGroupByClause().

◆ deparseStringLiteral()

void deparseStringLiteral ( StringInfo  buf,
const char *  val 
)

Definition at line 2707 of file deparse.c.

2708 {
2709  const char *valptr;
2710 
2711  /*
2712  * Rather than making assumptions about the remote server's value of
2713  * standard_conforming_strings, always use E'foo' syntax if there are any
2714  * backslashes. This will fail on remote servers before 8.1, but those
2715  * are long out of support.
2716  */
2717  if (strchr(val, '\\') != NULL)
2719  appendStringInfoChar(buf, '\'');
2720  for (valptr = val; *valptr; valptr++)
2721  {
2722  char ch = *valptr;
2723 
2724  if (SQL_STR_DOUBLE(ch, true))
2727  }
2728  appendStringInfoChar(buf, '\'');
2729 }
#define ESCAPE_STRING_SYNTAX
Definition: c.h:1179
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1176
long val
Definition: informix.c:664

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

1677 {
1678  StringInfo buf = context->buf;
1679  RelOptInfo *foreignrel = context->foreignrel;
1680  bool first;
1681  ListCell *lc;
1682 
1683  /* Should only be called in these cases. */
1684  Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1685 
1686  first = true;
1687  foreach(lc, foreignrel->reltarget->exprs)
1688  {
1689  Node *node = (Node *) lfirst(lc);
1690 
1691  if (!first)
1692  appendStringInfoString(buf, ", ");
1693  first = false;
1694 
1695  deparseExpr((Expr *) node, context);
1696  }
1697 
1698  /* Don't generate bad syntax if no expressions */
1699  if (first)
1700  appendStringInfoString(buf, "NULL");
1701 }

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

Referenced by deparseSelectSql().

◆ deparseSubscriptingRef()

static void deparseSubscriptingRef ( SubscriptingRef node,
deparse_expr_cxt context 
)
static

Definition at line 3025 of file deparse.c.

3026 {
3027  StringInfo buf = context->buf;
3028  ListCell *lowlist_item;
3029  ListCell *uplist_item;
3030 
3031  /* Always parenthesize the expression. */
3032  appendStringInfoChar(buf, '(');
3033 
3034  /*
3035  * Deparse referenced array expression first. If that expression includes
3036  * a cast, we have to parenthesize to prevent the array subscript from
3037  * being taken as typename decoration. We can avoid that in the typical
3038  * case of subscripting a Var, but otherwise do it.
3039  */
3040  if (IsA(node->refexpr, Var))
3041  deparseExpr(node->refexpr, context);
3042  else
3043  {
3044  appendStringInfoChar(buf, '(');
3045  deparseExpr(node->refexpr, context);
3046  appendStringInfoChar(buf, ')');
3047  }
3048 
3049  /* Deparse subscript expressions. */
3050  lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
3051  foreach(uplist_item, node->refupperindexpr)
3052  {
3053  appendStringInfoChar(buf, '[');
3054  if (lowlist_item)
3055  {
3056  deparseExpr(lfirst(lowlist_item), context);
3057  appendStringInfoChar(buf, ':');
3058  lowlist_item = lnext(node->reflowerindexpr, lowlist_item);
3059  }
3060  deparseExpr(lfirst(uplist_item), context);
3061  appendStringInfoChar(buf, ']');
3062  }
3063 
3064  appendStringInfoChar(buf, ')');
3065 }
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
List * refupperindexpr
Definition: primnodes.h:620
Expr * refexpr
Definition: primnodes.h:628
List * reflowerindexpr
Definition: primnodes.h:626

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

Referenced by deparseExpr().

◆ deparseTargetList()

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

Definition at line 1403 of file deparse.c.

1411 {
1412  TupleDesc tupdesc = RelationGetDescr(rel);
1413  bool have_wholerow;
1414  bool first;
1415  int i;
1416 
1417  *retrieved_attrs = NIL;
1418 
1419  /* If there's a whole-row reference, we'll need all the columns. */
1421  attrs_used);
1422 
1423  first = true;
1424  for (i = 1; i <= tupdesc->natts; i++)
1425  {
1426  Form_pg_attribute attr = TupleDescAttr(tupdesc, i - 1);
1427 
1428  /* Ignore dropped attributes. */
1429  if (attr->attisdropped)
1430  continue;
1431 
1432  if (have_wholerow ||
1434  attrs_used))
1435  {
1436  if (!first)
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 2504 of file deparse.c.

2508 {
2509  ListCell *cell;
2510 
2511  appendStringInfoString(buf, "TRUNCATE ");
2512 
2513  foreach(cell, rels)
2514  {
2515  Relation rel = lfirst(cell);
2516 
2517  if (cell != list_head(rels))
2518  appendStringInfoString(buf, ", ");
2519 
2520  deparseRelation(buf, rel);
2521  }
2522 
2523  appendStringInfo(buf, " %s IDENTITY",
2524  restart_seqs ? "RESTART" : "CONTINUE");
2525 
2526  if (behavior == DROP_RESTRICT)
2527  appendStringInfoString(buf, " RESTRICT");
2528  else if (behavior == DROP_CASCADE)
2529  appendStringInfoString(buf, " CASCADE");
2530 }
@ DROP_CASCADE
Definition: parsenodes.h:2194
@ DROP_RESTRICT
Definition: parsenodes.h:2193

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

2080 {
2081  TupleDesc tupdesc = RelationGetDescr(rel);
2082  AttrNumber pindex;
2083  bool first;
2084  ListCell *lc;
2085 
2086  appendStringInfoString(buf, "UPDATE ");
2087  deparseRelation(buf, rel);
2088  appendStringInfoString(buf, " SET ");
2089 
2090  pindex = 2; /* ctid is always the first param */
2091  first = true;
2092  foreach(lc, targetAttrs)
2093  {
2094  int attnum = lfirst_int(lc);
2095  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2096 
2097  if (!first)
2098  appendStringInfoString(buf, ", ");
2099  first = false;
2100 
2101  deparseColumnRef(buf, rtindex, attnum, rte, false);
2102  if (attr->attgenerated)
2103  appendStringInfoString(buf, " = DEFAULT");
2104  else
2105  {
2106  appendStringInfo(buf, " = $%d", pindex);
2107  pindex++;
2108  }
2109  }
2110  appendStringInfoString(buf, " WHERE ctid = $1");
2111 
2112  deparseReturningList(buf, rte, rtindex, rel,
2113  rel->trigdesc && rel->trigdesc->trig_update_after_row,
2114  withCheckOptionList, returningList, retrieved_attrs);
2115 }
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 2807 of file deparse.c.

2808 {
2809  Relids relids = context->scanrel->relids;
2810  int relno;
2811  int colno;
2812 
2813  /* Qualify columns when multiple relations are involved. */
2814  bool qualify_col = (bms_membership(relids) == BMS_MULTIPLE);
2815 
2816  /*
2817  * If the Var belongs to the foreign relation that is deparsed as a
2818  * subquery, use the relation and column alias to the Var provided by the
2819  * subquery, instead of the remote name.
2820  */
2821  if (is_subquery_var(node, context->scanrel, &relno, &colno))
2822  {
2823  appendStringInfo(context->buf, "%s%d.%s%d",
2825  SUBQUERY_COL_ALIAS_PREFIX, colno);
2826  return;
2827  }
2828 
2829  if (bms_is_member(node->varno, relids) && node->varlevelsup == 0)
2830  deparseColumnRef(context->buf, node->varno, node->varattno,
2831  planner_rt_fetch(node->varno, context->root),
2832  qualify_col);
2833  else
2834  {
2835  /* Treat like a Param */
2836  if (context->params_list)
2837  {
2838  int pindex = 0;
2839  ListCell *lc;
2840 
2841  /* find its index in params_list */
2842  foreach(lc, *context->params_list)
2843  {
2844  pindex++;
2845  if (equal(node, (Node *) lfirst(lc)))
2846  break;
2847  }
2848  if (lc == NULL)
2849  {
2850  /* not in list, so add it */
2851  pindex++;
2852  *context->params_list = lappend(*context->params_list, node);
2853  }
2854 
2855  printRemoteParam(pindex, node->vartype, node->vartypmod, context);
2856  }
2857  else
2858  {
2859  printRemotePlaceholder(node->vartype, node->vartypmod, context);
2860  }
2861  }
2862 }
static bool is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:3953
AttrNumber varattno
Definition: primnodes.h:238
int varno
Definition: primnodes.h:233
Index varlevelsup
Definition: primnodes.h:258

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

Referenced by deparseExpr().

◆ foreign_expr_walker()

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

Definition at line 308 of file deparse.c.

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

1604 {
1605  switch (jointype)
1606  {
1607  case JOIN_INNER:
1608  return "INNER";
1609 
1610  case JOIN_LEFT:
1611  return "LEFT";
1612 
1613  case JOIN_RIGHT:
1614  return "RIGHT";
1615 
1616  case JOIN_FULL:
1617  return "FULL";
1618 
1619  default:
1620  /* Shouldn't come here, but protect from buggy code. */
1621  elog(ERROR, "unsupported join type %d", jointype);
1622  }
1623 
1624  /* Keep compiler happy */
1625  return NULL;
1626 }
@ JOIN_FULL
Definition: nodes.h:306
@ JOIN_RIGHT
Definition: nodes.h:307
@ JOIN_LEFT
Definition: nodes.h:305

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

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

4017 {
4018  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
4019  int i;
4020  ListCell *lc;
4021 
4022  /* Get the relation alias ID */
4023  *relno = fpinfo->relation_index;
4024 
4025  /* Get the column alias ID */
4026  i = 1;
4027  foreach(lc, foreignrel->reltarget->exprs)
4028  {
4029  Var *tlvar = (Var *) lfirst(lc);
4030 
4031  /*
4032  * Match reltarget entries only on varno/varattno. Ideally there
4033  * would be some cross-check on varnullingrels, but it's unclear what
4034  * to do exactly; we don't have enough context to know what that value
4035  * should be.
4036  */
4037  if (IsA(tlvar, Var) &&
4038  tlvar->varno == node->varno &&
4039  tlvar->varattno == node->varattno)
4040  {
4041  *colno = i;
4042  return;
4043  }
4044  i++;
4045  }
4046 
4047  /* Shouldn't get here */
4048  elog(ERROR, "unexpected expression in subquery output");
4049 }

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

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

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

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

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

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

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

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

3954 {
3955  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
3956  RelOptInfo *outerrel = fpinfo->outerrel;
3957  RelOptInfo *innerrel = fpinfo->innerrel;
3958 
3959  /* Should only be called in these cases. */
3960  Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
3961 
3962  /*
3963  * If the given relation isn't a join relation, it doesn't have any lower
3964  * subqueries, so the Var isn't a subquery output column.
3965  */
3966  if (!IS_JOIN_REL(foreignrel))
3967  return false;
3968 
3969  /*
3970  * If the Var doesn't belong to any lower subqueries, it isn't a subquery
3971  * output column.
3972  */
3973  if (!bms_is_member(node->varno, fpinfo->lower_subquery_rels))
3974  return false;
3975 
3976  if (bms_is_member(node->varno, outerrel->relids))
3977  {
3978  /*
3979  * If outer relation is deparsed as a subquery, the Var is an output
3980  * column of the subquery; get the IDs for the relation/column alias.
3981  */
3982  if (fpinfo->make_outerrel_subquery)
3983  {
3984  get_relation_column_alias_ids(node, outerrel, relno, colno);
3985  return true;
3986  }
3987 
3988  /* Otherwise, recurse into the outer relation. */
3989  return is_subquery_var(node, outerrel, relno, colno);
3990  }
3991  else
3992  {
3993  Assert(bms_is_member(node->varno, innerrel->relids));
3994 
3995  /*
3996  * If inner relation is deparsed as a subquery, the Var is an output
3997  * column of the subquery; get the IDs for the relation/column alias.
3998  */
3999  if (fpinfo->make_innerrel_subquery)
4000  {
4001  get_relation_column_alias_ids(node, innerrel, relno, colno);
4002  return true;
4003  }
4004 
4005  /* Otherwise, recurse into the inner relation. */
4006  return is_subquery_var(node, innerrel, relno, colno);
4007  }
4008 }
static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:4015

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

3230 {
3231  /*
3232  * We allow the foreign Var to have an implicit RelabelType, mainly so
3233  * that this'll work with varchar columns. Note that deparseRelabelType
3234  * will not print such a cast, so we're not breaking the restriction that
3235  * the expression print as a plain Var. We won't risk it for an implicit
3236  * cast that requires a function, nor for non-implicit RelabelType; such
3237  * cases seem too likely to involve semantics changes compared to what
3238  * would happen on the remote side.
3239  */
3240  if (IsA(node, RelabelType) &&
3241  ((RelabelType *) node)->relabelformat == COERCE_IMPLICIT_CAST)
3242  node = ((RelabelType *) node)->arg;
3243 
3244  if (IsA(node, Var))
3245  {
3246  /*
3247  * The Var must be one that'll deparse as a foreign column reference
3248  * (cf. deparseVar).
3249  */
3250  Var *var = (Var *) node;
3251  Relids relids = context->scanrel->relids;
3252 
3253  if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
3254  return true;
3255  }
3256 
3257  return false;
3258 }

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

Referenced by deparseOpExpr().

◆ printRemoteParam()

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

Definition at line 3681 of file deparse.c.

3683 {
3684  StringInfo buf = context->buf;
3685  char *ptypename = deparse_type_name(paramtype, paramtypmod);
3686 
3687  appendStringInfo(buf, "$%d::%s", paramindex, ptypename);
3688 }

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

Referenced by deparseParam(), and deparseVar().

◆ printRemotePlaceholder()

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

Definition at line 3707 of file deparse.c.

3709 {
3710  StringInfo buf = context->buf;
3711  char *ptypename = deparse_type_name(paramtype, paramtypmod);
3712 
3713  appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
3714 }

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

Referenced by deparseParam(), and deparseVar().

◆ rebuildInsertSql()

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

Definition at line 2015 of file deparse.c.

2019 {
2020  TupleDesc tupdesc = RelationGetDescr(rel);
2021  int i;
2022  int pindex;
2023  bool first;
2024  ListCell *lc;
2025 
2026  /* Make sure the values_end_len is sensible */
2027  Assert((values_end_len > 0) && (values_end_len <= strlen(orig_query)));
2028 
2029  /* Copy up to the end of the first record from the original query */
2030  appendBinaryStringInfo(buf, orig_query, values_end_len);
2031 
2032  /*
2033  * Add records to VALUES clause (we already have parameters for the first
2034  * row, so start at the right offset).
2035  */
2036  pindex = num_params + 1;
2037  for (i = 0; i < num_rows; i++)
2038  {
2039  appendStringInfoString(buf, ", (");
2040 
2041  first = true;
2042  foreach(lc, target_attrs)
2043  {
2044  int attnum = lfirst_int(lc);
2045  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2046 
2047  if (!first)
2048  appendStringInfoString(buf, ", ");
2049  first = false;
2050 
2051  if (attr->attgenerated)
2052  appendStringInfoString(buf, "DEFAULT");
2053  else
2054  {
2055  appendStringInfo(buf, "$%d", pindex);
2056  pindex++;
2057  }
2058  }
2059 
2060  appendStringInfoChar(buf, ')');
2061  }
2062 
2063  /* Copy stuff after VALUES clause from the original query */
2064  appendStringInfoString(buf, orig_query + values_end_len);
2065 }

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

Referenced by execute_foreign_modify().