Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 86d4914

Browse files
committed
Avoid doing catalog lookups in postgres_fdw's conversion_error_callback.
As in 50371df, this is a bad idea since the callback can't really know what error is being thrown and thus whether or not it is safe to attempt catalog accesses. Rather than pushing said accesses into the mainline code where they'd usually be a waste of cycles, we can look at the query's rangetable instead. This change does mean that we'll be printing query aliases (if any were used) rather than the table or column's true name. But that doesn't seem like a bad thing: it's certainly a more useful definition in self-join cases, for instance. In any case, it seems unlikely that any applications would be depending on this detail, so it seems safe to change. Patch by me. Original complaint by Andres Freund; Bharath Rupireddy noted the connection to conversion_error_callback. Discussion: https://postgr.es/m/20210106020229.ne5xnuu6wlondjpe@alap3.anarazel.de
1 parent 94911ec commit 86d4914

File tree

3 files changed

+49
-51
lines changed

3 files changed

+49
-51
lines changed

contrib/postgres_fdw/expected/postgres_fdw.out

+8-6
Original file line numberDiff line numberDiff line change
@@ -4096,15 +4096,17 @@ DROP TABLE reind_fdw_parent;
40964096
-- conversion error
40974097
-- ===================================================================
40984098
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE int;
4099-
SELECT * FROM ft1 WHERE c1 = 1; -- ERROR
4099+
SELECT * FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8) WHERE x1 = 1; -- ERROR
41004100
ERROR: invalid input syntax for type integer: "foo"
4101-
CONTEXT: column "c8" of foreign table "ft1"
4102-
SELECT ft1.c1, ft2.c2, ft1.c8 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR
4101+
CONTEXT: column "x8" of foreign table "ftx"
4102+
SELECT ftx.x1, ft2.c2, ftx.x8 FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2
4103+
WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR
41034104
ERROR: invalid input syntax for type integer: "foo"
4104-
CONTEXT: column "c8" of foreign table "ft1"
4105-
SELECT ft1.c1, ft2.c2, ft1 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR
4105+
CONTEXT: column "x8" of foreign table "ftx"
4106+
SELECT ftx.x1, ft2.c2, ftx FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2
4107+
WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR
41064108
ERROR: invalid input syntax for type integer: "foo"
4107-
CONTEXT: whole-row reference to foreign table "ft1"
4109+
CONTEXT: whole-row reference to foreign table "ftx"
41084110
SELECT sum(c2), array_agg(c8) FROM ft1 GROUP BY c8; -- ERROR
41094111
ERROR: invalid input syntax for type integer: "foo"
41104112
CONTEXT: processing expression at position 2 in select list

contrib/postgres_fdw/postgres_fdw.c

+36-42
Original file line numberDiff line numberDiff line change
@@ -302,16 +302,8 @@ typedef struct
302302
*/
303303
typedef struct ConversionLocation
304304
{
305-
Relation rel; /* foreign table's relcache entry. */
306305
AttrNumber cur_attno; /* attribute number being processed, or 0 */
307-
308-
/*
309-
* In case of foreign join push down, fdw_scan_tlist is used to identify
310-
* the Var node corresponding to the error location and
311-
* fsstate->ss.ps.state gives access to the RTEs of corresponding relation
312-
* to get the relation name and attribute name.
313-
*/
314-
ForeignScanState *fsstate;
306+
ForeignScanState *fsstate; /* plan node being processed */
315307
} ConversionLocation;
316308

317309
/* Callback argument for ec_member_matches_foreign */
@@ -7082,7 +7074,6 @@ make_tuple_from_result_row(PGresult *res,
70827074
/*
70837075
* Set up and install callback to report where conversion error occurs.
70847076
*/
7085-
errpos.rel = rel;
70867077
errpos.cur_attno = 0;
70877078
errpos.fsstate = fsstate;
70887079
errcallback.callback = conversion_error_callback;
@@ -7185,70 +7176,73 @@ make_tuple_from_result_row(PGresult *res,
71857176
/*
71867177
* Callback function which is called when error occurs during column value
71877178
* conversion. Print names of column and relation.
7179+
*
7180+
* Note that this function mustn't do any catalog lookups, since we are in
7181+
* an already-failed transaction. Fortunately, we can get the needed info
7182+
* from the query's rangetable instead.
71887183
*/
71897184
static void
71907185
conversion_error_callback(void *arg)
71917186
{
7187+
ConversionLocation *errpos = (ConversionLocation *) arg;
7188+
ForeignScanState *fsstate = errpos->fsstate;
7189+
ForeignScan *fsplan = castNode(ForeignScan, fsstate->ss.ps.plan);
7190+
int varno = 0;
7191+
AttrNumber colno = 0;
71927192
const char *attname = NULL;
71937193
const char *relname = NULL;
71947194
bool is_wholerow = false;
7195-
ConversionLocation *errpos = (ConversionLocation *) arg;
71967195

7197-
if (errpos->rel)
7196+
if (fsplan->scan.scanrelid > 0)
71987197
{
71997198
/* error occurred in a scan against a foreign table */
7200-
TupleDesc tupdesc = RelationGetDescr(errpos->rel);
7201-
Form_pg_attribute attr = TupleDescAttr(tupdesc, errpos->cur_attno - 1);
7202-
7203-
if (errpos->cur_attno > 0 && errpos->cur_attno <= tupdesc->natts)
7204-
attname = NameStr(attr->attname);
7205-
else if (errpos->cur_attno == SelfItemPointerAttributeNumber)
7206-
attname = "ctid";
7207-
7208-
relname = RelationGetRelationName(errpos->rel);
7199+
varno = fsplan->scan.scanrelid;
7200+
colno = errpos->cur_attno;
72097201
}
72107202
else
72117203
{
72127204
/* error occurred in a scan against a foreign join */
7213-
ForeignScanState *fsstate = errpos->fsstate;
7214-
ForeignScan *fsplan = castNode(ForeignScan, fsstate->ss.ps.plan);
7215-
EState *estate = fsstate->ss.ps.state;
72167205
TargetEntry *tle;
72177206

72187207
tle = list_nth_node(TargetEntry, fsplan->fdw_scan_tlist,
72197208
errpos->cur_attno - 1);
72207209

72217210
/*
72227211
* Target list can have Vars and expressions. For Vars, we can get
7223-
* its relation, however for expressions we can't. Thus for
7212+
* some information, however for expressions we can't. Thus for
72247213
* expressions, just show generic context message.
72257214
*/
72267215
if (IsA(tle->expr, Var))
72277216
{
7228-
RangeTblEntry *rte;
72297217
Var *var = (Var *) tle->expr;
72307218

7231-
rte = exec_rt_fetch(var->varno, estate);
7232-
7233-
if (var->varattno == 0)
7234-
is_wholerow = true;
7235-
else
7236-
attname = get_attname(rte->relid, var->varattno, false);
7237-
7238-
relname = get_rel_name(rte->relid);
7219+
varno = var->varno;
7220+
colno = var->varattno;
72397221
}
7240-
else
7241-
errcontext("processing expression at position %d in select list",
7242-
errpos->cur_attno);
72437222
}
72447223

7245-
if (relname)
7224+
if (varno > 0)
72467225
{
7247-
if (is_wholerow)
7248-
errcontext("whole-row reference to foreign table \"%s\"", relname);
7249-
else if (attname)
7250-
errcontext("column \"%s\" of foreign table \"%s\"", attname, relname);
7226+
EState *estate = fsstate->ss.ps.state;
7227+
RangeTblEntry *rte = exec_rt_fetch(varno, estate);
7228+
7229+
relname = rte->eref->aliasname;
7230+
7231+
if (colno == 0)
7232+
is_wholerow = true;
7233+
else if (colno > 0 && colno <= list_length(rte->eref->colnames))
7234+
attname = strVal(list_nth(rte->eref->colnames, colno - 1));
7235+
else if (colno == SelfItemPointerAttributeNumber)
7236+
attname = "ctid";
72517237
}
7238+
7239+
if (relname && is_wholerow)
7240+
errcontext("whole-row reference to foreign table \"%s\"", relname);
7241+
else if (relname && attname)
7242+
errcontext("column \"%s\" of foreign table \"%s\"", attname, relname);
7243+
else
7244+
errcontext("processing expression at position %d in select list",
7245+
errpos->cur_attno);
72527246
}
72537247

72547248
/*

contrib/postgres_fdw/sql/postgres_fdw.sql

+5-3
Original file line numberDiff line numberDiff line change
@@ -1129,9 +1129,11 @@ DROP TABLE reind_fdw_parent;
11291129
-- conversion error
11301130
-- ===================================================================
11311131
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE int;
1132-
SELECT * FROM ft1 WHERE c1 = 1; -- ERROR
1133-
SELECT ft1.c1, ft2.c2, ft1.c8 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR
1134-
SELECT ft1.c1, ft2.c2, ft1 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR
1132+
SELECT * FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8) WHERE x1 = 1; -- ERROR
1133+
SELECT ftx.x1, ft2.c2, ftx.x8 FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2
1134+
WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR
1135+
SELECT ftx.x1, ft2.c2, ftx FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2
1136+
WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR
11351137
SELECT sum(c2), array_agg(c8) FROM ft1 GROUP BY c8; -- ERROR
11361138
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum;
11371139

0 commit comments

Comments
 (0)