postgres.git / summary / log / commit / refs

commit    18f51083c990c710bf7d5292965d0b3c0ef23dfa
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Fri Sep 02 18:54:40 2022 +0000

    Fix oversight in recent MULTIEXPR_SUBLINK fix.
    
    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 | 40 +++++++++++++++++++++++++++++++--- src/test/regress/expected/inherit.out | 24 ++++++++++---------- src/test/regress/sql/inherit.sql | 10 ++++----- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 927d6a43bde..a873d72b3a2 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -914,20 +914,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 SubscriptingRefs 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, SubscriptingRef)) + { + SubscriptingRef *sbsref = (SubscriptingRef *) expr; + + if (sbsref->refassgnexpr == NULL) + break; + + expr = (Node *) sbsref->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; diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index 6e134d53f64..ed99bdde7f8 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1717,49 +1717,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 inhpar_1 -> 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)), inhpar_1.ctid, p2.ctid + Output: $6, inhpar_1.f2[1] := $7, (SubPlan 1 (returns $2,$3)), inhpar_1.ctid, p2.ctid Hash Cond: (inhpar_1.f1 = p2.unique1) -> Seq Scan on public.inhcld inhpar_1 - Output: inhpar_1.ctid, inhpar_1.f1 + Output: inhpar_1.f2, inhpar_1.ctid, inhpar_1.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 diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index fd4f252c291..7d3813704e1 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -632,7 +632,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); @@ -640,11 +640,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; [parent: d7bc6ea052ea]