aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-06-02 14:38:14 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-06-02 14:38:14 -0400
commitbdd096f1aec040574ff36a16946579b23a0e4879 (patch)
treeb3d4a729443c7248f8c1e9ef0026d61146368366
parent762fe98b1ba63101bbf1fe8fcd1e23532d2c4f41 (diff)
downloadpostgresql-bdd096f1aec040574ff36a16946579b23a0e4879.tar.gz
postgresql-bdd096f1aec040574ff36a16946579b23a0e4879.zip
Fix planner's row-mark code for inheritance from a foreign table.
Commit 428b260f8 broke planning of cases where row marks are needed (SELECT FOR UPDATE, etc) and one of the query's tables is a foreign table that has regular table(s) as inheritance children. We got the reverse case right, but apparently were thinking that foreign tables couldn't be inheritance parents. Not so; so we need to be able to add a CTID junk column while adding a new child, not only a wholerow junk column. Back-patch to v12 where the faulty code came in. Amit Langote Discussion: https://postgr.es/m/CA+HiwqEmo3FV1LAQ4TVyS2h1WM=kMkZUmbNuZSCnfHvMcUcPeA@mail.gmail.com
-rw-r--r--contrib/postgres_fdw/expected/postgres_fdw.out86
-rw-r--r--contrib/postgres_fdw/sql/postgres_fdw.sql21
-rw-r--r--src/backend/optimizer/util/inherit.c21
3 files changed, 126 insertions, 2 deletions
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 252b8dab601..6397afae211 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -7190,6 +7190,92 @@ select * from bar where f1 in (select f1 from foo) for share;
4 | 44
(4 rows)
+-- Now check SELECT FOR UPDATE/SHARE with an inherited source table,
+-- where the parent is itself a foreign table
+create table loct4 (f1 int, f2 int, f3 int);
+create foreign table foo2child (f3 int) inherits (foo2)
+ server loopback options (table_name 'loct4');
+NOTICE: moving and merging column "f3" with inherited definition
+DETAIL: User-specified column moved to the position of the inherited column.
+explain (verbose, costs off)
+select * from bar where f1 in (select f1 from foo2) for share;
+ QUERY PLAN
+---------------------------------------------------------------------------------------
+ LockRows
+ Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.tableoid
+ -> Hash Join
+ Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.tableoid
+ Inner Unique: true
+ Hash Cond: (bar.f1 = foo2.f1)
+ -> Append
+ -> Seq Scan on public.bar
+ Output: bar.f1, bar.f2, bar.ctid, bar.*, bar.tableoid
+ -> Foreign Scan on public.bar2
+ Output: bar2.f1, bar2.f2, bar2.ctid, bar2.*, bar2.tableoid
+ Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE
+ -> Hash
+ Output: foo2.*, foo2.f1, foo2.tableoid
+ -> HashAggregate
+ Output: foo2.*, foo2.f1, foo2.tableoid
+ Group Key: foo2.f1
+ -> Append
+ -> Foreign Scan on public.foo2
+ Output: foo2.*, foo2.f1, foo2.tableoid
+ Remote SQL: SELECT f1, f2, f3 FROM public.loct1
+ -> Foreign Scan on public.foo2child
+ Output: foo2child.*, foo2child.f1, foo2child.tableoid
+ Remote SQL: SELECT f1, f2, f3 FROM public.loct4
+(24 rows)
+
+select * from bar where f1 in (select f1 from foo2) for share;
+ f1 | f2
+----+----
+ 2 | 22
+ 4 | 44
+(2 rows)
+
+drop foreign table foo2child;
+-- And with a local child relation of the foreign table parent
+create table foo2child (f3 int) inherits (foo2);
+NOTICE: moving and merging column "f3" with inherited definition
+DETAIL: User-specified column moved to the position of the inherited column.
+explain (verbose, costs off)
+select * from bar where f1 in (select f1 from foo2) for share;
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------
+ LockRows
+ Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.ctid, foo2.tableoid
+ -> Hash Join
+ Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.ctid, foo2.tableoid
+ Inner Unique: true
+ Hash Cond: (bar.f1 = foo2.f1)
+ -> Append
+ -> Seq Scan on public.bar
+ Output: bar.f1, bar.f2, bar.ctid, bar.*, bar.tableoid
+ -> Foreign Scan on public.bar2
+ Output: bar2.f1, bar2.f2, bar2.ctid, bar2.*, bar2.tableoid
+ Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE
+ -> Hash
+ Output: foo2.*, foo2.f1, foo2.ctid, foo2.tableoid
+ -> HashAggregate
+ Output: foo2.*, foo2.f1, foo2.ctid, foo2.tableoid
+ Group Key: foo2.f1
+ -> Append
+ -> Foreign Scan on public.foo2
+ Output: foo2.*, foo2.f1, foo2.ctid, foo2.tableoid
+ Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
+ -> Seq Scan on public.foo2child
+ Output: foo2child.*, foo2child.f1, foo2child.ctid, foo2child.tableoid
+(23 rows)
+
+select * from bar where f1 in (select f1 from foo2) for share;
+ f1 | f2
+----+----
+ 2 | 22
+ 4 | 44
+(2 rows)
+
+drop table foo2child;
-- Check UPDATE with inherited target and an inherited source table
explain (verbose, costs off)
update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index a957ef1b1df..7e0c35cc746 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -1834,6 +1834,27 @@ explain (verbose, costs off)
select * from bar where f1 in (select f1 from foo) for share;
select * from bar where f1 in (select f1 from foo) for share;
+-- Now check SELECT FOR UPDATE/SHARE with an inherited source table,
+-- where the parent is itself a foreign table
+create table loct4 (f1 int, f2 int, f3 int);
+create foreign table foo2child (f3 int) inherits (foo2)
+ server loopback options (table_name 'loct4');
+
+explain (verbose, costs off)
+select * from bar where f1 in (select f1 from foo2) for share;
+select * from bar where f1 in (select f1 from foo2) for share;
+
+drop foreign table foo2child;
+
+-- And with a local child relation of the foreign table parent
+create table foo2child (f3 int) inherits (foo2);
+
+explain (verbose, costs off)
+select * from bar where f1 in (select f1 from foo2) for share;
+select * from bar where f1 in (select f1 from foo2) for share;
+
+drop table foo2child;
+
-- Check UPDATE with inherited target and an inherited source table
explain (verbose, costs off)
update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index f0953475b1f..a48600e3d72 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -231,8 +231,25 @@ expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel,
char resname[32];
List *newvars = NIL;
- /* The old PlanRowMark should already have necessitated adding TID */
- Assert(old_allMarkTypes & ~(1 << ROW_MARK_COPY));
+ /* Add TID junk Var if needed, unless we had it already */
+ if (new_allMarkTypes & ~(1 << ROW_MARK_COPY) &&
+ !(old_allMarkTypes & ~(1 << ROW_MARK_COPY)))
+ {
+ /* Need to fetch TID */
+ var = makeVar(oldrc->rti,
+ SelfItemPointerAttributeNumber,
+ TIDOID,
+ -1,
+ InvalidOid,
+ 0);
+ snprintf(resname, sizeof(resname), "ctid%u", oldrc->rowmarkId);
+ tle = makeTargetEntry((Expr *) var,
+ list_length(root->processed_tlist) + 1,
+ pstrdup(resname),
+ true);
+ root->processed_tlist = lappend(root->processed_tlist, tle);
+ newvars = lappend(newvars, var);
+ }
/* Add whole-row junk Var if needed, unless we had it already */
if ((new_allMarkTypes & (1 << ROW_MARK_COPY)) &&