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 deparseAnalyzeSql (StringInfo buf, Relation rel, 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 3538 of file deparse.c.

3539 {
3540  StringInfo buf = context->buf;
3541  ListCell *lc;
3542  bool first = true;
3543 
3544  foreach(lc, orderList)
3545  {
3546  SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
3547  Node *sortexpr;
3548 
3549  if (!first)
3550  appendStringInfoString(buf, ", ");
3551  first = false;
3552 
3553  /* Deparse the sort expression proper. */
3554  sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
3555  false, context);
3556  /* Add decoration as needed. */
3557  appendOrderBySuffix(srt->sortop, exprType(sortexpr), srt->nulls_first,
3558  context);
3559  }
3560 }
static Node * deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
Definition: deparse.c:3832
static void appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first, deparse_expr_cxt *context)
Definition: deparse.c:3567
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
#define lfirst(lc)
Definition: pg_list.h:170
static char * buf
Definition: pg_test_fsync.c:67
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
Definition: nodes.h:112
Index tleSortGroupRef
Definition: parsenodes.h:1320
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:2673
#define IsA(nodeptr, _type_)
Definition: nodes.h:162
void reset_transmission_modes(int nestlevel)
int set_transmission_modes(void)
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c: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 3797 of file deparse.c.

3798 {
3799  StringInfo buf = context->buf;
3800  HeapTuple proctup;
3801  Form_pg_proc procform;
3802  const char *proname;
3803 
3804  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3805  if (!HeapTupleIsValid(proctup))
3806  elog(ERROR, "cache lookup failed for function %u", funcid);
3807  procform = (Form_pg_proc) GETSTRUCT(proctup);
3808 
3809  /* Print schema name only if it's not pg_catalog */
3810  if (procform->pronamespace != PG_CATALOG_NAMESPACE)
3811  {
3812  const char *schemaname;
3813 
3814  schemaname = get_namespace_name(procform->pronamespace);
3815  appendStringInfo(buf, "%s.", quote_identifier(schemaname));
3816  }
3817 
3818  /* Always print the function name */
3819  proname = NameStr(procform->proname);
3821 
3822  ReleaseSysCache(proctup);
3823 }
#define NameStr(name)
Definition: c.h:682
#define ERROR
Definition: elog.h:35
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
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:600
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:11529
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ 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 3651 of file deparse.c.

3652 {
3653  StringInfo buf = context->buf;
3654  Query *query = context->root->parse;
3655  ListCell *lc;
3656  bool first = true;
3657 
3658  /* Nothing to be done, if there's no GROUP BY clause in the query. */
3659  if (!query->groupClause)
3660  return;
3661 
3662  appendStringInfoString(buf, " GROUP BY ");
3663 
3664  /*
3665  * Queries with grouping sets are not pushed down, so we don't expect
3666  * grouping sets here.
3667  */
3668  Assert(!query->groupingSets);
3669 
3670  foreach(lc, query->groupClause)
3671  {
3672  SortGroupClause *grp = (SortGroupClause *) lfirst(lc);
3673 
3674  if (!first)
3675  appendStringInfoString(buf, ", ");
3676  first = false;
3677 
3678  deparseSortGroupClause(grp->tleSortGroupRef, tlist, true, context);
3679  }
3680 }
Assert(fmt[strlen(fmt) - 1] !='\n')
Query * parse
Definition: pathnodes.h:196
List * groupClause
Definition: parsenodes.h:170
List * groupingSets
Definition: parsenodes.h:173
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 3769 of file deparse.c.

3770 {
3771  PlannerInfo *root = context->root;
3772  StringInfo buf = context->buf;
3773  int nestlevel;
3774 
3775  /* Make sure any constants in the exprs are printed portably */
3776  nestlevel = set_transmission_modes();
3777 
3778  if (root->parse->limitCount)
3779  {
3780  appendStringInfoString(buf, " LIMIT ");
3781  deparseExpr((Expr *) root->parse->limitCount, context);
3782  }
3783  if (root->parse->limitOffset)
3784  {
3785  appendStringInfoString(buf, " OFFSET ");
3786  deparseExpr((Expr *) root->parse->limitOffset, context);
3787  }
3788 
3789  reset_transmission_modes(nestlevel);
3790 }
Node * limitCount
Definition: parsenodes.h:184
Node * limitOffset
Definition: parsenodes.h:183

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

3694 {
3695  ListCell *lcell;
3696  int nestlevel;
3697  const char *delim = " ";
3698  StringInfo buf = context->buf;
3699 
3700  /* Make sure any constants in the exprs are printed portably */
3701  nestlevel = set_transmission_modes();
3702 
3703  appendStringInfoString(buf, " ORDER BY");
3704  foreach(lcell, pathkeys)
3705  {
3706  PathKey *pathkey = lfirst(lcell);
3707  EquivalenceMember *em;
3708  Expr *em_expr;
3709  Oid oprid;
3710 
3711  if (has_final_sort)
3712  {
3713  /*
3714  * By construction, context->foreignrel is the input relation to
3715  * the final sort.
3716  */
3717  em = find_em_for_rel_target(context->root,
3718  pathkey->pk_eclass,
3719  context->foreignrel);
3720  }
3721  else
3722  em = find_em_for_rel(context->root,
3723  pathkey->pk_eclass,
3724  context->scanrel);
3725 
3726  /*
3727  * We don't expect any error here; it would mean that shippability
3728  * wasn't verified earlier. For the same reason, we don't recheck
3729  * shippability of the sort operator.
3730  */
3731  if (em == NULL)
3732  elog(ERROR, "could not find pathkey item to sort");
3733 
3734  em_expr = em->em_expr;
3735 
3736  /*
3737  * Lookup the operator corresponding to the strategy in the opclass.
3738  * The datatype used by the opfamily is not necessarily the same as
3739  * the expression type (for array types for example).
3740  */
3742  em->em_datatype,
3743  em->em_datatype,
3744  pathkey->pk_strategy);
3745  if (!OidIsValid(oprid))
3746  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
3747  pathkey->pk_strategy, em->em_datatype, em->em_datatype,
3748  pathkey->pk_opfamily);
3749 
3750  appendStringInfoString(buf, delim);
3751  deparseExpr(em_expr, context);
3752 
3753  /*
3754  * Here we need to use the expression's actual type to discover
3755  * whether the desired operator will be the default or not.
3756  */
3757  appendOrderBySuffix(oprid, exprType((Node *) em_expr),
3758  pathkey->pk_nulls_first, context);
3759 
3760  delim = ", ";
3761  }
3762  reset_transmission_modes(nestlevel);
3763 }
#define OidIsValid(objectId)
Definition: c.h:711
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:1370
int pk_strategy
Definition: pathnodes.h:1369
EquivalenceClass * pk_eclass
Definition: pathnodes.h:1367
Oid pk_opfamily
Definition: pathnodes.h:1368
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_eclass, 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 3567 of file deparse.c.

3569 {
3570  StringInfo buf = context->buf;
3571  TypeCacheEntry *typentry;
3572 
3573  /* See whether operator is default < or > for sort expr's datatype. */
3574  typentry = lookup_type_cache(sortcoltype,
3576 
3577  if (sortop == typentry->lt_opr)
3578  appendStringInfoString(buf, " ASC");
3579  else if (sortop == typentry->gt_opr)
3580  appendStringInfoString(buf, " DESC");
3581  else
3582  {
3583  HeapTuple opertup;
3584  Form_pg_operator operform;
3585 
3586  appendStringInfoString(buf, " USING ");
3587 
3588  /* Append operator name. */
3589  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(sortop));
3590  if (!HeapTupleIsValid(opertup))
3591  elog(ERROR, "cache lookup failed for operator %u", sortop);
3592  operform = (Form_pg_operator) GETSTRUCT(opertup);
3593  deparseOperatorName(buf, operform);
3594  ReleaseSysCache(opertup);
3595  }
3596 
3597  if (nulls_first)
3598  appendStringInfoString(buf, " NULLS FIRST");
3599  else
3600  appendStringInfoString(buf, " NULLS LAST");
3601 }
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform)
Definition: deparse.c:3195
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:339
#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:793
#define lfirst_node(type, lc)
Definition: pg_list.h:174
#define NIL
Definition: pg_list.h:66
Definition: pg_list.h:52
List * exprs
Definition: pathnodes.h:1415
struct PathTarget * reltarget
Definition: pathnodes.h:837
Expr * clause
Definition: pathnodes.h:2423
List * add_to_flat_tlist(List *tlist, List *exprs)
Definition: tlist.c:132
List * pull_var_clause(Node *node, int flags)
Definition: var.c:597

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:112
#define FORMAT_TYPE_FORCE_QUALIFY
Definition: builtins.h:114
uint16 bits16
Definition: c.h:450
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 3446 of file deparse.c.

3447 {
3448  StringInfo buf = context->buf;
3449  bool use_variadic;
3450 
3451  /* Only basic, non-split aggregation accepted. */
3452  Assert(node->aggsplit == AGGSPLIT_SIMPLE);
3453 
3454  /* Check if need to print VARIADIC (cf. ruleutils.c) */
3455  use_variadic = node->aggvariadic;
3456 
3457  /* Find aggregate name from aggfnoid which is a pg_proc entry */
3458  appendFunctionName(node->aggfnoid, context);
3459  appendStringInfoChar(buf, '(');
3460 
3461  /* Add DISTINCT */
3462  appendStringInfoString(buf, (node->aggdistinct != NIL) ? "DISTINCT " : "");
3463 
3464  if (AGGKIND_IS_ORDERED_SET(node->aggkind))
3465  {
3466  /* Add WITHIN GROUP (ORDER BY ..) */
3467  ListCell *arg;
3468  bool first = true;
3469 
3470  Assert(!node->aggvariadic);
3471  Assert(node->aggorder != NIL);
3472 
3473  foreach(arg, node->aggdirectargs)
3474  {
3475  if (!first)
3476  appendStringInfoString(buf, ", ");
3477  first = false;
3478 
3479  deparseExpr((Expr *) lfirst(arg), context);
3480  }
3481 
3482  appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
3483  appendAggOrderBy(node->aggorder, node->args, context);
3484  }
3485  else
3486  {
3487  /* aggstar can be set only in zero-argument aggregates */
3488  if (node->aggstar)
3489  appendStringInfoChar(buf, '*');
3490  else
3491  {
3492  ListCell *arg;
3493  bool first = true;
3494 
3495  /* Add all the arguments */
3496  foreach(arg, node->args)
3497  {
3498  TargetEntry *tle = (TargetEntry *) lfirst(arg);
3499  Node *n = (Node *) tle->expr;
3500 
3501  if (tle->resjunk)
3502  continue;
3503 
3504  if (!first)
3505  appendStringInfoString(buf, ", ");
3506  first = false;
3507 
3508  /* Add VARIADIC */
3509  if (use_variadic && lnext(node->args, arg) == NULL)
3510  appendStringInfoString(buf, "VARIADIC ");
3511 
3512  deparseExpr((Expr *) n, context);
3513  }
3514  }
3515 
3516  /* Add ORDER BY */
3517  if (node->aggorder != NIL)
3518  {
3519  appendStringInfoString(buf, " ORDER BY ");
3520  appendAggOrderBy(node->aggorder, node->args, context);
3521  }
3522  }
3523 
3524  /* Add FILTER (WHERE ..) */
3525  if (node->aggfilter != NULL)
3526  {
3527  appendStringInfoString(buf, ") FILTER (WHERE ");
3528  deparseExpr((Expr *) node->aggfilter, context);
3529  }
3530 
3531  appendStringInfoChar(buf, ')');
3532 }
static void appendFunctionName(Oid funcid, deparse_expr_cxt *context)
Definition: deparse.c:3797
static void appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
Definition: deparse.c:3538
@ AGGSPLIT_SIMPLE
Definition: nodes.h:368
void * arg
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:341
bool aggstar
Definition: primnodes.h:409
Oid aggfnoid
Definition: primnodes.h:373
List * aggdistinct
Definition: primnodes.h:403
List * aggdirectargs
Definition: primnodes.h:394
bool aggvariadic
Definition: primnodes.h:415
char aggkind
Definition: primnodes.h:418
List * args
Definition: primnodes.h:397
Expr * aggfilter
Definition: primnodes.h:406
List * aggorder
Definition: primnodes.h:400
AggSplit aggsplit
Definition: primnodes.h:427
Expr * expr
Definition: primnodes.h:1555
bool resjunk
Definition: primnodes.h:1562

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

Referenced by deparseExpr().

◆ 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 }
void deparseStringLiteral(StringInfo buf, const char *val)
Definition: deparse.c:2638
static void deparseRelation(StringInfo buf, Relation rel)
Definition: deparse.c:2598
NameData relname
Definition: pg_class.h:38
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
char data[NAMEDATALEN]
Definition: c.h:678

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

Referenced by postgresAnalyzeForeignTable().

◆ deparseAnalyzeSql()

void deparseAnalyzeSql ( StringInfo  buf,
Relation  rel,
List **  retrieved_attrs 
)

Definition at line 2377 of file deparse.c.

2378 {
2379  Oid relid = RelationGetRelid(rel);
2380  TupleDesc tupdesc = RelationGetDescr(rel);
2381  int i;
2382  char *colname;
2383  List *options;
2384  ListCell *lc;
2385  bool first = true;
2386 
2387  *retrieved_attrs = NIL;
2388 
2389  appendStringInfoString(buf, "SELECT ");
2390  for (i = 0; i < tupdesc->natts; i++)
2391  {
2392  /* Ignore dropped columns. */
2393  if (TupleDescAttr(tupdesc, i)->attisdropped)
2394  continue;
2395 
2396  if (!first)
2397  appendStringInfoString(buf, ", ");
2398  first = false;
2399 
2400  /* Use attribute name or column_name option. */
2401  colname = NameStr(TupleDescAttr(tupdesc, i)->attname);
2402  options = GetForeignColumnOptions(relid, i + 1);
2403 
2404  foreach(lc, options)
2405  {
2406  DefElem *def = (DefElem *) lfirst(lc);
2407 
2408  if (strcmp(def->defname, "column_name") == 0)
2409  {
2410  colname = defGetString(def);
2411  break;
2412  }
2413  }
2414 
2416 
2417  *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
2418  }
2419 
2420  /* Don't generate bad syntax for zero-column relation. */
2421  if (first)
2422  appendStringInfoString(buf, "NULL");
2423 
2424  /*
2425  * Construct FROM clause
2426  */
2427  appendStringInfoString(buf, " FROM ");
2428  deparseRelation(buf, rel);
2429 }
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
#define RelationGetRelid(relation)
Definition: rel.h:501
#define RelationGetDescr(relation)
Definition: rel.h:527
char * defname
Definition: parsenodes.h:777
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References appendStringInfoString(), attname, buf, defGetString(), DefElem::defname, deparseRelation(), 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 3420 of file deparse.c.

3421 {
3422  StringInfo buf = context->buf;
3423  bool first = true;
3424  ListCell *lc;
3425 
3426  appendStringInfoString(buf, "ARRAY[");
3427  foreach(lc, node->elements)
3428  {
3429  if (!first)
3430  appendStringInfoString(buf, ", ");
3431  deparseExpr(lfirst(lc), context);
3432  first = false;
3433  }
3434  appendStringInfoChar(buf, ']');
3435 
3436  /* If the array is empty, we need an explicit cast to the array type. */
3437  if (node->elements == NIL)
3438  appendStringInfo(buf, "::%s",
3439  deparse_type_name(node->array_typeid, -1));
3440 }
static char * deparse_type_name(Oid type_oid, int32 typemod)
Definition: deparse.c:1153
Oid array_typeid
Definition: primnodes.h:1175
List * elements
Definition: primnodes.h:1178

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), ArrayExpr::array_typeid, 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 3299 of file deparse.c.

3300 {
3301  StringInfo buf = context->buf;
3302  const char *op = NULL; /* keep compiler quiet */
3303  bool first;
3304  ListCell *lc;
3305 
3306  switch (node->boolop)
3307  {
3308  case AND_EXPR:
3309  op = "AND";
3310  break;
3311  case OR_EXPR:
3312  op = "OR";
3313  break;
3314  case NOT_EXPR:
3315  appendStringInfoString(buf, "(NOT ");
3316  deparseExpr(linitial(node->args), context);
3317  appendStringInfoChar(buf, ')');
3318  return;
3319  }
3320 
3321  appendStringInfoChar(buf, '(');
3322  first = true;
3323  foreach(lc, node->args)
3324  {
3325  if (!first)
3326  appendStringInfo(buf, " %s ", op);
3327  deparseExpr((Expr *) lfirst(lc), context);
3328  first = false;
3329  }
3330  appendStringInfoChar(buf, ')');
3331 }
#define linitial(l)
Definition: pg_list.h:176
@ AND_EXPR
Definition: primnodes.h:758
@ OR_EXPR
Definition: primnodes.h:758
@ NOT_EXPR
Definition: primnodes.h:758
BoolExprType boolop
Definition: primnodes.h:766
List * args
Definition: primnodes.h:767

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

3371 {
3372  StringInfo buf = context->buf;
3373  ListCell *lc;
3374 
3375  appendStringInfoString(buf, "(CASE");
3376 
3377  /* If this is a CASE arg WHEN then emit the arg expression */
3378  if (node->arg != NULL)
3379  {
3380  appendStringInfoChar(buf, ' ');
3381  deparseExpr(node->arg, context);
3382  }
3383 
3384  /* Add each condition/result of the CASE clause */
3385  foreach(lc, node->args)
3386  {
3387  CaseWhen *whenclause = (CaseWhen *) lfirst(lc);
3388 
3389  /* WHEN */
3390  appendStringInfoString(buf, " WHEN ");
3391  if (node->arg == NULL) /* CASE WHEN */
3392  deparseExpr(whenclause->expr, context);
3393  else /* CASE arg WHEN */
3394  {
3395  /* Ignore the CaseTestExpr and equality operator. */
3396  deparseExpr(lsecond(castNode(OpExpr, whenclause->expr)->args),
3397  context);
3398  }
3399 
3400  /* THEN */
3401  appendStringInfoString(buf, " THEN ");
3402  deparseExpr(whenclause->result, context);
3403  }
3404 
3405  /* add ELSE if present */
3406  if (node->defresult != NULL)
3407  {
3408  appendStringInfoString(buf, " ELSE ");
3409  deparseExpr(node->defresult, context);
3410  }
3411 
3412  /* append END */
3413  appendStringInfoString(buf, " END)");
3414 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:180
#define lsecond(l)
Definition: pg_list.h:181
Expr * arg
Definition: primnodes.h:1119
Expr * defresult
Definition: primnodes.h:1121
List * args
Definition: primnodes.h:1120
Expr * result
Definition: primnodes.h:1132
Expr * expr
Definition: primnodes.h:1131

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

2472 {
2473  /* We support fetching the remote side's CTID and OID. */
2474  if (varattno == SelfItemPointerAttributeNumber)
2475  {
2476  if (qualify_col)
2477  ADD_REL_QUALIFIER(buf, varno);
2478  appendStringInfoString(buf, "ctid");
2479  }
2480  else if (varattno < 0)
2481  {
2482  /*
2483  * All other system attributes are fetched as 0, except for table OID,
2484  * which is fetched as the local table OID. However, we must be
2485  * careful; the table could be beneath an outer join, in which case it
2486  * must go to NULL whenever the rest of the row does.
2487  */
2488  Oid fetchval = 0;
2489 
2490  if (varattno == TableOidAttributeNumber)
2491  fetchval = rte->relid;
2492 
2493  if (qualify_col)
2494  {
2495  appendStringInfoString(buf, "CASE WHEN (");
2496  ADD_REL_QUALIFIER(buf, varno);
2497  appendStringInfo(buf, "*)::text IS NOT NULL THEN %u END", fetchval);
2498  }
2499  else
2500  appendStringInfo(buf, "%u", fetchval);
2501  }
2502  else if (varattno == 0)
2503  {
2504  /* Whole row reference */
2505  Relation rel;
2506  Bitmapset *attrs_used;
2507 
2508  /* Required only to be passed down to deparseTargetList(). */
2509  List *retrieved_attrs;
2510 
2511  /*
2512  * The lock on the relation will be held by upper callers, so it's
2513  * fine to open it with no lock here.
2514  */
2515  rel = table_open(rte->relid, NoLock);
2516 
2517  /*
2518  * The local name of the foreign table can not be recognized by the
2519  * foreign server and the table it references on foreign server might
2520  * have different column ordering or different columns than those
2521  * declared locally. Hence we have to deparse whole-row reference as
2522  * ROW(columns referenced locally). Construct this by deparsing a
2523  * "whole row" attribute.
2524  */
2525  attrs_used = bms_add_member(NULL,
2527 
2528  /*
2529  * In case the whole-row reference is under an outer join then it has
2530  * to go NULL whenever the rest of the row goes NULL. Deparsing a join
2531  * query would always involve multiple relations, thus qualify_col
2532  * would be true.
2533  */
2534  if (qualify_col)
2535  {
2536  appendStringInfoString(buf, "CASE WHEN (");
2537  ADD_REL_QUALIFIER(buf, varno);
2538  appendStringInfoString(buf, "*)::text IS NOT NULL THEN ");
2539  }
2540 
2541  appendStringInfoString(buf, "ROW(");
2542  deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
2543  &retrieved_attrs);
2544  appendStringInfoChar(buf, ')');
2545 
2546  /* Complete the CASE WHEN statement started above. */
2547  if (qualify_col)
2548  appendStringInfoString(buf, " END");
2549 
2550  table_close(rel, NoLock);
2551  bms_free(attrs_used);
2552  }
2553  else
2554  {
2555  char *colname = NULL;
2556  List *options;
2557  ListCell *lc;
2558 
2559  /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
2560  Assert(!IS_SPECIAL_VARNO(varno));
2561 
2562  /*
2563  * If it's a column of a foreign table, and it has the column_name FDW
2564  * option, use that value.
2565  */
2566  options = GetForeignColumnOptions(rte->relid, varattno);
2567  foreach(lc, options)
2568  {
2569  DefElem *def = (DefElem *) lfirst(lc);
2570 
2571  if (strcmp(def->defname, "column_name") == 0)
2572  {
2573  colname = defGetString(def);
2574  break;
2575  }
2576  }
2577 
2578  /*
2579  * If it's a column of a regular table or it doesn't have column_name
2580  * FDW option, use attribute name.
2581  */
2582  if (colname == NULL)
2583  colname = get_attname(rte->relid, varattno, false);
2584 
2585  if (qualify_col)
2586  ADD_REL_QUALIFIER(buf, varno);
2587 
2589  }
2590 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:209
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:739
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:198
#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 2809 of file deparse.c.

2810 {
2811  StringInfo buf = context->buf;
2812  Oid typoutput;
2813  bool typIsVarlena;
2814  char *extval;
2815  bool isfloat = false;
2816  bool isstring = false;
2817  bool needlabel;
2818 
2819  if (node->constisnull)
2820  {
2821  appendStringInfoString(buf, "NULL");
2822  if (showtype >= 0)
2823  appendStringInfo(buf, "::%s",
2825  node->consttypmod));
2826  return;
2827  }
2828 
2830  &typoutput, &typIsVarlena);
2831  extval = OidOutputFunctionCall(typoutput, node->constvalue);
2832 
2833  switch (node->consttype)
2834  {
2835  case INT2OID:
2836  case INT4OID:
2837  case INT8OID:
2838  case OIDOID:
2839  case FLOAT4OID:
2840  case FLOAT8OID:
2841  case NUMERICOID:
2842  {
2843  /*
2844  * No need to quote unless it's a special value such as 'NaN'.
2845  * See comments in get_const_expr().
2846  */
2847  if (strspn(extval, "0123456789+-eE.") == strlen(extval))
2848  {
2849  if (extval[0] == '+' || extval[0] == '-')
2850  appendStringInfo(buf, "(%s)", extval);
2851  else
2852  appendStringInfoString(buf, extval);
2853  if (strcspn(extval, "eE.") != strlen(extval))
2854  isfloat = true; /* it looks like a float */
2855  }
2856  else
2857  appendStringInfo(buf, "'%s'", extval);
2858  }
2859  break;
2860  case BITOID:
2861  case VARBITOID:
2862  appendStringInfo(buf, "B'%s'", extval);
2863  break;
2864  case BOOLOID:
2865  if (strcmp(extval, "t") == 0)
2866  appendStringInfoString(buf, "true");
2867  else
2868  appendStringInfoString(buf, "false");
2869  break;
2870  default:
2871  deparseStringLiteral(buf, extval);
2872  isstring = true;
2873  break;
2874  }
2875 
2876  pfree(extval);
2877 
2878  if (showtype == -1)
2879  return; /* never print type label */
2880 
2881  /*
2882  * For showtype == 0, append ::typename unless the constant will be
2883  * implicitly typed as the right type when it is read in.
2884  *
2885  * XXX this code has to be kept in sync with the behavior of the parser,
2886  * especially make_const.
2887  */
2888  switch (node->consttype)
2889  {
2890  case BOOLOID:
2891  case INT4OID:
2892  case UNKNOWNOID:
2893  needlabel = false;
2894  break;
2895  case NUMERICOID:
2896  needlabel = !isfloat || (node->consttypmod >= 0);
2897  break;
2898  default:
2899  if (showtype == -2)
2900  {
2901  /* label unless we printed it as an untyped string */
2902  needlabel = !isstring;
2903  }
2904  else
2905  needlabel = true;
2906  break;
2907  }
2908  if (needlabel || showtype > 0)
2909  appendStringInfo(buf, "::%s",
2911  node->consttypmod));
2912 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1639
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2865
void pfree(void *pointer)
Definition: mcxt.c:1306
Oid consttype
Definition: primnodes.h:259
Datum constvalue
Definition: primnodes.h:263
bool constisnull
Definition: primnodes.h:264
int32 consttypmod
Definition: primnodes.h:260

References appendStringInfo(), appendStringInfoString(), deparse_expr_cxt::buf, buf, Const::constisnull, Const::consttype, Const::consttypmod, Const::constvalue, 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:116
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:514
@ RELOPT_JOINREL
Definition: pathnodes.h:771
RelOptKind reloptkind
Definition: pathnodes.h:809
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:2470
int16 attnum
Definition: pg_attribute.h:83
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:465
#define lfirst_int(lc)
Definition: pg_list.h:171

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(), TargetEntry::resjunk, 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 3223 of file deparse.c.

3224 {
3225  StringInfo buf = context->buf;
3226 
3227  Assert(list_length(node->args) == 2);
3228 
3229  appendStringInfoChar(buf, '(');
3230  deparseExpr(linitial(node->args), context);
3231  appendStringInfoString(buf, " IS DISTINCT FROM ");
3232  deparseExpr(lsecond(node->args), context);
3233  appendStringInfoChar(buf, ')');
3234 }
static int list_length(const List *l)
Definition: pg_list.h:150
List * args
Definition: primnodes.h:666

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

2674 {
2675  if (node == NULL)
2676  return;
2677 
2678  switch (nodeTag(node))
2679  {
2680  case T_Var:
2681  deparseVar((Var *) node, context);
2682  break;
2683  case T_Const:
2684  deparseConst((Const *) node, context, 0);
2685  break;
2686  case T_Param:
2687  deparseParam((Param *) node, context);
2688  break;
2689  case T_SubscriptingRef:
2690  deparseSubscriptingRef((SubscriptingRef *) node, context);
2691  break;
2692  case T_FuncExpr:
2693  deparseFuncExpr((FuncExpr *) node, context);
2694  break;
2695  case T_OpExpr:
2696  deparseOpExpr((OpExpr *) node, context);
2697  break;
2698  case T_DistinctExpr:
2699  deparseDistinctExpr((DistinctExpr *) node, context);
2700  break;
2701  case T_ScalarArrayOpExpr:
2702  deparseScalarArrayOpExpr((ScalarArrayOpExpr *) node, context);
2703  break;
2704  case T_RelabelType:
2705  deparseRelabelType((RelabelType *) node, context);
2706  break;
2707  case T_BoolExpr:
2708  deparseBoolExpr((BoolExpr *) node, context);
2709  break;
2710  case T_NullTest:
2711  deparseNullTest((NullTest *) node, context);
2712  break;
2713  case T_CaseExpr:
2714  deparseCaseExpr((CaseExpr *) node, context);
2715  break;
2716  case T_ArrayExpr:
2717  deparseArrayExpr((ArrayExpr *) node, context);
2718  break;
2719  case T_Aggref:
2720  deparseAggref((Aggref *) node, context);
2721  break;
2722  default:
2723  elog(ERROR, "unsupported expression type for deparse: %d",
2724  (int) nodeTag(node));
2725  break;
2726  }
2727 }
static void deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3370
static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3299
static void deparseAggref(Aggref *node, deparse_expr_cxt *context)
Definition: deparse.c:3446
static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
Definition: deparse.c:3286
static void deparseNullTest(NullTest *node, deparse_expr_cxt *context)
Definition: deparse.c:3337
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3065
static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype)
Definition: deparse.c:2809
static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3223
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3002
static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3420
static void deparseVar(Var *node, deparse_expr_cxt *context)
Definition: deparse.c:2738
static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
Definition: deparse.c:2956
static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3241
static void deparseParam(Param *node, deparse_expr_cxt *context)
Definition: deparse.c:2923
#define nodeTag(nodeptr)
Definition: nodes.h:116
Definition: primnodes.h:205

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:675
@ BMS_MULTIPLE
Definition: bitmapset.h:75
unsigned int Index
Definition: c.h:550
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:783
#define IS_JOIN_REL(rel)
Definition: pathnodes.h:788
Relids relids
Definition: pathnodes.h:815

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:428
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:287
void appendBinaryStringInfo(StringInfo str, const char *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:862

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

3003 {
3004  StringInfo buf = context->buf;
3005  bool use_variadic;
3006  bool first;
3007  ListCell *arg;
3008 
3009  /*
3010  * If the function call came from an implicit coercion, then just show the
3011  * first argument.
3012  */
3013  if (node->funcformat == COERCE_IMPLICIT_CAST)
3014  {
3015  deparseExpr((Expr *) linitial(node->args), context);
3016  return;
3017  }
3018 
3019  /*
3020  * If the function call came from a cast, then show the first argument
3021  * plus an explicit cast operation.
3022  */
3023  if (node->funcformat == COERCE_EXPLICIT_CAST)
3024  {
3025  Oid rettype = node->funcresulttype;
3026  int32 coercedTypmod;
3027 
3028  /* Get the typmod if this is a length-coercion function */
3029  (void) exprIsLengthCoercion((Node *) node, &coercedTypmod);
3030 
3031  deparseExpr((Expr *) linitial(node->args), context);
3032  appendStringInfo(buf, "::%s",
3033  deparse_type_name(rettype, coercedTypmod));
3034  return;
3035  }
3036 
3037  /* Check if need to print VARIADIC (cf. ruleutils.c) */
3038  use_variadic = node->funcvariadic;
3039 
3040  /*
3041  * Normal function: display as proname(args).
3042  */
3043  appendFunctionName(node->funcid, context);
3044  appendStringInfoChar(buf, '(');
3045 
3046  /* ... and all the arguments */
3047  first = true;
3048  foreach(arg, node->args)
3049  {
3050  if (!first)
3051  appendStringInfoString(buf, ", ");
3052  if (use_variadic && lnext(node->args, arg) == NULL)
3053  appendStringInfoString(buf, "VARIADIC ");
3054  deparseExpr((Expr *) lfirst(arg), context);
3055  first = false;
3056  }
3057  appendStringInfoChar(buf, ')');
3058 }
signed int int32
Definition: c.h:430
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:500
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:588
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:587
Oid funcid
Definition: primnodes.h:598
bool funcvariadic
Definition: primnodes.h:601
List * args
Definition: primnodes.h:606
CoercionForm funcformat
Definition: primnodes.h:603
Oid funcresulttype
Definition: primnodes.h:599

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::funcformat, FuncExpr::funcid, FuncExpr::funcresulttype, FuncExpr::funcvariadic, 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:207
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:1047
@ 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:262
@ CMD_UPDATE
Definition: nodes.h:260
while(p+4<=pend)
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:487
Relids lower_subquery_rels
Definition: postgres_fdw.h:119
LockClauseStrength strength
Definition: plannodes.h:1378
List * rowMarks
Definition: pathnodes.h:355
Relids all_result_relids
Definition: pathnodes.h:338
CmdType commandType
Definition: parsenodes.h:124

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

3338 {
3339  StringInfo buf = context->buf;
3340 
3341  appendStringInfoChar(buf, '(');
3342  deparseExpr(node->arg, context);
3343 
3344  /*
3345  * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
3346  * shorter and traditional. If it's a rowtype input but we're applying a
3347  * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
3348  * correct.
3349  */
3350  if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
3351  {
3352  if (node->nulltesttype == IS_NULL)
3353  appendStringInfoString(buf, " IS NULL)");
3354  else
3355  appendStringInfoString(buf, " IS NOT NULL)");
3356  }
3357  else
3358  {
3359  if (node->nulltesttype == IS_NULL)
3360  appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)");
3361  else
3362  appendStringInfoString(buf, " IS DISTINCT FROM NULL)");
3363  }
3364 }
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2613
@ IS_NULL
Definition: primnodes.h:1359
NullTestType nulltesttype
Definition: primnodes.h:1366
bool argisrow
Definition: primnodes.h:1367
Expr * arg
Definition: primnodes.h:1365

References appendStringInfoChar(), appendStringInfoString(), NullTest::arg, NullTest::argisrow, 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 3195 of file deparse.c.

3196 {
3197  char *opname;
3198 
3199  /* opname is not a SQL identifier, so we should not quote it. */
3200  opname = NameStr(opform->oprname);
3201 
3202  /* Print schema name only if it's not pg_catalog */
3203  if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
3204  {
3205  const char *opnspname;
3206 
3207  opnspname = get_namespace_name(opform->oprnamespace);
3208  /* Print fully qualified operator name. */
3209  appendStringInfo(buf, "OPERATOR(%s.%s)",
3210  quote_identifier(opnspname), opname);
3211  }
3212  else
3213  {
3214  /* Just print operator name. */
3215  appendStringInfoString(buf, opname);
3216  }
3217 }

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

3066 {
3067  StringInfo buf = context->buf;
3068  HeapTuple tuple;
3069  Form_pg_operator form;
3070  Expr *right;
3071  bool canSuppressRightConstCast = false;
3072  char oprkind;
3073 
3074  /* Retrieve information about the operator from system catalog. */
3075  tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
3076  if (!HeapTupleIsValid(tuple))
3077  elog(ERROR, "cache lookup failed for operator %u", node->opno);
3078  form = (Form_pg_operator) GETSTRUCT(tuple);
3079  oprkind = form->oprkind;
3080 
3081  /* Sanity check. */
3082  Assert((oprkind == 'l' && list_length(node->args) == 1) ||
3083  (oprkind == 'b' && list_length(node->args) == 2));
3084 
3085  right = llast(node->args);
3086 
3087  /* Always parenthesize the expression. */
3088  appendStringInfoChar(buf, '(');
3089 
3090  /* Deparse left operand, if any. */
3091  if (oprkind == 'b')
3092  {
3093  Expr *left = linitial(node->args);
3094  Oid leftType = exprType((Node *) left);
3095  Oid rightType = exprType((Node *) right);
3096  bool canSuppressLeftConstCast = false;
3097 
3098  /*
3099  * When considering a binary operator, if one operand is a Const that
3100  * can be printed as a bare string literal or NULL (i.e., it will look
3101  * like type UNKNOWN to the remote parser), the Const normally
3102  * receives an explicit cast to the operator's input type. However,
3103  * in Const-to-Var comparisons where both operands are of the same
3104  * type, we prefer to suppress the explicit cast, leaving the Const's
3105  * type resolution up to the remote parser. The remote's resolution
3106  * heuristic will assume that an unknown input type being compared to
3107  * a known input type is of that known type as well.
3108  *
3109  * This hack allows some cases to succeed where a remote column is
3110  * declared with a different type in the local (foreign) table. By
3111  * emitting "foreigncol = 'foo'" not "foreigncol = 'foo'::text" or the
3112  * like, we allow the remote parser to pick an "=" operator that's
3113  * compatible with whatever type the remote column really is, such as
3114  * an enum.
3115  *
3116  * We allow cast suppression to happen only when the other operand is
3117  * a plain foreign Var. Although the remote's unknown-type heuristic
3118  * would apply to other cases just as well, we would be taking a
3119  * bigger risk that the inferred type is something unexpected. With
3120  * this restriction, if anything goes wrong it's the user's fault for
3121  * not declaring the local column with the same type as the remote
3122  * column.
3123  */
3124  if (leftType == rightType)
3125  {
3126  if (IsA(left, Const))
3127  canSuppressLeftConstCast = isPlainForeignVar(right, context);
3128  else if (IsA(right, Const))
3129  canSuppressRightConstCast = isPlainForeignVar(left, context);
3130  }
3131 
3132  if (canSuppressLeftConstCast)
3133  deparseConst((Const *) left, context, -2);
3134  else
3135  deparseExpr(left, context);
3136 
3137  appendStringInfoChar(buf, ' ');
3138  }
3139 
3140  /* Deparse operator name. */
3141  deparseOperatorName(buf, form);
3142 
3143  /* Deparse right operand. */
3144  appendStringInfoChar(buf, ' ');
3145 
3146  if (canSuppressRightConstCast)
3147  deparseConst((Const *) right, context, -2);
3148  else
3149  deparseExpr(right, context);
3150 
3151  appendStringInfoChar(buf, ')');
3152 
3153  ReleaseSysCache(tuple);
3154 }
static bool isPlainForeignVar(Expr *node, deparse_expr_cxt *context)
Definition: deparse.c:3160
#define llast(l)
Definition: pg_list.h:196
Oid opno
Definition: primnodes.h:648

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

2924 {
2925  if (context->params_list)
2926  {
2927  int pindex = 0;
2928  ListCell *lc;
2929 
2930  /* find its index in params_list */
2931  foreach(lc, *context->params_list)
2932  {
2933  pindex++;
2934  if (equal(node, (Node *) lfirst(lc)))
2935  break;
2936  }
2937  if (lc == NULL)
2938  {
2939  /* not in list, so add it */
2940  pindex++;
2941  *context->params_list = lappend(*context->params_list, node);
2942  }
2943 
2944  printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
2945  }
2946  else
2947  {
2948  printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
2949  }
2950 }
static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3612
static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3638
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:225
int32 paramtypmod
Definition: primnodes.h:314
Oid paramtype
Definition: primnodes.h:313

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

Referenced by deparseExpr().

◆ deparseRangeTblRef()

static void deparseRangeTblRef ( StringInfo  buf,
PlannerInfo root,
RelOptInfo foreignrel,
bool  make_subquery,
Index  ignore_rel,
List **  ignore_conds,
List **  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 3286 of file deparse.c.

3287 {
3288  deparseExpr(node->arg, context);
3289  if (node->relabelformat != COERCE_IMPLICIT_CAST)
3290  appendStringInfo(context->buf, "::%s",
3292  node->resulttypmod));
3293 }
int32 resulttypmod
Definition: primnodes.h:1003
CoercionForm relabelformat
Definition: primnodes.h:1005
Oid resulttype
Definition: primnodes.h:1002
Expr * arg
Definition: primnodes.h:1001

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

Referenced by deparseExpr().

◆ deparseRelation()

static void deparseRelation ( StringInfo  buf,
Relation  rel 
)
static

Definition at line 2598 of file deparse.c.

2599 {
2600  ForeignTable *table;
2601  const char *nspname = NULL;
2602  const char *relname = NULL;
2603  ListCell *lc;
2604 
2605  /* obtain additional catalog information. */
2606  table = GetForeignTable(RelationGetRelid(rel));
2607 
2608  /*
2609  * Use value of FDW options if any, instead of the name of object itself.
2610  */
2611  foreach(lc, table->options)
2612  {
2613  DefElem *def = (DefElem *) lfirst(lc);
2614 
2615  if (strcmp(def->defname, "schema_name") == 0)
2616  nspname = defGetString(def);
2617  else if (strcmp(def->defname, "table_name") == 0)
2618  relname = defGetString(def);
2619  }
2620 
2621  /*
2622  * Note: we could skip printing the schema name if it's pg_catalog, but
2623  * that doesn't seem worth the trouble.
2624  */
2625  if (nspname == NULL)
2626  nspname = get_namespace_name(RelationGetNamespace(rel));
2627  if (relname == NULL)
2629 
2630  appendStringInfo(buf, "%s.%s",
2632 }
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:250
#define RelationGetRelationName(relation)
Definition: rel.h:535
#define RelationGetNamespace(relation)
Definition: rel.h:542
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 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:186
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:281

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

3242 {
3243  StringInfo buf = context->buf;
3244  HeapTuple tuple;
3245  Form_pg_operator form;
3246  Expr *arg1;
3247  Expr *arg2;
3248 
3249  /* Retrieve information about the operator from system catalog. */
3250  tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
3251  if (!HeapTupleIsValid(tuple))
3252  elog(ERROR, "cache lookup failed for operator %u", node->opno);
3253  form = (Form_pg_operator) GETSTRUCT(tuple);
3254 
3255  /* Sanity check. */
3256  Assert(list_length(node->args) == 2);
3257 
3258  /* Always parenthesize the expression. */
3259  appendStringInfoChar(buf, '(');
3260 
3261  /* Deparse left operand. */
3262  arg1 = linitial(node->args);
3263  deparseExpr(arg1, context);
3264  appendStringInfoChar(buf, ' ');
3265 
3266  /* Deparse operator name plus decoration. */
3267  deparseOperatorName(buf, form);
3268  appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
3269 
3270  /* Deparse right operand. */
3271  arg2 = lsecond(node->args);
3272  deparseExpr(arg2, context);
3273 
3274  appendStringInfoChar(buf, ')');
3275 
3276  /* Always parenthesize the expression. */
3277  appendStringInfoChar(buf, ')');
3278 
3279  ReleaseSysCache(tuple);
3280 }

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:3651
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:3692
static void appendLimitClause(deparse_expr_cxt *context)
Definition: deparse.c:3769
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 3832 of file deparse.c.

3834 {
3835  StringInfo buf = context->buf;
3836  TargetEntry *tle;
3837  Expr *expr;
3838 
3839  tle = get_sortgroupref_tle(ref, tlist);
3840  expr = tle->expr;
3841 
3842  if (force_colno)
3843  {
3844  /* Use column-number form when requested by caller. */
3845  Assert(!tle->resjunk);
3846  appendStringInfo(buf, "%d", tle->resno);
3847  }
3848  else if (expr && IsA(expr, Const))
3849  {
3850  /*
3851  * Force a typecast here so that we don't emit something like "GROUP
3852  * BY 2", which will be misconstrued as a column position rather than
3853  * a constant.
3854  */
3855  deparseConst((Const *) expr, context, 1);
3856  }
3857  else if (!expr || IsA(expr, Var))
3858  deparseExpr(expr, context);
3859  else
3860  {
3861  /* Always parenthesize the expression. */
3862  appendStringInfoChar(buf, '(');
3863  deparseExpr(expr, context);
3864  appendStringInfoChar(buf, ')');
3865  }
3866 
3867  return (Node *) expr;
3868 }
AttrNumber resno
Definition: primnodes.h:1556
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, TargetEntry::resjunk, and TargetEntry::resno.

Referenced by appendAggOrderBy(), and appendGroupByClause().

◆ deparseStringLiteral()

void deparseStringLiteral ( StringInfo  buf,
const char *  val 
)

Definition at line 2638 of file deparse.c.

2639 {
2640  const char *valptr;
2641 
2642  /*
2643  * Rather than making assumptions about the remote server's value of
2644  * standard_conforming_strings, always use E'foo' syntax if there are any
2645  * backslashes. This will fail on remote servers before 8.1, but those
2646  * are long out of support.
2647  */
2648  if (strchr(val, '\\') != NULL)
2650  appendStringInfoChar(buf, '\'');
2651  for (valptr = val; *valptr; valptr++)
2652  {
2653  char ch = *valptr;
2654 
2655  if (SQL_STR_DOUBLE(ch, true))
2658  }
2659  appendStringInfoChar(buf, '\'');
2660 }
#define ESCAPE_STRING_SYNTAX
Definition: c.h:1105
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1102
long val
Definition: informix.c:664

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

Referenced by 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 2956 of file deparse.c.

2957 {
2958  StringInfo buf = context->buf;
2959  ListCell *lowlist_item;
2960  ListCell *uplist_item;
2961 
2962  /* Always parenthesize the expression. */
2963  appendStringInfoChar(buf, '(');
2964 
2965  /*
2966  * Deparse referenced array expression first. If that expression includes
2967  * a cast, we have to parenthesize to prevent the array subscript from
2968  * being taken as typename decoration. We can avoid that in the typical
2969  * case of subscripting a Var, but otherwise do it.
2970  */
2971  if (IsA(node->refexpr, Var))
2972  deparseExpr(node->refexpr, context);
2973  else
2974  {
2975  appendStringInfoChar(buf, '(');
2976  deparseExpr(node->refexpr, context);
2977  appendStringInfoChar(buf, ')');
2978  }
2979 
2980  /* Deparse subscript expressions. */
2981  lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
2982  foreach(uplist_item, node->refupperindexpr)
2983  {
2984  appendStringInfoChar(buf, '[');
2985  if (lowlist_item)
2986  {
2987  deparseExpr(lfirst(lowlist_item), context);
2988  appendStringInfoChar(buf, ':');
2989  lowlist_item = lnext(node->reflowerindexpr, lowlist_item);
2990  }
2991  deparseExpr(lfirst(uplist_item), context);
2992  appendStringInfoChar(buf, ']');
2993  }
2994 
2995  appendStringInfoChar(buf, ')');
2996 }
static ListCell * list_head(const List *l)
Definition: pg_list.h:126
List * refupperindexpr
Definition: primnodes.h:547
Expr * refexpr
Definition: primnodes.h:552
List * reflowerindexpr
Definition: primnodes.h:549

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

2439 {
2440  ListCell *cell;
2441 
2442  appendStringInfoString(buf, "TRUNCATE ");
2443 
2444  foreach(cell, rels)
2445  {
2446  Relation rel = lfirst(cell);
2447 
2448  if (cell != list_head(rels))
2449  appendStringInfoString(buf, ", ");
2450 
2451  deparseRelation(buf, rel);
2452  }
2453 
2454  appendStringInfo(buf, " %s IDENTITY",
2455  restart_seqs ? "RESTART" : "CONTINUE");
2456 
2457  if (behavior == DROP_RESTRICT)
2458  appendStringInfoString(buf, " RESTRICT");
2459  else if (behavior == DROP_CASCADE)
2460  appendStringInfoString(buf, " CASCADE");
2461 }
@ DROP_CASCADE
Definition: parsenodes.h:1936
@ DROP_RESTRICT
Definition: parsenodes.h:1935

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

2739 {
2740  Relids relids = context->scanrel->relids;
2741  int relno;
2742  int colno;
2743 
2744  /* Qualify columns when multiple relations are involved. */
2745  bool qualify_col = (bms_membership(relids) == BMS_MULTIPLE);
2746 
2747  /*
2748  * If the Var belongs to the foreign relation that is deparsed as a
2749  * subquery, use the relation and column alias to the Var provided by the
2750  * subquery, instead of the remote name.
2751  */
2752  if (is_subquery_var(node, context->scanrel, &relno, &colno))
2753  {
2754  appendStringInfo(context->buf, "%s%d.%s%d",
2756  SUBQUERY_COL_ALIAS_PREFIX, colno);
2757  return;
2758  }
2759 
2760  if (bms_is_member(node->varno, relids) && node->varlevelsup == 0)
2761  deparseColumnRef(context->buf, node->varno, node->varattno,
2762  planner_rt_fetch(node->varno, context->root),
2763  qualify_col);
2764  else
2765  {
2766  /* Treat like a Param */
2767  if (context->params_list)
2768  {
2769  int pindex = 0;
2770  ListCell *lc;
2771 
2772  /* find its index in params_list */
2773  foreach(lc, *context->params_list)
2774  {
2775  pindex++;
2776  if (equal(node, (Node *) lfirst(lc)))
2777  break;
2778  }
2779  if (lc == NULL)
2780  {
2781  /* not in list, so add it */
2782  pindex++;
2783  *context->params_list = lappend(*context->params_list, node);
2784  }
2785 
2786  printRemoteParam(pindex, node->vartype, node->vartypmod, context);
2787  }
2788  else
2789  {
2790  printRemotePlaceholder(node->vartype, node->vartypmod, context);
2791  }
2792  }
2793 }
static bool is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:3877
Oid vartype
Definition: primnodes.h:220
AttrNumber varattno
Definition: primnodes.h:217
int varno
Definition: primnodes.h:212
int32 vartypmod
Definition: primnodes.h:222
Index varlevelsup
Definition: primnodes.h:230

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, Var::varno, Var::vartype, and Var::vartypmod.

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:648
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:590
#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:305
Oid inputcollid
Definition: primnodes.h:382
Oid aggcollid
Definition: primnodes.h:379
Oid casecollid
Definition: primnodes.h:1118
Oid constcollid
Definition: primnodes.h:261
Oid opcollid
Definition: primnodes.h:660
Oid inputcollid
Definition: primnodes.h:663
ParamKind paramkind
Definition: primnodes.h:311
Oid paramcollid
Definition: primnodes.h:315
Oid resultcollid
Definition: primnodes.h:1004
Expr * refassgnexpr
Definition: primnodes.h:554
Oid varcollid
Definition: primnodes.h:224
RelOptInfo * foreignrel
Definition: deparse.c:71
Relids relids
Definition: deparse.c:72
FDWCollateState state
Definition: deparse.c:93
Definition: regguts.h:318
#define FirstNormalObjectId
Definition: transam.h:197

References a, Aggref::aggcollid, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggorder, Aggref::aggsplit, AGGSPLIT_SIMPLE, RelabelType::arg, CaseExpr::arg, NullTest::arg, Aggref::args, OpExpr::args, ScalarArrayOpExpr::args, CaseExpr::args, b, bms_is_member(), CaseExpr::casecollid, 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(), Aggref::inputcollid, OpExpr::inputcollid, ScalarArrayOpExpr::inputcollid, InvalidOid, is_shippable(), IS_UPPER_REL, IsA, lfirst, lfirst_node, linitial, list_length(), lookup_type_cache(), TypeCacheEntry::lt_opr, nodeTag, OidIsValid, OpExpr::opcollid, OpExpr::opno, ScalarArrayOpExpr::opno, PARAM_MULTIEXPR, Param::paramcollid, Param::paramkind, SubscriptingRef::refassgnexpr, SubscriptingRef::refcollid, SubscriptingRef::refexpr, SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, foreign_glob_cxt::relids, CaseWhen::result, RelabelType::resultcollid, SelfItemPointerAttributeNumber, SortGroupClause::sortop, foreign_loc_cxt::state, strip_implicit_coercions(), SortGroupClause::tleSortGroupRef, TYPECACHE_GT_OPR, TYPECACHE_LT_OPR, Var::varattno, Var::varcollid, 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:289
@ JOIN_RIGHT
Definition: nodes.h:290
@ JOIN_LEFT
Definition: nodes.h:288

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

3941 {
3942  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
3943  int i;
3944  ListCell *lc;
3945 
3946  /* Get the relation alias ID */
3947  *relno = fpinfo->relation_index;
3948 
3949  /* Get the column alias ID */
3950  i = 1;
3951  foreach(lc, foreignrel->reltarget->exprs)
3952  {
3953  if (equal(lfirst(lc), (Node *) node))
3954  {
3955  *colno = i;
3956  return;
3957  }
3958  i++;
3959  }
3960 
3961  /* Shouldn't get here */
3962  elog(ERROR, "unexpected expression in subquery output");
3963 }

References elog(), equal(), ERROR, PathTarget::exprs, i, lfirst, PgFdwRelationInfo::relation_index, and RelOptInfo::reltarget.

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:365
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(), PathKey::pk_eclass, 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 3877 of file deparse.c.

3878 {
3879  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
3880  RelOptInfo *outerrel = fpinfo->outerrel;
3881  RelOptInfo *innerrel = fpinfo->innerrel;
3882 
3883  /* Should only be called in these cases. */
3884  Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
3885 
3886  /*
3887  * If the given relation isn't a join relation, it doesn't have any lower
3888  * subqueries, so the Var isn't a subquery output column.
3889  */
3890  if (!IS_JOIN_REL(foreignrel))
3891  return false;
3892 
3893  /*
3894  * If the Var doesn't belong to any lower subqueries, it isn't a subquery
3895  * output column.
3896  */
3897  if (!bms_is_member(node->varno, fpinfo->lower_subquery_rels))
3898  return false;
3899 
3900  if (bms_is_member(node->varno, outerrel->relids))
3901  {
3902  /*
3903  * If outer relation is deparsed as a subquery, the Var is an output
3904  * column of the subquery; get the IDs for the relation/column alias.
3905  */
3906  if (fpinfo->make_outerrel_subquery)
3907  {
3908  get_relation_column_alias_ids(node, outerrel, relno, colno);
3909  return true;
3910  }
3911 
3912  /* Otherwise, recurse into the outer relation. */
3913  return is_subquery_var(node, outerrel, relno, colno);
3914  }
3915  else
3916  {
3917  Assert(bms_is_member(node->varno, innerrel->relids));
3918 
3919  /*
3920  * If inner relation is deparsed as a subquery, the Var is an output
3921  * column of the subquery; get the IDs for the relation/column alias.
3922  */
3923  if (fpinfo->make_innerrel_subquery)
3924  {
3925  get_relation_column_alias_ids(node, innerrel, relno, colno);
3926  return true;
3927  }
3928 
3929  /* Otherwise, recurse into the inner relation. */
3930  return is_subquery_var(node, innerrel, relno, colno);
3931  }
3932 }
static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:3939

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

3161 {
3162  /*
3163  * We allow the foreign Var to have an implicit RelabelType, mainly so
3164  * that this'll work with varchar columns. Note that deparseRelabelType
3165  * will not print such a cast, so we're not breaking the restriction that
3166  * the expression print as a plain Var. We won't risk it for an implicit
3167  * cast that requires a function, nor for non-implicit RelabelType; such
3168  * cases seem too likely to involve semantics changes compared to what
3169  * would happen on the remote side.
3170  */
3171  if (IsA(node, RelabelType) &&
3172  ((RelabelType *) node)->relabelformat == COERCE_IMPLICIT_CAST)
3173  node = ((RelabelType *) node)->arg;
3174 
3175  if (IsA(node, Var))
3176  {
3177  /*
3178  * The Var must be one that'll deparse as a foreign column reference
3179  * (cf. deparseVar).
3180  */
3181  Var *var = (Var *) node;
3182  Relids relids = context->scanrel->relids;
3183 
3184  if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
3185  return true;
3186  }
3187 
3188  return false;
3189 }

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

3614 {
3615  StringInfo buf = context->buf;
3616  char *ptypename = deparse_type_name(paramtype, paramtypmod);
3617 
3618  appendStringInfo(buf, "$%d::%s", paramindex, ptypename);
3619 }

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

3640 {
3641  StringInfo buf = context->buf;
3642  char *ptypename = deparse_type_name(paramtype, paramtypmod);
3643 
3644  appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
3645 }

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