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_collation.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.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 *expr, 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 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)
 
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 108 of file deparse.c.

◆ REL_ALIAS_PREFIX

#define REL_ALIAS_PREFIX   "r"

Definition at line 106 of file deparse.c.

◆ SUBQUERY_COL_ALIAS_PREFIX

#define SUBQUERY_COL_ALIAS_PREFIX   "c"

Definition at line 111 of file deparse.c.

◆ SUBQUERY_REL_ALIAS_PREFIX

#define SUBQUERY_REL_ALIAS_PREFIX   "s"

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

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

Function Documentation

◆ appendAggOrderBy()

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

Definition at line 3438 of file deparse.c.

3439 {
3440  StringInfo buf = context->buf;
3441  ListCell *lc;
3442  bool first = true;
3443 
3444  foreach(lc, orderList)
3445  {
3446  SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
3447  Node *sortexpr;
3448  Oid sortcoltype;
3449  TypeCacheEntry *typentry;
3450 
3451  if (!first)
3452  appendStringInfoString(buf, ", ");
3453  first = false;
3454 
3455  sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
3456  false, context);
3457  sortcoltype = exprType(sortexpr);
3458  /* See whether operator is default < or > for datatype */
3459  typentry = lookup_type_cache(sortcoltype,
3461  if (srt->sortop == typentry->lt_opr)
3462  appendStringInfoString(buf, " ASC");
3463  else if (srt->sortop == typentry->gt_opr)
3464  appendStringInfoString(buf, " DESC");
3465  else
3466  {
3467  HeapTuple opertup;
3468  Form_pg_operator operform;
3469 
3470  appendStringInfoString(buf, " USING ");
3471 
3472  /* Append operator name. */
3473  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(srt->sortop));
3474  if (!HeapTupleIsValid(opertup))
3475  elog(ERROR, "cache lookup failed for operator %u", srt->sortop);
3476  operform = (Form_pg_operator) GETSTRUCT(opertup);
3477  deparseOperatorName(buf, operform);
3478  ReleaseSysCache(opertup);
3479  }
3480 
3481  if (srt->nulls_first)
3482  appendStringInfoString(buf, " NULLS FIRST");
3483  else
3484  appendStringInfoString(buf, " NULLS LAST");
3485  }
3486 }
static Node * deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
Definition: deparse.c:3690
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform)
Definition: deparse.c:3095
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
#define lfirst(lc)
Definition: pg_list.h:169
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static char * buf
Definition: pg_test_fsync.c:70
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
unsigned int Oid
Definition: postgres_ext.h:31
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
Definition: nodes.h:539
Index tleSortGroupRef
Definition: parsenodes.h:1295
StringInfo buf
Definition: deparse.c:102
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1198
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1150
@ 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(), deparseSortGroupClause(), elog, ERROR, exprType(), GETSTRUCT, TypeCacheEntry::gt_opr, HeapTupleIsValid, lfirst, lookup_type_cache(), TypeCacheEntry::lt_opr, SortGroupClause::nulls_first, ObjectIdGetDatum, OPEROID, ReleaseSysCache(), SearchSysCache1(), SortGroupClause::sortop, SortGroupClause::tleSortGroupRef, TYPECACHE_GT_OPR, and TYPECACHE_LT_OPR.

Referenced by deparseAggref().

◆ appendConditions()

static void appendConditions ( List exprs,
deparse_expr_cxt context 
)
static

Definition at line 1469 of file deparse.c.

1470 {
1471  int nestlevel;
1472  ListCell *lc;
1473  bool is_first = true;
1474  StringInfo buf = context->buf;
1475 
1476  /* Make sure any constants in the exprs are printed portably */
1477  nestlevel = set_transmission_modes();
1478 
1479  foreach(lc, exprs)
1480  {
1481  Expr *expr = (Expr *) lfirst(lc);
1482 
1483  /* Extract clause from RestrictInfo, if required */
1484  if (IsA(expr, RestrictInfo))
1485  expr = ((RestrictInfo *) expr)->clause;
1486 
1487  /* Connect expressions with "AND" and parenthesize each condition. */
1488  if (!is_first)
1489  appendStringInfoString(buf, " AND ");
1490 
1491  appendStringInfoChar(buf, '(');
1492  deparseExpr(expr, context);
1493  appendStringInfoChar(buf, ')');
1494 
1495  is_first = false;
1496  }
1497 
1498  reset_transmission_modes(nestlevel);
1499 }
static void deparseExpr(Expr *expr, deparse_expr_cxt *context)
Definition: deparse.c:2573
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
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 3655 of file deparse.c.

3656 {
3657  StringInfo buf = context->buf;
3658  HeapTuple proctup;
3659  Form_pg_proc procform;
3660  const char *proname;
3661 
3662  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3663  if (!HeapTupleIsValid(proctup))
3664  elog(ERROR, "cache lookup failed for function %u", funcid);
3665  procform = (Form_pg_proc) GETSTRUCT(proctup);
3666 
3667  /* Print schema name only if it's not pg_catalog */
3668  if (procform->pronamespace != PG_CATALOG_NAMESPACE)
3669  {
3670  const char *schemaname;
3671 
3672  schemaname = get_namespace_name(procform->pronamespace);
3673  appendStringInfo(buf, "%s.", quote_identifier(schemaname));
3674  }
3675 
3676  /* Always print the function name */
3677  proname = NameStr(procform->proname);
3679 
3680  ReleaseSysCache(proctup);
3681 }
#define NameStr(name)
Definition: c.h:681
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
NameData proname
Definition: pg_proc.h:35
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:11440
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
@ PROCOID
Definition: syscache.h:77

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

3537 {
3538  StringInfo buf = context->buf;
3539  Query *query = context->root->parse;
3540  ListCell *lc;
3541  bool first = true;
3542 
3543  /* Nothing to be done, if there's no GROUP BY clause in the query. */
3544  if (!query->groupClause)
3545  return;
3546 
3547  appendStringInfoString(buf, " GROUP BY ");
3548 
3549  /*
3550  * Queries with grouping sets are not pushed down, so we don't expect
3551  * grouping sets here.
3552  */
3553  Assert(!query->groupingSets);
3554 
3555  foreach(lc, query->groupClause)
3556  {
3557  SortGroupClause *grp = (SortGroupClause *) lfirst(lc);
3558 
3559  if (!first)
3560  appendStringInfoString(buf, ", ");
3561  first = false;
3562 
3563  deparseSortGroupClause(grp->tleSortGroupRef, tlist, true, context);
3564  }
3565 }
Assert(fmt[strlen(fmt) - 1] !='\n')
Query * parse
Definition: pathnodes.h:162
List * groupClause
Definition: parsenodes.h:157
List * groupingSets
Definition: parsenodes.h:160
PlannerInfo * root
Definition: deparse.c:97

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

3628 {
3629  PlannerInfo *root = context->root;
3630  StringInfo buf = context->buf;
3631  int nestlevel;
3632 
3633  /* Make sure any constants in the exprs are printed portably */
3634  nestlevel = set_transmission_modes();
3635 
3636  if (root->parse->limitCount)
3637  {
3638  appendStringInfoString(buf, " LIMIT ");
3639  deparseExpr((Expr *) root->parse->limitCount, context);
3640  }
3641  if (root->parse->limitOffset)
3642  {
3643  appendStringInfoString(buf, " OFFSET ");
3644  deparseExpr((Expr *) root->parse->limitOffset, context);
3645  }
3646 
3647  reset_transmission_modes(nestlevel);
3648 }
Node * limitCount
Definition: parsenodes.h:171
Node * limitOffset
Definition: parsenodes.h:170

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

3575 {
3576  ListCell *lcell;
3577  int nestlevel;
3578  char *delim = " ";
3579  RelOptInfo *baserel = context->scanrel;
3580  StringInfo buf = context->buf;
3581 
3582  /* Make sure any constants in the exprs are printed portably */
3583  nestlevel = set_transmission_modes();
3584 
3585  appendStringInfoString(buf, " ORDER BY");
3586  foreach(lcell, pathkeys)
3587  {
3588  PathKey *pathkey = lfirst(lcell);
3589  Expr *em_expr;
3590 
3591  if (has_final_sort)
3592  {
3593  /*
3594  * By construction, context->foreignrel is the input relation to
3595  * the final sort.
3596  */
3597  em_expr = find_em_expr_for_input_target(context->root,
3598  pathkey->pk_eclass,
3599  context->foreignrel->reltarget);
3600  }
3601  else
3602  em_expr = find_em_expr_for_rel(pathkey->pk_eclass, baserel);
3603 
3604  Assert(em_expr != NULL);
3605 
3606  appendStringInfoString(buf, delim);
3607  deparseExpr(em_expr, context);
3608  if (pathkey->pk_strategy == BTLessStrategyNumber)
3609  appendStringInfoString(buf, " ASC");
3610  else
3611  appendStringInfoString(buf, " DESC");
3612 
3613  if (pathkey->pk_nulls_first)
3614  appendStringInfoString(buf, " NULLS FIRST");
3615  else
3616  appendStringInfoString(buf, " NULLS LAST");
3617 
3618  delim = ", ";
3619  }
3620  reset_transmission_modes(nestlevel);
3621 }
Expr * find_em_expr_for_input_target(PlannerInfo *root, EquivalenceClass *ec, PathTarget *target)
Expr * find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel)
Definition: equivclass.c:939
#define BTLessStrategyNumber
Definition: stratnum.h:29
bool pk_nulls_first
Definition: pathnodes.h:1070
int pk_strategy
Definition: pathnodes.h:1069
EquivalenceClass * pk_eclass
Definition: pathnodes.h:1067
struct PathTarget * reltarget
Definition: pathnodes.h:692
RelOptInfo * foreignrel
Definition: deparse.c:98
RelOptInfo * scanrel
Definition: deparse.c:99

References appendStringInfoString(), Assert(), BTLessStrategyNumber, deparse_expr_cxt::buf, buf, deparseExpr(), find_em_expr_for_input_target(), find_em_expr_for_rel(), deparse_expr_cxt::foreignrel, lfirst, PathKey::pk_eclass, PathKey::pk_nulls_first, PathKey::pk_strategy, RelOptInfo::reltarget, reset_transmission_modes(), deparse_expr_cxt::root, deparse_expr_cxt::scanrel, and set_transmission_modes().

Referenced by deparseSelectStmtForRel().

◆ build_tlist_to_deparse()

List* build_tlist_to_deparse ( RelOptInfo foreignrel)

Definition at line 1072 of file deparse.c.

1073 {
1074  List *tlist = NIL;
1075  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1076  ListCell *lc;
1077 
1078  /*
1079  * For an upper relation, we have already built the target list while
1080  * checking shippability, so just return that.
1081  */
1082  if (IS_UPPER_REL(foreignrel))
1083  return fpinfo->grouped_tlist;
1084 
1085  /*
1086  * We require columns specified in foreignrel->reltarget->exprs and those
1087  * required for evaluating the local conditions.
1088  */
1089  tlist = add_to_flat_tlist(tlist,
1090  pull_var_clause((Node *) foreignrel->reltarget->exprs,
1092  foreach(lc, fpinfo->local_conds)
1093  {
1094  RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
1095 
1096  tlist = add_to_flat_tlist(tlist,
1097  pull_var_clause((Node *) rinfo->clause,
1099  }
1100 
1101  return tlist;
1102 }
#define PVC_RECURSE_PLACEHOLDERS
Definition: optimizer.h:191
#define IS_UPPER_REL(rel)
Definition: pathnodes.h:664
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:65
Definition: pg_list.h:51
List * exprs
Definition: pathnodes.h:1111
void * fdw_private
Definition: pathnodes.h:737
Expr * clause
Definition: pathnodes.h:2059
List * add_to_flat_tlist(List *tlist, List *exprs)
Definition: tlist.c:121
List * pull_var_clause(Node *node, int flags)
Definition: var.c:604

References add_to_flat_tlist(), RestrictInfo::clause, PathTarget::exprs, RelOptInfo::fdw_private, 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 208 of file deparse.c.

213 {
214  ListCell *lc;
215 
216  *remote_conds = NIL;
217  *local_conds = NIL;
218 
219  foreach(lc, input_conds)
220  {
222 
223  if (is_foreign_expr(root, baserel, ri->clause))
224  *remote_conds = lappend(*remote_conds, ri);
225  else
226  *local_conds = lappend(*local_conds, ri);
227  }
228 }
bool is_foreign_expr(PlannerInfo *root, RelOptInfo *baserel, Expr *expr)
Definition: deparse.c:234
List * lappend(List *list, void *datum)
Definition: list.c:336

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

1054 {
1056 
1057  if (!is_builtin(type_oid))
1058  flags |= FORMAT_TYPE_FORCE_QUALIFY;
1059 
1060  return format_type_extended(type_oid, typemod, flags);
1061 }
#define FORMAT_TYPE_TYPEMOD_GIVEN
Definition: builtins.h:111
#define FORMAT_TYPE_FORCE_QUALIFY
Definition: builtins.h:113
uint16 bits16
Definition: c.h:449
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 3346 of file deparse.c.

3347 {
3348  StringInfo buf = context->buf;
3349  bool use_variadic;
3350 
3351  /* Only basic, non-split aggregation accepted. */
3352  Assert(node->aggsplit == AGGSPLIT_SIMPLE);
3353 
3354  /* Check if need to print VARIADIC (cf. ruleutils.c) */
3355  use_variadic = node->aggvariadic;
3356 
3357  /* Find aggregate name from aggfnoid which is a pg_proc entry */
3358  appendFunctionName(node->aggfnoid, context);
3359  appendStringInfoChar(buf, '(');
3360 
3361  /* Add DISTINCT */
3362  appendStringInfoString(buf, (node->aggdistinct != NIL) ? "DISTINCT " : "");
3363 
3364  if (AGGKIND_IS_ORDERED_SET(node->aggkind))
3365  {
3366  /* Add WITHIN GROUP (ORDER BY ..) */
3367  ListCell *arg;
3368  bool first = true;
3369 
3370  Assert(!node->aggvariadic);
3371  Assert(node->aggorder != NIL);
3372 
3373  foreach(arg, node->aggdirectargs)
3374  {
3375  if (!first)
3376  appendStringInfoString(buf, ", ");
3377  first = false;
3378 
3379  deparseExpr((Expr *) lfirst(arg), context);
3380  }
3381 
3382  appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
3383  appendAggOrderBy(node->aggorder, node->args, context);
3384  }
3385  else
3386  {
3387  /* aggstar can be set only in zero-argument aggregates */
3388  if (node->aggstar)
3389  appendStringInfoChar(buf, '*');
3390  else
3391  {
3392  ListCell *arg;
3393  bool first = true;
3394 
3395  /* Add all the arguments */
3396  foreach(arg, node->args)
3397  {
3398  TargetEntry *tle = (TargetEntry *) lfirst(arg);
3399  Node *n = (Node *) tle->expr;
3400 
3401  if (tle->resjunk)
3402  continue;
3403 
3404  if (!first)
3405  appendStringInfoString(buf, ", ");
3406  first = false;
3407 
3408  /* Add VARIADIC */
3409  if (use_variadic && lnext(node->args, arg) == NULL)
3410  appendStringInfoString(buf, "VARIADIC ");
3411 
3412  deparseExpr((Expr *) n, context);
3413  }
3414  }
3415 
3416  /* Add ORDER BY */
3417  if (node->aggorder != NIL)
3418  {
3419  appendStringInfoString(buf, " ORDER BY ");
3420  appendAggOrderBy(node->aggorder, node->args, context);
3421  }
3422  }
3423 
3424  /* Add FILTER (WHERE ..) */
3425  if (node->aggfilter != NULL)
3426  {
3427  appendStringInfoString(buf, ") FILTER (WHERE ");
3428  deparseExpr((Expr *) node->aggfilter, context);
3429  }
3430 
3431  appendStringInfoChar(buf, ')');
3432 }
static void appendFunctionName(Oid funcid, deparse_expr_cxt *context)
Definition: deparse.c:3655
static void appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
Definition: deparse.c:3438
@ AGGSPLIT_SIMPLE
Definition: nodes.h:793
void * arg
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
bool aggstar
Definition: primnodes.h:334
Oid aggfnoid
Definition: primnodes.h:323
List * aggdistinct
Definition: primnodes.h:332
List * aggdirectargs
Definition: primnodes.h:329
bool aggvariadic
Definition: primnodes.h:335
char aggkind
Definition: primnodes.h:337
List * args
Definition: primnodes.h:330
Expr * aggfilter
Definition: primnodes.h:333
List * aggorder
Definition: primnodes.h:331
AggSplit aggsplit
Definition: primnodes.h:339
Expr * expr
Definition: primnodes.h:1455
bool resjunk
Definition: primnodes.h:1462

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

2258 {
2260 
2261  /* We'll need the remote relation name as a literal. */
2263  deparseRelation(&relname, rel);
2264 
2265  appendStringInfoString(buf, "SELECT pg_catalog.pg_relation_size(");
2267  appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
2268 }
void deparseStringLiteral(StringInfo buf, const char *val)
Definition: deparse.c:2538
static void deparseRelation(StringInfo buf, Relation rel)
Definition: deparse.c:2498
NameData relname
Definition: pg_class.h:38
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
char data[NAMEDATALEN]
Definition: c.h:677

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

2278 {
2279  Oid relid = RelationGetRelid(rel);
2280  TupleDesc tupdesc = RelationGetDescr(rel);
2281  int i;
2282  char *colname;
2283  List *options;
2284  ListCell *lc;
2285  bool first = true;
2286 
2287  *retrieved_attrs = NIL;
2288 
2289  appendStringInfoString(buf, "SELECT ");
2290  for (i = 0; i < tupdesc->natts; i++)
2291  {
2292  /* Ignore dropped columns. */
2293  if (TupleDescAttr(tupdesc, i)->attisdropped)
2294  continue;
2295 
2296  if (!first)
2297  appendStringInfoString(buf, ", ");
2298  first = false;
2299 
2300  /* Use attribute name or column_name option. */
2301  colname = NameStr(TupleDescAttr(tupdesc, i)->attname);
2302  options = GetForeignColumnOptions(relid, i + 1);
2303 
2304  foreach(lc, options)
2305  {
2306  DefElem *def = (DefElem *) lfirst(lc);
2307 
2308  if (strcmp(def->defname, "column_name") == 0)
2309  {
2310  colname = defGetString(def);
2311  break;
2312  }
2313  }
2314 
2316 
2317  *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
2318  }
2319 
2320  /* Don't generate bad syntax for zero-column relation. */
2321  if (first)
2322  appendStringInfoString(buf, "NULL");
2323 
2324  /*
2325  * Construct FROM clause
2326  */
2327  appendStringInfoString(buf, " FROM ");
2328  deparseRelation(buf, rel);
2329 }
char * defGetString(DefElem *def)
Definition: define.c:49
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition: foreign.c:286
int i
Definition: isn.c:73
List * lappend_int(List *list, int datum)
Definition: list.c:354
NameData attname
Definition: pg_attribute.h:41
static char ** options
#define RelationGetRelid(relation)
Definition: rel.h:478
#define RelationGetDescr(relation)
Definition: rel.h:504
char * defname
Definition: parsenodes.h:758
#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 3320 of file deparse.c.

3321 {
3322  StringInfo buf = context->buf;
3323  bool first = true;
3324  ListCell *lc;
3325 
3326  appendStringInfoString(buf, "ARRAY[");
3327  foreach(lc, node->elements)
3328  {
3329  if (!first)
3330  appendStringInfoString(buf, ", ");
3331  deparseExpr(lfirst(lc), context);
3332  first = false;
3333  }
3334  appendStringInfoChar(buf, ']');
3335 
3336  /* If the array is empty, we need an explicit cast to the array type. */
3337  if (node->elements == NIL)
3338  appendStringInfo(buf, "::%s",
3339  deparse_type_name(node->array_typeid, -1));
3340 }
static char * deparse_type_name(Oid type_oid, int32 typemod)
Definition: deparse.c:1053
Oid array_typeid
Definition: primnodes.h:1034
List * elements
Definition: primnodes.h:1037

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

3200 {
3201  StringInfo buf = context->buf;
3202  const char *op = NULL; /* keep compiler quiet */
3203  bool first;
3204  ListCell *lc;
3205 
3206  switch (node->boolop)
3207  {
3208  case AND_EXPR:
3209  op = "AND";
3210  break;
3211  case OR_EXPR:
3212  op = "OR";
3213  break;
3214  case NOT_EXPR:
3215  appendStringInfoString(buf, "(NOT ");
3216  deparseExpr(linitial(node->args), context);
3217  appendStringInfoChar(buf, ')');
3218  return;
3219  }
3220 
3221  appendStringInfoChar(buf, '(');
3222  first = true;
3223  foreach(lc, node->args)
3224  {
3225  if (!first)
3226  appendStringInfo(buf, " %s ", op);
3227  deparseExpr((Expr *) lfirst(lc), context);
3228  first = false;
3229  }
3230  appendStringInfoChar(buf, ')');
3231 }
#define linitial(l)
Definition: pg_list.h:174
@ AND_EXPR
Definition: primnodes.h:619
@ OR_EXPR
Definition: primnodes.h:619
@ NOT_EXPR
Definition: primnodes.h:619
BoolExprType boolop
Definition: primnodes.h:625
List * args
Definition: primnodes.h:626

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

3271 {
3272  StringInfo buf = context->buf;
3273  ListCell *lc;
3274 
3275  appendStringInfoString(buf, "(CASE");
3276 
3277  /* If this is a CASE arg WHEN then emit the arg expression */
3278  if (node->arg != NULL)
3279  {
3280  appendStringInfoChar(buf, ' ');
3281  deparseExpr(node->arg, context);
3282  }
3283 
3284  /* Add each condition/result of the CASE clause */
3285  foreach(lc, node->args)
3286  {
3287  CaseWhen *whenclause = (CaseWhen *) lfirst(lc);
3288 
3289  /* WHEN */
3290  appendStringInfoString(buf, " WHEN ");
3291  if (node->arg == NULL) /* CASE WHEN */
3292  deparseExpr(whenclause->expr, context);
3293  else /* CASE arg WHEN */
3294  {
3295  /* Ignore the CaseTestExpr and equality operator. */
3296  deparseExpr(lsecond(castNode(OpExpr, whenclause->expr)->args),
3297  context);
3298  }
3299 
3300  /* THEN */
3301  appendStringInfoString(buf, " THEN ");
3302  deparseExpr(whenclause->result, context);
3303  }
3304 
3305  /* add ELSE if present */
3306  if (node->defresult != NULL)
3307  {
3308  appendStringInfoString(buf, " ELSE ");
3309  deparseExpr(node->defresult, context);
3310  }
3311 
3312  /* append END */
3313  appendStringInfoString(buf, " END)");
3314 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:607
#define lsecond(l)
Definition: pg_list.h:179
Expr * arg
Definition: primnodes.h:978
Expr * defresult
Definition: primnodes.h:980
List * args
Definition: primnodes.h:979
Expr * result
Definition: primnodes.h:991
Expr * expr
Definition: primnodes.h:990

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

2372 {
2373  /* We support fetching the remote side's CTID and OID. */
2374  if (varattno == SelfItemPointerAttributeNumber)
2375  {
2376  if (qualify_col)
2377  ADD_REL_QUALIFIER(buf, varno);
2378  appendStringInfoString(buf, "ctid");
2379  }
2380  else if (varattno < 0)
2381  {
2382  /*
2383  * All other system attributes are fetched as 0, except for table OID,
2384  * which is fetched as the local table OID. However, we must be
2385  * careful; the table could be beneath an outer join, in which case it
2386  * must go to NULL whenever the rest of the row does.
2387  */
2388  Oid fetchval = 0;
2389 
2390  if (varattno == TableOidAttributeNumber)
2391  fetchval = rte->relid;
2392 
2393  if (qualify_col)
2394  {
2395  appendStringInfoString(buf, "CASE WHEN (");
2396  ADD_REL_QUALIFIER(buf, varno);
2397  appendStringInfo(buf, "*)::text IS NOT NULL THEN %u END", fetchval);
2398  }
2399  else
2400  appendStringInfo(buf, "%u", fetchval);
2401  }
2402  else if (varattno == 0)
2403  {
2404  /* Whole row reference */
2405  Relation rel;
2406  Bitmapset *attrs_used;
2407 
2408  /* Required only to be passed down to deparseTargetList(). */
2409  List *retrieved_attrs;
2410 
2411  /*
2412  * The lock on the relation will be held by upper callers, so it's
2413  * fine to open it with no lock here.
2414  */
2415  rel = table_open(rte->relid, NoLock);
2416 
2417  /*
2418  * The local name of the foreign table can not be recognized by the
2419  * foreign server and the table it references on foreign server might
2420  * have different column ordering or different columns than those
2421  * declared locally. Hence we have to deparse whole-row reference as
2422  * ROW(columns referenced locally). Construct this by deparsing a
2423  * "whole row" attribute.
2424  */
2425  attrs_used = bms_add_member(NULL,
2427 
2428  /*
2429  * In case the whole-row reference is under an outer join then it has
2430  * to go NULL whenever the rest of the row goes NULL. Deparsing a join
2431  * query would always involve multiple relations, thus qualify_col
2432  * would be true.
2433  */
2434  if (qualify_col)
2435  {
2436  appendStringInfoString(buf, "CASE WHEN (");
2437  ADD_REL_QUALIFIER(buf, varno);
2438  appendStringInfoString(buf, "*)::text IS NOT NULL THEN ");
2439  }
2440 
2441  appendStringInfoString(buf, "ROW(");
2442  deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
2443  &retrieved_attrs);
2444  appendStringInfoChar(buf, ')');
2445 
2446  /* Complete the CASE WHEN statement started above. */
2447  if (qualify_col)
2448  appendStringInfoString(buf, " END");
2449 
2450  table_close(rel, NoLock);
2451  bms_free(attrs_used);
2452  }
2453  else
2454  {
2455  char *colname = NULL;
2456  List *options;
2457  ListCell *lc;
2458 
2459  /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */
2460  Assert(!IS_SPECIAL_VARNO(varno));
2461 
2462  /*
2463  * If it's a column of a foreign table, and it has the column_name FDW
2464  * option, use that value.
2465  */
2466  options = GetForeignColumnOptions(rte->relid, varattno);
2467  foreach(lc, options)
2468  {
2469  DefElem *def = (DefElem *) lfirst(lc);
2470 
2471  if (strcmp(def->defname, "column_name") == 0)
2472  {
2473  colname = defGetString(def);
2474  break;
2475  }
2476  }
2477 
2478  /*
2479  * If it's a column of a regular table or it doesn't have column_name
2480  * FDW option, use attribute name.
2481  */
2482  if (colname == NULL)
2483  colname = get_attname(rte->relid, varattno, false);
2484 
2485  if (qualify_col)
2486  ADD_REL_QUALIFIER(buf, varno);
2487 
2489  }
2490 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:738
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:1303
#define ADD_REL_QUALIFIER(buf, varno)
Definition: deparse.c:108
#define NoLock
Definition: lockdefs.h:34
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:825
#define IS_SPECIAL_VARNO(varno)
Definition: primnodes.h:180
#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:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

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

2710 {
2711  StringInfo buf = context->buf;
2712  Oid typoutput;
2713  bool typIsVarlena;
2714  char *extval;
2715  bool isfloat = false;
2716  bool isstring = false;
2717  bool needlabel;
2718 
2719  if (node->constisnull)
2720  {
2721  appendStringInfoString(buf, "NULL");
2722  if (showtype >= 0)
2723  appendStringInfo(buf, "::%s",
2725  node->consttypmod));
2726  return;
2727  }
2728 
2730  &typoutput, &typIsVarlena);
2731  extval = OidOutputFunctionCall(typoutput, node->constvalue);
2732 
2733  switch (node->consttype)
2734  {
2735  case INT2OID:
2736  case INT4OID:
2737  case INT8OID:
2738  case OIDOID:
2739  case FLOAT4OID:
2740  case FLOAT8OID:
2741  case NUMERICOID:
2742  {
2743  /*
2744  * No need to quote unless it's a special value such as 'NaN'.
2745  * See comments in get_const_expr().
2746  */
2747  if (strspn(extval, "0123456789+-eE.") == strlen(extval))
2748  {
2749  if (extval[0] == '+' || extval[0] == '-')
2750  appendStringInfo(buf, "(%s)", extval);
2751  else
2752  appendStringInfoString(buf, extval);
2753  if (strcspn(extval, "eE.") != strlen(extval))
2754  isfloat = true; /* it looks like a float */
2755  }
2756  else
2757  appendStringInfo(buf, "'%s'", extval);
2758  }
2759  break;
2760  case BITOID:
2761  case VARBITOID:
2762  appendStringInfo(buf, "B'%s'", extval);
2763  break;
2764  case BOOLOID:
2765  if (strcmp(extval, "t") == 0)
2766  appendStringInfoString(buf, "true");
2767  else
2768  appendStringInfoString(buf, "false");
2769  break;
2770  default:
2771  deparseStringLiteral(buf, extval);
2772  isstring = true;
2773  break;
2774  }
2775 
2776  pfree(extval);
2777 
2778  if (showtype == -1)
2779  return; /* never print type label */
2780 
2781  /*
2782  * For showtype == 0, append ::typename unless the constant will be
2783  * implicitly typed as the right type when it is read in.
2784  *
2785  * XXX this code has to be kept in sync with the behavior of the parser,
2786  * especially make_const.
2787  */
2788  switch (node->consttype)
2789  {
2790  case BOOLOID:
2791  case INT4OID:
2792  case UNKNOWNOID:
2793  needlabel = false;
2794  break;
2795  case NUMERICOID:
2796  needlabel = !isfloat || (node->consttypmod >= 0);
2797  break;
2798  default:
2799  if (showtype == -2)
2800  {
2801  /* label unless we printed it as an untyped string */
2802  needlabel = !isstring;
2803  }
2804  else
2805  needlabel = true;
2806  break;
2807  }
2808  if (needlabel || showtype > 0)
2809  appendStringInfo(buf, "::%s",
2811  node->consttypmod));
2812 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1653
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2854
void pfree(void *pointer)
Definition: mcxt.c:1169
Oid consttype
Definition: primnodes.h:215
Datum constvalue
Definition: primnodes.h:219
bool constisnull
Definition: primnodes.h:220
int32 consttypmod
Definition: primnodes.h:216

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

2124 {
2125  appendStringInfoString(buf, "DELETE FROM ");
2126  deparseRelation(buf, rel);
2127  appendStringInfoString(buf, " WHERE ctid = $1");
2128 
2129  deparseReturningList(buf, rte, rtindex, rel,
2130  rel->trigdesc && rel->trigdesc->trig_delete_after_row,
2131  NIL, returningList, retrieved_attrs);
2132 }
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:2200
TriggerDesc * trigdesc
Definition: rel.h:115
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 2149 of file deparse.c.

2156 {
2157  deparse_expr_cxt context;
2158 
2159  /* Set up context struct for recursion */
2160  context.root = root;
2161  context.foreignrel = foreignrel;
2162  context.scanrel = foreignrel;
2163  context.buf = buf;
2164  context.params_list = params_list;
2165 
2166  appendStringInfoString(buf, "DELETE FROM ");
2167  deparseRelation(buf, rel);
2168  if (foreignrel->reloptkind == RELOPT_JOINREL)
2169  appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2170 
2171  if (foreignrel->reloptkind == RELOPT_JOINREL)
2172  {
2173  List *ignore_conds = NIL;
2174 
2175  appendStringInfoString(buf, " USING ");
2176  deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2177  &ignore_conds, params_list);
2178  remote_conds = list_concat(remote_conds, ignore_conds);
2179  }
2180 
2181  if (remote_conds)
2182  {
2183  appendStringInfoString(buf, " WHERE ");
2184  appendConditions(remote_conds, &context);
2185  }
2186 
2187  if (foreignrel->reloptkind == RELOPT_JOINREL)
2188  deparseExplicitTargetList(returningList, true, retrieved_attrs,
2189  &context);
2190  else
2191  deparseReturningList(buf, planner_rt_fetch(rtindex, root),
2192  rtindex, rel, false,
2193  NIL, returningList, retrieved_attrs);
2194 }
#define REL_ALIAS_PREFIX
Definition: deparse.c:106
static void appendConditions(List *exprs, deparse_expr_cxt *context)
Definition: deparse.c:1469
static void deparseExplicitTargetList(List *tlist, bool is_returning, List **retrieved_attrs, deparse_expr_cxt *context)
Definition: deparse.c:1540
static void deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool use_alias, Index ignore_rel, List **ignore_conds, List **params_list)
Definition: deparse.c:1617
List * list_concat(List *list1, const List *list2)
Definition: list.c:540
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:388
@ RELOPT_JOINREL
Definition: pathnodes.h:642
RelOptKind reloptkind
Definition: pathnodes.h:678
List ** params_list
Definition: deparse.c:103

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

2044 {
2045  deparse_expr_cxt context;
2046  int nestlevel;
2047  bool first;
2048  RangeTblEntry *rte = planner_rt_fetch(rtindex, root);
2049  ListCell *lc,
2050  *lc2;
2051 
2052  /* Set up context struct for recursion */
2053  context.root = root;
2054  context.foreignrel = foreignrel;
2055  context.scanrel = foreignrel;
2056  context.buf = buf;
2057  context.params_list = params_list;
2058 
2059  appendStringInfoString(buf, "UPDATE ");
2060  deparseRelation(buf, rel);
2061  if (foreignrel->reloptkind == RELOPT_JOINREL)
2062  appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2063  appendStringInfoString(buf, " SET ");
2064 
2065  /* Make sure any constants in the exprs are printed portably */
2066  nestlevel = set_transmission_modes();
2067 
2068  first = true;
2069  forboth(lc, targetlist, lc2, targetAttrs)
2070  {
2071  TargetEntry *tle = lfirst_node(TargetEntry, lc);
2072  int attnum = lfirst_int(lc2);
2073 
2074  /* update's new-value expressions shouldn't be resjunk */
2075  Assert(!tle->resjunk);
2076 
2077  if (!first)
2078  appendStringInfoString(buf, ", ");
2079  first = false;
2080 
2081  deparseColumnRef(buf, rtindex, attnum, rte, false);
2082  appendStringInfoString(buf, " = ");
2083  deparseExpr((Expr *) tle->expr, &context);
2084  }
2085 
2086  reset_transmission_modes(nestlevel);
2087 
2088  if (foreignrel->reloptkind == RELOPT_JOINREL)
2089  {
2090  List *ignore_conds = NIL;
2091 
2092  appendStringInfoString(buf, " FROM ");
2093  deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2094  &ignore_conds, params_list);
2095  remote_conds = list_concat(remote_conds, ignore_conds);
2096  }
2097 
2098  if (remote_conds)
2099  {
2100  appendStringInfoString(buf, " WHERE ");
2101  appendConditions(remote_conds, &context);
2102  }
2103 
2104  if (foreignrel->reloptkind == RELOPT_JOINREL)
2105  deparseExplicitTargetList(returningList, true, retrieved_attrs,
2106  &context);
2107  else
2108  deparseReturningList(buf, rte, rtindex, rel, false,
2109  NIL, returningList, retrieved_attrs);
2110 }
static void deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte, bool qualify_col)
Definition: deparse.c:2370
int16 attnum
Definition: pg_attribute.h:83
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
#define lfirst_int(lc)
Definition: pg_list.h:170

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

3124 {
3125  StringInfo buf = context->buf;
3126 
3127  Assert(list_length(node->args) == 2);
3128 
3129  appendStringInfoChar(buf, '(');
3130  deparseExpr(linitial(node->args), context);
3131  appendStringInfoString(buf, " IS DISTINCT FROM ");
3132  deparseExpr(lsecond(node->args), context);
3133  appendStringInfoChar(buf, ')');
3134 }
static int list_length(const List *l)
Definition: pg_list.h:149
List * args
Definition: primnodes.h:548

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

1544 {
1545  ListCell *lc;
1546  StringInfo buf = context->buf;
1547  int i = 0;
1548 
1549  *retrieved_attrs = NIL;
1550 
1551  foreach(lc, tlist)
1552  {
1553  TargetEntry *tle = lfirst_node(TargetEntry, lc);
1554 
1555  if (i > 0)
1556  appendStringInfoString(buf, ", ");
1557  else if (is_returning)
1558  appendStringInfoString(buf, " RETURNING ");
1559 
1560  deparseExpr((Expr *) tle->expr, context);
1561 
1562  *retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
1563  i++;
1564  }
1565 
1566  if (i == 0 && !is_returning)
1567  appendStringInfoString(buf, "NULL");
1568 }

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 expr,
deparse_expr_cxt context 
)
static

Definition at line 2573 of file deparse.c.

2574 {
2575  if (node == NULL)
2576  return;
2577 
2578  switch (nodeTag(node))
2579  {
2580  case T_Var:
2581  deparseVar((Var *) node, context);
2582  break;
2583  case T_Const:
2584  deparseConst((Const *) node, context, 0);
2585  break;
2586  case T_Param:
2587  deparseParam((Param *) node, context);
2588  break;
2589  case T_SubscriptingRef:
2590  deparseSubscriptingRef((SubscriptingRef *) node, context);
2591  break;
2592  case T_FuncExpr:
2593  deparseFuncExpr((FuncExpr *) node, context);
2594  break;
2595  case T_OpExpr:
2596  deparseOpExpr((OpExpr *) node, context);
2597  break;
2598  case T_DistinctExpr:
2599  deparseDistinctExpr((DistinctExpr *) node, context);
2600  break;
2601  case T_ScalarArrayOpExpr:
2602  deparseScalarArrayOpExpr((ScalarArrayOpExpr *) node, context);
2603  break;
2604  case T_RelabelType:
2605  deparseRelabelType((RelabelType *) node, context);
2606  break;
2607  case T_BoolExpr:
2608  deparseBoolExpr((BoolExpr *) node, context);
2609  break;
2610  case T_NullTest:
2611  deparseNullTest((NullTest *) node, context);
2612  break;
2613  case T_CaseExpr:
2614  deparseCaseExpr((CaseExpr *) node, context);
2615  break;
2616  case T_ArrayExpr:
2617  deparseArrayExpr((ArrayExpr *) node, context);
2618  break;
2619  case T_Aggref:
2620  deparseAggref((Aggref *) node, context);
2621  break;
2622  default:
2623  elog(ERROR, "unsupported expression type for deparse: %d",
2624  (int) nodeTag(node));
2625  break;
2626  }
2627 }
static void deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3270
static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3199
static void deparseAggref(Aggref *node, deparse_expr_cxt *context)
Definition: deparse.c:3346
static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
Definition: deparse.c:3186
static void deparseNullTest(NullTest *node, deparse_expr_cxt *context)
Definition: deparse.c:3237
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:2965
static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype)
Definition: deparse.c:2709
static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3123
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:2902
static void deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3320
static void deparseVar(Var *node, deparse_expr_cxt *context)
Definition: deparse.c:2638
static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
Definition: deparse.c:2856
static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node, deparse_expr_cxt *context)
Definition: deparse.c:3141
static void deparseParam(Param *node, deparse_expr_cxt *context)
Definition: deparse.c:2823
#define nodeTag(nodeptr)
Definition: nodes.h:543
@ T_ArrayExpr
Definition: nodes.h:183
@ T_BoolExpr
Definition: nodes.h:169
@ T_OpExpr
Definition: nodes.h:165
@ T_ScalarArrayOpExpr
Definition: nodes.h:168
@ T_CaseExpr
Definition: nodes.h:180
@ T_RelabelType
Definition: nodes.h:175
@ T_Aggref
Definition: nodes.h:159
@ T_Const
Definition: nodes.h:157
@ T_Param
Definition: nodes.h:158
@ T_DistinctExpr
Definition: nodes.h:166
@ T_FuncExpr
Definition: nodes.h:163
@ T_Var
Definition: nodes.h:156
@ T_NullTest
Definition: nodes.h:190
@ T_SubscriptingRef
Definition: nodes.h:162
Definition: primnodes.h:187

References deparseAggref(), deparseArrayExpr(), deparseBoolExpr(), deparseCaseExpr(), deparseConst(), deparseDistinctExpr(), deparseFuncExpr(), deparseNullTest(), deparseOpExpr(), deparseParam(), deparseRelabelType(), deparseScalarArrayOpExpr(), deparseSubscriptingRef(), deparseVar(), elog, ERROR, nodeTag, T_Aggref, T_ArrayExpr, T_BoolExpr, T_CaseExpr, T_Const, T_DistinctExpr, T_FuncExpr, T_NullTest, T_OpExpr, T_Param, T_RelabelType, T_ScalarArrayOpExpr, T_SubscriptingRef, and T_Var.

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

1270 {
1271  StringInfo buf = context->buf;
1272  RelOptInfo *scanrel = context->scanrel;
1273 
1274  /* For upper relations, scanrel must be either a joinrel or a baserel */
1275  Assert(!IS_UPPER_REL(context->foreignrel) ||
1276  IS_JOIN_REL(scanrel) || IS_SIMPLE_REL(scanrel));
1277 
1278  /* Construct FROM clause */
1279  appendStringInfoString(buf, " FROM ");
1280  deparseFromExprForRel(buf, context->root, scanrel,
1281  (bms_membership(scanrel->relids) == BMS_MULTIPLE),
1282  (Index) 0, NULL, context->params_list);
1283 
1284  /* Construct WHERE clause */
1285  if (quals != NIL)
1286  {
1287  appendStringInfoString(buf, " WHERE ");
1288  appendConditions(quals, context);
1289  }
1290 }
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:674
@ BMS_MULTIPLE
Definition: bitmapset.h:70
unsigned int Index
Definition: c.h:549
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:654
#define IS_JOIN_REL(rel)
Definition: pathnodes.h:659
Relids relids
Definition: pathnodes.h:681

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

1620 {
1621  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1622 
1623  if (IS_JOIN_REL(foreignrel))
1624  {
1625  StringInfoData join_sql_o;
1626  StringInfoData join_sql_i;
1627  RelOptInfo *outerrel = fpinfo->outerrel;
1628  RelOptInfo *innerrel = fpinfo->innerrel;
1629  bool outerrel_is_target = false;
1630  bool innerrel_is_target = false;
1631 
1632  if (ignore_rel > 0 && bms_is_member(ignore_rel, foreignrel->relids))
1633  {
1634  /*
1635  * If this is an inner join, add joinclauses to *ignore_conds and
1636  * set it to empty so that those can be deparsed into the WHERE
1637  * clause. Note that since the target relation can never be
1638  * within the nullable side of an outer join, those could safely
1639  * be pulled up into the WHERE clause (see foreign_join_ok()).
1640  * Note also that since the target relation is only inner-joined
1641  * to any other relation in the query, all conditions in the join
1642  * tree mentioning the target relation could be deparsed into the
1643  * WHERE clause by doing this recursively.
1644  */
1645  if (fpinfo->jointype == JOIN_INNER)
1646  {
1647  *ignore_conds = list_concat(*ignore_conds,
1648  fpinfo->joinclauses);
1649  fpinfo->joinclauses = NIL;
1650  }
1651 
1652  /*
1653  * Check if either of the input relations is the target relation.
1654  */
1655  if (outerrel->relid == ignore_rel)
1656  outerrel_is_target = true;
1657  else if (innerrel->relid == ignore_rel)
1658  innerrel_is_target = true;
1659  }
1660 
1661  /* Deparse outer relation if not the target relation. */
1662  if (!outerrel_is_target)
1663  {
1664  initStringInfo(&join_sql_o);
1665  deparseRangeTblRef(&join_sql_o, root, outerrel,
1666  fpinfo->make_outerrel_subquery,
1667  ignore_rel, ignore_conds, params_list);
1668 
1669  /*
1670  * If inner relation is the target relation, skip deparsing it.
1671  * Note that since the join of the target relation with any other
1672  * relation in the query is an inner join and can never be within
1673  * the nullable side of an outer join, the join could be
1674  * interchanged with higher-level joins (cf. identity 1 on outer
1675  * join reordering shown in src/backend/optimizer/README), which
1676  * means it's safe to skip the target-relation deparsing here.
1677  */
1678  if (innerrel_is_target)
1679  {
1680  Assert(fpinfo->jointype == JOIN_INNER);
1681  Assert(fpinfo->joinclauses == NIL);
1682  appendBinaryStringInfo(buf, join_sql_o.data, join_sql_o.len);
1683  return;
1684  }
1685  }
1686 
1687  /* Deparse inner relation if not the target relation. */
1688  if (!innerrel_is_target)
1689  {
1690  initStringInfo(&join_sql_i);
1691  deparseRangeTblRef(&join_sql_i, root, innerrel,
1692  fpinfo->make_innerrel_subquery,
1693  ignore_rel, ignore_conds, params_list);
1694 
1695  /*
1696  * If outer relation is the target relation, skip deparsing it.
1697  * See the above note about safety.
1698  */
1699  if (outerrel_is_target)
1700  {
1701  Assert(fpinfo->jointype == JOIN_INNER);
1702  Assert(fpinfo->joinclauses == NIL);
1703  appendBinaryStringInfo(buf, join_sql_i.data, join_sql_i.len);
1704  return;
1705  }
1706  }
1707 
1708  /* Neither of the relations is the target relation. */
1709  Assert(!outerrel_is_target && !innerrel_is_target);
1710 
1711  /*
1712  * For a join relation FROM clause entry is deparsed as
1713  *
1714  * ((outer relation) <join type> (inner relation) ON (joinclauses))
1715  */
1716  appendStringInfo(buf, "(%s %s JOIN %s ON ", join_sql_o.data,
1717  get_jointype_name(fpinfo->jointype), join_sql_i.data);
1718 
1719  /* Append join clause; (TRUE) if no join clause */
1720  if (fpinfo->joinclauses)
1721  {
1722  deparse_expr_cxt context;
1723 
1724  context.buf = buf;
1725  context.foreignrel = foreignrel;
1726  context.scanrel = foreignrel;
1727  context.root = root;
1728  context.params_list = params_list;
1729 
1730  appendStringInfoChar(buf, '(');
1731  appendConditions(fpinfo->joinclauses, &context);
1732  appendStringInfoChar(buf, ')');
1733  }
1734  else
1735  appendStringInfoString(buf, "(TRUE)");
1736 
1737  /* End the FROM clause entry. */
1738  appendStringInfoChar(buf, ')');
1739  }
1740  else
1741  {
1742  RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1743 
1744  /*
1745  * Core code already has some lock on each rel being planned, so we
1746  * can use NoLock here.
1747  */
1748  Relation rel = table_open(rte->relid, NoLock);
1749 
1750  deparseRelation(buf, rel);
1751 
1752  /*
1753  * Add a unique alias to avoid any conflict in relation names due to
1754  * pulled up subqueries in the query being built for a pushed down
1755  * join.
1756  */
1757  if (use_alias)
1758  appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, foreignrel->relid);
1759 
1760  table_close(rel, NoLock);
1761  }
1762 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
static void deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool make_subquery, Index ignore_rel, List **ignore_conds, List **params_list)
Definition: deparse.c:1768
const char * get_jointype_name(JoinType jointype)
Definition: deparse.c:1503
@ JOIN_INNER
Definition: nodes.h:712
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:709

References appendBinaryStringInfo(), appendConditions(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), bms_is_member(), deparse_expr_cxt::buf, buf, StringInfoData::data, deparseRangeTblRef(), deparseRelation(), RelOptInfo::fdw_private, 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 2902 of file deparse.c.

2903 {
2904  StringInfo buf = context->buf;
2905  bool use_variadic;
2906  bool first;
2907  ListCell *arg;
2908 
2909  /*
2910  * If the function call came from an implicit coercion, then just show the
2911  * first argument.
2912  */
2913  if (node->funcformat == COERCE_IMPLICIT_CAST)
2914  {
2915  deparseExpr((Expr *) linitial(node->args), context);
2916  return;
2917  }
2918 
2919  /*
2920  * If the function call came from a cast, then show the first argument
2921  * plus an explicit cast operation.
2922  */
2923  if (node->funcformat == COERCE_EXPLICIT_CAST)
2924  {
2925  Oid rettype = node->funcresulttype;
2926  int32 coercedTypmod;
2927 
2928  /* Get the typmod if this is a length-coercion function */
2929  (void) exprIsLengthCoercion((Node *) node, &coercedTypmod);
2930 
2931  deparseExpr((Expr *) linitial(node->args), context);
2932  appendStringInfo(buf, "::%s",
2933  deparse_type_name(rettype, coercedTypmod));
2934  return;
2935  }
2936 
2937  /* Check if need to print VARIADIC (cf. ruleutils.c) */
2938  use_variadic = node->funcvariadic;
2939 
2940  /*
2941  * Normal function: display as proname(args).
2942  */
2943  appendFunctionName(node->funcid, context);
2944  appendStringInfoChar(buf, '(');
2945 
2946  /* ... and all the arguments */
2947  first = true;
2948  foreach(arg, node->args)
2949  {
2950  if (!first)
2951  appendStringInfoString(buf, ", ");
2952  if (use_variadic && lnext(node->args, arg) == NULL)
2953  appendStringInfoString(buf, "VARIADIC ");
2954  deparseExpr((Expr *) lfirst(arg), context);
2955  first = false;
2956  }
2957  appendStringInfoChar(buf, ')');
2958 }
signed int int32
Definition: c.h:429
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:503
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:485
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:484
Oid funcid
Definition: primnodes.h:495
bool funcvariadic
Definition: primnodes.h:498
List * args
Definition: primnodes.h:503
CoercionForm funcformat
Definition: primnodes.h:500
Oid funcresulttype
Definition: primnodes.h:496

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

1847 {
1848  TupleDesc tupdesc = RelationGetDescr(rel);
1849  AttrNumber pindex;
1850  bool first;
1851  ListCell *lc;
1852 
1853  appendStringInfoString(buf, "INSERT INTO ");
1854  deparseRelation(buf, rel);
1855 
1856  if (targetAttrs)
1857  {
1858  appendStringInfoChar(buf, '(');
1859 
1860  first = true;
1861  foreach(lc, targetAttrs)
1862  {
1863  int attnum = lfirst_int(lc);
1864 
1865  if (!first)
1866  appendStringInfoString(buf, ", ");
1867  first = false;
1868 
1869  deparseColumnRef(buf, rtindex, attnum, rte, false);
1870  }
1871 
1872  appendStringInfoString(buf, ") VALUES (");
1873 
1874  pindex = 1;
1875  first = true;
1876  foreach(lc, targetAttrs)
1877  {
1878  int attnum = lfirst_int(lc);
1879  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
1880 
1881  if (!first)
1882  appendStringInfoString(buf, ", ");
1883  first = false;
1884 
1885  if (attr->attgenerated)
1886  appendStringInfoString(buf, "DEFAULT");
1887  else
1888  {
1889  appendStringInfo(buf, "$%d", pindex);
1890  pindex++;
1891  }
1892  }
1893 
1894  appendStringInfoChar(buf, ')');
1895  }
1896  else
1897  appendStringInfoString(buf, " DEFAULT VALUES");
1898  *values_end_len = buf->len;
1899 
1900  if (doNothing)
1901  appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
1902 
1903  deparseReturningList(buf, rte, rtindex, rel,
1904  rel->trigdesc && rel->trigdesc->trig_insert_after_row,
1905  withCheckOptionList, returningList, retrieved_attrs);
1906 }
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 1379 of file deparse.c.

1380 {
1381  StringInfo buf = context->buf;
1382  PlannerInfo *root = context->root;
1383  RelOptInfo *rel = context->scanrel;
1384  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1385  int relid = -1;
1386 
1387  while ((relid = bms_next_member(rel->relids, relid)) >= 0)
1388  {
1389  /*
1390  * Ignore relation if it appears in a lower subquery. Locking clause
1391  * for such a relation is included in the subquery if necessary.
1392  */
1393  if (bms_is_member(relid, fpinfo->lower_subquery_rels))
1394  continue;
1395 
1396  /*
1397  * Add FOR UPDATE/SHARE if appropriate. We apply locking during the
1398  * initial row fetch, rather than later on as is done for local
1399  * tables. The extra roundtrips involved in trying to duplicate the
1400  * local semantics exactly don't seem worthwhile (see also comments
1401  * for RowMarkType).
1402  *
1403  * Note: because we actually run the query as a cursor, this assumes
1404  * that DECLARE CURSOR ... FOR UPDATE is supported, which it isn't
1405  * before 8.3.
1406  */
1407  if (bms_is_member(relid, root->all_result_relids) &&
1408  (root->parse->commandType == CMD_UPDATE ||
1409  root->parse->commandType == CMD_DELETE))
1410  {
1411  /* Relation is UPDATE/DELETE target, so use FOR UPDATE */
1412  appendStringInfoString(buf, " FOR UPDATE");
1413 
1414  /* Add the relation alias if we are here for a join relation */
1415  if (IS_JOIN_REL(rel))
1416  appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1417  }
1418  else
1419  {
1420  PlanRowMark *rc = get_plan_rowmark(root->rowMarks, relid);
1421 
1422  if (rc)
1423  {
1424  /*
1425  * Relation is specified as a FOR UPDATE/SHARE target, so
1426  * handle that. (But we could also see LCS_NONE, meaning this
1427  * isn't a target relation after all.)
1428  *
1429  * For now, just ignore any [NO] KEY specification, since (a)
1430  * it's not clear what that means for a remote table that we
1431  * don't have complete information about, and (b) it wouldn't
1432  * work anyway on older remote servers. Likewise, we don't
1433  * worry about NOWAIT.
1434  */
1435  switch (rc->strength)
1436  {
1437  case LCS_NONE:
1438  /* No locking needed */
1439  break;
1440  case LCS_FORKEYSHARE:
1441  case LCS_FORSHARE:
1442  appendStringInfoString(buf, " FOR SHARE");
1443  break;
1444  case LCS_FORNOKEYUPDATE:
1445  case LCS_FORUPDATE:
1446  appendStringInfoString(buf, " FOR UPDATE");
1447  break;
1448  }
1449 
1450  /* Add the relation alias if we are here for a join relation */
1451  if (bms_membership(rel->relids) == BMS_MULTIPLE &&
1452  rc->strength != LCS_NONE)
1453  appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
1454  }
1455  }
1456  }
1457 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1045
@ 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:688
@ CMD_UPDATE
Definition: nodes.h:686
while(p+4<=pend)
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:425
Relids lower_subquery_rels
Definition: postgres_fdw.h:119
LockClauseStrength strength
Definition: plannodes.h:1143
List * rowMarks
Definition: pathnodes.h:288
Relids all_result_relids
Definition: pathnodes.h:276
CmdType commandType
Definition: parsenodes.h:119

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, RelOptInfo::fdw_private, 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 3237 of file deparse.c.

3238 {
3239  StringInfo buf = context->buf;
3240 
3241  appendStringInfoChar(buf, '(');
3242  deparseExpr(node->arg, context);
3243 
3244  /*
3245  * For scalar inputs, we prefer to print as IS [NOT] NULL, which is
3246  * shorter and traditional. If it's a rowtype input but we're applying a
3247  * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically
3248  * correct.
3249  */
3250  if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg)))
3251  {
3252  if (node->nulltesttype == IS_NULL)
3253  appendStringInfoString(buf, " IS NULL)");
3254  else
3255  appendStringInfoString(buf, " IS NOT NULL)");
3256  }
3257  else
3258  {
3259  if (node->nulltesttype == IS_NULL)
3260  appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)");
3261  else
3262  appendStringInfoString(buf, " IS DISTINCT FROM NULL)");
3263  }
3264 }
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2602
@ IS_NULL
Definition: primnodes.h:1259
NullTestType nulltesttype
Definition: primnodes.h:1266
bool argisrow
Definition: primnodes.h:1267
Expr * arg
Definition: primnodes.h:1265

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

3096 {
3097  char *opname;
3098 
3099  /* opname is not a SQL identifier, so we should not quote it. */
3100  opname = NameStr(opform->oprname);
3101 
3102  /* Print schema name only if it's not pg_catalog */
3103  if (opform->oprnamespace != PG_CATALOG_NAMESPACE)
3104  {
3105  const char *opnspname;
3106 
3107  opnspname = get_namespace_name(opform->oprnamespace);
3108  /* Print fully qualified operator name. */
3109  appendStringInfo(buf, "OPERATOR(%s.%s)",
3110  quote_identifier(opnspname), opname);
3111  }
3112  else
3113  {
3114  /* Just print operator name. */
3115  appendStringInfoString(buf, opname);
3116  }
3117 }

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

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

◆ deparseOpExpr()

static void deparseOpExpr ( OpExpr node,
deparse_expr_cxt context 
)
static

Definition at line 2965 of file deparse.c.

2966 {
2967  StringInfo buf = context->buf;
2968  HeapTuple tuple;
2969  Form_pg_operator form;
2970  Expr *right;
2971  bool canSuppressRightConstCast = false;
2972  char oprkind;
2973 
2974  /* Retrieve information about the operator from system catalog. */
2975  tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
2976  if (!HeapTupleIsValid(tuple))
2977  elog(ERROR, "cache lookup failed for operator %u", node->opno);
2978  form = (Form_pg_operator) GETSTRUCT(tuple);
2979  oprkind = form->oprkind;
2980 
2981  /* Sanity check. */
2982  Assert((oprkind == 'l' && list_length(node->args) == 1) ||
2983  (oprkind == 'b' && list_length(node->args) == 2));
2984 
2985  right = llast(node->args);
2986 
2987  /* Always parenthesize the expression. */
2988  appendStringInfoChar(buf, '(');
2989 
2990  /* Deparse left operand, if any. */
2991  if (oprkind == 'b')
2992  {
2993  Expr *left = linitial(node->args);
2994  Oid leftType = exprType((Node *) left);
2995  Oid rightType = exprType((Node *) right);
2996  bool canSuppressLeftConstCast = false;
2997 
2998  /*
2999  * When considering a binary operator, if one operand is a Const that
3000  * can be printed as a bare string literal or NULL (i.e., it will look
3001  * like type UNKNOWN to the remote parser), the Const normally
3002  * receives an explicit cast to the operator's input type. However,
3003  * in Const-to-Var comparisons where both operands are of the same
3004  * type, we prefer to suppress the explicit cast, leaving the Const's
3005  * type resolution up to the remote parser. The remote's resolution
3006  * heuristic will assume that an unknown input type being compared to
3007  * a known input type is of that known type as well.
3008  *
3009  * This hack allows some cases to succeed where a remote column is
3010  * declared with a different type in the local (foreign) table. By
3011  * emitting "foreigncol = 'foo'" not "foreigncol = 'foo'::text" or the
3012  * like, we allow the remote parser to pick an "=" operator that's
3013  * compatible with whatever type the remote column really is, such as
3014  * an enum.
3015  *
3016  * We allow cast suppression to happen only when the other operand is
3017  * a plain foreign Var. Although the remote's unknown-type heuristic
3018  * would apply to other cases just as well, we would be taking a
3019  * bigger risk that the inferred type is something unexpected. With
3020  * this restriction, if anything goes wrong it's the user's fault for
3021  * not declaring the local column with the same type as the remote
3022  * column.
3023  */
3024  if (leftType == rightType)
3025  {
3026  if (IsA(left, Const))
3027  canSuppressLeftConstCast = isPlainForeignVar(right, context);
3028  else if (IsA(right, Const))
3029  canSuppressRightConstCast = isPlainForeignVar(left, context);
3030  }
3031 
3032  if (canSuppressLeftConstCast)
3033  deparseConst((Const *) left, context, -2);
3034  else
3035  deparseExpr(left, context);
3036 
3037  appendStringInfoChar(buf, ' ');
3038  }
3039 
3040  /* Deparse operator name. */
3041  deparseOperatorName(buf, form);
3042 
3043  /* Deparse right operand. */
3044  appendStringInfoChar(buf, ' ');
3045 
3046  if (canSuppressRightConstCast)
3047  deparseConst((Const *) right, context, -2);
3048  else
3049  deparseExpr(right, context);
3050 
3051  appendStringInfoChar(buf, ')');
3052 
3053  ReleaseSysCache(tuple);
3054 }
static bool isPlainForeignVar(Expr *node, deparse_expr_cxt *context)
Definition: deparse.c:3060
#define llast(l)
Definition: pg_list.h:194
Oid opno
Definition: primnodes.h:542

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

2824 {
2825  if (context->params_list)
2826  {
2827  int pindex = 0;
2828  ListCell *lc;
2829 
2830  /* find its index in params_list */
2831  foreach(lc, *context->params_list)
2832  {
2833  pindex++;
2834  if (equal(node, (Node *) lfirst(lc)))
2835  break;
2836  }
2837  if (lc == NULL)
2838  {
2839  /* not in list, so add it */
2840  pindex++;
2841  *context->params_list = lappend(*context->params_list, node);
2842  }
2843 
2844  printRemoteParam(pindex, node->paramtype, node->paramtypmod, context);
2845  }
2846  else
2847  {
2848  printRemotePlaceholder(node->paramtype, node->paramtypmod, context);
2849  }
2850 }
static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3497
static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod, deparse_expr_cxt *context)
Definition: deparse.c:3523
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3170
int32 paramtypmod
Definition: primnodes.h:270
Oid paramtype
Definition: primnodes.h:269

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

1771 {
1772  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1773 
1774  /* Should only be called in these cases. */
1775  Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1776 
1777  Assert(fpinfo->local_conds == NIL);
1778 
1779  /* If make_subquery is true, deparse the relation as a subquery. */
1780  if (make_subquery)
1781  {
1782  List *retrieved_attrs;
1783  int ncols;
1784 
1785  /*
1786  * The given relation shouldn't contain the target relation, because
1787  * this should only happen for input relations for a full join, and
1788  * such relations can never contain an UPDATE/DELETE target.
1789  */
1790  Assert(ignore_rel == 0 ||
1791  !bms_is_member(ignore_rel, foreignrel->relids));
1792 
1793  /* Deparse the subquery representing the relation. */
1794  appendStringInfoChar(buf, '(');
1795  deparseSelectStmtForRel(buf, root, foreignrel, NIL,
1796  fpinfo->remote_conds, NIL,
1797  false, false, true,
1798  &retrieved_attrs, params_list);
1799  appendStringInfoChar(buf, ')');
1800 
1801  /* Append the relation alias. */
1803  fpinfo->relation_index);
1804 
1805  /*
1806  * Append the column aliases if needed. Note that the subquery emits
1807  * expressions specified in the relation's reltarget (see
1808  * deparseSubqueryTargetList).
1809  */
1810  ncols = list_length(foreignrel->reltarget->exprs);
1811  if (ncols > 0)
1812  {
1813  int i;
1814 
1815  appendStringInfoChar(buf, '(');
1816  for (i = 1; i <= ncols; i++)
1817  {
1818  if (i > 1)
1819  appendStringInfoString(buf, ", ");
1820 
1822  }
1823  appendStringInfoChar(buf, ')');
1824  }
1825  }
1826  else
1827  deparseFromExprForRel(buf, root, foreignrel, true, ignore_rel,
1828  ignore_conds, params_list);
1829 }
#define SUBQUERY_REL_ALIAS_PREFIX
Definition: deparse.c:110
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:1129
#define SUBQUERY_COL_ALIAS_PREFIX
Definition: deparse.c:111

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), bms_is_member(), buf, deparseFromExprForRel(), deparseSelectStmtForRel(), PathTarget::exprs, RelOptInfo::fdw_private, 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 3186 of file deparse.c.

3187 {
3188  deparseExpr(node->arg, context);
3189  if (node->relabelformat != COERCE_IMPLICIT_CAST)
3190  appendStringInfo(context->buf, "::%s",
3192  node->resulttypmod));
3193 }
int32 resulttypmod
Definition: primnodes.h:862
CoercionForm relabelformat
Definition: primnodes.h:864
Oid resulttype
Definition: primnodes.h:861
Expr * arg
Definition: primnodes.h:860

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

2499 {
2500  ForeignTable *table;
2501  const char *nspname = NULL;
2502  const char *relname = NULL;
2503  ListCell *lc;
2504 
2505  /* obtain additional catalog information. */
2506  table = GetForeignTable(RelationGetRelid(rel));
2507 
2508  /*
2509  * Use value of FDW options if any, instead of the name of object itself.
2510  */
2511  foreach(lc, table->options)
2512  {
2513  DefElem *def = (DefElem *) lfirst(lc);
2514 
2515  if (strcmp(def->defname, "schema_name") == 0)
2516  nspname = defGetString(def);
2517  else if (strcmp(def->defname, "table_name") == 0)
2518  relname = defGetString(def);
2519  }
2520 
2521  /*
2522  * Note: we could skip printing the schema name if it's pg_catalog, but
2523  * that doesn't seem worth the trouble.
2524  */
2525  if (nspname == NULL)
2526  nspname = get_namespace_name(RelationGetNamespace(rel));
2527  if (relname == NULL)
2529 
2530  appendStringInfo(buf, "%s.%s",
2532 }
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:248
#define RelationGetRelationName(relation)
Definition: rel.h:512
#define RelationGetNamespace(relation)
Definition: rel.h:519
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 2200 of file deparse.c.

2206 {
2207  Bitmapset *attrs_used = NULL;
2208 
2209  if (trig_after_row)
2210  {
2211  /* whole-row reference acquires all non-system columns */
2212  attrs_used =
2214  }
2215 
2216  if (withCheckOptionList != NIL)
2217  {
2218  /*
2219  * We need the attrs, non-system and system, mentioned in the local
2220  * query's WITH CHECK OPTION list.
2221  *
2222  * Note: we do this to ensure that WCO constraints will be evaluated
2223  * on the data actually inserted/updated on the remote side, which
2224  * might differ from the data supplied by the core code, for example
2225  * as a result of remote triggers.
2226  */
2227  pull_varattnos((Node *) withCheckOptionList, rtindex,
2228  &attrs_used);
2229  }
2230 
2231  if (returningList != NIL)
2232  {
2233  /*
2234  * We need the attrs, non-system and system, mentioned in the local
2235  * query's RETURNING list.
2236  */
2237  pull_varattnos((Node *) returningList, rtindex,
2238  &attrs_used);
2239  }
2240 
2241  if (attrs_used != NULL)
2242  deparseTargetList(buf, rte, rtindex, rel, true, attrs_used, false,
2243  retrieved_attrs);
2244  else
2245  *retrieved_attrs = NIL;
2246 }
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:288

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

3142 {
3143  StringInfo buf = context->buf;
3144  HeapTuple tuple;
3145  Form_pg_operator form;
3146  Expr *arg1;
3147  Expr *arg2;
3148 
3149  /* Retrieve information about the operator from system catalog. */
3150  tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
3151  if (!HeapTupleIsValid(tuple))
3152  elog(ERROR, "cache lookup failed for operator %u", node->opno);
3153  form = (Form_pg_operator) GETSTRUCT(tuple);
3154 
3155  /* Sanity check. */
3156  Assert(list_length(node->args) == 2);
3157 
3158  /* Always parenthesize the expression. */
3159  appendStringInfoChar(buf, '(');
3160 
3161  /* Deparse left operand. */
3162  arg1 = linitial(node->args);
3163  deparseExpr(arg1, context);
3164  appendStringInfoChar(buf, ' ');
3165 
3166  /* Deparse operator name plus decoration. */
3167  deparseOperatorName(buf, form);
3168  appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL");
3169 
3170  /* Deparse right operand. */
3171  arg2 = lsecond(node->args);
3172  deparseExpr(arg2, context);
3173 
3174  appendStringInfoChar(buf, ')');
3175 
3176  /* Always parenthesize the expression. */
3177  appendStringInfoChar(buf, ')');
3178 
3179  ReleaseSysCache(tuple);
3180 }

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

1213 {
1214  StringInfo buf = context->buf;
1215  RelOptInfo *foreignrel = context->foreignrel;
1216  PlannerInfo *root = context->root;
1217  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
1218 
1219  /*
1220  * Construct SELECT list
1221  */
1222  appendStringInfoString(buf, "SELECT ");
1223 
1224  if (is_subquery)
1225  {
1226  /*
1227  * For a relation that is deparsed as a subquery, emit expressions
1228  * specified in the relation's reltarget. Note that since this is for
1229  * the subquery, no need to care about *retrieved_attrs.
1230  */
1231  deparseSubqueryTargetList(context);
1232  }
1233  else if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
1234  {
1235  /*
1236  * For a join or upper relation the input tlist gives the list of
1237  * columns required to be fetched from the foreign server.
1238  */
1239  deparseExplicitTargetList(tlist, false, retrieved_attrs, context);
1240  }
1241  else
1242  {
1243  /*
1244  * For a base relation fpinfo->attrs_used gives the list of columns
1245  * required to be fetched from the foreign server.
1246  */
1247  RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
1248 
1249  /*
1250  * Core code already has some lock on each rel being planned, so we
1251  * can use NoLock here.
1252  */
1253  Relation rel = table_open(rte->relid, NoLock);
1254 
1255  deparseTargetList(buf, rte, foreignrel->relid, rel, false,
1256  fpinfo->attrs_used, false, retrieved_attrs);
1257  table_close(rel, NoLock);
1258  }
1259 }
static void deparseSubqueryTargetList(deparse_expr_cxt *context)
Definition: deparse.c:1576
Bitmapset * attrs_used
Definition: postgres_fdw.h:50

References appendStringInfoString(), PgFdwRelationInfo::attrs_used, deparse_expr_cxt::buf, buf, deparseExplicitTargetList(), deparseSubqueryTargetList(), deparseTargetList(), RelOptInfo::fdw_private, 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 1129 of file deparse.c.

1133 {
1134  deparse_expr_cxt context;
1135  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
1136  List *quals;
1137 
1138  /*
1139  * We handle relations for foreign tables, joins between those and upper
1140  * relations.
1141  */
1142  Assert(IS_JOIN_REL(rel) || IS_SIMPLE_REL(rel) || IS_UPPER_REL(rel));
1143 
1144  /* Fill portions of context common to upper, join and base relation */
1145  context.buf = buf;
1146  context.root = root;
1147  context.foreignrel = rel;
1148  context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel;
1149  context.params_list = params_list;
1150 
1151  /* Construct SELECT clause */
1152  deparseSelectSql(tlist, is_subquery, retrieved_attrs, &context);
1153 
1154  /*
1155  * For upper relations, the WHERE clause is built from the remote
1156  * conditions of the underlying scan relation; otherwise, we can use the
1157  * supplied list of remote conditions directly.
1158  */
1159  if (IS_UPPER_REL(rel))
1160  {
1161  PgFdwRelationInfo *ofpinfo;
1162 
1163  ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
1164  quals = ofpinfo->remote_conds;
1165  }
1166  else
1167  quals = remote_conds;
1168 
1169  /* Construct FROM and WHERE clauses */
1170  deparseFromExpr(quals, &context);
1171 
1172  if (IS_UPPER_REL(rel))
1173  {
1174  /* Append GROUP BY clause */
1175  appendGroupByClause(tlist, &context);
1176 
1177  /* Append HAVING clause */
1178  if (remote_conds)
1179  {
1180  appendStringInfoString(buf, " HAVING ");
1181  appendConditions(remote_conds, &context);
1182  }
1183  }
1184 
1185  /* Add ORDER BY clause if we found any useful pathkeys */
1186  if (pathkeys)
1187  appendOrderByClause(pathkeys, has_final_sort, &context);
1188 
1189  /* Add LIMIT clause if necessary */
1190  if (has_limit)
1191  appendLimitClause(&context);
1192 
1193  /* Add any necessary FOR UPDATE/SHARE. */
1194  deparseLockingClause(&context);
1195 }
static void appendGroupByClause(List *tlist, deparse_expr_cxt *context)
Definition: deparse.c:3536
static void deparseFromExpr(List *quals, deparse_expr_cxt *context)
Definition: deparse.c:1269
static void deparseLockingClause(deparse_expr_cxt *context)
Definition: deparse.c:1379
static void appendOrderByClause(List *pathkeys, bool has_final_sort, deparse_expr_cxt *context)
Definition: deparse.c:3573
static void appendLimitClause(deparse_expr_cxt *context)
Definition: deparse.c:3627
static void deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs, deparse_expr_cxt *context)
Definition: deparse.c:1211

References appendConditions(), appendGroupByClause(), appendLimitClause(), appendOrderByClause(), appendStringInfoString(), Assert(), deparse_expr_cxt::buf, buf, deparseFromExpr(), deparseLockingClause(), deparseSelectSql(), RelOptInfo::fdw_private, 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 3690 of file deparse.c.

3692 {
3693  StringInfo buf = context->buf;
3694  TargetEntry *tle;
3695  Expr *expr;
3696 
3697  tle = get_sortgroupref_tle(ref, tlist);
3698  expr = tle->expr;
3699 
3700  if (force_colno)
3701  {
3702  /* Use column-number form when requested by caller. */
3703  Assert(!tle->resjunk);
3704  appendStringInfo(buf, "%d", tle->resno);
3705  }
3706  else if (expr && IsA(expr, Const))
3707  {
3708  /*
3709  * Force a typecast here so that we don't emit something like "GROUP
3710  * BY 2", which will be misconstrued as a column position rather than
3711  * a constant.
3712  */
3713  deparseConst((Const *) expr, context, 1);
3714  }
3715  else if (!expr || IsA(expr, Var))
3716  deparseExpr(expr, context);
3717  else
3718  {
3719  /* Always parenthesize the expression. */
3720  appendStringInfoChar(buf, '(');
3721  deparseExpr(expr, context);
3722  appendStringInfoChar(buf, ')');
3723  }
3724 
3725  return (Node *) expr;
3726 }
AttrNumber resno
Definition: primnodes.h:1456
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition: tlist.c:334

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

2539 {
2540  const char *valptr;
2541 
2542  /*
2543  * Rather than making assumptions about the remote server's value of
2544  * standard_conforming_strings, always use E'foo' syntax if there are any
2545  * backslashes. This will fail on remote servers before 8.1, but those
2546  * are long out of support.
2547  */
2548  if (strchr(val, '\\') != NULL)
2550  appendStringInfoChar(buf, '\'');
2551  for (valptr = val; *valptr; valptr++)
2552  {
2553  char ch = *valptr;
2554 
2555  if (SQL_STR_DOUBLE(ch, true))
2558  }
2559  appendStringInfoChar(buf, '\'');
2560 }
#define ESCAPE_STRING_SYNTAX
Definition: c.h:1164
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1161
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 1576 of file deparse.c.

1577 {
1578  StringInfo buf = context->buf;
1579  RelOptInfo *foreignrel = context->foreignrel;
1580  bool first;
1581  ListCell *lc;
1582 
1583  /* Should only be called in these cases. */
1584  Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
1585 
1586  first = true;
1587  foreach(lc, foreignrel->reltarget->exprs)
1588  {
1589  Node *node = (Node *) lfirst(lc);
1590 
1591  if (!first)
1592  appendStringInfoString(buf, ", ");
1593  first = false;
1594 
1595  deparseExpr((Expr *) node, context);
1596  }
1597 
1598  /* Don't generate bad syntax if no expressions */
1599  if (first)
1600  appendStringInfoString(buf, "NULL");
1601 }

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

2857 {
2858  StringInfo buf = context->buf;
2859  ListCell *lowlist_item;
2860  ListCell *uplist_item;
2861 
2862  /* Always parenthesize the expression. */
2863  appendStringInfoChar(buf, '(');
2864 
2865  /*
2866  * Deparse referenced array expression first. If that expression includes
2867  * a cast, we have to parenthesize to prevent the array subscript from
2868  * being taken as typename decoration. We can avoid that in the typical
2869  * case of subscripting a Var, but otherwise do it.
2870  */
2871  if (IsA(node->refexpr, Var))
2872  deparseExpr(node->refexpr, context);
2873  else
2874  {
2875  appendStringInfoChar(buf, '(');
2876  deparseExpr(node->refexpr, context);
2877  appendStringInfoChar(buf, ')');
2878  }
2879 
2880  /* Deparse subscript expressions. */
2881  lowlist_item = list_head(node->reflowerindexpr); /* could be NULL */
2882  foreach(uplist_item, node->refupperindexpr)
2883  {
2884  appendStringInfoChar(buf, '[');
2885  if (lowlist_item)
2886  {
2887  deparseExpr(lfirst(lowlist_item), context);
2888  appendStringInfoChar(buf, ':');
2889  lowlist_item = lnext(node->reflowerindexpr, lowlist_item);
2890  }
2891  deparseExpr(lfirst(uplist_item), context);
2892  appendStringInfoChar(buf, ']');
2893  }
2894 
2895  appendStringInfoChar(buf, ')');
2896 }
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
List * refupperindexpr
Definition: primnodes.h:444
Expr * refexpr
Definition: primnodes.h:449
List * reflowerindexpr
Definition: primnodes.h:446

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

1311 {
1312  TupleDesc tupdesc = RelationGetDescr(rel);
1313  bool have_wholerow;
1314  bool first;
1315  int i;
1316 
1317  *retrieved_attrs = NIL;
1318 
1319  /* If there's a whole-row reference, we'll need all the columns. */
1321  attrs_used);
1322 
1323  first = true;
1324  for (i = 1; i <= tupdesc->natts; i++)
1325  {
1326  Form_pg_attribute attr = TupleDescAttr(tupdesc, i - 1);
1327 
1328  /* Ignore dropped attributes. */
1329  if (attr->attisdropped)
1330  continue;
1331 
1332  if (have_wholerow ||
1334  attrs_used))
1335  {
1336  if (!first)
1337  appendStringInfoString(buf, ", ");
1338  else if (is_returning)
1339  appendStringInfoString(buf, " RETURNING ");
1340  first = false;
1341 
1342  deparseColumnRef(buf, rtindex, i, rte, qualify_col);
1343 
1344  *retrieved_attrs = lappend_int(*retrieved_attrs, i);
1345  }
1346  }
1347 
1348  /*
1349  * Add ctid if needed. We currently don't support retrieving any other
1350  * system columns.
1351  */
1353  attrs_used))
1354  {
1355  if (!first)
1356  appendStringInfoString(buf, ", ");
1357  else if (is_returning)
1358  appendStringInfoString(buf, " RETURNING ");
1359  first = false;
1360 
1361  if (qualify_col)
1362  ADD_REL_QUALIFIER(buf, rtindex);
1363  appendStringInfoString(buf, "ctid");
1364 
1365  *retrieved_attrs = lappend_int(*retrieved_attrs,
1367  }
1368 
1369  /* Don't generate bad syntax if no undropped columns */
1370  if (first && !is_returning)
1371  appendStringInfoString(buf, "NULL");
1372 }

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

2339 {
2340  ListCell *cell;
2341 
2342  appendStringInfoString(buf, "TRUNCATE ");
2343 
2344  foreach(cell, rels)
2345  {
2346  Relation rel = lfirst(cell);
2347 
2348  if (cell != list_head(rels))
2349  appendStringInfoString(buf, ", ");
2350 
2351  deparseRelation(buf, rel);
2352  }
2353 
2354  appendStringInfo(buf, " %s IDENTITY",
2355  restart_seqs ? "RESTART" : "CONTINUE");
2356 
2357  if (behavior == DROP_RESTRICT)
2358  appendStringInfoString(buf, " RESTRICT");
2359  else if (behavior == DROP_CASCADE)
2360  appendStringInfoString(buf, " CASCADE");
2361 }
@ DROP_CASCADE
Definition: parsenodes.h:1862
@ DROP_RESTRICT
Definition: parsenodes.h:1861

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

1980 {
1981  TupleDesc tupdesc = RelationGetDescr(rel);
1982  AttrNumber pindex;
1983  bool first;
1984  ListCell *lc;
1985 
1986  appendStringInfoString(buf, "UPDATE ");
1987  deparseRelation(buf, rel);
1988  appendStringInfoString(buf, " SET ");
1989 
1990  pindex = 2; /* ctid is always the first param */
1991  first = true;
1992  foreach(lc, targetAttrs)
1993  {
1994  int attnum = lfirst_int(lc);
1995  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
1996 
1997  if (!first)
1998  appendStringInfoString(buf, ", ");
1999  first = false;
2000 
2001  deparseColumnRef(buf, rtindex, attnum, rte, false);
2002  if (attr->attgenerated)
2003  appendStringInfoString(buf, " = DEFAULT");
2004  else
2005  {
2006  appendStringInfo(buf, " = $%d", pindex);
2007  pindex++;
2008  }
2009  }
2010  appendStringInfoString(buf, " WHERE ctid = $1");
2011 
2012  deparseReturningList(buf, rte, rtindex, rel,
2013  rel->trigdesc && rel->trigdesc->trig_update_after_row,
2014  withCheckOptionList, returningList, retrieved_attrs);
2015 }
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 2638 of file deparse.c.

2639 {
2640  Relids relids = context->scanrel->relids;
2641  int relno;
2642  int colno;
2643 
2644  /* Qualify columns when multiple relations are involved. */
2645  bool qualify_col = (bms_membership(relids) == BMS_MULTIPLE);
2646 
2647  /*
2648  * If the Var belongs to the foreign relation that is deparsed as a
2649  * subquery, use the relation and column alias to the Var provided by the
2650  * subquery, instead of the remote name.
2651  */
2652  if (is_subquery_var(node, context->scanrel, &relno, &colno))
2653  {
2654  appendStringInfo(context->buf, "%s%d.%s%d",
2656  SUBQUERY_COL_ALIAS_PREFIX, colno);
2657  return;
2658  }
2659 
2660  if (bms_is_member(node->varno, relids) && node->varlevelsup == 0)
2661  deparseColumnRef(context->buf, node->varno, node->varattno,
2662  planner_rt_fetch(node->varno, context->root),
2663  qualify_col);
2664  else
2665  {
2666  /* Treat like a Param */
2667  if (context->params_list)
2668  {
2669  int pindex = 0;
2670  ListCell *lc;
2671 
2672  /* find its index in params_list */
2673  foreach(lc, *context->params_list)
2674  {
2675  pindex++;
2676  if (equal(node, (Node *) lfirst(lc)))
2677  break;
2678  }
2679  if (lc == NULL)
2680  {
2681  /* not in list, so add it */
2682  pindex++;
2683  *context->params_list = lappend(*context->params_list, node);
2684  }
2685 
2686  printRemoteParam(pindex, node->vartype, node->vartypmod, context);
2687  }
2688  else
2689  {
2690  printRemotePlaceholder(node->vartype, node->vartypmod, context);
2691  }
2692  }
2693 }
static bool is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:3735
Oid vartype
Definition: primnodes.h:193
AttrNumber varattno
Definition: primnodes.h:191
int varno
Definition: primnodes.h:189
int32 vartypmod
Definition: primnodes.h:194
Index varlevelsup
Definition: primnodes.h:196

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

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

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, CaseExpr::defresult, CaseWhen::expr, TargetEntry::expr, exprType(), FDW_COLLATE_NONE, FDW_COLLATE_SAFE, FDW_COLLATE_UNSAFE, RelOptInfo::fdw_private, fe(), 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(), T_Aggref, T_ArrayExpr, T_BoolExpr, T_CaseExpr, T_CaseTestExpr, T_Const, T_DistinctExpr, T_FuncExpr, T_List, T_NullTest, T_OpExpr, T_Param, T_RelabelType, T_ScalarArrayOpExpr, T_SubscriptingRef, T_Var, 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 1503 of file deparse.c.

1504 {
1505  switch (jointype)
1506  {
1507  case JOIN_INNER:
1508  return "INNER";
1509 
1510  case JOIN_LEFT:
1511  return "LEFT";
1512 
1513  case JOIN_RIGHT:
1514  return "RIGHT";
1515 
1516  case JOIN_FULL:
1517  return "FULL";
1518 
1519  default:
1520  /* Shouldn't come here, but protect from buggy code. */
1521  elog(ERROR, "unsupported join type %d", jointype);
1522  }
1523 
1524  /* Keep compiler happy */
1525  return NULL;
1526 }
@ JOIN_FULL
Definition: nodes.h:714
@ JOIN_RIGHT
Definition: nodes.h:715
@ JOIN_LEFT
Definition: nodes.h:713

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

3799 {
3800  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
3801  int i;
3802  ListCell *lc;
3803 
3804  /* Get the relation alias ID */
3805  *relno = fpinfo->relation_index;
3806 
3807  /* Get the column alias ID */
3808  i = 1;
3809  foreach(lc, foreignrel->reltarget->exprs)
3810  {
3811  if (equal(lfirst(lc), (Node *) node))
3812  {
3813  *colno = i;
3814  return;
3815  }
3816  i++;
3817  }
3818 
3819  /* Shouldn't get here */
3820  elog(ERROR, "unexpected expression in subquery output");
3821 }

References elog, equal(), ERROR, PathTarget::exprs, RelOptInfo::fdw_private, 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 234 of file deparse.c.

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

References foreign_loc_cxt::collation, contain_mutable_functions(), FDW_COLLATE_NONE, FDW_COLLATE_UNSAFE, RelOptInfo::fdw_private, 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(), add_foreign_ordered_paths(), classifyConditions(), foreign_grouping_ok(), foreign_join_ok(), get_useful_pathkeys_for_relation(), postgresGetForeignPaths(), postgresGetForeignPlan(), and postgresPlanDirectModify().

◆ is_foreign_param()

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

Definition at line 1005 of file deparse.c.

1008 {
1009  if (expr == NULL)
1010  return false;
1011 
1012  switch (nodeTag(expr))
1013  {
1014  case T_Var:
1015  {
1016  /* It would have to be sent unless it's a foreign Var */
1017  Var *var = (Var *) expr;
1018  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) (baserel->fdw_private);
1019  Relids relids;
1020 
1021  if (IS_UPPER_REL(baserel))
1022  relids = fpinfo->outerrel->relids;
1023  else
1024  relids = baserel->relids;
1025 
1026  if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
1027  return false; /* foreign Var, so not a param */
1028  else
1029  return true; /* it'd have to be a param */
1030  break;
1031  }
1032  case T_Param:
1033  /* Params always have to be sent to the foreign server */
1034  return true;
1035  default:
1036  break;
1037  }
1038  return false;
1039 }

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

Referenced by foreign_grouping_ok().

◆ is_subquery_var()

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

Definition at line 3735 of file deparse.c.

3736 {
3737  PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
3738  RelOptInfo *outerrel = fpinfo->outerrel;
3739  RelOptInfo *innerrel = fpinfo->innerrel;
3740 
3741  /* Should only be called in these cases. */
3742  Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
3743 
3744  /*
3745  * If the given relation isn't a join relation, it doesn't have any lower
3746  * subqueries, so the Var isn't a subquery output column.
3747  */
3748  if (!IS_JOIN_REL(foreignrel))
3749  return false;
3750 
3751  /*
3752  * If the Var doesn't belong to any lower subqueries, it isn't a subquery
3753  * output column.
3754  */
3755  if (!bms_is_member(node->varno, fpinfo->lower_subquery_rels))
3756  return false;
3757 
3758  if (bms_is_member(node->varno, outerrel->relids))
3759  {
3760  /*
3761  * If outer relation is deparsed as a subquery, the Var is an output
3762  * column of the subquery; get the IDs for the relation/column alias.
3763  */
3764  if (fpinfo->make_outerrel_subquery)
3765  {
3766  get_relation_column_alias_ids(node, outerrel, relno, colno);
3767  return true;
3768  }
3769 
3770  /* Otherwise, recurse into the outer relation. */
3771  return is_subquery_var(node, outerrel, relno, colno);
3772  }
3773  else
3774  {
3775  Assert(bms_is_member(node->varno, innerrel->relids));
3776 
3777  /*
3778  * If inner relation is deparsed as a subquery, the Var is an output
3779  * column of the subquery; get the IDs for the relation/column alias.
3780  */
3781  if (fpinfo->make_innerrel_subquery)
3782  {
3783  get_relation_column_alias_ids(node, innerrel, relno, colno);
3784  return true;
3785  }
3786 
3787  /* Otherwise, recurse into the inner relation. */
3788  return is_subquery_var(node, innerrel, relno, colno);
3789  }
3790 }
static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
Definition: deparse.c:3797

References Assert(), bms_is_member(), RelOptInfo::fdw_private, 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 3060 of file deparse.c.

3061 {
3062  /*
3063  * We allow the foreign Var to have an implicit RelabelType, mainly so
3064  * that this'll work with varchar columns. Note that deparseRelabelType
3065  * will not print such a cast, so we're not breaking the restriction that
3066  * the expression print as a plain Var. We won't risk it for an implicit
3067  * cast that requires a function, nor for non-implicit RelabelType; such
3068  * cases seem too likely to involve semantics changes compared to what
3069  * would happen on the remote side.
3070  */
3071  if (IsA(node, RelabelType) &&
3072  ((RelabelType *) node)->relabelformat == COERCE_IMPLICIT_CAST)
3073  node = ((RelabelType *) node)->arg;
3074 
3075  if (IsA(node, Var))
3076  {
3077  /*
3078  * The Var must be one that'll deparse as a foreign column reference
3079  * (cf. deparseVar).
3080  */
3081  Var *var = (Var *) node;
3082  Relids relids = context->scanrel->relids;
3083 
3084  if (bms_is_member(var->varno, relids) && var->varlevelsup == 0)
3085  return true;
3086  }
3087 
3088  return false;
3089 }

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

3499 {
3500  StringInfo buf = context->buf;
3501  char *ptypename = deparse_type_name(paramtype, paramtypmod);
3502 
3503  appendStringInfo(buf, "$%d::%s", paramindex, ptypename);
3504 }

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

3525 {
3526  StringInfo buf = context->buf;
3527  char *ptypename = deparse_type_name(paramtype, paramtypmod);
3528 
3529  appendStringInfo(buf, "((SELECT null::%s)::%s)", ptypename, ptypename);
3530 }

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

1919 {
1920  TupleDesc tupdesc = RelationGetDescr(rel);
1921  int i;
1922  int pindex;
1923  bool first;
1924  ListCell *lc;
1925 
1926  /* Make sure the values_end_len is sensible */
1927  Assert((values_end_len > 0) && (values_end_len <= strlen(orig_query)));
1928 
1929  /* Copy up to the end of the first record from the original query */
1930  appendBinaryStringInfo(buf, orig_query, values_end_len);
1931 
1932  /*
1933  * Add records to VALUES clause (we already have parameters for the first
1934  * row, so start at the right offset).
1935  */
1936  pindex = num_params + 1;
1937  for (i = 0; i < num_rows; i++)
1938  {
1939  appendStringInfoString(buf, ", (");
1940 
1941  first = true;
1942  foreach(lc, target_attrs)
1943  {
1944  int attnum = lfirst_int(lc);
1945  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
1946 
1947  if (!first)
1948  appendStringInfoString(buf, ", ");
1949  first = false;
1950 
1951  if (attr->attgenerated)
1952  appendStringInfoString(buf, "DEFAULT");
1953  else
1954  {
1955  appendStringInfo(buf, "$%d", pindex);
1956  pindex++;
1957  }
1958  }
1959 
1960  appendStringInfoChar(buf, ')');
1961  }
1962 
1963  /* Copy stuff after VALUES clause from the original query */
1964  appendStringInfoString(buf, orig_query + values_end_len);
1965 }

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

Referenced by execute_foreign_modify().