Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a34e6f7

Browse files
Alexander PyhalovGleb Kashkin
authored and
Commitfest Bot
committed
Push join with function scan to remote server
The patch allows pushing joins with function RTEs to PostgreSQL data sources in general and postgres_fdw specifically. Co-authored-by: Gleb Kashkin <g.kashkin@postgrespro.ru>
1 parent 65db396 commit a34e6f7

File tree

9 files changed

+1046
-105
lines changed

9 files changed

+1046
-105
lines changed

contrib/postgres_fdw/deparse.c

Lines changed: 142 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype);
153153
static void deparseParam(Param *node, deparse_expr_cxt *context);
154154
static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context);
155155
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context);
156+
static void deparseFuncColnames(StringInfo buf, int varno, RangeTblEntry *rte, bool qualify_col);
156157
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context);
157158
static bool isPlainForeignVar(Expr *node, deparse_expr_cxt *context);
158159
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform);
@@ -1977,23 +1978,98 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
19771978
{
19781979
RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
19791980

1980-
/*
1981-
* Core code already has some lock on each rel being planned, so we
1982-
* can use NoLock here.
1983-
*/
1984-
Relation rel = table_open(rte->relid, NoLock);
1981+
Assert(rte->rtekind == RTE_RELATION || rte->rtekind == RTE_FUNCTION);
1982+
if (rte->rtekind == RTE_RELATION)
1983+
{
1984+
/*
1985+
* Core code already has some lock on each rel being planned, so
1986+
* we can use NoLock here.
1987+
*/
1988+
Relation rel = table_open(rte->relid, NoLock);
19851989

1986-
deparseRelation(buf, rel);
1990+
deparseRelation(buf, rel);
1991+
1992+
table_close(rel, NoLock);
1993+
}
1994+
else if (rte->rtekind == RTE_FUNCTION)
1995+
{
1996+
RangeTblFunction *rtfunc;
1997+
deparse_expr_cxt context;
1998+
ListCell *lc;
1999+
bool first = true;
2000+
int n;
2001+
2002+
n = list_length(rte->functions);
2003+
Assert(n >= 1);
2004+
2005+
if (n > 1)
2006+
appendStringInfoString(buf, "ROWS FROM (");
2007+
2008+
foreach(lc, rte->functions)
2009+
{
2010+
if (!first)
2011+
appendStringInfoString(buf, ", ");
2012+
else
2013+
first = false;
2014+
2015+
rtfunc = (RangeTblFunction *) lfirst(lc);
2016+
2017+
context.root = root;
2018+
context.foreignrel = foreignrel;
2019+
context.scanrel = foreignrel;
2020+
context.buf = buf;
2021+
context.params_list = params_list;
2022+
2023+
deparseExpr((Expr *) rtfunc->funcexpr, &context);
2024+
}
2025+
2026+
if (n > 1)
2027+
appendStringInfoString(buf, ")");
2028+
}
19872029

19882030
/*
19892031
* Add a unique alias to avoid any conflict in relation names due to
19902032
* pulled up subqueries in the query being built for a pushed down
19912033
* join.
19922034
*/
19932035
if (use_alias)
2036+
{
19942037
appendStringInfo(buf, " %s%d", REL_ALIAS_PREFIX, foreignrel->relid);
2038+
if (rte->rtekind == RTE_FUNCTION)
2039+
{
2040+
appendStringInfo(buf, " (");
2041+
deparseFuncColnames(buf, 0, rte, false);
2042+
appendStringInfo(buf, ") ");
2043+
}
2044+
}
2045+
}
2046+
}
19952047

1996-
table_close(rel, NoLock);
2048+
/*
2049+
* Deparse function columns alias list
2050+
*/
2051+
static void
2052+
deparseFuncColnames(StringInfo buf, int varno, RangeTblEntry *rte, bool qualify_col)
2053+
{
2054+
bool first = true;
2055+
ListCell *lc;
2056+
2057+
Assert(rte);
2058+
Assert(rte->rtekind == RTE_FUNCTION);
2059+
Assert(rte->eref);
2060+
2061+
foreach(lc, rte->eref->colnames)
2062+
{
2063+
char *colname = strVal(lfirst(lc));
2064+
2065+
if (colname[0] == '\0')
2066+
continue;
2067+
if (!first)
2068+
appendStringInfoString(buf, ",");
2069+
if (qualify_col)
2070+
ADD_REL_QUALIFIER(buf, varno);
2071+
appendStringInfoString(buf, quote_identifier(colname));
2072+
first = false;
19972073
}
19982074
}
19992075

@@ -2717,23 +2793,6 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte,
27172793
/* Required only to be passed down to deparseTargetList(). */
27182794
List *retrieved_attrs;
27192795

2720-
/*
2721-
* The lock on the relation will be held by upper callers, so it's
2722-
* fine to open it with no lock here.
2723-
*/
2724-
rel = table_open(rte->relid, NoLock);
2725-
2726-
/*
2727-
* The local name of the foreign table can not be recognized by the
2728-
* foreign server and the table it references on foreign server might
2729-
* have different column ordering or different columns than those
2730-
* declared locally. Hence we have to deparse whole-row reference as
2731-
* ROW(columns referenced locally). Construct this by deparsing a
2732-
* "whole row" attribute.
2733-
*/
2734-
attrs_used = bms_add_member(NULL,
2735-
0 - FirstLowInvalidHeapAttributeNumber);
2736-
27372796
/*
27382797
* In case the whole-row reference is under an outer join then it has
27392798
* to go NULL whenever the rest of the row goes NULL. Deparsing a join
@@ -2748,16 +2807,43 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte,
27482807
}
27492808

27502809
appendStringInfoString(buf, "ROW(");
2751-
deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
2752-
&retrieved_attrs);
2810+
if (rte->rtekind == RTE_RELATION)
2811+
{
2812+
/*
2813+
* The local name of the foreign table can not be recognized by
2814+
* the foreign server and the table it references on foreign
2815+
* server might have different column ordering or different
2816+
* columns than those declared locally. Hence we have to deparse
2817+
* whole-row reference as ROW(columns referenced locally).
2818+
* Construct this by deparsing a "whole row" attribute.
2819+
*/
2820+
attrs_used = bms_add_member(NULL,
2821+
0 - FirstLowInvalidHeapAttributeNumber);
2822+
2823+
/*
2824+
* The lock on the relation will be held by upper callers, so it's
2825+
* fine to open it with no lock here.
2826+
*/
2827+
rel = table_open(rte->relid, NoLock);
2828+
deparseTargetList(buf, rte, varno, rel, false, attrs_used, qualify_col,
2829+
&retrieved_attrs);
2830+
table_close(rel, NoLock);
2831+
bms_free(attrs_used);
2832+
}
2833+
else if (rte->rtekind == RTE_FUNCTION)
2834+
{
2835+
/*
2836+
* Function call is translated as-is, function returns the same
2837+
* columns in the same order as on local server
2838+
*/
2839+
deparseFuncColnames(buf, varno, rte, qualify_col);
2840+
}
27532841
appendStringInfoChar(buf, ')');
27542842

27552843
/* Complete the CASE WHEN statement started above. */
27562844
if (qualify_col)
27572845
appendStringInfoString(buf, " END");
27582846

2759-
table_close(rel, NoLock);
2760-
bms_free(attrs_used);
27612847
}
27622848
else
27632849
{
@@ -2772,29 +2858,40 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte,
27722858
* If it's a column of a foreign table, and it has the column_name FDW
27732859
* option, use that value.
27742860
*/
2775-
options = GetForeignColumnOptions(rte->relid, varattno);
2776-
foreach(lc, options)
2861+
if (rte->rtekind == RTE_RELATION)
27772862
{
2778-
DefElem *def = (DefElem *) lfirst(lc);
2779-
2780-
if (strcmp(def->defname, "column_name") == 0)
2863+
options = GetForeignColumnOptions(rte->relid, varattno);
2864+
foreach(lc, options)
27812865
{
2782-
colname = defGetString(def);
2783-
break;
2866+
DefElem *def = (DefElem *) lfirst(lc);
2867+
2868+
if (strcmp(def->defname, "column_name") == 0)
2869+
{
2870+
colname = defGetString(def);
2871+
break;
2872+
}
27842873
}
2785-
}
27862874

2787-
/*
2788-
* If it's a column of a regular table or it doesn't have column_name
2789-
* FDW option, use attribute name.
2790-
*/
2791-
if (colname == NULL)
2792-
colname = get_attname(rte->relid, varattno, false);
2875+
/*
2876+
* If it's a column of a regular table or it doesn't have
2877+
* column_name FDW option, use attribute name.
2878+
*/
2879+
if (colname == NULL)
2880+
colname = get_attname(rte->relid, varattno, false);
27932881

2794-
if (qualify_col)
2795-
ADD_REL_QUALIFIER(buf, varno);
2882+
if (qualify_col)
2883+
ADD_REL_QUALIFIER(buf, varno);
27962884

2797-
appendStringInfoString(buf, quote_identifier(colname));
2885+
appendStringInfoString(buf, quote_identifier(colname));
2886+
}
2887+
else if (rte->rtekind == RTE_FUNCTION)
2888+
{
2889+
colname = get_rte_attribute_name(rte, varattno);
2890+
2891+
if (qualify_col)
2892+
ADD_REL_QUALIFIER(buf, varno);
2893+
appendStringInfoString(buf, quote_identifier(colname));
2894+
}
27982895
}
27992896
}
28002897

0 commit comments

Comments
 (0)