@@ -286,7 +286,8 @@ typedef struct
286
286
typedef struct ConversionLocation
287
287
{
288
288
AttrNumber cur_attno ; /* attribute number being processed, or 0 */
289
- ForeignScanState * fsstate ; /* plan node being processed */
289
+ Relation rel ; /* foreign table being processed, or NULL */
290
+ ForeignScanState * fsstate ; /* plan node being processed, or NULL */
290
291
} ConversionLocation ;
291
292
292
293
/* Callback argument for ec_member_matches_foreign */
@@ -6345,7 +6346,12 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
6345
6346
* rel is the local representation of the foreign table, attinmeta is
6346
6347
* conversion data for the rel's tupdesc, and retrieved_attrs is an
6347
6348
* integer list of the table column numbers present in the PGresult.
6349
+ * fsstate is the ForeignScan plan node's execution state.
6348
6350
* temp_context is a working context that can be reset after each tuple.
6351
+ *
6352
+ * Note: either rel or fsstate, but not both, can be NULL. rel is NULL
6353
+ * if we're processing a remote join, while fsstate is NULL in a non-query
6354
+ * context such as ANALYZE, or if we're processing a non-scan query node.
6349
6355
*/
6350
6356
static HeapTuple
6351
6357
make_tuple_from_result_row (PGresult * res ,
@@ -6376,6 +6382,10 @@ make_tuple_from_result_row(PGresult *res,
6376
6382
*/
6377
6383
oldcontext = MemoryContextSwitchTo (temp_context );
6378
6384
6385
+ /*
6386
+ * Get the tuple descriptor for the row. Use the rel's tupdesc if rel is
6387
+ * provided, otherwise look to the scan node's ScanTupleSlot.
6388
+ */
6379
6389
if (rel )
6380
6390
tupdesc = RelationGetDescr (rel );
6381
6391
else
@@ -6393,6 +6403,7 @@ make_tuple_from_result_row(PGresult *res,
6393
6403
* Set up and install callback to report where conversion error occurs.
6394
6404
*/
6395
6405
errpos .cur_attno = 0 ;
6406
+ errpos .rel = rel ;
6396
6407
errpos .fsstate = fsstate ;
6397
6408
errcallback .callback = conversion_error_callback ;
6398
6409
errcallback .arg = (void * ) & errpos ;
@@ -6497,60 +6508,87 @@ make_tuple_from_result_row(PGresult *res,
6497
6508
*
6498
6509
* Note that this function mustn't do any catalog lookups, since we are in
6499
6510
* an already-failed transaction. Fortunately, we can get the needed info
6500
- * from the query's rangetable instead.
6511
+ * from the relation or the query's rangetable instead.
6501
6512
*/
6502
6513
static void
6503
6514
conversion_error_callback (void * arg )
6504
6515
{
6505
6516
ConversionLocation * errpos = (ConversionLocation * ) arg ;
6517
+ Relation rel = errpos -> rel ;
6506
6518
ForeignScanState * fsstate = errpos -> fsstate ;
6507
- ForeignScan * fsplan = castNode (ForeignScan , fsstate -> ss .ps .plan );
6508
- int varno = 0 ;
6509
- AttrNumber colno = 0 ;
6510
6519
const char * attname = NULL ;
6511
6520
const char * relname = NULL ;
6512
6521
bool is_wholerow = false;
6513
6522
6514
- if (fsplan -> scan .scanrelid > 0 )
6515
- {
6516
- /* error occurred in a scan against a foreign table */
6517
- varno = fsplan -> scan .scanrelid ;
6518
- colno = errpos -> cur_attno ;
6519
- }
6520
- else
6523
+ /*
6524
+ * If we're in a scan node, always use aliases from the rangetable, for
6525
+ * consistency between the simple-relation and remote-join cases. Look at
6526
+ * the relation's tupdesc only if we're not in a scan node.
6527
+ */
6528
+ if (fsstate )
6521
6529
{
6522
- /* error occurred in a scan against a foreign join */
6523
- TargetEntry * tle ;
6530
+ /* ForeignScan case */
6531
+ ForeignScan * fsplan = castNode (ForeignScan , fsstate -> ss .ps .plan );
6532
+ int varno = 0 ;
6533
+ AttrNumber colno = 0 ;
6524
6534
6525
- tle = list_nth_node (TargetEntry , fsplan -> fdw_scan_tlist ,
6526
- errpos -> cur_attno - 1 );
6535
+ if (fsplan -> scan .scanrelid > 0 )
6536
+ {
6537
+ /* error occurred in a scan against a foreign table */
6538
+ varno = fsplan -> scan .scanrelid ;
6539
+ colno = errpos -> cur_attno ;
6540
+ }
6541
+ else
6542
+ {
6543
+ /* error occurred in a scan against a foreign join */
6544
+ TargetEntry * tle ;
6527
6545
6528
- /*
6529
- * Target list can have Vars and expressions. For Vars, we can get
6530
- * some information, however for expressions we can't. Thus for
6531
- * expressions, just show generic context message.
6532
- */
6533
- if (IsA (tle -> expr , Var ))
6546
+ tle = list_nth_node (TargetEntry , fsplan -> fdw_scan_tlist ,
6547
+ errpos -> cur_attno - 1 );
6548
+
6549
+ /*
6550
+ * Target list can have Vars and expressions. For Vars, we can
6551
+ * get some information, however for expressions we can't. Thus
6552
+ * for expressions, just show generic context message.
6553
+ */
6554
+ if (IsA (tle -> expr , Var ))
6555
+ {
6556
+ Var * var = (Var * ) tle -> expr ;
6557
+
6558
+ varno = var -> varno ;
6559
+ colno = var -> varattno ;
6560
+ }
6561
+ }
6562
+
6563
+ if (varno > 0 )
6534
6564
{
6535
- Var * var = (Var * ) tle -> expr ;
6565
+ EState * estate = fsstate -> ss .ps .state ;
6566
+ RangeTblEntry * rte = exec_rt_fetch (varno , estate );
6536
6567
6537
- varno = var -> varno ;
6538
- colno = var -> varattno ;
6568
+ relname = rte -> eref -> aliasname ;
6569
+
6570
+ if (colno == 0 )
6571
+ is_wholerow = true;
6572
+ else if (colno > 0 && colno <= list_length (rte -> eref -> colnames ))
6573
+ attname = strVal (list_nth (rte -> eref -> colnames , colno - 1 ));
6574
+ else if (colno == SelfItemPointerAttributeNumber )
6575
+ attname = "ctid" ;
6539
6576
}
6540
6577
}
6541
-
6542
- if (varno > 0 )
6578
+ else if (rel )
6543
6579
{
6544
- EState * estate = fsstate -> ss . ps . state ;
6545
- RangeTblEntry * rte = exec_rt_fetch ( varno , estate );
6580
+ /* Non-ForeignScan case (we should always have a rel here) */
6581
+ TupleDesc tupdesc = RelationGetDescr ( rel );
6546
6582
6547
- relname = rte -> eref -> aliasname ;
6583
+ relname = RelationGetRelationName (rel );
6584
+ if (errpos -> cur_attno > 0 && errpos -> cur_attno <= tupdesc -> natts )
6585
+ {
6586
+ Form_pg_attribute attr = TupleDescAttr (tupdesc ,
6587
+ errpos -> cur_attno - 1 );
6548
6588
6549
- if (colno == 0 )
6550
- is_wholerow = true;
6551
- else if (colno > 0 && colno <= list_length (rte -> eref -> colnames ))
6552
- attname = strVal (list_nth (rte -> eref -> colnames , colno - 1 ));
6553
- else if (colno == SelfItemPointerAttributeNumber )
6589
+ attname = NameStr (attr -> attname );
6590
+ }
6591
+ else if (errpos -> cur_attno == SelfItemPointerAttributeNumber )
6554
6592
attname = "ctid" ;
6555
6593
}
6556
6594
0 commit comments