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

Go to the source code of this file.

Data Structures

struct  foreign_glob_cxt
 
struct  foreign_loc_cxt
 
struct  deparse_expr_cxt
 

Macros

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

Typedefs

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

Enumerations

enum  FDWCollateState { FDW_COLLATE_NONE , FDW_COLLATE_SAFE , FDW_COLLATE_UNSAFE }
 

Functions

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

Macro Definition Documentation

◆ ADD_REL_QUALIFIER

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

Definition at line 111 of file deparse.c.

◆ REL_ALIAS_PREFIX

#define REL_ALIAS_PREFIX   "r"

Definition at line 109 of file deparse.c.

◆ SUBQUERY_COL_ALIAS_PREFIX

#define SUBQUERY_COL_ALIAS_PREFIX   "c"

Definition at line 114 of file deparse.c.

◆ SUBQUERY_REL_ALIAS_PREFIX

#define SUBQUERY_REL_ALIAS_PREFIX   "s"

Definition at line 113 of file deparse.c.

Typedef Documentation

◆ deparse_expr_cxt

◆ foreign_glob_cxt

◆ foreign_loc_cxt

Enumeration Type Documentation

◆ FDWCollateState

Enumerator
FDW_COLLATE_NONE 
FDW_COLLATE_SAFE 
FDW_COLLATE_UNSAFE 

Definition at line 79 of file deparse.c.

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

Function Documentation

◆ appendAggOrderBy()

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

Definition at line 3801 of file deparse.c.

3802{
3803 StringInfo buf = context->buf;
3804 ListCell *lc;
3805 bool first = true;
3806
3807 foreach(lc, orderList)
3808 {
3809 SortGroupClause *srt = (SortGroupClause *) lfirst(lc);
3810 Node *sortexpr;
3811
3812 if (!first)
3814 first = false;
3815
3816 /* Deparse the sort expression proper. */
3817 sortexpr = deparseSortGroupClause(srt->tleSortGroupRef, targetList,
3818 false, context);
3819 /* Add decoration as needed. */
3820 appendOrderBySuffix(srt->sortop, exprType(sortexpr), srt->nulls_first,
3821 context);
3822 }
3823}
static Node * deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context)
Definition: deparse.c:4119
static void appendOrderBySuffix(Oid sortop, Oid sortcoltype, bool nulls_first, deparse_expr_cxt *context)
Definition: deparse.c:3830
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
#define lfirst(lc)
Definition: pg_list.h:172
static char * buf
Definition: pg_test_fsync.c:72
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
Definition: nodes.h:135
Index tleSortGroupRef
Definition: parsenodes.h:1469
StringInfo buf
Definition: deparse.c:105

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

Referenced by deparseAggref().

◆ appendConditions()

static void appendConditions ( List exprs,
deparse_expr_cxt context 
)
static

Definition at line 1602 of file deparse.c.

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

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

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

◆ appendFunctionName()

static void appendFunctionName ( Oid  funcid,
deparse_expr_cxt context 
)
static

Definition at line 4084 of file deparse.c.

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

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

Referenced by deparseAggref(), and deparseFuncExpr().

◆ appendGroupByClause()

static void appendGroupByClause ( List tlist,
deparse_expr_cxt context 
)
static

Definition at line 3914 of file deparse.c.

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

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

Referenced by deparseSelectStmtForRel().

◆ appendLimitClause()

static void appendLimitClause ( deparse_expr_cxt context)
static

Definition at line 4056 of file deparse.c.

4057{
4058 PlannerInfo *root = context->root;
4059 StringInfo buf = context->buf;
4060 int nestlevel;
4061
4062 /* Make sure any constants in the exprs are printed portably */
4063 nestlevel = set_transmission_modes();
4064
4065 if (root->parse->limitCount)
4066 {
4067 appendStringInfoString(buf, " LIMIT ");
4068 deparseExpr((Expr *) root->parse->limitCount, context);
4069 }
4070 if (root->parse->limitOffset)
4071 {
4072 appendStringInfoString(buf, " OFFSET ");
4073 deparseExpr((Expr *) root->parse->limitOffset, context);
4074 }
4075
4076 reset_transmission_modes(nestlevel);
4077}
tree ctl root
Definition: radixtree.h:1857

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

Referenced by deparseSelectStmtForRel().

◆ appendOrderByClause()

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

Definition at line 3962 of file deparse.c.

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

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

Referenced by deparseSelectStmtForRel().

◆ appendOrderBySuffix()

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

Definition at line 3830 of file deparse.c.

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

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

Referenced by appendAggOrderBy(), and appendOrderByClause().

◆ appendWhereClause()

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

Definition at line 1639 of file deparse.c.

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

References appendConditions(), appendStringInfoString(), deparse_expr_cxt::buf, buf, lfirst, and NIL.

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

◆ build_tlist_to_deparse()

List * build_tlist_to_deparse ( RelOptInfo foreignrel)

Definition at line 1209 of file deparse.c.

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

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

Referenced by estimate_path_cost_size(), and postgresGetForeignPlan().

◆ classifyConditions()

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

Definition at line 218 of file deparse.c.

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

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

Referenced by estimate_path_cost_size(), and postgresGetForeignRelSize().

◆ deparse_type_name()

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

Definition at line 1190 of file deparse.c.

1191{
1193
1194 if (!is_builtin(type_oid))
1196
1197 return format_type_extended(type_oid, typemod, flags);
1198}
#define FORMAT_TYPE_TYPEMOD_GIVEN
Definition: builtins.h:124
#define FORMAT_TYPE_FORCE_QUALIFY
Definition: builtins.h:126
uint16 bits16
Definition: c.h:549
char * format_type_extended(Oid type_oid, int32 typemod, bits16 flags)
Definition: format_type.c:112
bool is_builtin(Oid objectId)
Definition: shippable.c:152

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

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

◆ deparseAggref()

static void deparseAggref ( Aggref node,
deparse_expr_cxt context 
)
static

Definition at line 3709 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseAnalyzeInfoSql()

void deparseAnalyzeInfoSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2552 of file deparse.c.

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

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

Referenced by postgresGetAnalyzeInfoForForeignTable().

◆ deparseAnalyzeSizeSql()

void deparseAnalyzeSizeSql ( StringInfo  buf,
Relation  rel 
)

Definition at line 2530 of file deparse.c.

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

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

Referenced by postgresAnalyzeForeignTable().

◆ deparseAnalyzeSql()

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

Definition at line 2592 of file deparse.c.

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

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

Referenced by postgresAcquireSampleRowsFunc().

◆ deparseArrayCoerceExpr()

static void deparseArrayCoerceExpr ( ArrayCoerceExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3544 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseArrayExpr()

static void deparseArrayExpr ( ArrayExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3683 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseBoolExpr()

static void deparseBoolExpr ( BoolExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3562 of file deparse.c.

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

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

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

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

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

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

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

◆ deparseConst()

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

Definition at line 3054 of file deparse.c.

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

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

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

◆ deparseDeleteSql()

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

Definition at line 2393 of file deparse.c.

2397{
2398 appendStringInfoString(buf, "DELETE FROM ");
2399 deparseRelation(buf, rel);
2400 appendStringInfoString(buf, " WHERE ctid = $1");
2401
2402 deparseReturningList(buf, rte, rtindex, rel,
2404 NIL, returningList, retrieved_attrs);
2405}
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:2473
TriggerDesc * trigdesc
Definition: rel.h:117
bool trig_delete_after_row
Definition: reltrigger.h:67

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

Referenced by postgresPlanForeignModify().

◆ deparseDirectDeleteSql()

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

Definition at line 2422 of file deparse.c.

2429{
2430 deparse_expr_cxt context;
2431 List *additional_conds = NIL;
2432
2433 /* Set up context struct for recursion */
2434 context.root = root;
2435 context.foreignrel = foreignrel;
2436 context.scanrel = foreignrel;
2437 context.buf = buf;
2438 context.params_list = params_list;
2439
2440 appendStringInfoString(buf, "DELETE FROM ");
2441 deparseRelation(buf, rel);
2442 if (foreignrel->reloptkind == RELOPT_JOINREL)
2443 appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, rtindex);
2444
2445 if (foreignrel->reloptkind == RELOPT_JOINREL)
2446 {
2447 List *ignore_conds = NIL;
2448
2449 appendStringInfoString(buf, " USING ");
2450 deparseFromExprForRel(buf, root, foreignrel, true, rtindex,
2451 &ignore_conds, &additional_conds, params_list);
2452 remote_conds = list_concat(remote_conds, ignore_conds);
2453 }
2454
2455 appendWhereClause(remote_conds, additional_conds, &context);
2456
2457 if (additional_conds != NIL)
2458 list_free_deep(additional_conds);
2459
2460 if (foreignrel->reloptkind == RELOPT_JOINREL)
2461 deparseExplicitTargetList(returningList, true, retrieved_attrs,
2462 &context);
2463 else
2465 rtindex, rel, false,
2466 NIL, returningList, retrieved_attrs);
2467}
#define REL_ALIAS_PREFIX
Definition: deparse.c:109
static void deparseExplicitTargetList(List *tlist, bool is_returning, List **retrieved_attrs, deparse_expr_cxt *context)
Definition: deparse.c:1712
static void deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, bool use_alias, Index ignore_rel, List **ignore_conds, List **additional_conds, List **params_list)
Definition: deparse.c:1792
static void appendWhereClause(List *exprs, List *additional_conds, deparse_expr_cxt *context)
Definition: deparse.c:1639
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
void list_free_deep(List *list)
Definition: list.c:1560
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:610
@ RELOPT_JOINREL
Definition: pathnodes.h:884
RelOptKind reloptkind
Definition: pathnodes.h:921
List ** params_list
Definition: deparse.c:106

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

Referenced by postgresPlanDirectModify().

◆ deparseDirectUpdateSql()

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

Definition at line 2307 of file deparse.c.

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

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

Referenced by postgresPlanDirectModify().

◆ deparseDistinctExpr()

static void deparseDistinctExpr ( DistinctExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3468 of file deparse.c.

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

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

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

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

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

◆ deparseExpr()

static void deparseExpr ( Expr node,
deparse_expr_cxt context 
)
static

Definition at line 2915 of file deparse.c.

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

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

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

◆ deparseFromExpr()

static void deparseFromExpr ( List quals,
deparse_expr_cxt context 
)
static

Definition at line 1406 of file deparse.c.

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

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

Referenced by deparseSelectStmtForRel().

◆ deparseFromExprForRel()

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

Definition at line 1792 of file deparse.c.

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

References appendBinaryStringInfo(), appendConditions(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), appendWhereClause(), Assert(), bms_is_member(), deparse_expr_cxt::buf, buf, StringInfoData::data, deparseRangeTblRef(), deparseRelation(), deparse_expr_cxt::foreignrel, get_jointype_name(), if(), initStringInfo(), PgFdwRelationInfo::innerrel, IS_JOIN_REL, JOIN_INNER, JOIN_SEMI, PgFdwRelationInfo::joinclauses, PgFdwRelationInfo::jointype, lappend(), StringInfoData::len, list_concat(), list_free(), list_free_deep(), PgFdwRelationInfo::make_innerrel_subquery, PgFdwRelationInfo::make_outerrel_subquery, NIL, NoLock, PgFdwRelationInfo::outerrel, deparse_expr_cxt::params_list, planner_rt_fetch, REL_ALIAS_PREFIX, RelOptInfo::relid, RelOptInfo::relids, deparse_expr_cxt::root, root, deparse_expr_cxt::scanrel, str, table_close(), and table_open().

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

◆ deparseFuncExpr()

static void deparseFuncExpr ( FuncExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3247 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseInsertSql()

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

Definition at line 2114 of file deparse.c.

2119{
2120 TupleDesc tupdesc = RelationGetDescr(rel);
2121 AttrNumber pindex;
2122 bool first;
2123 ListCell *lc;
2124
2125 appendStringInfoString(buf, "INSERT INTO ");
2126 deparseRelation(buf, rel);
2127
2128 if (targetAttrs)
2129 {
2131
2132 first = true;
2133 foreach(lc, targetAttrs)
2134 {
2135 int attnum = lfirst_int(lc);
2136
2137 if (!first)
2139 first = false;
2140
2141 deparseColumnRef(buf, rtindex, attnum, rte, false);
2142 }
2143
2144 appendStringInfoString(buf, ") VALUES (");
2145
2146 pindex = 1;
2147 first = true;
2148 foreach(lc, targetAttrs)
2149 {
2150 int attnum = lfirst_int(lc);
2151 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
2152
2153 if (!first)
2155 first = false;
2156
2157 if (attr->attgenerated)
2158 appendStringInfoString(buf, "DEFAULT");
2159 else
2160 {
2161 appendStringInfo(buf, "$%d", pindex);
2162 pindex++;
2163 }
2164 }
2165
2167 }
2168 else
2169 appendStringInfoString(buf, " DEFAULT VALUES");
2170 *values_end_len = buf->len;
2171
2172 if (doNothing)
2173 appendStringInfoString(buf, " ON CONFLICT DO NOTHING");
2174
2175 deparseReturningList(buf, rte, rtindex, rel,
2177 withCheckOptionList, returningList, retrieved_attrs);
2178}
int16 AttrNumber
Definition: attnum.h:21
bool attgenerated
Definition: tupdesc.h:78
bool trig_insert_after_row
Definition: reltrigger.h:57
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:175

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

Referenced by postgresBeginForeignInsert(), and postgresPlanForeignModify().

◆ deparseLockingClause()

static void deparseLockingClause ( deparse_expr_cxt context)
static

Definition at line 1512 of file deparse.c.

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

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

Referenced by deparseSelectStmtForRel().

◆ deparseNullTest()

static void deparseNullTest ( NullTest node,
deparse_expr_cxt context 
)
static

Definition at line 3600 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseOperatorName()

static void deparseOperatorName ( StringInfo  buf,
Form_pg_operator  opform 
)
static

Definition at line 3440 of file deparse.c.

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

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

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

◆ deparseOpExpr()

static void deparseOpExpr ( OpExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3310 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseParam()

static void deparseParam ( Param node,
deparse_expr_cxt context 
)
static

Definition at line 3168 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseRangeTblRef()

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

Definition at line 2039 of file deparse.c.

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

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

Referenced by deparseFromExprForRel().

◆ deparseRelabelType()

static void deparseRelabelType ( RelabelType node,
deparse_expr_cxt context 
)
static

Definition at line 3531 of file deparse.c.

3532{
3533 deparseExpr(node->arg, context);
3534 if (node->relabelformat != COERCE_IMPLICIT_CAST)
3535 appendStringInfo(context->buf, "::%s",
3537 node->resulttypmod));
3538}
Oid resulttype
Definition: primnodes.h:1218
Expr * arg
Definition: primnodes.h:1217

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

Referenced by deparseExpr().

◆ deparseRelation()

static void deparseRelation ( StringInfo  buf,
Relation  rel 
)
static

Definition at line 2840 of file deparse.c.

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

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

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

◆ deparseReturningList()

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

Definition at line 2473 of file deparse.c.

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

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

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

◆ deparseScalarArrayOpExpr()

static void deparseScalarArrayOpExpr ( ScalarArrayOpExpr node,
deparse_expr_cxt context 
)
static

Definition at line 3486 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ deparseSelectSql()

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

Definition at line 1348 of file deparse.c.

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

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

Referenced by deparseSelectStmtForRel().

◆ deparseSelectStmtForRel()

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

Definition at line 1266 of file deparse.c.

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

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

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

◆ deparseSortGroupClause()

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

Definition at line 4119 of file deparse.c.

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

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

Referenced by appendAggOrderBy(), and appendGroupByClause().

◆ deparseStringLiteral()

void deparseStringLiteral ( StringInfo  buf,
const char *  val 
)

Definition at line 2880 of file deparse.c.

2881{
2882 const char *valptr;
2883
2884 /*
2885 * Rather than making assumptions about the remote server's value of
2886 * standard_conforming_strings, always use E'foo' syntax if there are any
2887 * backslashes. This will fail on remote servers before 8.1, but those
2888 * are long out of support.
2889 */
2890 if (strchr(val, '\\') != NULL)
2893 for (valptr = val; *valptr; valptr++)
2894 {
2895 char ch = *valptr;
2896
2897 if (SQL_STR_DOUBLE(ch, true))
2900 }
2902}
#define ESCAPE_STRING_SYNTAX
Definition: c.h:1154
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1151
long val
Definition: informix.c:689

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

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

◆ deparseSubqueryTargetList()

static void deparseSubqueryTargetList ( deparse_expr_cxt context)
static

Definition at line 1748 of file deparse.c.

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

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

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

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

Referenced by deparseExpr().

◆ deparseTargetList()

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

Definition at line 1438 of file deparse.c.

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

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

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

◆ deparseTruncateSql()

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

Definition at line 2677 of file deparse.c.

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

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

2252{
2253 TupleDesc tupdesc = RelationGetDescr(rel);
2254 AttrNumber pindex;
2255 bool first;
2256 ListCell *lc;
2257
2258 appendStringInfoString(buf, "UPDATE ");
2259 deparseRelation(buf, rel);
2260 appendStringInfoString(buf, " SET ");
2261
2262 pindex = 2; /* ctid is always the first param */
2263 first = true;
2264 foreach(lc, targetAttrs)
2265 {
2266 int attnum = lfirst_int(lc);
2267 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, attnum - 1);
2268
2269 if (!first)
2271 first = false;
2272
2273 deparseColumnRef(buf, rtindex, attnum, rte, false);
2274 if (attr->attgenerated)
2275 appendStringInfoString(buf, " = DEFAULT");
2276 else
2277 {
2278 appendStringInfo(buf, " = $%d", pindex);
2279 pindex++;
2280 }
2281 }
2282 appendStringInfoString(buf, " WHERE ctid = $1");
2283
2284 deparseReturningList(buf, rte, rtindex, rel,
2286 withCheckOptionList, returningList, retrieved_attrs);
2287}
bool trig_update_after_row
Definition: reltrigger.h:62

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

Referenced by postgresPlanForeignModify().

◆ deparseVar()

static void deparseVar ( Var node,
deparse_expr_cxt context 
)
static

Definition at line 2983 of file deparse.c.

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

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

Referenced by deparseExpr().

◆ foreign_expr_walker()

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

Definition at line 312 of file deparse.c.

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

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

Referenced by foreign_expr_walker(), and is_foreign_expr().

◆ get_jointype_name()

const char * get_jointype_name ( JoinType  jointype)

Definition at line 1672 of file deparse.c.

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

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

Referenced by deparseFromExprForRel(), and foreign_join_ok().

◆ get_relation_column_alias_ids()

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

Definition at line 4226 of file deparse.c.

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

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

Referenced by is_subquery_var().

◆ is_foreign_expr()

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

Definition at line 244 of file deparse.c.

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

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

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

◆ is_foreign_param()

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

Definition at line 1115 of file deparse.c.

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

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

Referenced by foreign_grouping_ok().

◆ is_foreign_pathkey()

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

Definition at line 1156 of file deparse.c.

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

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

Referenced by get_useful_pathkeys_for_relation().

◆ is_subquery_var()

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

Definition at line 4164 of file deparse.c.

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

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

Referenced by deparseVar(), and is_subquery_var().

◆ isPlainForeignVar()

static bool isPlainForeignVar ( Expr node,
deparse_expr_cxt context 
)
static

Definition at line 3405 of file deparse.c.

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

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

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

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

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

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

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

References appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), CompactAttribute::attgenerated, attnum, buf, i, lfirst_int, RelationGetDescr, and TupleDescCompactAttr().

Referenced by execute_foreign_modify().