Re: Volatile functions in WITH - Mailing list pgsql-sql

From Ben Morrow
Subject Re: Volatile functions in WITH
Date
Msg-id 20130220081905.GA95525@anubis.morrow.me.uk
Whole thread Raw
In response to Re: Volatile functions in WITH  (Sergey Konoplev <gray.ru@gmail.com>)
Responses Re: Volatile functions in WITH
List pgsql-sql
Quoth gray.ru@gmail.com (Sergey Konoplev):
> On Sat, Feb 16, 2013 at 11:58 PM, Ben Morrow <ben@morrow.me.uk> wrote:
> >     WITH "exp" AS ( -- as before
> >     ),
> >     "subst" AS (
> >         SELECT add_item(e.basket, e.nref, e.count)
> >         FROM "exp" e
> >         WHERE e.nref IS NOT NULL
> >     )
> >     SELECT DISTINCT e.msg
> >     FROM "exp" e
> 
> Alternatively I suppose you can try this one:
> 
>  WITH "exp" AS (
>         DELETE FROM "item" i
>         USING "item_expired" e
>         WHERE e.oref = i.ref
>         AND i.basket = $1
>         RETURNING i.basket, e.oref, e.nref, i.count, e.msg
>     ),
>     "upd" AS (
>         UPDATE "item" SET "count" = e.count
>         FROM "exp" e
>         WHERE e.nref IS NOT NULL
>         AND ("basket", "nref") IS NOT DISTINCT FROM (e.basket, e.nref)
>         RETURNING "basket", "nref"
>     )
>    "ins" AS (
>         INSERT INTO "item" ("basket", "ref", "count")
>         SELECT e.basket, e.nref, e.count
>         FROM "exp" e LEFT JOIN "upd" u
>         ON ("basket", "nref") IS NOT DISTINCT FROM (e.basket, e.nref)
>         WHERE e.nref IS NOT NULL AND (u.basket, u.nref) IS NULL
>     )
>     SELECT DISTINCT e.msg
>     FROM "exp" e

That's not reliable. A concurrent txn could insert a conflicting row
between the update and the insert, which would cause the insert to fail
with a unique constraint violation.

> > then the planner sees that the results of "subst" are not used, and
> > doesn't include it in the query plan at all.
> >
> > Is there any way I can tell WITH that add_item is actually a data-
> > modifying statement? Adding FOR UPDATE doesn't seem to help (I didn't
> > really expect it would.)
> 
> In this regard I would like to listen to gugrus' opinion too.
> 
> EXPLAIN ANALYZE WITH t AS (SELECT random()) SELECT 1;
>                                      QUERY PLAN
> ------------------------------------------------------------------------------------
>  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.002..0.003
> rows=1 loops=1)
>  Total runtime: 0.063 ms
> (2 rows)
> 
> EXPLAIN ANALYZE WITH t AS (SELECT random()) SELECT 1 from t;
>                                          QUERY PLAN
> --------------------------------------------------------------------------------------------
>  CTE Scan on t  (cost=0.01..0.03 rows=1 width=0) (actual
> time=0.048..0.052 rows=1 loops=1)
>    CTE t
>      ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual
> time=0.038..0.039 rows=1 loops=1)
>  Total runtime: 0.131 ms
> (4 rows)
> 
> I couldn't manage to come to any solution except faking the reference
> in the resulting query:
> 
> WITH t AS (SELECT random()) SELECT 1 UNION ALL (SELECT 1 FROM t LIMIT 0);

Yes, I can do experiments too; the alternatives I gave before both work
on my test database. What I was asking was whether they are guaranteed
to work in all situations, given that the planner can in principle see
that the extra table reference won't affect the result.

Ben




pgsql-sql by date:

Previous
From: Sergey Konoplev
Date:
Subject: Re: Volatile functions in WITH
Next
From: Sergey Konoplev
Date:
Subject: Re: Volatile functions in WITH