Skip to content

Commit da7d44b

Browse files
committed
postgres_fdw: Clean up handling of system columns.
Previously, querying the xmin column of a single postgres_fdw foreign table fetched the tuple length, xmax the typmod, and cmin or cmax the composite type OID of the tuple. However, when you queried several such tables and the join got shipped to the remote side, these columns ended up containing the remote values of the corresponding columns. Both behaviors are rather unprincipled, the former for obvious reasons and the latter because the remote values of these columns don't have any local significance; our transaction IDs are in a different space than those of the remote machine. Clean this up by setting all of these fields to 0 in both cases. Also fix the handling of tableoid to be sane. Robert Haas and Ashutosh Bapat, reviewed by Etsuro Fujita.
1 parent 5702277 commit da7d44b

File tree

3 files changed

+78
-22
lines changed

3 files changed

+78
-22
lines changed

contrib/postgres_fdw/deparse.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1571,13 +1571,38 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, PlannerInfo *root,
15711571
{
15721572
RangeTblEntry *rte;
15731573

1574-
/* varattno can be a whole-row reference, ctid or a regular table column */
15751574
if (varattno == SelfItemPointerAttributeNumber)
15761575
{
1576+
/* We support fetching the remote side's CTID. */
15771577
if (qualify_col)
15781578
ADD_REL_QUALIFIER(buf, varno);
15791579
appendStringInfoString(buf, "ctid");
15801580
}
1581+
else if (varattno < 0)
1582+
{
1583+
/*
1584+
* All other system attributes are fetched as 0, except for table OID,
1585+
* which is fetched as the local table OID. However, we must be
1586+
* careful; the table could be beneath an outer join, in which case
1587+
* it must go to NULL whenever the rest of the row does.
1588+
*/
1589+
Oid fetchval = 0;
1590+
1591+
if (varattno == TableOidAttributeNumber)
1592+
{
1593+
rte = planner_rt_fetch(varno, root);
1594+
fetchval = rte->relid;
1595+
}
1596+
1597+
if (qualify_col)
1598+
{
1599+
appendStringInfoString(buf, "CASE WHEN ");
1600+
ADD_REL_QUALIFIER(buf, varno);
1601+
appendStringInfo(buf, "* IS NOT NULL THEN %u END", fetchval);
1602+
}
1603+
else
1604+
appendStringInfo(buf, "%u", fetchval);
1605+
}
15811606
else if (varattno == 0)
15821607
{
15831608
/* Whole row reference */
@@ -1606,10 +1631,29 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, PlannerInfo *root,
16061631
*/
16071632
attrs_used = bms_add_member(NULL,
16081633
0 - FirstLowInvalidHeapAttributeNumber);
1634+
1635+
/*
1636+
* In case the whole-row reference is under an outer join then it has to
1637+
* go NULL whenver the rest of the row goes NULL. Deparsing a join query
1638+
* would always involve multiple relations, thus qualify_col would be
1639+
* true.
1640+
*/
1641+
if (qualify_col)
1642+
{
1643+
appendStringInfoString(buf, "CASE WHEN ");
1644+
ADD_REL_QUALIFIER(buf, varno);
1645+
appendStringInfo(buf, "* IS NOT NULL THEN ");
1646+
}
1647+
16091648
appendStringInfoString(buf, "ROW(");
16101649
deparseTargetList(buf, root, varno, rel, false, attrs_used, qualify_col,
16111650
&retrieved_attrs);
16121651
appendStringInfoString(buf, ")");
1652+
1653+
/* Complete the CASE WHEN statement started above. */
1654+
if (qualify_col)
1655+
appendStringInfo(buf," END");
1656+
16131657
heap_close(rel, NoLock);
16141658
bms_free(attrs_used);
16151659
}

0 commit comments

Comments
 (0)