Thread: pgsql: Fix calculation of plan node extParams to account for the

pgsql: Fix calculation of plan node extParams to account for the

From
tgl@postgresql.org (Tom Lane)
Date:
Log Message:
-----------
Fix calculation of plan node extParams to account for the possibility that one
initPlan sets a parameter for another.  This could not (I think) happen before
8.1, but it's possible now because the initPlans generated by MIN/MAX
optimization might themselves use initPlans.  We attach those initPlans as
siblings of the MIN/MAX ones, not children, to avoid duplicate computation
when multiple MIN/MAX aggregates are present; so this leads to the case of an
initPlan needing the result of a sibling initPlan, which is not possible with
ordinary query nesting.  Hadn't been noticed because in most contexts having
too much stuff listed in extParam is fairly harmless.  Fixes "plan should not
reference subplan's variable" bug reported by Catalin Pitis.

Tags:
----
REL8_1_STABLE

Modified Files:
--------------
    pgsql/src/backend/optimizer/plan:
        subselect.c (r1.100.2.2 -> r1.100.2.3)

(http://developer.postgresql.org/cvsweb.cgi/pgsql/src/backend/optimizer/plan/subselect.c.diff?r1=1.100.2.2&r2=1.100.2.3)

Re: pgsql: Fix calculation of plan node extParams to account for the

From
"Jackie Leng"
Date:
I trid the following two queries in the version before your patch:
(1) which is reported in the bug("plan should not reference subplan's
variable") reported by Catalin Pitis:

    INSERT INTO PROJECT(PROJECT_ID,PROJECT_DESC)(SELECT
MAX(PROJECT_ID),'MYPROJECT' FROM PROJECT WHERE NOT EXISTS  (
SELECT PROJECT_DESC FROM PROJECT WHERE PROJECT_DESC = 'MYPROJECT'  ) );

    it reported an error;
(2)
    select * from project where (1,1) = (SELECT MAX(PROJECT_ID),1 FROM
PROJECT WHERE NOT EXISTS  (SELECT PROJECT_DESC FROM     PROJECT WHERE
PROJECT_DESC = 'MYPROJECT'))

    but, there was no error at all!!

Then I noticed that when add IDs of all PARAM_EXEC params appearing in the
given expression tree to the result set:
(1) for subplans corresponding to a SubLink, it was processed like this:
    /* in finalize_primnode */

     if (is_subplan(node))
     {
          SubPlan    *subplan = (SubPlan *) node;

          /* Add outer-level params needed by the subplan to paramids */
          context->paramids = bms_join(context->paramids,
                  bms_intersect(subplan->plan->extParam,
                       context->outer_params));
          /* fall through to recurse into subplan args */
     }

    Attention: there's a bms_intersect op here before bms_join.

(2) but for subplans correspoonding to a RangeTable, say SubqueryScan, it
was processed like this:

      /* in finalize_plan */
      case T_SubqueryScan:

       /*
        * In a SubqueryScan, SS_finalize_plan has already been run on the
        * subplan by the inner invocation of subquery_planner, so there's
        * no need to do it again. Instead, just pull out the subplan's
        * extParams list, which represents the params it needs from my
        * level and higher levels.
        */
       context.paramids = bms_add_members(context.paramids,
             ((SubqueryScan *) plan)->subplan->extParam);
       break;

    Attention: there's no bms_intersect .

So, my question is why not just add a bms_intersect in the second occasion
just like the first one? Do we need to change so much?


"Tom Lane" <tgl@postgresql.org> д����Ϣ����
:20060503002507.562419FB1F8@postgresql.org...
> Log Message:
> -----------
> Fix calculation of plan node extParams to account for the possibility that
one
> initPlan sets a parameter for another.  This could not (I think) happen
before
> 8.1, but it's possible now because the initPlans generated by MIN/MAX
> optimization might themselves use initPlans.  We attach those initPlans as
> siblings of the MIN/MAX ones, not children, to avoid duplicate computation
> when multiple MIN/MAX aggregates are present; so this leads to the case of
an
> initPlan needing the result of a sibling initPlan, which is not possible
with
> ordinary query nesting.  Hadn't been noticed because in most contexts
having
> too much stuff listed in extParam is fairly harmless.  Fixes "plan should
not
> reference subplan's variable" bug reported by Catalin Pitis.
>
> Tags:
> ----
> REL8_1_STABLE
>
> Modified Files:
> --------------
>     pgsql/src/backend/optimizer/plan:
>         subselect.c (r1.100.2.2 -> r1.100.2.3)
>
(http://developer.postgresql.org/cvsweb.cgi/pgsql/src/backend/optimizer/plan
/subselect.c.diff?r1=1.100.2.2&r2=1.100.2.3)
>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: don't forget to increase your free space map settings
>



Re: pgsql: Fix calculation of plan node extParams to account for the

From
Tom Lane
Date:
"Jackie Leng" <lengjianquan@163.com> writes:
> So, my question is why not just add a bms_intersect in the second occasion
> just like the first one? Do we need to change so much?

finalize_plan already has a bms_intersect, but it's further down in the
routine (to share code instead of duplicating it in each of the switch
cases) --- in CVS HEAD, line 1199.  This is not relevant to the patch
AFAICS.

            regards, tom lane

Re: pgsql: Fix calculation of plan node extParams to account for the

From
"Jackie Leng"
Date:
Yes, finalize_plan really has a bms_intersect, but it's used to compute
"plan->extParam":

 /* Now we have all the paramids */

 if (!bms_is_subset(context.paramids, valid_params))
  elog(ERROR, "plan should not reference subplan's variable");

 plan->extParam = bms_intersect(context.paramids, outer_params);
 plan->allParam = context.paramids;


But what I means is that when we compute "context.paramids", we can filter
out those params refering to a sibling initPlan through bms_intersect, just
like the process to subplan in "finalize_primnode". So, we can change the
following code in finalize_plan. I think it's equivalent to your methods:

  case T_SubqueryScan:

   /*
    * In a SubqueryScan, SS_finalize_plan has already been run on the
    * subplan by the inner invocation of subquery_planner, so there's
    * no need to do it again. Instead, just pull out the subplan's
    * extParams list, which represents the params it needs from my
    * level and higher levels.
    */
   context.paramids = bms_add_members(context.paramids,
     bms_intersect(((SubqueryScan *) plan)->subplan->extParam,
outer_params)); << this line was changed >>
   break;

Am I right?
Thank you! :)


"Tom Lane" <tgl@sss.pgh.pa.us> д����Ϣ����
:21744.1149198794@sss.pgh.pa.us...
> "Jackie Leng" <lengjianquan@163.com> writes:
> > So, my question is why not just add a bms_intersect in the second
occasion
> > just like the first one? Do we need to change so much?
>
> finalize_plan already has a bms_intersect, but it's further down in the
> routine (to share code instead of duplicating it in each of the switch
> cases) --- in CVS HEAD, line 1199.  This is not relevant to the patch
> AFAICS.
>
> regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: In versions below 8.0, the planner will ignore your desire to
>        choose an index scan if your joining column's datatypes do not
>        match
>