Thread: Check constraints and function volatility categories

Check constraints and function volatility categories

From
Dane Foster
Date:
Hello,

I'm discovering that I need to write quite a few functions for use strictly w/ check constraints and I'm wondering if declaring the volatility category for said functions will affect their behavior when invoked by PostgreSQL's check constraint mechanism.

Essentially what I'm trying to figure out is if volatility categories increase or decrease the latency of executing check constraints. I've done some micro benchmarks but I have no experience benchmarking anything in PostgreSQL to trust that I'm measuring the right thing. So I'm asking the experts.

I'm running PostgreSQL 9.5 on Ubuntu Linux 15.10. I don't know if this matters but this is my workstation which is a pretty zippy AlienWare X51 w/ 16GB RAM on a Core i7-4770 processor.

Thanks,

Dane

Re: Check constraints and function volatility categories

From
Adrian Klaver
Date:
On 02/01/2016 11:17 AM, Dane Foster wrote:
> Hello,
>
> I'm discovering that I need to write quite a few functions for use
> strictly w/ check constraints and I'm wondering if declaring the
> volatility category for said functions will affect their behavior when
> invoked by PostgreSQL's check constraint mechanism.
>
> Essentially what I'm trying to figure out is if volatility categories
> increase or decrease the latency of executing check constraints. I've
> done some micro benchmarks but I have no experience benchmarking
> anything in PostgreSQL to trust that I'm measuring the right thing. So
> I'm asking the experts.

The above is sort of backwards. You need to ask what the function does
and from that determine what is the most appropriate volatitity
category. For more detailed info see:

http://www.postgresql.org/docs/9.5/interactive/xfunc-volatility.html

It would help to see some samples of the actual functions.

>
> I'm running PostgreSQL 9.5 on Ubuntu Linux 15.10. I don't know if this
> matters but this is my workstation which is a pretty zippy AlienWare X51
> w/ 16GB RAM on a Core i7-4770 processor.
>
> Thanks,
>
> Dane


--
Adrian Klaver
adrian.klaver@aklaver.com


Re: Check constraints and function volatility categories

From
"David G. Johnston"
Date:
On Mon, Feb 1, 2016 at 12:41 PM, Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 02/01/2016 11:17 AM, Dane Foster wrote:
Hello,

I'm discovering that I need to write quite a few functions for use
strictly w/ check constraints and I'm wondering if declaring the
volatility category for said functions will affect their behavior when
invoked by PostgreSQL's check constraint mechanism.

​Adrian's point is spot-on but the important thing to consider in this situation is that check constraints are assumed to be immutable and if you implement a check function that is not you don't get to complain what you see something broken.  The nature and use of an immutable check constraint only has a single dynamic - execute the function using the given values once for every record INSERT or UPDATE.  There is no reason, and I suspect there is no actual, attempt to even look at the volatility category of said function before performing those actions.  It is possible that two records inserted or updated in the same query could make use of the caching possibilities afforded by immutable functions but if so assume it is being done unconditionally.

David J.

Re: Check constraints and function volatility categories

From
Dane Foster
Date:
On Mon, Feb 1, 2016 at 2:41 PM, Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 02/01/2016 11:17 AM, Dane Foster wrote:
Hello,

I'm discovering that I need to write quite a few functions for use
strictly w/ check constraints and I'm wondering if declaring the
volatility category for said functions will affect their behavior when
invoked by PostgreSQL's check constraint mechanism.

Essentially what I'm trying to figure out is if volatility categories
increase or decrease the latency of executing check constraints. I've
done some micro benchmarks but I have no experience benchmarking
anything in PostgreSQL to trust that I'm measuring the right thing. So
I'm asking the experts.

The above is sort of backwards. You need to ask what the function does and from that determine what is the most appropriate volatitity category. For more detailed info see:

http://www.postgresql.org/docs/9.5/interactive/xfunc-volatility.html

​I did that already and all of the ones written so far would be STABLE. The gist of all of them is they check for the presence or absence of a particular type of thing to exist in some other table. Unfortunately the "type" definition can't be expressed as a primary key so I can't use foreign keys to enforce consistency.
 
It would help to see some samples of the actual functions.
​-- $1: The class event primary key
-- $2: The discount code
CREATE FUNCTION discounts_enabled_for(INT, CITXT70) RETURNS BOOLEAN AS $$
SELECT NOT
  CASE (SELECT type FROM discount_codes WHERE code = $2)
    WHEN 'giftcert'::DISC_CODE_TYPE THEN TRUE
    WHEN 'coupon'::DISC_CODE_TYPE
      THEN (SELECT no_coupons FROM class_events WHERE cid = $1)
      ELSE (SELECT no_vouchers FROM class_events WHERE cid = $1)
  END;
$$ LANGUAGE SQL STRICT LEAKPROOF;
COMMENT ON FUNCTION discounts_enabled_for(INT, CITXT70) IS
$$Determines if a class event accepts coupon or voucher discounts.$$;

CREATE TABLE group_codes (
  cid  INTEGER
       PRIMARY KEY
       REFERENCES class_events ON DELETE CASCADE ON UPDATE CASCADE,
  code CITXT70
       NOT NULL
       REFERENCES discount_codes ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT discounts_enabled CHECK (discounts_enabled_for(cid, code))
);
CREATE INDEX ON group_codes USING GIN (code);
COMMENT ON TABLE group_codes IS
$$Discount codes that are exclusive to a set of class events.$$;


I'm running PostgreSQL 9.5 on Ubuntu Linux 15.10. I don't know if this
matters but this is my workstation which is a pretty zippy AlienWare X51
w/ 16GB RAM on a Core i7-4770 processor.

Thanks,

Dane


--
Adrian Klaver
adrian.klaver@aklaver.com

Re: Check constraints and function volatility categories

From
Dane Foster
Date:

On Mon, Feb 1, 2016 at 2:56 PM, David G. Johnston <david.g.johnston@gmail.com> wrote:
On Mon, Feb 1, 2016 at 12:41 PM, Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 02/01/2016 11:17 AM, Dane Foster wrote:
Hello,

I'm discovering that I need to write quite a few functions for use
strictly w/ check constraints and I'm wondering if declaring the
volatility category for said functions will affect their behavior when
invoked by PostgreSQL's check constraint mechanism.

​Adrian's point is spot-on but the important thing to consider in this situation is that check constraints are assumed to be immutable and if you implement a check function that is not you don't get to complain what you see something broken.  The nature and use of an immutable check constraint only has a single dynamic - execute the function using the given values once for every record INSERT or UPDATE.  There is no reason, and I suspect there is no actual, attempt to even look at the volatility category of said function before performing those actions.  It is possible that two records inserted or updated in the same query could make use of the caching possibilities afforded by immutable functions but if so assume it is being done unconditionally.

David J.

​Your point about ".. check ​constraints are assumed to be immutable ..", is that in the manual? Because I don't remember reading it in the constraints section, nor in the volatility categories section, nor in the server programming sections. Granted, I haven't read the whole manual yet nor do I have what I've read so far memorized, but I think that little fact would have struck a cord in my gray matter. So if you can point me to the spot in the manual where this is covered I would appreciate it.​

Thanks,

Dane

Re: Check constraints and function volatility categories

From
"David G. Johnston"
Date:
On Mon, Feb 1, 2016 at 1:30 PM, Dane Foster <studdugie@gmail.com> wrote:

On Mon, Feb 1, 2016 at 2:56 PM, David G. Johnston <david.g.johnston@gmail.com> wrote:
On Mon, Feb 1, 2016 at 12:41 PM, Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 02/01/2016 11:17 AM, Dane Foster wrote:
Hello,

I'm discovering that I need to write quite a few functions for use
strictly w/ check constraints and I'm wondering if declaring the
volatility category for said functions will affect their behavior when
invoked by PostgreSQL's check constraint mechanism.

​Adrian's point is spot-on but the important thing to consider in this situation is that check constraints are assumed to be immutable and if you implement a check function that is not you don't get to complain what you see something broken.  The nature and use of an immutable check constraint only has a single dynamic - execute the function using the given values once for every record INSERT or UPDATE.  There is no reason, and I suspect there is no actual, attempt to even look at the volatility category of said function before performing those actions.  It is possible that two records inserted or updated in the same query could make use of the caching possibilities afforded by immutable functions but if so assume it is being done unconditionally.

David J.

​Your point about ".. check ​constraints are assumed to be immutable ..", is that in the manual? Because I don't remember reading it in the constraints section, nor in the volatility categories section, nor in the server programming sections. Granted, I haven't read the whole manual yet nor do I have what I've read so far memorized, but I think that little fact would have struck a cord in my gray matter. So if you can point me to the spot in the manual where this is covered I would appreciate it.​



​"""​
 CHECK ( expression ) [ NO INHERIT ]
The CHECK clause specifies an expression producing a Boolean result which new or updated rows must satisfy for an insert or update operation to succeed. Expressions evaluating to TRUE or UNKNOWN succeed. Should any row of an insert or update operation produce a FALSE result, an error exception is raised and the insert or update does not alter the database. A check constraint specified as a column constraint should reference that column's value only, while an expression appearing in a table constraint can reference multiple columns.

Currently, CHECK expressions cannot contain subqueries nor refer to variables other than columns of the current row. The system column tableoid may be referenced, but not any other system column.

A constraint marked with NO INHERIT will not propagate to child tables.

When a table has multiple CHECK constraints, they will be tested for each row in alphabetical order by name, after checking NOT NULL constraints. (PostgreSQL versions before 9.5 did not honor any particular firing order for CHECK constraints.)
​"""

While you've managed to fool the system by wrapping your query into a function you've violated the documented restrictions and so any breakage is on you - not the system.

Also, consider that at the time you insert a row the check constraint passes but then you alter the other table so that, if you tried to insert the row again it would fail.  Since check constraints are only evaluated upon INSERT/UPDATE of the data on the same table you would have a violation.

So, while the documentation doesn't explicitly say that functions used in CHECK must be IMMUTABLE that is what it all boils down to when you put all of these things together.

David J.


Re: Check constraints and function volatility categories

From
Dane Foster
Date:
On Mon, Feb 1, 2016 at 3:22 PM, Dane Foster <studdugie@gmail.com> wrote:

On Mon, Feb 1, 2016 at 2:41 PM, Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 02/01/2016 11:17 AM, Dane Foster wrote:
Hello,

I'm discovering that I need to write quite a few functions for use
strictly w/ check constraints and I'm wondering if declaring the
volatility category for said functions will affect their behavior when
invoked by PostgreSQL's check constraint mechanism.

Essentially what I'm trying to figure out is if volatility categories
increase or decrease the latency of executing check constraints. I've
done some micro benchmarks but I have no experience benchmarking
anything in PostgreSQL to trust that I'm measuring the right thing. So
I'm asking the experts.

The above is sort of backwards. You need to ask what the function does and from that determine what is the most appropriate volatitity category. For more detailed info see:

http://www.postgresql.org/docs/9.5/interactive/xfunc-volatility.html

​I did that already and all of the ones written so far would be STABLE. The gist of all of them is they check for the presence or absence of a particular type of thing to exist in some other table. Unfortunately the "type" definition can't be expressed as a primary key so I can't use foreign keys to enforce consistency.
 
It would help to see some samples of the actual functions.
​-- $1: The class event primary key
-- $2: The discount code
CREATE FUNCTION discounts_enabled_for(INT, CITXT70) RETURNS BOOLEAN AS $$
SELECT NOT
  CASE (SELECT type FROM discount_codes WHERE code = $2)
    WHEN 'giftcert'::DISC_CODE_TYPE THEN TRUE
    WHEN 'coupon'::DISC_CODE_TYPE
      THEN (SELECT no_coupons FROM class_events WHERE cid = $1)
      ELSE (SELECT no_vouchers FROM class_events WHERE cid = $1)
  END;
$$ LANGUAGE SQL STRICT LEAKPROOF;
COMMENT ON FUNCTION discounts_enabled_for(INT, CITXT70) IS
$$Determines if a class event accepts coupon or voucher discounts.$$;

CREATE TABLE group_codes (
  cid  INTEGER
       PRIMARY KEY
       REFERENCES class_events ON DELETE CASCADE ON UPDATE CASCADE,
  code CITXT70
       NOT NULL
       REFERENCES discount_codes ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT discounts_enabled CHECK (discounts_enabled_for(cid, code))
);
CREATE INDEX ON group_codes USING GIN (code);
COMMENT ON TABLE group_codes IS
$$Discount codes that are exclusive to a set of class events.$$;

​I just realized there is little bug in the function body. So before anyone gets distracted by it I wanted to let you know that I know it exists and has been fixed internally.​

Re: Check constraints and function volatility categories

From
Adrian Klaver
Date:
On 02/01/2016 12:36 PM, David G. Johnston wrote:
> On Mon, Feb 1, 2016 at 1:30 PM, Dane Foster <studdugie@gmail.com
> <mailto:studdugie@gmail.com>>wrote:
>
>
>     On Mon, Feb 1, 2016 at 2:56 PM, David G. Johnston
>     <david.g.johnston@gmail.com <mailto:david.g.johnston@gmail.com>> wrote:
>
>         On Mon, Feb 1, 2016 at 12:41 PM, Adrian Klaver
>         <adrian.klaver@aklaver.com <mailto:adrian.klaver@aklaver.com>>wrote:
>
>             On 02/01/2016 11:17 AM, Dane Foster wrote:
>
>                 Hello,
>
>                 I'm discovering that I need to write quite a few
>                 functions for use
>                 strictly w/ check constraints and I'm wondering if
>                 declaring the
>                 volatility category for said functions will affect their
>                 behavior when
>                 invoked by PostgreSQL's check constraint mechanism.
>
>
>         ​Adrian's point is spot-on but the important thing to consider
>         in this situation is that check constraints are assumed to be
>         immutable and if you implement a check function that is not you
>         don't get to complain what you see something broken.  The nature
>         and use of an immutable check constraint only has a single
>         dynamic - execute the function using the given values once for
>         every record INSERT or UPDATE.  There is no reason, and I
>         suspect there is no actual, attempt to even look at the
>         volatility category of said function before performing those
>         actions.  It is possible that two records inserted or updated in
>         the same query could make use of the caching possibilities
>         afforded by immutable functions but if so assume it is being
>         done unconditionally.
>
>         David J.
>
>     ​Your point about ".. check ​constraints are assumed to be immutable
>     ..", is that in the manual? Because I don't remember reading it in
>     the constraints section, nor in the volatility categories section,
>     nor in the server programming sections. Granted, I haven't read the
>     whole manual yet nor do I have what I've read so far memorized, but
>     I think that little fact would have struck a cord in my gray matter.
>     So if you can point me to the spot in the manual where this is
>     covered I would appreciate it.​
>
>
>
> ​http://www.postgresql.org/docs/9.5/interactive/sql-createtable.html​
> ​Second Paragraph​
>
> ​"""​
>   CHECK ( expression ) [ NO INHERIT ]
> The CHECK clause specifies an expression producing a Boolean result
> which new or updated rows must satisfy for an insert or update operation
> to succeed. Expressions evaluating to TRUE or UNKNOWN succeed. Should
> any row of an insert or update operation produce a FALSE result, an
> error exception is raised and the insert or update does not alter the
> database. A check constraint specified as a column constraint should
> reference that column's value only, while an expression appearing in a
> table constraint can reference multiple columns.
>
> Currently, CHECK expressions cannot contain subqueries nor refer to
> variables other than columns of the current row. The system column
> tableoid may be referenced, but not any other system column.
>
> A constraint marked with NO INHERIT will not propagate to child tables.
>
> When a table has multiple CHECK constraints, they will be tested for
> each row in alphabetical order by name, after checking NOT NULL
> constraints. (PostgreSQL versions before 9.5 did not honor any
> particular firing order for CHECK constraints.)
> ​"""
>
> While you've managed to fool the system by wrapping your query into a
> function you've violated the documented restrictions and so any breakage
> is on you - not the system.

As an example of where this leads see:

http://www.postgresql.org/message-id/7224.1452275604@sss.pgh.pa.us

>
> Also, consider that at the time you insert a row the check constraint
> passes but then you alter the other table so that, if you tried to
> insert the row again it would fail.  Since check constraints are only
> evaluated upon INSERT/UPDATE of the data on the same table you would
> have a violation.
>
> So, while the documentation doesn't explicitly say that functions used
> in CHECK must be IMMUTABLE that is what it all boils down to when you
> put all of these things together.
>
> David J.
>
>


--
Adrian Klaver
adrian.klaver@aklaver.com


Re: Check constraints and function volatility categories

From
Dane Foster
Date:
On Mon, Feb 1, 2016 at 3:36 PM, David G. Johnston <david.g.johnston@gmail.com> wrote:
On Mon, Feb 1, 2016 at 1:30 PM, Dane Foster <studdugie@gmail.com> wrote:

On Mon, Feb 1, 2016 at 2:56 PM, David G. Johnston <david.g.johnston@gmail.com> wrote:
On Mon, Feb 1, 2016 at 12:41 PM, Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 02/01/2016 11:17 AM, Dane Foster wrote:
Hello,

I'm discovering that I need to write quite a few functions for use
strictly w/ check constraints and I'm wondering if declaring the
volatility category for said functions will affect their behavior when
invoked by PostgreSQL's check constraint mechanism.

​Adrian's point is spot-on but the important thing to consider in this situation is that check constraints are assumed to be immutable and if you implement a check function that is not you don't get to complain what you see something broken.  The nature and use of an immutable check constraint only has a single dynamic - execute the function using the given values once for every record INSERT or UPDATE.  There is no reason, and I suspect there is no actual, attempt to even look at the volatility category of said function before performing those actions.  It is possible that two records inserted or updated in the same query could make use of the caching possibilities afforded by immutable functions but if so assume it is being done unconditionally.

David J.

​Your point about ".. check ​constraints are assumed to be immutable ..", is that in the manual? Because I don't remember reading it in the constraints section, nor in the volatility categories section, nor in the server programming sections. Granted, I haven't read the whole manual yet nor do I have what I've read so far memorized, but I think that little fact would have struck a cord in my gray matter. So if you can point me to the spot in the manual where this is covered I would appreciate it.​



​"""​
 CHECK ( expression ) [ NO INHERIT ]
The CHECK clause specifies an expression producing a Boolean result which new or updated rows must satisfy for an insert or update operation to succeed. Expressions evaluating to TRUE or UNKNOWN succeed. Should any row of an insert or update operation produce a FALSE result, an error exception is raised and the insert or update does not alter the database. A check constraint specified as a column constraint should reference that column's value only, while an expression appearing in a table constraint can reference multiple columns.

Currently, CHECK expressions cannot contain subqueries nor refer to variables other than columns of the current row. The system column tableoid may be referenced, but not any other system column.

A constraint marked with NO INHERIT will not propagate to child tables.

When a table has multiple CHECK constraints, they will be tested for each row in alphabetical order by name, after checking NOT NULL constraints. (PostgreSQL versions before 9.5 did not honor any particular firing order for CHECK constraints.)
​"""

While you've managed to fool the system by wrapping your query into a function you've violated the documented restrictions and so any breakage is on you - not the system.

Also, consider that at the time you insert a row the check constraint passes but then you alter the other table so that, if you tried to insert the row again it would fail.  Since check constraints are only evaluated upon INSERT/UPDATE of the data on the same table you would have a violation.

So, while the documentation doesn't explicitly say that functions used in CHECK must be IMMUTABLE that is what it all boils down to when you put all of these things together.

David J.

​Though I understand the thinking you have applied to conclude that a CHECK constraint is supposed to be IMMUTABLE I don't necessarily agree w/ it nor has the section you quoted made that expectation clear. Because when I read it the first time and even again now it is not immediately apparent that that assumption exists. But if it is true, as in, that is the intent of the code then it should be made explicit in the documentation.

​Regards,​

​Dane​

Re: Check constraints and function volatility categories

From
Karsten Hilbert
Date:
On Mon, Feb 01, 2016 at 12:41:30PM -0800, Adrian Klaver wrote:

>> While you've managed to fool the system by wrapping your query into a
>> function you've violated the documented restrictions and so any breakage
>> is on you - not the system.
>
> As an example of where this leads see:
>
> http://www.postgresql.org/message-id/7224.1452275604@sss.pgh.pa.us

For the record, with the help of this list I have managed to
work myself out of the corner I had painted myself into.

Karsten
--
GPG key ID E4071346 @ eu.pool.sks-keyservers.net
E167 67FD A291 2BEA 73BD  4537 78B9 A9F9 E407 1346


Re: Check constraints and function volatility categories

From
Dane Foster
Date:
On Mon, Feb 1, 2016 at 3:41 PM, Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 02/01/2016 12:36 PM, David G. Johnston wrote:
On Mon, Feb 1, 2016 at 1:30 PM, Dane Foster <studdugie@gmail.com
<mailto:studdugie@gmail.com>>wrote:


    On Mon, Feb 1, 2016 at 2:56 PM, David G. Johnston
    <david.g.johnston@gmail.com <mailto:david.g.johnston@gmail.com>> wrote:

        On Mon, Feb 1, 2016 at 12:41 PM, Adrian Klaver
        <adrian.klaver@aklaver.com <mailto:adrian.klaver@aklaver.com>>wrote:


            On 02/01/2016 11:17 AM, Dane Foster wrote:

                Hello,

                I'm discovering that I need to write quite a few
                functions for use
                strictly w/ check constraints and I'm wondering if
                declaring the
                volatility category for said functions will affect their
                behavior when
                invoked by PostgreSQL's check constraint mechanism.


        ​Adrian's point is spot-on but the important thing to consider
        in this situation is that check constraints are assumed to be
        immutable and if you implement a check function that is not you
        don't get to complain what you see something broken.  The nature
        and use of an immutable check constraint only has a single
        dynamic - execute the function using the given values once for
        every record INSERT or UPDATE.  There is no reason, and I
        suspect there is no actual, attempt to even look at the
        volatility category of said function before performing those
        actions.  It is possible that two records inserted or updated in
        the same query could make use of the caching possibilities
        afforded by immutable functions but if so assume it is being
        done unconditionally.

        David J.

    ​Your point about ".. check ​constraints are assumed to be immutable
    ..", is that in the manual? Because I don't remember reading it in
    the constraints section, nor in the volatility categories section,
    nor in the server programming sections. Granted, I haven't read the
    whole manual yet nor do I have what I've read so far memorized, but
    I think that little fact would have struck a cord in my gray matter.
    So if you can point me to the spot in the manual where this is
    covered I would appreciate it.​



http://www.postgresql.org/docs/9.5/interactive/sql-createtable.html
​Second Paragraph​

​"""​
  CHECK ( expression ) [ NO INHERIT ]
The CHECK clause specifies an expression producing a Boolean result
which new or updated rows must satisfy for an insert or update operation
to succeed. Expressions evaluating to TRUE or UNKNOWN succeed. Should
any row of an insert or update operation produce a FALSE result, an
error exception is raised and the insert or update does not alter the
database. A check constraint specified as a column constraint should
reference that column's value only, while an expression appearing in a
table constraint can reference multiple columns.

Currently, CHECK expressions cannot contain subqueries nor refer to
variables other than columns of the current row. The system column
tableoid may be referenced, but not any other system column.

A constraint marked with NO INHERIT will not propagate to child tables.

When a table has multiple CHECK constraints, they will be tested for
each row in alphabetical order by name, after checking NOT NULL
constraints. (PostgreSQL versions before 9.5 did not honor any
particular firing order for CHECK constraints.)
​"""

While you've managed to fool the system by wrapping your query into a
function you've violated the documented restrictions and so any breakage
is on you - not the system.

As an example of where this leads see:

http://www.postgresql.org/message-id/7224.1452275604@sss.pgh.pa.us

​Thanks for the heads up. The good news is all machine access to the data will be via functions and views so I can inline the constraint in the right places. In other news, this sucks! I have no idea what it would take to implement a more flexible constraint mechanism where these types of dependencies can be expressed declaratively but it would be great if someone w/ the know-how did. As is evident by the fact that I wasn't the only one to not realize the rabbit hole I was heading down, it would be a useful feature.
 
​As always thanks for setting me straight,

Dane

Re: Check constraints and function volatility categories

From
Adrian Klaver
Date:
On 02/01/2016 12:52 PM, Dane Foster wrote:
> On Mon, Feb 1, 2016 at 3:41 PM, Adrian Klaver <adrian.klaver@aklaver.com
> <mailto:adrian.klaver@aklaver.com>> wrote:
>

>
>     As an example of where this leads see:
>
>     http://www.postgresql.org/message-id/7224.1452275604@sss.pgh.pa.us
>
> ​Thanks for the heads up. The good news is all machine access to the
> data will be via functions and views so I can inline the constraint in
> the right places. In other news, this sucks! I have no idea what it

I could see moving your constraint into a per row trigger.

> would take to implement a more flexible constraint mechanism where these
> types of dependencies can be expressed declaratively but it would be
> great if someone w/ the know-how did. As is evident by the fact that I
> wasn't the only one to not realize the rabbit hole I was heading down,
> it would be a useful feature.
> ​
> ​As always thanks for setting me straight,
>
> Dane
>


--
Adrian Klaver
adrian.klaver@aklaver.com


Re: Check constraints and function volatility categories

From
"David G. Johnston"
Date:
On Mon, Feb 1, 2016 at 2:11 PM, Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 02/01/2016 12:52 PM, Dane Foster wrote:
On Mon, Feb 1, 2016 at 3:41 PM, Adrian Klaver <adrian.klaver@aklaver.com
<mailto:adrian.klaver@aklaver.com>> wrote:



    As an example of where this leads see:

    http://www.postgresql.org/message-id/7224.1452275604@sss.pgh.pa.us

​Thanks for the heads up. The good news is all machine access to the
data will be via functions and views so I can inline the constraint in
the right places. In other news, this sucks! I have no idea what it

I could see moving your constraint into a per row trigger.

You'd need to basically replicate the current FK constraint setup but with custom queries...you need the insert/update trigger on the main table and then a insert/update/delete trigger on the referenced table to ensure that actions just rejected if the relevant detail on the main table isn't changed.  Then decide whether you need something like "ON UPDATE/DELETE CASCADE" instead of the default 'reject' behavior.

I take it you would need to ensure that these triggers are disabled during dump/restore but am not certain on that point.

David J.

Re: Check constraints and function volatility categories

From
Adrian Klaver
Date:
On 02/01/2016 01:23 PM, David G. Johnston wrote:
> On Mon, Feb 1, 2016 at 2:11 PM, Adrian Klaver <adrian.klaver@aklaver.com
> <mailto:adrian.klaver@aklaver.com>>wrote:
>
>     On 02/01/2016 12:52 PM, Dane Foster wrote:
>
>         On Mon, Feb 1, 2016 at 3:41 PM, Adrian Klaver
>         <adrian.klaver@aklaver.com <mailto:adrian.klaver@aklaver.com>
>         <mailto:adrian.klaver@aklaver.com
>         <mailto:adrian.klaver@aklaver.com>>> wrote:
>
>
>
>              As an example of where this leads see:
>
>         http://www.postgresql.org/message-id/7224.1452275604@sss.pgh.pa.us
>
>         ​Thanks for the heads up. The good news is all machine access to the
>         data will be via functions and views so I can inline the
>         constraint in
>         the right places. In other news, this sucks! I have no idea what it
>
>
>     I could see moving your constraint into a per row trigger.
>
>
> You'd need to basically replicate the current FK constraint setup but
> with custom queries...you need the insert/update trigger on the main
> table and then a insert/update/delete trigger on the referenced table to
> ensure that actions just rejected if the relevant detail on the main
> table isn't changed.  Then decide whether you need something like "ON
> UPDATE/DELETE CASCADE" instead of the default 'reject' behavior.
>
> I take it you would need to ensure that these triggers are disabled
> during dump/restore but am not certain on that point.

Well this brings up another part to Danes post(that contained the
function definition):

"Unfortunately the "type" definition can't be expressed as a primary key
so I can't use foreign keys to enforce consistency."

Not sure what exactly is meant by "type", though I suspect it is this:
"SELECT type FROM discount_codes WHERE code ..."

FYI, I know type is non-reserved word, but I would avoid using it as a
column name. I went down that path and got myself confused in a hurry:)

In any case it should be pointed out that FKs do not necessarily have to
point to PKs:

http://www.postgresql.org/docs/9.5/interactive/sql-createtable.html

"The referenced columns must be the columns of a non-deferrable unique
or primary key constraint in the referenced table"

>
> David J.
>


--
Adrian Klaver
adrian.klaver@aklaver.com


Re: Check constraints and function volatility categories

From
Dane Foster
Date:
On Mon, Feb 1, 2016 at 4:48 PM, Adrian Klaver <adrian.klaver@aklaver.com> wrote:


             As an example of where this leads see:

        http://www.postgresql.org/message-id/7224.1452275604@sss.pgh.pa.us

        ​Thanks for the heads up. The good news is all machine access to the
        data will be via functions and views so I can inline the
        constraint in
        the right places. In other news, this sucks! I have no idea what it


    I could see moving your constraint into a per row trigger.


You'd need to basically replicate the current FK constraint setup but
with custom queries...you need the insert/update trigger on the main
table and then a insert/update/delete trigger on the referenced table to
ensure that actions just rejected if the relevant detail on the main
table isn't changed.  Then decide whether you need something like "ON
UPDATE/DELETE CASCADE" instead of the default 'reject' behavior.

I take it you would need to ensure that these triggers are disabled
during dump/restore but am not certain on that point.

Well this brings up another part to Danes post(that contained the function definition):

"Unfortunately the "type" definition can't be expressed as a primary key so I can't use foreign keys to enforce consistency."

Not sure what exactly is meant by "type", though I suspect it is this:
"SELECT type FROM discount_codes WHERE code ..."
​Type in the context that I'm using it simply means the type of thing the function is checking to see exists​ or not. The example I gave unfortunately had a column named type that confuses the situation but in actually that example is the only one that actually has a column named type involved in evaluation.

 
FYI, I know type is non-reserved word, but I would avoid using it as a column name. I went down that path and got myself confused in a hurry:)

In any case it should be pointed out that FKs do not necessarily have to point to PKs:

http://www.postgresql.org/docs/9.5/interactive/sql-createtable.html

"The referenced columns must be the columns of a non-deferrable unique or primary key constraint in the referenced table"
​I am aware of the fact that FKs don't have to point to PKs but they do have to point to something backed by a unique indexed and that is what makes them unsuitable for my needs. Here is an example where foreign keys can't play a role,  but this time as a description.

The system can send out surveys to solicit feedback. The admin can customize the surveys and associate them w/ specific class events. The constraint is this, once a survey has a respondent then the survey can no longer be edited.

​I'm going to try out David's idea of using triggers to implement the more complex constraints and inline the simpler ones in functions where appropriate.

Regards,


Dane​