Commit e690b951 authored by Tom Lane's avatar Tom Lane

Avoid retrieving dummy NULL columns in postgres_fdw.

This should provide some marginal overall savings, since it surely takes
many more cycles for the remote server to deal with the NULL columns than
it takes for postgres_fdw not to emit them.  But really the reason is to
keep the emitted queries from looking quite so silly ...
parent 9cbc4b80
...@@ -106,10 +106,12 @@ static void deparseTargetList(StringInfo buf, ...@@ -106,10 +106,12 @@ static void deparseTargetList(StringInfo buf,
PlannerInfo *root, PlannerInfo *root,
Index rtindex, Index rtindex,
Relation rel, Relation rel,
Bitmapset *attrs_used); Bitmapset *attrs_used,
List **retrieved_attrs);
static void deparseReturningList(StringInfo buf, PlannerInfo *root, static void deparseReturningList(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel, Index rtindex, Relation rel,
List *returningList); List *returningList,
List **retrieved_attrs);
static void deparseColumnRef(StringInfo buf, int varno, int varattno, static void deparseColumnRef(StringInfo buf, int varno, int varattno,
PlannerInfo *root); PlannerInfo *root);
static void deparseRelation(StringInfo buf, Relation rel); static void deparseRelation(StringInfo buf, Relation rel);
...@@ -652,12 +654,16 @@ is_builtin(Oid oid) ...@@ -652,12 +654,16 @@ is_builtin(Oid oid)
* Construct a simple SELECT statement that retrieves desired columns * Construct a simple SELECT statement that retrieves desired columns
* of the specified foreign table, and append it to "buf". The output * of the specified foreign table, and append it to "buf". The output
* contains just "SELECT ... FROM tablename". * contains just "SELECT ... FROM tablename".
*
* We also create an integer List of the columns being retrieved, which is
* returned to *retrieved_attrs.
*/ */
void void
deparseSelectSql(StringInfo buf, deparseSelectSql(StringInfo buf,
PlannerInfo *root, PlannerInfo *root,
RelOptInfo *baserel, RelOptInfo *baserel,
Bitmapset *attrs_used) Bitmapset *attrs_used,
List **retrieved_attrs)
{ {
RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root); RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root);
Relation rel; Relation rel;
...@@ -672,7 +678,8 @@ deparseSelectSql(StringInfo buf, ...@@ -672,7 +678,8 @@ deparseSelectSql(StringInfo buf,
* Construct SELECT list * Construct SELECT list
*/ */
appendStringInfoString(buf, "SELECT "); appendStringInfoString(buf, "SELECT ");
deparseTargetList(buf, root, baserel->relid, rel, attrs_used); deparseTargetList(buf, root, baserel->relid, rel, attrs_used,
retrieved_attrs);
/* /*
* Construct FROM clause * Construct FROM clause
...@@ -687,24 +694,24 @@ deparseSelectSql(StringInfo buf, ...@@ -687,24 +694,24 @@ deparseSelectSql(StringInfo buf,
* Emit a target list that retrieves the columns specified in attrs_used. * Emit a target list that retrieves the columns specified in attrs_used.
* This is used for both SELECT and RETURNING targetlists. * This is used for both SELECT and RETURNING targetlists.
* *
* We list attributes in order of the foreign table's columns, but replace * The tlist text is appended to buf, and we also create an integer List
* any attributes that need not be fetched with NULL constants. (We can't * of the columns being retrieved, which is returned to *retrieved_attrs.
* just omit such attributes, or we'll lose track of which columns are
* which at runtime.) Note however that any dropped columns are ignored.
* Also, if ctid needs to be retrieved, it's added at the end.
*/ */
static void static void
deparseTargetList(StringInfo buf, deparseTargetList(StringInfo buf,
PlannerInfo *root, PlannerInfo *root,
Index rtindex, Index rtindex,
Relation rel, Relation rel,
Bitmapset *attrs_used) Bitmapset *attrs_used,
List **retrieved_attrs)
{ {
TupleDesc tupdesc = RelationGetDescr(rel); TupleDesc tupdesc = RelationGetDescr(rel);
bool have_wholerow; bool have_wholerow;
bool first; bool first;
int i; int i;
*retrieved_attrs = NIL;
/* If there's a whole-row reference, we'll need all the columns. */ /* If there's a whole-row reference, we'll need all the columns. */
have_wholerow = bms_is_member(0 - FirstLowInvalidHeapAttributeNumber, have_wholerow = bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
attrs_used); attrs_used);
...@@ -718,16 +725,18 @@ deparseTargetList(StringInfo buf, ...@@ -718,16 +725,18 @@ deparseTargetList(StringInfo buf,
if (attr->attisdropped) if (attr->attisdropped)
continue; continue;
if (have_wholerow ||
bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
attrs_used))
{
if (!first) if (!first)
appendStringInfoString(buf, ", "); appendStringInfoString(buf, ", ");
first = false; first = false;
if (have_wholerow ||
bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
attrs_used))
deparseColumnRef(buf, rtindex, i, root); deparseColumnRef(buf, rtindex, i, root);
else
appendStringInfoString(buf, "NULL"); *retrieved_attrs = lappend_int(*retrieved_attrs, i);
}
} }
/* /*
...@@ -742,6 +751,9 @@ deparseTargetList(StringInfo buf, ...@@ -742,6 +751,9 @@ deparseTargetList(StringInfo buf,
first = false; first = false;
appendStringInfoString(buf, "ctid"); appendStringInfoString(buf, "ctid");
*retrieved_attrs = lappend_int(*retrieved_attrs,
SelfItemPointerAttributeNumber);
} }
/* Don't generate bad syntax if no undropped columns */ /* Don't generate bad syntax if no undropped columns */
...@@ -809,11 +821,16 @@ appendWhereClause(StringInfo buf, ...@@ -809,11 +821,16 @@ appendWhereClause(StringInfo buf,
/* /*
* deparse remote INSERT statement * deparse remote INSERT statement
*
* The statement text is appended to buf, and we also create an integer List
* of the columns being retrieved by RETURNING (if any), which is returned
* to *retrieved_attrs.
*/ */
void void
deparseInsertSql(StringInfo buf, PlannerInfo *root, deparseInsertSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel, Index rtindex, Relation rel,
List *targetAttrs, List *returningList) List *targetAttrs, List *returningList,
List **retrieved_attrs)
{ {
AttrNumber pindex; AttrNumber pindex;
bool first; bool first;
...@@ -858,16 +875,24 @@ deparseInsertSql(StringInfo buf, PlannerInfo *root, ...@@ -858,16 +875,24 @@ deparseInsertSql(StringInfo buf, PlannerInfo *root,
appendStringInfoString(buf, " DEFAULT VALUES"); appendStringInfoString(buf, " DEFAULT VALUES");
if (returningList) if (returningList)
deparseReturningList(buf, root, rtindex, rel, returningList); deparseReturningList(buf, root, rtindex, rel, returningList,
retrieved_attrs);
else
*retrieved_attrs = NIL;
} }
/* /*
* deparse remote UPDATE statement * deparse remote UPDATE statement
*
* The statement text is appended to buf, and we also create an integer List
* of the columns being retrieved by RETURNING (if any), which is returned
* to *retrieved_attrs.
*/ */
void void
deparseUpdateSql(StringInfo buf, PlannerInfo *root, deparseUpdateSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel, Index rtindex, Relation rel,
List *targetAttrs, List *returningList) List *targetAttrs, List *returningList,
List **retrieved_attrs)
{ {
AttrNumber pindex; AttrNumber pindex;
bool first; bool first;
...@@ -894,23 +919,34 @@ deparseUpdateSql(StringInfo buf, PlannerInfo *root, ...@@ -894,23 +919,34 @@ deparseUpdateSql(StringInfo buf, PlannerInfo *root,
appendStringInfoString(buf, " WHERE ctid = $1"); appendStringInfoString(buf, " WHERE ctid = $1");
if (returningList) if (returningList)
deparseReturningList(buf, root, rtindex, rel, returningList); deparseReturningList(buf, root, rtindex, rel, returningList,
retrieved_attrs);
else
*retrieved_attrs = NIL;
} }
/* /*
* deparse remote DELETE statement * deparse remote DELETE statement
*
* The statement text is appended to buf, and we also create an integer List
* of the columns being retrieved by RETURNING (if any), which is returned
* to *retrieved_attrs.
*/ */
void void
deparseDeleteSql(StringInfo buf, PlannerInfo *root, deparseDeleteSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel, Index rtindex, Relation rel,
List *returningList) List *returningList,
List **retrieved_attrs)
{ {
appendStringInfoString(buf, "DELETE FROM "); appendStringInfoString(buf, "DELETE FROM ");
deparseRelation(buf, rel); deparseRelation(buf, rel);
appendStringInfoString(buf, " WHERE ctid = $1"); appendStringInfoString(buf, " WHERE ctid = $1");
if (returningList) if (returningList)
deparseReturningList(buf, root, rtindex, rel, returningList); deparseReturningList(buf, root, rtindex, rel, returningList,
retrieved_attrs);
else
*retrieved_attrs = NIL;
} }
/* /*
...@@ -919,7 +955,8 @@ deparseDeleteSql(StringInfo buf, PlannerInfo *root, ...@@ -919,7 +955,8 @@ deparseDeleteSql(StringInfo buf, PlannerInfo *root,
static void static void
deparseReturningList(StringInfo buf, PlannerInfo *root, deparseReturningList(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel, Index rtindex, Relation rel,
List *returningList) List *returningList,
List **retrieved_attrs)
{ {
Bitmapset *attrs_used; Bitmapset *attrs_used;
...@@ -931,7 +968,8 @@ deparseReturningList(StringInfo buf, PlannerInfo *root, ...@@ -931,7 +968,8 @@ deparseReturningList(StringInfo buf, PlannerInfo *root,
&attrs_used); &attrs_used);
appendStringInfoString(buf, " RETURNING "); appendStringInfoString(buf, " RETURNING ");
deparseTargetList(buf, root, rtindex, rel, attrs_used); deparseTargetList(buf, root, rtindex, rel, attrs_used,
retrieved_attrs);
} }
/* /*
...@@ -959,10 +997,11 @@ deparseAnalyzeSizeSql(StringInfo buf, Relation rel) ...@@ -959,10 +997,11 @@ deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
/* /*
* Construct SELECT statement to acquire sample rows of given relation. * Construct SELECT statement to acquire sample rows of given relation.
* *
* Note: command is appended to whatever might be in buf already. * SELECT command is appended to buf, and list of columns retrieved
* is returned to *retrieved_attrs.
*/ */
void void
deparseAnalyzeSql(StringInfo buf, Relation rel) deparseAnalyzeSql(StringInfo buf, Relation rel, List **retrieved_attrs)
{ {
Oid relid = RelationGetRelid(rel); Oid relid = RelationGetRelid(rel);
TupleDesc tupdesc = RelationGetDescr(rel); TupleDesc tupdesc = RelationGetDescr(rel);
...@@ -972,6 +1011,8 @@ deparseAnalyzeSql(StringInfo buf, Relation rel) ...@@ -972,6 +1011,8 @@ deparseAnalyzeSql(StringInfo buf, Relation rel)
ListCell *lc; ListCell *lc;
bool first = true; bool first = true;
*retrieved_attrs = NIL;
appendStringInfoString(buf, "SELECT "); appendStringInfoString(buf, "SELECT ");
for (i = 0; i < tupdesc->natts; i++) for (i = 0; i < tupdesc->natts; i++)
{ {
...@@ -999,6 +1040,8 @@ deparseAnalyzeSql(StringInfo buf, Relation rel) ...@@ -999,6 +1040,8 @@ deparseAnalyzeSql(StringInfo buf, Relation rel)
} }
appendStringInfoString(buf, quote_identifier(colname)); appendStringInfoString(buf, quote_identifier(colname));
*retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
} }
/* Don't generate bad syntax for zero-column relation. */ /* Don't generate bad syntax for zero-column relation. */
......
This diff is collapsed.
...@@ -49,7 +49,8 @@ extern bool is_foreign_expr(PlannerInfo *root, ...@@ -49,7 +49,8 @@ extern bool is_foreign_expr(PlannerInfo *root,
extern void deparseSelectSql(StringInfo buf, extern void deparseSelectSql(StringInfo buf,
PlannerInfo *root, PlannerInfo *root,
RelOptInfo *baserel, RelOptInfo *baserel,
Bitmapset *attrs_used); Bitmapset *attrs_used,
List **retrieved_attrs);
extern void appendWhereClause(StringInfo buf, extern void appendWhereClause(StringInfo buf,
PlannerInfo *root, PlannerInfo *root,
RelOptInfo *baserel, RelOptInfo *baserel,
...@@ -58,14 +59,18 @@ extern void appendWhereClause(StringInfo buf, ...@@ -58,14 +59,18 @@ extern void appendWhereClause(StringInfo buf,
List **params); List **params);
extern void deparseInsertSql(StringInfo buf, PlannerInfo *root, extern void deparseInsertSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel, Index rtindex, Relation rel,
List *targetAttrs, List *returningList); List *targetAttrs, List *returningList,
List **retrieved_attrs);
extern void deparseUpdateSql(StringInfo buf, PlannerInfo *root, extern void deparseUpdateSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel, Index rtindex, Relation rel,
List *targetAttrs, List *returningList); List *targetAttrs, List *returningList,
List **retrieved_attrs);
extern void deparseDeleteSql(StringInfo buf, PlannerInfo *root, extern void deparseDeleteSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel, Index rtindex, Relation rel,
List *returningList); List *returningList,
List **retrieved_attrs);
extern void deparseAnalyzeSizeSql(StringInfo buf, Relation rel); extern void deparseAnalyzeSizeSql(StringInfo buf, Relation rel);
extern void deparseAnalyzeSql(StringInfo buf, Relation rel); extern void deparseAnalyzeSql(StringInfo buf, Relation rel,
List **retrieved_attrs);
#endif /* POSTGRES_FDW_H */ #endif /* POSTGRES_FDW_H */
...@@ -311,7 +311,9 @@ UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT ...@@ -311,7 +311,9 @@ UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9; FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;
UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9; FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;
DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING *; EXPLAIN (verbose, costs off)
DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING c1, c4;
DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING c1, c4;
EXPLAIN (verbose, costs off) EXPLAIN (verbose, costs off)
DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2; DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2;
DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2; DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment