@@ -303,7 +303,8 @@ typedef struct
303
303
typedef struct ConversionLocation
304
304
{
305
305
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 */
307
308
}ConversionLocation ;
308
309
309
310
/* Callback argument for ec_member_matches_foreign */
@@ -7117,7 +7118,12 @@ complete_pending_request(AsyncRequest *areq)
7117
7118
* rel is the local representation of the foreign table, attinmeta is
7118
7119
* conversion data for the rel's tupdesc, and retrieved_attrs is an
7119
7120
* integer list of the table column numbers present in the PGresult.
7121
+ * fsstate is the ForeignScan plan node's execution state.
7120
7122
* temp_context is a working context that can be reset after each tuple.
7123
+ *
7124
+ * Note: either rel or fsstate, but not both, can be NULL. rel is NULL
7125
+ * if we're processing a remote join, while fsstate is NULL in a non-query
7126
+ * context such as ANALYZE, or if we're processing a non-scan query node.
7121
7127
*/
7122
7128
static HeapTuple
7123
7129
make_tuple_from_result_row (PGresult * res ,
@@ -7148,6 +7154,10 @@ make_tuple_from_result_row(PGresult *res,
7148
7154
*/
7149
7155
oldcontext = MemoryContextSwitchTo (temp_context );
7150
7156
7157
+ /*
7158
+ * Get the tuple descriptor for the row. Use the rel's tupdesc if rel is
7159
+ * provided, otherwise look to the scan node's ScanTupleSlot.
7160
+ */
7151
7161
if (rel )
7152
7162
tupdesc = RelationGetDescr (rel );
7153
7163
else
@@ -7165,6 +7175,7 @@ make_tuple_from_result_row(PGresult *res,
7165
7175
* Set up and install callback to report where conversion error occurs.
7166
7176
*/
7167
7177
errpos .cur_attno = 0 ;
7178
+ errpos .rel = rel ;
7168
7179
errpos .fsstate = fsstate ;
7169
7180
errcallback .callback = conversion_error_callback ;
7170
7181
errcallback .arg = (void * )& errpos ;
@@ -7269,60 +7280,87 @@ make_tuple_from_result_row(PGresult *res,
7269
7280
*
7270
7281
* Note that this function mustn't do any catalog lookups, since we are in
7271
7282
* an already-failed transaction. Fortunately, we can get the needed info
7272
- * from the query's rangetable instead.
7283
+ * from therelation or the query's rangetable instead.
7273
7284
*/
7274
7285
static void
7275
7286
conversion_error_callback (void * arg )
7276
7287
{
7277
7288
ConversionLocation * errpos = (ConversionLocation * )arg ;
7289
+ Relation rel = errpos -> rel ;
7278
7290
ForeignScanState * fsstate = errpos -> fsstate ;
7279
- ForeignScan * fsplan = castNode (ForeignScan ,fsstate -> ss .ps .plan );
7280
- int varno = 0 ;
7281
- AttrNumber colno = 0 ;
7282
7291
const char * attname = NULL ;
7283
7292
const char * relname = NULL ;
7284
7293
bool is_wholerow = false;
7285
7294
7286
- if (fsplan -> scan .scanrelid > 0 )
7287
- {
7288
- /* error occurred in a scan against a foreign table */
7289
- varno = fsplan -> scan .scanrelid ;
7290
- colno = errpos -> cur_attno ;
7291
- }
7292
- else
7295
+ /*
7296
+ * If we're in a scan node, always use aliases from the rangetable, for
7297
+ * consistency between the simple-relation and remote-join cases. Look at
7298
+ * the relation's tupdesc only if we're not in a scan node.
7299
+ */
7300
+ if (fsstate )
7293
7301
{
7294
- /* error occurred in a scan against a foreign join */
7295
- TargetEntry * tle ;
7302
+ /* ForeignScan case */
7303
+ ForeignScan * fsplan = castNode (ForeignScan ,fsstate -> ss .ps .plan );
7304
+ int varno = 0 ;
7305
+ AttrNumber colno = 0 ;
7296
7306
7297
- tle = list_nth_node (TargetEntry ,fsplan -> fdw_scan_tlist ,
7298
- errpos -> cur_attno - 1 );
7307
+ if (fsplan -> scan .scanrelid > 0 )
7308
+ {
7309
+ /* error occurred in a scan against a foreign table */
7310
+ varno = fsplan -> scan .scanrelid ;
7311
+ colno = errpos -> cur_attno ;
7312
+ }
7313
+ else
7314
+ {
7315
+ /* error occurred in a scan against a foreign join */
7316
+ TargetEntry * tle ;
7299
7317
7300
- /*
7301
- * Target list can have Vars and expressions. For Vars, we can get
7302
- * some information, however for expressions we can't. Thus for
7303
- * expressions, just show generic context message.
7304
- */
7305
- if (IsA (tle -> expr ,Var ))
7318
+ tle = list_nth_node (TargetEntry ,fsplan -> fdw_scan_tlist ,
7319
+ errpos -> cur_attno - 1 );
7320
+
7321
+ /*
7322
+ * Target list can have Vars and expressions. For Vars, we can
7323
+ * get some information, however for expressions we can't. Thus
7324
+ * for expressions, just show generic context message.
7325
+ */
7326
+ if (IsA (tle -> expr ,Var ))
7327
+ {
7328
+ Var * var = (Var * )tle -> expr ;
7329
+
7330
+ varno = var -> varno ;
7331
+ colno = var -> varattno ;
7332
+ }
7333
+ }
7334
+
7335
+ if (varno > 0 )
7306
7336
{
7307
- Var * var = (Var * )tle -> expr ;
7337
+ EState * estate = fsstate -> ss .ps .state ;
7338
+ RangeTblEntry * rte = exec_rt_fetch (varno ,estate );
7308
7339
7309
- varno = var -> varno ;
7310
- colno = var -> varattno ;
7340
+ relname = rte -> eref -> aliasname ;
7341
+
7342
+ if (colno == 0 )
7343
+ is_wholerow = true;
7344
+ else if (colno > 0 && colno <=list_length (rte -> eref -> colnames ))
7345
+ attname = strVal (list_nth (rte -> eref -> colnames ,colno - 1 ));
7346
+ else if (colno == SelfItemPointerAttributeNumber )
7347
+ attname = "ctid" ;
7311
7348
}
7312
7349
}
7313
-
7314
- if (varno > 0 )
7350
+ else if (rel )
7315
7351
{
7316
- EState * estate = fsstate -> ss . ps . state ;
7317
- RangeTblEntry * rte = exec_rt_fetch ( varno , estate );
7352
+ /* Non-ForeignScan case (we should always have a rel here) */
7353
+ TupleDesc tupdesc = RelationGetDescr ( rel );
7318
7354
7319
- relname = rte -> eref -> aliasname ;
7355
+ relname = RelationGetRelationName (rel );
7356
+ if (errpos -> cur_attno > 0 && errpos -> cur_attno <=tupdesc -> natts )
7357
+ {
7358
+ Form_pg_attribute attr = TupleDescAttr (tupdesc ,
7359
+ errpos -> cur_attno - 1 );
7320
7360
7321
- if (colno == 0 )
7322
- is_wholerow = true;
7323
- else if (colno > 0 && colno <=list_length (rte -> eref -> colnames ))
7324
- attname = strVal (list_nth (rte -> eref -> colnames ,colno - 1 ));
7325
- else if (colno == SelfItemPointerAttributeNumber )
7361
+ attname = NameStr (attr -> attname );
7362
+ }
7363
+ else if (errpos -> cur_attno == SelfItemPointerAttributeNumber )
7326
7364
attname = "ctid" ;
7327
7365
}
7328
7366