Disallow MERGE cleanly for foreign partitions

While directly targetting a foreign table with MERGE was already
expressly forbidden, we failed to catch the case of a partitioned table
that has a foreign table as a partition; and the result if you try is an
incomprehensible error.  Fix that by adding a specific check.

Backpatch to 15.

Reported-by: Tatsuhiro Nakamori <bt22nakamorit@oss.nttdata.com>
Discussion: https://postgr.es/m/bt22nakamorit@oss.nttdata.com
This commit is contained in:
Alvaro Herrera 2022-10-15 19:24:26 +02:00
parent 27ca0bce5f
commit 16d11d6843
No known key found for this signature in database
GPG Key ID: 1C20ACB9D5C564AE
3 changed files with 29 additions and 0 deletions

View File

@ -8251,6 +8251,11 @@ select tableoid::regclass, * FROM remp2;
(3 rows)
delete from itrtest;
-- MERGE ought to fail cleanly
merge into itrtest using (select 1, 'foo') as source on (true)
when matched then do nothing;
ERROR: cannot execute MERGE on relation "remp1"
DETAIL: This operation is not supported for foreign tables.
create unique index loct1_idx on loct1 (a);
-- DO NOTHING without an inference specification is supported
insert into itrtest values (1, 'foo') on conflict do nothing returning *;

View File

@ -2194,6 +2194,10 @@ select tableoid::regclass, * FROM remp2;
delete from itrtest;
-- MERGE ought to fail cleanly
merge into itrtest using (select 1, 'foo') as source on (true)
when matched then do nothing;
create unique index loct1_idx on loct1 (a);
-- DO NOTHING without an inference specification is supported

View File

@ -7084,12 +7084,32 @@ make_modifytable(PlannerInfo *root, Plan *subplan,
RelOptInfo *resultRel = root->simple_rel_array[rti];
fdwroutine = resultRel->fdwroutine;
/*
* MERGE is not currently supported for foreign tables and we
* already checked when the table mentioned in the query is
* foreign; but we can still get here if a partitioned table has a
* foreign table as partition. Disallow that now, to avoid an
* uglier error message later.
*/
if (operation == CMD_MERGE && fdwroutine != NULL)
{
RangeTblEntry *rte = root->simple_rte_array[rti];
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot execute MERGE on relation \"%s\"",
get_rel_name(rte->relid)),
errdetail_relkind_not_supported(rte->relkind));
}
}
else
{
RangeTblEntry *rte = planner_rt_fetch(rti, root);
Assert(rte->rtekind == RTE_RELATION);
Assert(operation != CMD_MERGE);
if (rte->relkind == RELKIND_FOREIGN_TABLE)
fdwroutine = GetFdwRoutineByRelId(rte->relid);
else