Assertion failure in plpgsql with INSTEAD OF rule

From: Heikki Linnakangas <heikki(dot)linnakangas(at)enterprisedb(dot)com>
To: PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>
Subject: Assertion failure in plpgsql with INSTEAD OF rule
Date: 2009-01-12 08:23:46
Message-ID: 496AFE12.3090903@enterprisedb.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Martin Pihlak 2009-01-12 09:38:51 Re: reducing statistics write overhead
Previous Message Charlie Savage 2009-01-12 07:41:57 Re: 2 small patches that fix 8.3.5 compile issues on Vista+MingW+Msys