Re: BUG #15577: Query returns different results when executed multiple times - Mailing list pgsql-bugs

From Tom Lane
Subject Re: BUG #15577: Query returns different results when executed multiple times
Date
Msg-id 2887.1547141893@sss.pgh.pa.us
Whole thread Raw
In response to Re: BUG #15577: Query returns different results when executed multiple times  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: BUG #15577: Query returns different results when executedmultiple times  (Thomas Munro <thomas.munro@enterprisedb.com>)
List pgsql-bugs
I wrote:
> Well, if we posit that the problems are limited to false Param-sharing,
> my inclination is to fix it by simplifying rather than adding complexity.
> To wit, let's just assign a new PARAM_EXEC slot for every NestLoopParam
> and never try to share them.  The argument that sharing them would work
> for NLPs representing the same Var hinged on the assumption that nested
> NestLoops would necessarily execute "in sync", which we now see is false
> at least when Gathers are in between.

Here's a POC patch for that.  It's seriously ugly, but it passes
check-world and I can no longer reproduce the problem using
mockup_bug15577_v2.sql.

At this point assign_nestloop_param_var and
assign_nestloop_param_placeholdervar are dead code, and there's a bunch
of incorrect comments in subselect.c, and I really need to refactor
the division of labor between createplan.c and subselect.c (for one
thing, this is an abuse of the documented purpose of
SS_make_initplan_output_param).  But functionally I think it does the
right thing.  Please test and verify that you no longer see the race
condition.

            regards, tom lane

diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 066685c..6ce5938 100644
*** a/src/backend/optimizer/plan/createplan.c
--- b/src/backend/optimizer/plan/createplan.c
*************** replace_nestloop_params_mutator(Node *no
*** 4360,4379 ****
          /* If not to be replaced, we can just return the Var unmodified */
          if (!bms_is_member(var->varno, root->curOuterRels))
              return node;
!         /* Create a Param representing the Var */
!         param = assign_nestloop_param_var(root, var);
!         /* Is this param already listed in root->curOuterParams? */
          foreach(lc, root->curOuterParams)
          {
              nlp = (NestLoopParam *) lfirst(lc);
!             if (nlp->paramno == param->paramid)
              {
!                 Assert(equal(var, nlp->paramval));
!                 /* Present, so we can just return the Param */
                  return (Node *) param;
              }
          }
!         /* No, so add it */
          nlp = makeNode(NestLoopParam);
          nlp->paramno = param->paramid;
          nlp->paramval = var;
--- 4360,4389 ----
          /* If not to be replaced, we can just return the Var unmodified */
          if (!bms_is_member(var->varno, root->curOuterRels))
              return node;
!         /* Is this Var already listed in root->curOuterParams? */
          foreach(lc, root->curOuterParams)
          {
              nlp = (NestLoopParam *) lfirst(lc);
!             if (equal(var, nlp->paramval))
              {
!                 /* Yes, so just make a Param referencing this NLP's slot */
!                 param = makeNode(Param);
!                 param->paramkind = PARAM_EXEC;
!                 param->paramid = nlp->paramno;
!                 param->paramtype = var->vartype;
!                 param->paramtypmod = var->vartypmod;
!                 param->paramcollid = var->varcollid;
!                 param->location = var->location;
                  return (Node *) param;
              }
          }
!         /* No, so assign a PARAM_EXEC slot for a new NLP */
!         param = SS_make_initplan_output_param(root,
!                                               var->vartype,
!                                               var->vartypmod,
!                                               var->varcollid);
!         param->location = var->location;
!         /* Add it to the list of NLPs */
          nlp = makeNode(NestLoopParam);
          nlp->paramno = param->paramid;
          nlp->paramval = var;
*************** replace_nestloop_params_mutator(Node *no
*** 4423,4442 ****
                                                  root);
              return (Node *) newphv;
          }
!         /* Create a Param representing the PlaceHolderVar */
!         param = assign_nestloop_param_placeholdervar(root, phv);
!         /* Is this param already listed in root->curOuterParams? */
          foreach(lc, root->curOuterParams)
          {
              nlp = (NestLoopParam *) lfirst(lc);
!             if (nlp->paramno == param->paramid)
              {
!                 Assert(equal(phv, nlp->paramval));
!                 /* Present, so we can just return the Param */
                  return (Node *) param;
              }
          }
!         /* No, so add it */
          nlp = makeNode(NestLoopParam);
          nlp->paramno = param->paramid;
          nlp->paramval = (Var *) phv;
--- 4433,4461 ----
                                                  root);
              return (Node *) newphv;
          }
!         /* Is this PHV already listed in root->curOuterParams? */
          foreach(lc, root->curOuterParams)
          {
              nlp = (NestLoopParam *) lfirst(lc);
!             if (equal(phv, nlp->paramval))
              {
!                 /* Yes, so just make a Param referencing this NLP's slot */
!                 param = makeNode(Param);
!                 param->paramkind = PARAM_EXEC;
!                 param->paramid = nlp->paramno;
!                 param->paramtype = exprType((Node *) phv->phexpr);
!                 param->paramtypmod = exprTypmod((Node *) phv->phexpr);
!                 param->paramcollid = exprCollation((Node *) phv->phexpr);
!                 param->location = -1;
                  return (Node *) param;
              }
          }
!         /* No, so assign a PARAM_EXEC slot for a new NLP */
!         param = SS_make_initplan_output_param(root,
!                                               exprType((Node *) phv->phexpr),
!                                               exprTypmod((Node *) phv->phexpr),
!                                               exprCollation((Node *) phv->phexpr));
!         /* Add it to the list of NLPs */
          nlp = makeNode(NestLoopParam);
          nlp->paramno = param->paramid;
          nlp->paramval = (Var *) phv;

pgsql-bugs by date:

Previous
From: Alvaro Herrera
Date:
Subject: Re: BUG #15587: Partitions with ALTER TABLE ADD CONSTRAINT
Next
From: Tom Lane
Date:
Subject: Re: BUG #15587: Partitions with ALTER TABLE ADD CONSTRAINT