Hi,

On 2016/02/09 14:09, Ashutosh Bapat wrote:
Sorry, I was wrong. For public user mapping userid is 0 (InvalidOid),
which is returned as is in UserMapping object. I confused InvalidOid
with -1.

I think the following umid handling in postgresGetForeignPlan has the same issue:

    /*
     * Build the fdw_private list that will be available to the executor.
     * Items in the list must match order in enum FdwScanPrivateIndex.
     */
    fdw_private = list_make4(makeString(sql.data),
                             retrieved_attrs,
                             makeInteger(fpinfo->fetch_size),
                             makeInteger(foreignrel->umid));

I don't think it's correct to use makeInteger for the foreignrel's umid.

You store the umid in the fdw_private list here and extract it from the list in postgresBeginForeignScan, to get the user mapping. But we really need that? We have a validated plan when getting called from postgresBeginForeignScan, so if foreign join, we can simply pick any of the plan's fs_relids and use it to identify which user to do the remote access as, in the same way as for foreign tables.

Attached is a patch for that.

Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/postgres_fdw.c
--- b/contrib/postgres_fdw/postgres_fdw.c
***************
*** 65,72 **** enum FdwScanPrivateIndex
  	FdwScanPrivateRetrievedAttrs,
  	/* Integer representing the desired fetch_size */
  	FdwScanPrivateFetchSize,
- 	/* Oid of user mapping to be used while connecting to the foreign server */
- 	FdwScanPrivateUserMappingOid,
  
  	/*
  	 * String describing join i.e. names of relations being joined and types
--- 65,70 ----
***************
*** 1133,1142 **** postgresGetForeignPlan(PlannerInfo *root,
  	 * Build the fdw_private list that will be available to the executor.
  	 * Items in the list must match order in enum FdwScanPrivateIndex.
  	 */
! 	fdw_private = list_make4(makeString(sql.data),
  							 retrieved_attrs,
! 							 makeInteger(fpinfo->fetch_size),
! 							 makeInteger(foreignrel->umid));
  	if (foreignrel->reloptkind == RELOPT_JOINREL)
  		fdw_private = lappend(fdw_private,
  							  makeString(fpinfo->relation_name->data));
--- 1131,1139 ----
  	 * Build the fdw_private list that will be available to the executor.
  	 * Items in the list must match order in enum FdwScanPrivateIndex.
  	 */
! 	fdw_private = list_make3(makeString(sql.data),
  							 retrieved_attrs,
! 							 makeInteger(fpinfo->fetch_size));
  	if (foreignrel->reloptkind == RELOPT_JOINREL)
  		fdw_private = lappend(fdw_private,
  							  makeString(fpinfo->relation_name->data));
***************
*** 1168,1174 **** postgresBeginForeignScan(ForeignScanState *node, int eflags)
--- 1165,1175 ----
  	ForeignScan *fsplan = (ForeignScan *) node->ss.ps.plan;
  	EState	   *estate = node->ss.ps.state;
  	PgFdwScanState *fsstate;
+ 	RangeTblEntry *rte;
+ 	Oid			userid;
+ 	ForeignTable *table;
  	UserMapping *user;
+ 	int			rtindex;
  	int			numParams;
  	int			i;
  	ListCell   *lc;
***************
*** 1193,1221 **** postgresBeginForeignScan(ForeignScanState *node, int eflags)
  	 * information goes stale between planning and execution, plan will be
  	 * invalidated and replanned.
  	 */
- 	if (fsplan->scan.scanrelid > 0)
- 	{
- 		ForeignTable *table;
  
! 		/*
! 		 * Identify which user to do the remote access as.  This should match
! 		 * what ExecCheckRTEPerms() does.
! 		 */
! 		RangeTblEntry *rte = rt_fetch(fsplan->scan.scanrelid, estate->es_range_table);
! 		Oid			userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
! 
! 		fsstate->rel = node->ss.ss_currentRelation;
! 		table = GetForeignTable(RelationGetRelid(fsstate->rel));
! 
! 		user = GetUserMapping(userid, table->serverid);
! 	}
  	else
  	{
! 		Oid			umid = intVal(list_nth(fsplan->fdw_private, FdwScanPrivateUserMappingOid));
! 
! 		user = GetUserMappingById(umid);
! 		Assert(fsplan->fs_server == user->serverid);
  	}
  
  	/*
  	 * Get connection to the foreign server.  Connection manager will
--- 1194,1217 ----
  	 * information goes stale between planning and execution, plan will be
  	 * invalidated and replanned.
  	 */
  
! 	/*
! 	 * Identify which user to do the remote access as.  This should match what
! 	 * ExecCheckRTEPerms() does.
! 	 */
! 	if (fsplan->scan.scanrelid > 0)
! 		rtindex = fsplan->scan.scanrelid;
  	else
  	{
! 		/* Pick the lowest-numbered one as a representative */
! 		rtindex = bms_first_member(fsplan->fs_relids);
  	}
+ 	rte = rt_fetch(rtindex, estate->es_range_table);
+ 	userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
+ 
+ 	/* Get info about foreign table */
+ 	table = GetForeignTable(rte->relid);
+ 	user = GetUserMapping(userid, table->serverid);
  
  	/*
  	 * Get connection to the foreign server.  Connection manager will
***************
*** 1252,1260 **** postgresBeginForeignScan(ForeignScanState *node, int eflags)
--- 1248,1262 ----
  	 * into local representation and error reporting during that process.
  	 */
  	if (fsplan->scan.scanrelid > 0)
+ 	{
+ 		fsstate->rel = node->ss.ss_currentRelation;
  		fsstate->tupdesc = RelationGetDescr(fsstate->rel);
+ 	}
  	else
+ 	{
+ 		fsstate->rel = NULL;
  		fsstate->tupdesc = node->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
+ 	}
  
  	fsstate->attinmeta = TupleDescGetAttInMetadata(fsstate->tupdesc);
  
-- 
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