| From: | Carl Sverre <sverre(dot)carl(at)gmail(dot)com> | 
|---|---|
| To: | dean(dot)a(dot)rasheed(at)gmail(dot)com | 
| Cc: | "Charles Clavadetscher (SwissPUG)" <clavadetscher(at)swisspug(dot)org>, Adrian Klaver <adrian(dot)klaver(at)aklaver(dot)com>, pgsql-general(at)lists(dot)postgresql(dot)org | 
| Subject: | Re: Postgres trigger side-effect is occurring out of order with row-level security select policy | 
| Date: | 2018-10-01 20:45:22 | 
| Message-ID: | CADUo9RH9aAhO5vMMgwSnOWK-Cn9V=0sQ6_3V-wGCxuHTT08xeA@mail.gmail.com | 
| Views: | Whole Thread | Raw Message | Download mbox | Resend email | 
| Thread: | |
| Lists: | pgsql-general | 
Dean,
Thank you for the pointer towards visibility/volatility.  I think that
completely explains the effect that I am seeing in my repro.  I
experimented with using a VOLATILE function for the SELECT RLS using
statement and while it completely solves my issue, it incurs too high a
cost for query execution due to the RLS policy no longer being inlined into
the scan.
I have documented your answer and my experimentation on the stack overflow
answer:
https://stackoverflow.com/questions/52565720/postgres-trigger-side-effect-is-occurring-out-of-order-with-row-level-security-s
Feel free to make edits/suggestions if you feel I missed something in
summarizing the solution.  Also, this thread is still open to anyone who
can provide a solution which does not incur an optimization penalty -
however based on my new understanding of the underlying behavior I don't
believe this is possible.
Thank's to everyone for their contribution in figuring this out - much
appreciated.
Carl Sverre
On Mon, Oct 1, 2018 at 4:02 AM Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com>
wrote:
> The real issue here is to do with the visibility of the data inserted
> by the trigger function from within the same command. In general, data
> inserted by a command is not visible from within that same command.
>
> The easiest way to see what's going on is with a simple example.
> Consider the following (based on the original example, but without any
> RLS):
>
>
> DROP TABLE IF EXISTS a,b;
>
> CREATE TABLE a (id text);
> CREATE TABLE b (id text);
>
> CREATE OR REPLACE FUNCTION reproHandler() RETURNS TRIGGER AS $$
> BEGIN
>     RAISE NOTICE USING MESSAGE = 'inside trigger handler';
>     INSERT INTO b (id) VALUES (NEW.id);
>     RETURN NEW;
> END;
> $$ LANGUAGE plpgsql;
>
> CREATE TRIGGER reproTrigger BEFORE INSERT ON a
> FOR EACH ROW EXECUTE PROCEDURE reproHandler();
>
> CREATE OR REPLACE FUNCTION check_b1(text) RETURNS boolean AS $$
> BEGIN
>   RETURN (EXISTS (SELECT * FROM b WHERE b.id = $1));
> END
> $$ LANGUAGE plpgsql STABLE;
>
> CREATE OR REPLACE FUNCTION check_b2(text) RETURNS boolean AS $$
> BEGIN
>   RETURN (EXISTS (SELECT * FROM b WHERE b.id = $1));
> END
> $$ LANGUAGE plpgsql VOLATILE;
>
> INSERT INTO a VALUES ('xxx')
>   RETURNING id, check_b1(id), check_b2(id),
>             (EXISTS (SELECT * FROM b WHERE b.id = a.id));
>
> NOTICE:  inside trigger handler
>  id  | check_b1 | check_b2 | exists
> -----+----------+----------+--------
>  xxx | f        | t        | f
> (1 row)
>
> INSERT 0 1
>
>
> Notice that the functions check_b1() and check_b2() are identical,
> except that check_b1() is declared STABLE and check_b2() is declared
> VOLATILE, and that makes all the difference. Quoting from the
> documentation for function volatility [1]:
>
>     For functions written in SQL or in any of the standard procedural
>     languages, there is a second important property determined by the
>     volatility category, namely the visibility of any data changes that
>     have been made by the SQL command that is calling the function. A
>     VOLATILE function will see such changes, a STABLE or IMMUTABLE
>     function will not.
>
> [1] https://www.postgresql.org/docs/10/static/xfunc-volatility.html
>
> Also notice that the inline EXISTS query behaves in the same way as
> the STABLE function -- i.e., it does not see changes made in the
> current query.
>
> So returning to the RLS example, because the RLS SELECT policy is
> defined using inline SQL, it cannot see the changes made by the
> trigger. If you want to see such changes, you need to define a
> VOLATILE function to do the RLS check.
>
> Regards,
> Dean
>
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Tom Lane | 2018-10-01 21:29:19 | Re: CREATE TABLE AS SELECT hangs | 
| Previous Message | Andreas Kretschmer | 2018-10-01 19:55:57 | Re: Price Request MXO-PPQ-101164 |