]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix oversight in recent MULTIEXPR_SUBLINK fix.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 2 Sep 2022 18:54:40 +0000 (14:54 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 2 Sep 2022 18:54:40 +0000 (14:54 -0400)
Commits 3f7323cbb et al missed the possibility that the Params
they are looking for could be buried under implicit coercions,
as well as other stuff that processIndirection() could add to
the original targetlist entry.  Copy the code in ruleutils.c
that deals with such cases.  (I thought about refactoring so
that there's just one copy; but seeing that we only need this
in old back branches, it seems not worth the trouble.)

Per off-list report from Andre Lin.  As before, only v10-v13
need the patch.

Discussion: https://postgr.es/m/17596-c5357f61427a81dc@postgresql.org

src/backend/optimizer/plan/subselect.c
src/test/regress/expected/inherit.out
src/test/regress/sql/inherit.sql

index e6fd8a1993751d92ce1a80d424cc7d9a7413ff1a..0d4d0d98abedba8eb94dccf569f4d2ab755e2771 100644 (file)
@@ -915,20 +915,54 @@ SS_make_multiexprs_unique(PlannerInfo *root, PlannerInfo *subroot)
        /*
         * Now we must find the Param nodes that reference the MULTIEXPR outputs
         * and update their sublink IDs so they'll reference the new outputs.
-        * Fortunately, those too must be at top level of the cloned targetlist.
+        * Fortunately, those too must be in the cloned targetlist, but they could
+        * be buried under FieldStores and ArrayRefs and CoerceToDomains
+        * (cf processIndirection()), and underneath those there could be an
+        * implicit type coercion.
         */
        offset = list_length(root->multiexpr_params);
 
        foreach(lc, subroot->parse->targetList)
        {
                TargetEntry *tent = (TargetEntry *) lfirst(lc);
+               Node       *expr;
                Param      *p;
                int                     subqueryid;
                int                     colno;
 
-               if (!IsA(tent->expr, Param))
+               expr = (Node *) tent->expr;
+               while (expr)
+               {
+                       if (IsA(expr, FieldStore))
+                       {
+                               FieldStore *fstore = (FieldStore *) expr;
+
+                               expr = (Node *) linitial(fstore->newvals);
+                       }
+                       else if (IsA(expr, ArrayRef))
+                       {
+                               ArrayRef *aref = (ArrayRef *) expr;
+
+                               if (aref->refassgnexpr == NULL)
+                                       break;
+
+                               expr = (Node *) aref->refassgnexpr;
+                       }
+                       else if (IsA(expr, CoerceToDomain))
+                       {
+                               CoerceToDomain *cdomain = (CoerceToDomain *) expr;
+
+                               if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
+                                       break;
+                               expr = (Node *) cdomain->arg;
+                       }
+                       else
+                               break;
+               }
+               expr = strip_implicit_coercions(expr);
+               if (expr == NULL || !IsA(expr, Param))
                        continue;
-               p = (Param *) tent->expr;
+               p = (Param *) expr;
                if (p->paramkind != PARAM_MULTIEXPR)
                        continue;
                subqueryid = p->paramid >> 16;
index fb651546148655bc01eb156aa98e96cabd8fc25f..3cb124dd205cbc9a03ecba15a99f08a96d5b8c46 100644 (file)
@@ -1748,49 +1748,49 @@ reset enable_bitmapscan;
 --
 -- Check handling of MULTIEXPR SubPlans in inherited updates
 --
-create table inhpar(f1 int, f2 name);
+create table inhpar(f1 int, f2 text[]);
 insert into inhpar select generate_series(1,10);
 create table inhcld() inherits(inhpar);
 insert into inhcld select generate_series(11,10000);
 vacuum analyze inhcld;
 vacuum analyze inhpar;
 explain (verbose, costs off)
-update inhpar set (f1, f2) = (select p2.unique2, p2.stringu1
-                              from int4_tbl limit 1)
+update inhpar set (f1, f2[1]) = (select p2.unique2, p2.stringu1
+                                 from int4_tbl limit 1)
 from onek p2 where inhpar.f1 = p2.unique1;
-                                QUERY PLAN                                 
----------------------------------------------------------------------------
+                                        QUERY PLAN                                         
+-------------------------------------------------------------------------------------------
  Update on public.inhpar
    Update on public.inhpar
    Update on public.inhcld
    ->  Merge Join
-         Output: $4, $5, (SubPlan 1 (returns $2,$3)), inhpar.ctid, p2.ctid
+         Output: $4, inhpar.f2[1] := $5, (SubPlan 1 (returns $2,$3)), inhpar.ctid, p2.ctid
          Merge Cond: (p2.unique1 = inhpar.f1)
          ->  Index Scan using onek_unique1 on public.onek p2
                Output: p2.unique2, p2.stringu1, p2.ctid, p2.unique1
          ->  Sort
-               Output: inhpar.ctid, inhpar.f1
+               Output: inhpar.f2, inhpar.ctid, inhpar.f1
                Sort Key: inhpar.f1
                ->  Seq Scan on public.inhpar
-                     Output: inhpar.ctid, inhpar.f1
+                     Output: inhpar.f2, inhpar.ctid, inhpar.f1
          SubPlan 1 (returns $2,$3)
            ->  Limit
                  Output: (p2.unique2), (p2.stringu1)
                  ->  Seq Scan on public.int4_tbl
                        Output: p2.unique2, p2.stringu1
    ->  Hash Join
-         Output: $6, $7, (SubPlan 1 (returns $2,$3)), inhcld.ctid, p2.ctid
+         Output: $6, inhcld.f2[1] := $7, (SubPlan 1 (returns $2,$3)), inhcld.ctid, p2.ctid
          Hash Cond: (inhcld.f1 = p2.unique1)
          ->  Seq Scan on public.inhcld
-               Output: inhcld.ctid, inhcld.f1
+               Output: inhcld.f2, inhcld.ctid, inhcld.f1
          ->  Hash
                Output: p2.unique2, p2.stringu1, p2.ctid, p2.unique1
                ->  Seq Scan on public.onek p2
                      Output: p2.unique2, p2.stringu1, p2.ctid, p2.unique1
 (27 rows)
 
-update inhpar set (f1, f2) = (select p2.unique2, p2.stringu1
-                              from int4_tbl limit 1)
+update inhpar set (f1, f2[1]) = (select p2.unique2, p2.stringu1
+                                 from int4_tbl limit 1)
 from onek p2 where inhpar.f1 = p2.unique1;
 drop table inhpar cascade;
 NOTICE:  drop cascades to table inhcld
index 88a0651804b136764b9d671186796d753b5eea95..3fbd75c7e5e74b78218b523dca076e0311100a9c 100644 (file)
@@ -653,7 +653,7 @@ reset enable_bitmapscan;
 --
 -- Check handling of MULTIEXPR SubPlans in inherited updates
 --
-create table inhpar(f1 int, f2 name);
+create table inhpar(f1 int, f2 text[]);
 insert into inhpar select generate_series(1,10);
 create table inhcld() inherits(inhpar);
 insert into inhcld select generate_series(11,10000);
@@ -661,11 +661,11 @@ vacuum analyze inhcld;
 vacuum analyze inhpar;
 
 explain (verbose, costs off)
-update inhpar set (f1, f2) = (select p2.unique2, p2.stringu1
-                              from int4_tbl limit 1)
+update inhpar set (f1, f2[1]) = (select p2.unique2, p2.stringu1
+                                 from int4_tbl limit 1)
 from onek p2 where inhpar.f1 = p2.unique1;
-update inhpar set (f1, f2) = (select p2.unique2, p2.stringu1
-                              from int4_tbl limit 1)
+update inhpar set (f1, f2[1]) = (select p2.unique2, p2.stringu1
+                                 from int4_tbl limit 1)
 from onek p2 where inhpar.f1 = p2.unique1;
 
 drop table inhpar cascade;