Re: Exclude constraint using custom operator - Mailing list pgsql-general

From Tobia Conforto
Subject Re: Exclude constraint using custom operator
Date
Msg-id B4214DCA-9E12-411A-ADD9-68A4BE55E31A@gruppo4.eu
Whole thread Raw
In response to Exclude constraint using custom operator  (Tobia Conforto <tobia.conforto@gruppo4.eu>)
Responses Re: Exclude constraint using custom operator
List pgsql-general
Stated differently, is there a simple way to extend or "subclass" the builtin range_ops operator family, adding my own
operatorto it, so that I can use it in an exclude index? 

I couldn't find a SQL definition for the range_ops family, probably because it's defined and implemented in C and
headerfiles. 

-Tobia


> On 5 Apr 2016, at 19:30, Tobia Conforto <tobia.conforto@gruppo4.eu> wrote:
>
> Hello
>
> I'd like to use the Nested Set model[1] to represent a hierarchical data structure in PostgreSQL. I'm considering
usinga single int4range column instead of the traditional two columns (lft and rgt) because the two values do in fact
representa range of integers. This should allow me to add a constraint to the range column that checks the consistency
ofthe Nested Set model. 
>
> My column is currently:
>
>     pos int4range not null check (lower(pos) between 1 and upper(pos) - 2)
>
> This is already performing the traditional check of lft >= 1 and rgt > lft, given the canonical form of an int4range.
>
> Additionally, I would like to add an exclude constraint to validate the Nested Set model: any two ranges must be
disjoint(not a.pos && b.pos) OR strictly contained one within the other, without sharing either bound. 
>
> One possible expression for the *exclusion* is that two bad ranges overlap and each is right- or left-bound by the
other.I can easily write that as a commutative operator[2]: 
>
>     create function bad_nested(int4range, int4range) returns boolean as $$
>     begin
>         return $1 && $2 and ($1 &< $2 or $1 &> $2) and ($2 &< $1 or $2 &> $1);
>     end;
>     $$ language 'plpgsql' immutable;
>
>     create operator &/ (
>         leftarg    = int4range
>     ,    rightarg   = int4range
>     ,    procedure  = bad_nested
>     ,    commutator = &/
>     );
>
> Unfortunately, trying to use this operator in an exclude constraint makes PostgreSQL complain about operator
families:
>
>     create table test (
>         pos int4range not null check (lower(pos) between 1 and upper(pos) - 2)
>     ,    exclude using gist (pos with &/)
>     );
>
>     ERROR: operator &/(int4range,int4range) is not a member of operator family "range_ops"
>     Detail: The exclusion operator must be related to the index operator class for the constraint.
>
> I don't fully understand operator classes / families and I find the manual is being somewhat cryptic about them.
>
> Can anybody suggest the right create statement(s) to enable using my operator in a GiST index?
>
> What other "strategies", functions, or operators should I write? The standard ordering of ranges with "<" should be
enough,because it maps to the traditional ordering of nested sets. 
>
> Can I do everything in sql / plpgsql or do I need to write C code?
>
>
> -Tobia
>
>
> [1] https://en.wikipedia.org/wiki/Nested_set_model
>
> [2] There may be simpler / faster expressions for the same condition. A custom plpgsql expression on the lower and
upperbounds will probably be faster, if I store the four integers as local variables. But that's just an optimization. 
>



pgsql-general by date:

Previous
From: Rakesh Kumar
Date:
Subject: Trying to understand page structures in PG
Next
From: Albe Laurenz
Date:
Subject: Re: Trying to understand page structures in PG