@@ -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 */
@@ -7113,7 +7114,12 @@ complete_pending_request(AsyncRequest *areq)
7113
7114
* rel is the local representation of the foreign table, attinmeta is
7114
7115
* conversion data for the rel's tupdesc, and retrieved_attrs is an
7115
7116
* integer list of the table column numbers present in the PGresult.
7117
+ * fsstate is the ForeignScan plan node's execution state.
7116
7118
* 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.
7117
7123
*/
7118
7124
static HeapTuple
7119
7125
make_tuple_from_result_row (PGresult * res ,
@@ -7144,6 +7150,10 @@ make_tuple_from_result_row(PGresult *res,
7144
7150
*/
7145
7151
oldcontext = MemoryContextSwitchTo (temp_context );
7146
7152
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
+ */
7147
7157
if (rel )
7148
7158
tupdesc = RelationGetDescr (rel );
7149
7159
else
@@ -7161,6 +7171,7 @@ make_tuple_from_result_row(PGresult *res,
7161
7171
* Set up and install callback to report where conversion error occurs.
7162
7172
*/
7163
7173
errpos .cur_attno = 0 ;
7174
+ errpos .rel = rel ;
7164
7175
errpos .fsstate = fsstate ;
7165
7176
errcallback .callback = conversion_error_callback ;
7166
7177
errcallback .arg = (void * ) & errpos ;
@@ -7265,60 +7276,87 @@ make_tuple_from_result_row(PGresult *res,
7265
7276
*
7266
7277
* Note that this function mustn't do any catalog lookups, since we are in
7267
7278
* 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.
7269
7280
*/
7270
7281
static void
7271
7282
conversion_error_callback (void * arg )
7272
7283
{
7273
7284
ConversionLocation * errpos = (ConversionLocation * ) arg ;
7285
+ Relation rel = errpos -> rel ;
7274
7286
ForeignScanState * fsstate = errpos -> fsstate ;
7275
- ForeignScan * fsplan = castNode (ForeignScan , fsstate -> ss .ps .plan );
7276
- int varno = 0 ;
7277
- AttrNumber colno = 0 ;
7278
7287
const char * attname = NULL ;
7279
7288
const char * relname = NULL ;
7280
7289
bool is_wholerow = false;
7281
7290
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 )
7289
7297
{
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 ;
7292
7302
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 ;
7295
7313
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 )
7302
7332
{
7303
- Var * var = (Var * ) tle -> expr ;
7333
+ EState * estate = fsstate -> ss .ps .state ;
7334
+ RangeTblEntry * rte = exec_rt_fetch (varno , estate );
7304
7335
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" ;
7307
7344
}
7308
7345
}
7309
-
7310
- if (varno > 0 )
7346
+ else if (rel )
7311
7347
{
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 );
7314
7350
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 );
7316
7356
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 )
7322
7360
attname = "ctid" ;
7323
7361
}
7324
7362
0 commit comments