writable FDWs / update targets confusion - Mailing list pgsql-hackers

From Tomas Vondra
Subject writable FDWs / update targets confusion
Date
Msg-id 8b848b463a71b7a905bc5ef18b95528e.squirrel@sq.gransy.com
Whole thread Raw
Responses Re: writable FDWs / update targets confusion  (Albe Laurenz <laurenz.albe@wien.gv.at>)
List pgsql-hackers
Hi,

I'm working on adding write support to one of my FDWs. Adding INSERT went
pretty fine, but when adding DELETE/UPDATE I got really confused about how
the update targets are supposed to work.

My understanding of how it's supposed to work is this:
(1) AddForeignUpdateTargets adds columns that serve as ID of the record    (e.g. postgres_fdw adds 'ctid')
(2) planning the inner foreign scan handles the new column appropriately    (e.g. scans system columns, as in case of
'ctid'etc.)
 
(3) IterateForeignScan will see the column in the tuple descriptor, will    set it just like any other column, etc.
(4) ExecForeignDelete will fetch the new column and do something with it

However no matter what I do, I can't get the steps (3) and (4) working this
way. This is what I do in AddForeignUpdateTargets (pretty much a 1:1 copy
from postgres_fdw, except that I'm using INT8OID instead of TIDOID):
   static void   myAddForeignUpdateTargets(Query *parsetree,                                   RangeTblEntry
*target_rte,                                  Relation target_relation)   {       Var         *var;       const char
*attrname;      TargetEntry *tle;
 
       /* Make a Var representing the desired value */       var = makeVar(parsetree->resultRelation,
 SelfItemPointerAttributeNumber,                     INT8OID,                     -1,                     InvalidOid,
                 0);
 
       /* Wrap it in a resjunk TLE with the right name ... */       attrname = "ctid";
       tle = makeTargetEntry((Expr *) var,                             list_length(parsetree->targetList) + 1,
                  pstrdup(attrname),                             true);
 
       /* ... and add it to the query's targetlist */       parsetree->targetList = lappend(parsetree->targetList,
tle);  }
 

Then in GetForeignPlan I collect all the attnums (including the new one),
and in BeginForeignScan decide which columns to actually fetch. So if any
attnum is (attnum < 0) I know I need to fetch the new 'ctid' column.

However in IterateForeignScan, the tuple descriptor does not change. It
still has only the columns of the foreign table, so I have no place to set
the ctid to. So even though
   ExecFindJunkAttributeInTlist(subplan->targetlist, "ctid");

return "1" I can't really set any of the column to the CTID, because the
column might be used in a WHERE condition.

And looking at postgres_fdw it seems to me it does not really set the ctid
into the tuple as a column, but just does this:
   if (ctid)       tuple->t_self = *ctid;

which I can't really do because I need to use INT8 and not TID. But even
if I do this,

Interestingly, if I do this in ExecForeignDelete
   static TupleTableSlot *   myExecForeignDelete(EState *estate,                             ResultRelInfo
*resultRelInfo,                            TupleTableSlot *slot,                             TupleTableSlot *planSlot)
{
 
       bool isNull;       MyModifyState state = (MyModifyState)resultRelInfo->ri_FdwState;       int64 ctid;
       Datum datum = ExecGetJunkAttribute(planSlot,                                          state->ctidAttno,
&isNull);
       ctid = DatumGetInt64(datum);
       elog(WARNING, "ID = %ld", ctid);
       if (isNull)           elog(ERROR, "ctid is NULL");
       /* FIXME not yet implemented */       return NULL;   }

I do get (isNull=FALSE) but the ctid evaluates to some random number, e.g.
   WARNING:  ID = 44384788 (44384788)   WARNING:  ID = 44392980 (44392980)

and so on.

So what did I get wrong? Is it possible to use arbitrary hidden column as
"junk" columns (documentation seems to suggest that)? What is the right
way to do that / whad did I get wrong?

regards
Tomas




pgsql-hackers by date:

Previous
From: Kohei KaiGai
Date:
Subject: Re: What's needed for cache-only table scan?
Next
From: Teodor Sigaev
Date:
Subject: GIN bugs in master branch