@@ -285,7 +285,8 @@ typedef struct
285
285
typedef struct ConversionLocation
286
286
{
287
287
AttrNumber cur_attno ;/* attribute number being processed, or 0 */
288
- ForeignScanState * fsstate ;/* plan node being processed */
288
+ Relation rel ;/* foreign table being processed, or NULL */
289
+ ForeignScanState * fsstate ;/* plan node being processed, or NULL */
289
290
}ConversionLocation ;
290
291
291
292
/* Callback argument for ec_member_matches_foreign */
@@ -6293,7 +6294,12 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
6293
6294
* rel is the local representation of the foreign table, attinmeta is
6294
6295
* conversion data for the rel's tupdesc, and retrieved_attrs is an
6295
6296
* integer list of the table column numbers present in the PGresult.
6297
+ * fsstate is the ForeignScan plan node's execution state.
6296
6298
* temp_context is a working context that can be reset after each tuple.
6299
+ *
6300
+ * Note: either rel or fsstate, but not both, can be NULL. rel is NULL
6301
+ * if we're processing a remote join, while fsstate is NULL in a non-query
6302
+ * context such as ANALYZE, or if we're processing a non-scan query node.
6297
6303
*/
6298
6304
static HeapTuple
6299
6305
make_tuple_from_result_row (PGresult * res ,
@@ -6324,6 +6330,10 @@ make_tuple_from_result_row(PGresult *res,
6324
6330
*/
6325
6331
oldcontext = MemoryContextSwitchTo (temp_context );
6326
6332
6333
+ /*
6334
+ * Get the tuple descriptor for the row. Use the rel's tupdesc if rel is
6335
+ * provided, otherwise look to the scan node's ScanTupleSlot.
6336
+ */
6327
6337
if (rel )
6328
6338
tupdesc = RelationGetDescr (rel );
6329
6339
else
@@ -6341,6 +6351,7 @@ make_tuple_from_result_row(PGresult *res,
6341
6351
* Set up and install callback to report where conversion error occurs.
6342
6352
*/
6343
6353
errpos .cur_attno = 0 ;
6354
+ errpos .rel = rel ;
6344
6355
errpos .fsstate = fsstate ;
6345
6356
errcallback .callback = conversion_error_callback ;
6346
6357
errcallback .arg = (void * )& errpos ;
@@ -6445,60 +6456,87 @@ make_tuple_from_result_row(PGresult *res,
6445
6456
*
6446
6457
* Note that this function mustn't do any catalog lookups, since we are in
6447
6458
* an already-failed transaction. Fortunately, we can get the needed info
6448
- * from the query's rangetable instead.
6459
+ * from therelation or the query's rangetable instead.
6449
6460
*/
6450
6461
static void
6451
6462
conversion_error_callback (void * arg )
6452
6463
{
6453
6464
ConversionLocation * errpos = (ConversionLocation * )arg ;
6465
+ Relation rel = errpos -> rel ;
6454
6466
ForeignScanState * fsstate = errpos -> fsstate ;
6455
- ForeignScan * fsplan = castNode (ForeignScan ,fsstate -> ss .ps .plan );
6456
- int varno = 0 ;
6457
- AttrNumber colno = 0 ;
6458
6467
const char * attname = NULL ;
6459
6468
const char * relname = NULL ;
6460
6469
bool is_wholerow = false;
6461
6470
6462
- if (fsplan -> scan .scanrelid > 0 )
6463
- {
6464
- /* error occurred in a scan against a foreign table */
6465
- varno = fsplan -> scan .scanrelid ;
6466
- colno = errpos -> cur_attno ;
6467
- }
6468
- else
6471
+ /*
6472
+ * If we're in a scan node, always use aliases from the rangetable, for
6473
+ * consistency between the simple-relation and remote-join cases. Look at
6474
+ * the relation's tupdesc only if we're not in a scan node.
6475
+ */
6476
+ if (fsstate )
6469
6477
{
6470
- /* error occurred in a scan against a foreign join */
6471
- TargetEntry * tle ;
6478
+ /* ForeignScan case */
6479
+ ForeignScan * fsplan = castNode (ForeignScan ,fsstate -> ss .ps .plan );
6480
+ int varno = 0 ;
6481
+ AttrNumber colno = 0 ;
6472
6482
6473
- tle = list_nth_node (TargetEntry ,fsplan -> fdw_scan_tlist ,
6474
- errpos -> cur_attno - 1 );
6483
+ if (fsplan -> scan .scanrelid > 0 )
6484
+ {
6485
+ /* error occurred in a scan against a foreign table */
6486
+ varno = fsplan -> scan .scanrelid ;
6487
+ colno = errpos -> cur_attno ;
6488
+ }
6489
+ else
6490
+ {
6491
+ /* error occurred in a scan against a foreign join */
6492
+ TargetEntry * tle ;
6475
6493
6476
- /*
6477
- * Target list can have Vars and expressions. For Vars, we can get
6478
- * some information, however for expressions we can't. Thus for
6479
- * expressions, just show generic context message.
6480
- */
6481
- if (IsA (tle -> expr ,Var ))
6494
+ tle = list_nth_node (TargetEntry ,fsplan -> fdw_scan_tlist ,
6495
+ errpos -> cur_attno - 1 );
6496
+
6497
+ /*
6498
+ * Target list can have Vars and expressions. For Vars, we can
6499
+ * get some information, however for expressions we can't. Thus
6500
+ * for expressions, just show generic context message.
6501
+ */
6502
+ if (IsA (tle -> expr ,Var ))
6503
+ {
6504
+ Var * var = (Var * )tle -> expr ;
6505
+
6506
+ varno = var -> varno ;
6507
+ colno = var -> varattno ;
6508
+ }
6509
+ }
6510
+
6511
+ if (varno > 0 )
6482
6512
{
6483
- Var * var = (Var * )tle -> expr ;
6513
+ EState * estate = fsstate -> ss .ps .state ;
6514
+ RangeTblEntry * rte = exec_rt_fetch (varno ,estate );
6484
6515
6485
- varno = var -> varno ;
6486
- colno = var -> varattno ;
6516
+ relname = rte -> eref -> aliasname ;
6517
+
6518
+ if (colno == 0 )
6519
+ is_wholerow = true;
6520
+ else if (colno > 0 && colno <=list_length (rte -> eref -> colnames ))
6521
+ attname = strVal (list_nth (rte -> eref -> colnames ,colno - 1 ));
6522
+ else if (colno == SelfItemPointerAttributeNumber )
6523
+ attname = "ctid" ;
6487
6524
}
6488
6525
}
6489
-
6490
- if (varno > 0 )
6526
+ else if (rel )
6491
6527
{
6492
- EState * estate = fsstate -> ss . ps . state ;
6493
- RangeTblEntry * rte = exec_rt_fetch ( varno , estate );
6528
+ /* Non-ForeignScan case (we should always have a rel here) */
6529
+ TupleDesc tupdesc = RelationGetDescr ( rel );
6494
6530
6495
- relname = rte -> eref -> aliasname ;
6531
+ relname = RelationGetRelationName (rel );
6532
+ if (errpos -> cur_attno > 0 && errpos -> cur_attno <=tupdesc -> natts )
6533
+ {
6534
+ Form_pg_attribute attr = TupleDescAttr (tupdesc ,
6535
+ errpos -> cur_attno - 1 );
6496
6536
6497
- if (colno == 0 )
6498
- is_wholerow = true;
6499
- else if (colno > 0 && colno <=list_length (rte -> eref -> colnames ))
6500
- attname = strVal (list_nth (rte -> eref -> colnames ,colno - 1 ));
6501
- else if (colno == SelfItemPointerAttributeNumber )
6537
+ attname = NameStr (attr -> attname );
6538
+ }
6539
+ else if (errpos -> cur_attno == SelfItemPointerAttributeNumber )
6502
6540
attname = "ctid" ;
6503
6541
}
6504
6542