Assertion failure in plpgsql with INSTEAD OF rule - Mailing list pgsql-hackers

From Heikki Linnakangas
Subject Assertion failure in plpgsql with INSTEAD OF rule
Date
Msg-id 496AFE12.3090903@enterprisedb.com
Whole thread Raw
Responses Re: Assertion failure in plpgsql with INSTEAD OF rule  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
This test case:

CREATE TABLE atable(n int);
CREATE TABLE btable(n int);

CREATE RULE insteadrule AS ON INSERT TO atable DO INSTEAD delete from 
btable;

CREATE FUNCTION rulecrash() RETURNS void AS $$
begin  insert into atable values(1);
end;
$$ LANGUAGE plpgsql;

SELECT rulecrash();

Fails an assertion on versions 8.2, 8.3 and CVS HEAD:

TRAP: FailedAssertion("!(stmt->mod_stmt)", File: "pl_exec.c", Line: 2800)

The assertion is in exec_stmt_execsql():

>     rc = SPI_execute_plan(expr->plan, values, nulls,
>                           estate->readonly_func, tcount);
> 
>     /*
>      * Check for error, and set FOUND if appropriate (for historical reasons
>      * we set FOUND only for certain query types).    Also Assert that we
>      * identified the statement type the same as SPI did.
>      */
>     switch (rc)
>     {
>         case SPI_OK_SELECT:
>             Assert(!stmt->mod_stmt);
>             exec_set_found(estate, (SPI_processed != 0));
>             break;
> 
>         case SPI_OK_INSERT:
>         case SPI_OK_UPDATE:
>         case SPI_OK_DELETE:
>         case SPI_OK_INSERT_RETURNING:
>         case SPI_OK_UPDATE_RETURNING:
>         case SPI_OK_DELETE_RETURNING:
>>>             Assert(stmt->mod_stmt);
>             exec_set_found(estate, (SPI_processed != 0));
>             break;
> 
>         case SPI_OK_SELINTO:
>         case SPI_OK_UTILITY:
>             Assert(!stmt->mod_stmt);
>             break;
> 
>         default:
>             elog(ERROR, "SPI_execute_plan failed executing query \"%s\": %s",
>                  expr->query, SPI_result_code_string(rc));
>     }

The problem is that mod_stmt is determined for the query that has 
canSetTag set, but in case of an INSTEAD OF rule that rewrites the 
statement into a different command, an INSERT into a DELETE in this 
case, canSetTag is not set. The return code of SPI_execute_plan still 
indicates SPI_OK_DELETE, so we have a mismatch in what that assertion is 
trying to check.

mod_stmt is used to control whether to throw an error if the query 
returns more than one row and there's an INTO, and ISTM the logic is 
correct for that use. However, the logic for when to set FOUND is 
different, so I think the correct fix is to simply remove the assertion. 
At least for back-branches; you could argue for changing the behavior of 
FOUND, but that could break existing applications.

Barring flaws in my diagnosis, I'm going to remove those Assertions.

--   Heikki Linnakangas  EnterpriseDB   http://www.enterprisedb.com


pgsql-hackers by date:

Previous
From: Charlie Savage
Date:
Subject: Re: 2 small patches that fix 8.3.5 compile issues on Vista+MingW+Msys
Next
From: Martin Pihlak
Date:
Subject: Re: reducing statistics write overhead