Re: rule-related crash in v11 - Mailing list pgsql-hackers

From Tom Lane
Subject Re: rule-related crash in v11
Date
Msg-id 15159.1527264628@sss.pgh.pa.us
Whole thread Raw
In response to Re: rule-related crash in v11  (Robert Haas <robertmhaas@gmail.com>)
List pgsql-hackers
Robert Haas <robertmhaas@gmail.com> writes:
> On Fri, May 25, 2018 at 11:21 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Looking at what mod_stmt is used for, we've got
>> (1) the Assert that's crashing, and its siblings, which are just meant
>> to cross-check that mod_stmt is consistent with the SPI return code.
>> (2) two places that decide to enforce STRICT behavior if mod_stmt
>> is true.
>> 
>> I think we could just drop those Asserts.  As for the other things,
>> maybe we should force STRICT on the basis of examining the raw
>> parsetree (which really is immutable) rather than what came out of
>> the planner.  It doesn't seem like a great idea that INSERT ... INTO
>> should stop being considered strict if there's currently a rewrite
>> rule that changes it into something else.

> Yes, that does sound like surprising behavior.

On closer inspection, the specific Assert you're hitting is the only one
of the bunch that's really bogus.  It's actually almost backwards: if we
have a statement that got rewritten into some other kind of statement by a
rule, it almost certainly *was* an INSERT/UPDATE/DELETE to start with.
But I think there are corner cases where spi.c can return SPI_OK_REWRITTEN
where we'd not have set mod_stmt (e.g., empty statement list), so I'm not
comfortable with asserting mod_stmt==true either.  So the attached patch
just drops it.

Not sure if this is worth a regression test case.

            regards, tom lane

diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 1eb421b..ef013bc 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** exec_stmt_execsql(PLpgSQL_execstate *est
*** 4031,4049 ****
          foreach(l, SPI_plan_get_plan_sources(expr->plan))
          {
              CachedPlanSource *plansource = (CachedPlanSource *) lfirst(l);
-             ListCell   *l2;

!             foreach(l2, plansource->query_list)
              {
!                 Query       *q = lfirst_node(Query, l2);
!
!                 if (q->canSetTag)
!                 {
!                     if (q->commandType == CMD_INSERT ||
!                         q->commandType == CMD_UPDATE ||
!                         q->commandType == CMD_DELETE)
!                         stmt->mod_stmt = true;
!                 }
              }
          }
      }
--- 4031,4050 ----
          foreach(l, SPI_plan_get_plan_sources(expr->plan))
          {
              CachedPlanSource *plansource = (CachedPlanSource *) lfirst(l);

!             /*
!              * We could look at the raw_parse_tree, but it seems simpler to
!              * check the command tag.  Note we should *not* look at the Query
!              * tree(s), since those are the result of rewriting and could have
!              * been transmogrified into something else entirely.
!              */
!             if (plansource->commandTag &&
!                 (strcmp(plansource->commandTag, "INSERT") == 0 ||
!                  strcmp(plansource->commandTag, "UPDATE") == 0 ||
!                  strcmp(plansource->commandTag, "DELETE") == 0))
              {
!                 stmt->mod_stmt = true;
!                 break;
              }
          }
      }
*************** exec_stmt_execsql(PLpgSQL_execstate *est
*** 4108,4119 ****
              break;

          case SPI_OK_REWRITTEN:
-             Assert(!stmt->mod_stmt);

              /*
               * The command was rewritten into another kind of command. It's
               * not clear what FOUND would mean in that case (and SPI doesn't
!              * return the row count either), so just set it to false.
               */
              exec_set_found(estate, false);
              break;
--- 4109,4120 ----
              break;

          case SPI_OK_REWRITTEN:

              /*
               * The command was rewritten into another kind of command. It's
               * not clear what FOUND would mean in that case (and SPI doesn't
!              * return the row count either), so just set it to false.  Note
!              * that we can't assert anything about mod_stmt here.
               */
              exec_set_found(estate, false);
              break;

pgsql-hackers by date:

Previous
From: Robert Haas
Date:
Subject: Re: rule-related crash in v11
Next
From: Greg Clough
Date:
Subject: RE: Enhancement Idea - Expose the active value of a parameter inpg_settings