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