Hello, I found that tuples come from file_fdw has strange xmin and xmax.

> postgres=# select tableoid, xmin, xmax, * from passwd1;
> tableoid | xmin |    xmax    |     uname     | pass |  uid  |  gid  | .. 
>    16396 |  244 | 4294967295 | root          | x    |     0 |     0 | root...
>    16396 |  252 | 4294967295 | bin           | x    |     1 |     1 | bin...
>    16396 |  284 | 4294967295 | daemon        | x    |     2 |     2 | 
> daemon...

Back to 9.1 gives the same result.

These xmin and xmax are the simple interpretations of a
DatumTupleFields filled by ExecMaterializedSlot() beeing fed the
source virtual tuple slot from file_fdw. On the other hand,
postgres_fdw gives sane xids (xmin = 2, xmax = 0).

This is because ForeignNext returns physical tuples in which
their headers are DatumTupleFields regardless whether the system
columns are requested or not. The fdw machinary desn't seem to
provide fdw handlers with a means to reject requests for
unavailable system columns, so the tuple header should be fixed
with the sane values as HeapTupleFields.

The patch attached fixes the header of materialized tuple to be
sane (2, 0) if the source slot was a virtual tuple in mechanism().


regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 9cc5345..59dc5f4 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -22,6 +22,8 @@
  */
 #include "postgres.h"
 
+#include "access/transam.h"
+#include "access/htup_details.h"
 #include "executor/executor.h"
 #include "executor/nodeForeignscan.h"
 #include "foreign/fdwapi.h"
@@ -58,8 +60,21 @@ ForeignNext(ForeignScanState *node)
 	 */
 	if (plan->fsSystemCol && !TupIsNull(slot))
 	{
+		bool		was_virtual_tuple = (slot->tts_tuple == NULL);
 		HeapTuple	tup = ExecMaterializeSlot(slot);
 
+		if (was_virtual_tuple)
+		{
+			/*
+			 * ExecMaterializeSlot fills the tuple header as a
+			 * DatumTupleFields if the slot was a virtual tuple, although a
+			 * physical one is needed by the callers. So rewrite the tuple
+			 * header as a sane HeapTupleFields.
+			 */
+			HeapTupleHeaderSetXmin(tup->t_data, FrozenTransactionId);
+			HeapTupleHeaderSetXmax(tup->t_data, InvalidTransactionId);
+			HeapTupleHeaderSetCmin(tup->t_data, FirstCommandId);
+		}
 		tup->t_tableOid = RelationGetRelid(node->ss.ss_currentRelation);
 	}
 
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to