@@ -303,7 +303,8 @@ typedef struct
303303typedef struct ConversionLocation
304304{
305305 AttrNumber cur_attno ; /* attribute number being processed, or 0 */
306- ForeignScanState * fsstate ; /* plan node being processed */
306+ Relation rel ; /* foreign table being processed, or NULL */
307+ ForeignScanState * fsstate ; /* plan node being processed, or NULL */
307308} ConversionLocation ;
308309
309310/* Callback argument for ec_member_matches_foreign */
@@ -7113,7 +7114,12 @@ complete_pending_request(AsyncRequest *areq)
71137114 * rel is the local representation of the foreign table, attinmeta is
71147115 * conversion data for the rel's tupdesc, and retrieved_attrs is an
71157116 * integer list of the table column numbers present in the PGresult.
7117+ * fsstate is the ForeignScan plan node's execution state.
71167118 * temp_context is a working context that can be reset after each tuple.
7119+ *
7120+ * Note: either rel or fsstate, but not both, can be NULL. rel is NULL
7121+ * if we're processing a remote join, while fsstate is NULL in a non-query
7122+ * context such as ANALYZE, or if we're processing a non-scan query node.
71177123 */
71187124static HeapTuple
71197125make_tuple_from_result_row (PGresult * res ,
@@ -7144,6 +7150,10 @@ make_tuple_from_result_row(PGresult *res,
71447150 */
71457151 oldcontext = MemoryContextSwitchTo (temp_context );
71467152
7153+ /*
7154+ * Get the tuple descriptor for the row. Use the rel's tupdesc if rel is
7155+ * provided, otherwise look to the scan node's ScanTupleSlot.
7156+ */
71477157 if (rel )
71487158 tupdesc = RelationGetDescr (rel );
71497159 else
@@ -7161,6 +7171,7 @@ make_tuple_from_result_row(PGresult *res,
71617171 * Set up and install callback to report where conversion error occurs.
71627172 */
71637173 errpos .cur_attno = 0 ;
7174+ errpos .rel = rel ;
71647175 errpos .fsstate = fsstate ;
71657176 errcallback .callback = conversion_error_callback ;
71667177 errcallback .arg = (void * ) & errpos ;
@@ -7265,60 +7276,87 @@ make_tuple_from_result_row(PGresult *res,
72657276 *
72667277 * Note that this function mustn't do any catalog lookups, since we are in
72677278 * an already-failed transaction. Fortunately, we can get the needed info
7268- * from the query's rangetable instead.
7279+ * from the relation or the query's rangetable instead.
72697280 */
72707281static void
72717282conversion_error_callback (void * arg )
72727283{
72737284 ConversionLocation * errpos = (ConversionLocation * ) arg ;
7285+ Relation rel = errpos -> rel ;
72747286 ForeignScanState * fsstate = errpos -> fsstate ;
7275- ForeignScan * fsplan = castNode (ForeignScan , fsstate -> ss .ps .plan );
7276- int varno = 0 ;
7277- AttrNumber colno = 0 ;
72787287 const char * attname = NULL ;
72797288 const char * relname = NULL ;
72807289 bool is_wholerow = false;
72817290
7282- if (fsplan -> scan .scanrelid > 0 )
7283- {
7284- /* error occurred in a scan against a foreign table */
7285- varno = fsplan -> scan .scanrelid ;
7286- colno = errpos -> cur_attno ;
7287- }
7288- else
7291+ /*
7292+ * If we're in a scan node, always use aliases from the rangetable, for
7293+ * consistency between the simple-relation and remote-join cases. Look at
7294+ * the relation's tupdesc only if we're not in a scan node.
7295+ */
7296+ if (fsstate )
72897297 {
7290- /* error occurred in a scan against a foreign join */
7291- TargetEntry * tle ;
7298+ /* ForeignScan case */
7299+ ForeignScan * fsplan = castNode (ForeignScan , fsstate -> ss .ps .plan );
7300+ int varno = 0 ;
7301+ AttrNumber colno = 0 ;
72927302
7293- tle = list_nth_node (TargetEntry , fsplan -> fdw_scan_tlist ,
7294- errpos -> cur_attno - 1 );
7303+ if (fsplan -> scan .scanrelid > 0 )
7304+ {
7305+ /* error occurred in a scan against a foreign table */
7306+ varno = fsplan -> scan .scanrelid ;
7307+ colno = errpos -> cur_attno ;
7308+ }
7309+ else
7310+ {
7311+ /* error occurred in a scan against a foreign join */
7312+ TargetEntry * tle ;
72957313
7296- /*
7297- * Target list can have Vars and expressions. For Vars, we can get
7298- * some information, however for expressions we can't. Thus for
7299- * expressions, just show generic context message.
7300- */
7301- if (IsA (tle -> expr , Var ))
7314+ tle = list_nth_node (TargetEntry , fsplan -> fdw_scan_tlist ,
7315+ errpos -> cur_attno - 1 );
7316+
7317+ /*
7318+ * Target list can have Vars and expressions. For Vars, we can
7319+ * get some information, however for expressions we can't. Thus
7320+ * for expressions, just show generic context message.
7321+ */
7322+ if (IsA (tle -> expr , Var ))
7323+ {
7324+ Var * var = (Var * ) tle -> expr ;
7325+
7326+ varno = var -> varno ;
7327+ colno = var -> varattno ;
7328+ }
7329+ }
7330+
7331+ if (varno > 0 )
73027332 {
7303- Var * var = (Var * ) tle -> expr ;
7333+ EState * estate = fsstate -> ss .ps .state ;
7334+ RangeTblEntry * rte = exec_rt_fetch (varno , estate );
73047335
7305- varno = var -> varno ;
7306- colno = var -> varattno ;
7336+ relname = rte -> eref -> aliasname ;
7337+
7338+ if (colno == 0 )
7339+ is_wholerow = true;
7340+ else if (colno > 0 && colno <= list_length (rte -> eref -> colnames ))
7341+ attname = strVal (list_nth (rte -> eref -> colnames , colno - 1 ));
7342+ else if (colno == SelfItemPointerAttributeNumber )
7343+ attname = "ctid" ;
73077344 }
73087345 }
7309-
7310- if (varno > 0 )
7346+ else if (rel )
73117347 {
7312- EState * estate = fsstate -> ss . ps . state ;
7313- RangeTblEntry * rte = exec_rt_fetch ( varno , estate );
7348+ /* Non-ForeignScan case (we should always have a rel here) */
7349+ TupleDesc tupdesc = RelationGetDescr ( rel );
73147350
7315- relname = rte -> eref -> aliasname ;
7351+ relname = RelationGetRelationName (rel );
7352+ if (errpos -> cur_attno > 0 && errpos -> cur_attno <= tupdesc -> natts )
7353+ {
7354+ Form_pg_attribute attr = TupleDescAttr (tupdesc ,
7355+ errpos -> cur_attno - 1 );
73167356
7317- if (colno == 0 )
7318- is_wholerow = true;
7319- else if (colno > 0 && colno <= list_length (rte -> eref -> colnames ))
7320- attname = strVal (list_nth (rte -> eref -> colnames , colno - 1 ));
7321- else if (colno == SelfItemPointerAttributeNumber )
7357+ attname = NameStr (attr -> attname );
7358+ }
7359+ else if (errpos -> cur_attno == SelfItemPointerAttributeNumber )
73227360 attname = "ctid" ;
73237361 }
73247362
0 commit comments