1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

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.
This commit is contained in:
Robert Haas
2016-04-15 11:58:56 -04:00
parent 5702277ca9
commit da7d44b627
3 changed files with 78 additions and 22 deletions

View File

@ -1571,13 +1571,38 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, PlannerInfo *root,
{
RangeTblEntry *rte;
/* varattno can be a whole-row reference, ctid or a regular table column */
if (varattno == SelfItemPointerAttributeNumber)
{
/* We support fetching the remote side's CTID. */
if (qualify_col)
ADD_REL_QUALIFIER(buf, varno);
appendStringInfoString(buf, "ctid");
}
else if (varattno < 0)
{
/*
* All other system attributes are fetched as 0, except for table OID,
* which is fetched as the local table OID. However, we must be
* careful; the table could be beneath an outer join, in which case
* it must go to NULL whenever the rest of the row does.
*/
Oid fetchval = 0;
if (varattno == TableOidAttributeNumber)
{
rte = planner_rt_fetch(varno, root);
fetchval = rte->relid;
}
if (qualify_col)
{
appendStringInfoString(buf, "CASE WHEN ");
ADD_REL_QUALIFIER(buf, varno);
appendStringInfo(buf, "* IS NOT NULL THEN %u END", fetchval);
}
else
appendStringInfo(buf, "%u", fetchval);
}
else if (varattno == 0)
{
/* Whole row reference */
@ -1606,10 +1631,29 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, PlannerInfo *root,
*/
attrs_used = bms_add_member(NULL,
0 - FirstLowInvalidHeapAttributeNumber);
/*
* In case the whole-row reference is under an outer join then it has to
* go NULL whenver the rest of the row goes NULL. Deparsing a join query
* would always involve multiple relations, thus qualify_col would be
* true.
*/
if (qualify_col)
{
appendStringInfoString(buf, "CASE WHEN ");
ADD_REL_QUALIFIER(buf, varno);
appendStringInfo(buf, "* IS NOT NULL THEN ");
}
appendStringInfoString(buf, "ROW(");
deparseTargetList(buf, root, varno, rel, false, attrs_used, qualify_col,
&retrieved_attrs);
appendStringInfoString(buf, ")");
/* Complete the CASE WHEN statement started above. */
if (qualify_col)
appendStringInfo(buf," END");
heap_close(rel, NoLock);
bms_free(attrs_used);
}