Robert Haas <robertmh...@gmail.com> writes:
> On Fri, May 25, 2018 at 11:21 AM, Tom Lane <t...@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;

Reply via email to