Search Postgresql Archives

Weird behavior with custom operators

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greetings,

I am using postgresql 8.4 (debian backport). In order to optimize some
of my code I decided to go with a custom data type to which I associated
operators and an operator class for indexation.

Here is the code I use :

-- 8<-------

CREATE TYPE tagvalue AS (storedvalue text);

CREATE OR REPLACE FUNCTION num_lt(tagvalue, double precision)
RETURNS BOOLEAN AS $$
DECLARE 
 r FLOAT;
 retval BOOLEAN;
BEGIN
 r := CAST(($1).storedvalue AS double precision);
 SELECT r < $2 INTO retval;
 RETURN retval;
EXCEPTION WHEN OTHERS THEN
 RETURN FALSE;
END;
$$
LANGUAGE plpgsql IMMUTABLE;

CREATE OR REPLACE FUNCTION num_gt(tagvalue, double precision)
RETURNS BOOLEAN AS $$
DECLARE
 r FLOAT;
 retval BOOLEAN;
BEGIN
 r := CAST(($1).storedvalue AS double precision);
 SELECT r > $2 INTO retval;
 RETURN retval;
EXCEPTION WHEN OTHERS THEN
 RETURN FALSE;
END;
$$
LANGUAGE plpgsql IMMUTABLE;

CREATE OR REPLACE FUNCTION num_lte(tagvalue, double precision)
RETURNS BOOLEAN AS $$
DECLARE
 r FLOAT;
 retval BOOLEAN;
BEGIN
 r := CAST(($1).storedvalue AS double precision);
 SELECT r <= $2 INTO retval;
 RETURN retval;
EXCEPTION WHEN OTHERS THEN
 RETURN FALSE;
END;
$$
LANGUAGE plpgsql IMMUTABLE;

CREATE OR REPLACE FUNCTION num_gte(tagvalue, double precision)
RETURNS BOOLEAN AS $$
DECLARE
 r FLOAT;
 retval BOOLEAN;
BEGIN
 r := CAST(($1).storedvalue AS double precision);
 SELECT r >= $2 INTO retval;
 RETURN retval;
EXCEPTION WHEN OTHERS THEN
 RETURN FALSE;
END;
$$
LANGUAGE plpgsql IMMUTABLE;

CREATE OR REPLACE FUNCTION num_eq(tagvalue, double precision)
RETURNS BOOLEAN AS $$
DECLARE
 r FLOAT;
 retval BOOLEAN;
BEGIN
 r := CAST(($1).storedvalue AS double precision);
 SELECT r = $2 INTO retval;
 RETURN retval;
EXCEPTION WHEN OTHERS THEN
 RETURN FALSE;
END;
$$
LANGUAGE plpgsql IMMUTABLE;

CREATE OR REPLACE FUNCTION num_neq(tagvalue, double precision)
RETURNS BOOLEAN AS $$
DECLARE
 r FLOAT;
 retval BOOLEAN;
BEGIN
 r := CAST(($1).storedvalue AS double precision);
 SELECT r != $2 INTO retval;
 RETURN retval;
EXCEPTION WHEN OTHERS THEN
 RETURN FALSE;
END;
$$
LANGUAGE plpgsql IMMUTABLE;

CREATE OR REPLACE FUNCTION txt_lt(tagvalue, text)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue < $2;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION txt_gt(tagvalue, text)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue > $2;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION txt_lte(tagvalue, text)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue <= $2;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION txt_gte(tagvalue, text)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue >= $2;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION txt_eq(tagvalue, text)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue = $2;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION txt_neq(tagvalue, text)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue != $2;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION tv_lt(tagvalue, tagvalue)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue < ($2).storedvalue;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION tv_gt(tagvalue, tagvalue)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue > ($2).storedvalue;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION tv_lte(tagvalue, tagvalue)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue <= ($2).storedvalue;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION tv_gte(tagvalue, tagvalue)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue >= ($2).storedvalue;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION tv_eq(tagvalue, tagvalue)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue = ($2).storedvalue;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION tv_eq(tagvalue, tagvalue)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue = ($2).storedvalue;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION tv_neq(tagvalue, tagvalue)
RETURNS BOOLEAN AS $$
 SELECT ($1).storedvalue != ($2).storedvalue;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE OPERATOR > (
 LEFTARG = tagvalue,
 RIGHTARG = double precision,
 PROCEDURE = num_gt,
 commutator = <,
 negator = <=,
 RESTRICT = scalargtsel,
 JOIN = scalargtjoinsel
);

CREATE OPERATOR < (
 LEFTARG = tagvalue,
 RIGHTARG = double precision,
 PROCEDURE = num_lt,
 commutator = >,
 negator = >=,
 RESTRICT = scalarltsel,
 JOIN = scalarltjoinsel
);

CREATE OPERATOR >= (
 LEFTARG = tagvalue,
 RIGHTARG = double precision,
 PROCEDURE = num_gte,
 commutator = <=,
 negator = <,
 RESTRICT = scalargtsel,
 JOIN = scalargtjoinsel
);

CREATE OPERATOR <= (
 LEFTARG = tagvalue,
 RIGHTARG = double precision,
 PROCEDURE = num_lte,
 commutator = >=,
 negator = >,
 RESTRICT = scalarltsel,
 JOIN = scalarltjoinsel
);

CREATE OPERATOR = (
 LEFTARG = tagvalue,
 RIGHTARG = double precision,
 PROCEDURE = num_eq,
 commutator = =,
 negator = !=,
 RESTRICT = eqsel,
 JOIN = eqjoinsel,
 HASHES,
 MERGES
);

CREATE OPERATOR != (
 LEFTARG = tagvalue,
 RIGHTARG = double precision,
 PROCEDURE = num_neq,
 commutator = !=,
 negator = =,
 RESTRICT = neqsel,
 JOIN = neqjoinsel
);

CREATE OPERATOR > (
 LEFTARG = tagvalue,
 RIGHTARG = text,
 PROCEDURE = txt_gt,
 commutator = <,
 negator = <=,
 RESTRICT = scalargtsel,
 JOIN = scalargtjoinsel
);

CREATE OPERATOR < (
 LEFTARG = tagvalue,
 RIGHTARG = text,
 PROCEDURE = txt_lt,
 commutator = >,
 negator = >=,
 RESTRICT = scalarltsel,
 JOIN = scalarltjoinsel
);

CREATE OPERATOR >= (
 LEFTARG = tagvalue,
 RIGHTARG = text,
 PROCEDURE = txt_gte,
 commutator = <=,
 negator = <,
 RESTRICT = scalargtsel,
 JOIN = scalargtjoinsel
);

CREATE OPERATOR <= (
 LEFTARG = tagvalue,
 RIGHTARG = text,
 PROCEDURE = txt_lte,
 commutator = >=,
 negator = >,
 RESTRICT = scalarltsel,
 JOIN = scalarltjoinsel
);

CREATE OPERATOR = (
 LEFTARG = tagvalue,
 RIGHTARG = text,
 PROCEDURE = txt_eq,
 commutator = =,
 negator = !=,
 RESTRICT = eqsel,
 JOIN = eqjoinsel,
 HASHES,
 MERGES
);

CREATE OPERATOR != (
 LEFTARG = tagvalue,
 RIGHTARG = text,
 PROCEDURE = txt_neq,
 commutator = !=,
 negator = =,
 RESTRICT = neqsel,
 JOIN = neqjoinsel
);

CREATE OPERATOR > (
 LEFTARG = tagvalue,
 RIGHTARG = tagvalue,
 PROCEDURE = tv_gt,
 commutator = <,
 negator = <=,
 RESTRICT = scalargtsel,
 JOIN = scalargtjoinsel
);

CREATE OPERATOR < (
 LEFTARG = tagvalue,
 RIGHTARG = tagvalue,
 PROCEDURE = tv_lt,
 commutator = >,
 negator = >=,
 RESTRICT = scalarltsel,
 JOIN = scalarltjoinsel
);

CREATE OPERATOR >= (
 LEFTARG = tagvalue,
 RIGHTARG = tagvalue,
 PROCEDURE = tv_gte,
 commutator = <=,
 negator = <,
 RESTRICT = scalargtsel,
 JOIN = scalargtjoinsel
);

CREATE OPERATOR <= (
 LEFTARG = tagvalue,
 RIGHTARG = tagvalue,
 PROCEDURE = tv_lte,
 commutator = >=,
 negator = >,
 RESTRICT = scalarltsel,
 JOIN = scalarltjoinsel
);

CREATE OPERATOR = (
 LEFTARG = tagvalue,
 RIGHTARG = tagvalue,
 PROCEDURE = tv_eq,
 commutator = =,
 negator = !=,
 RESTRICT = eqsel,
 JOIN = eqjoinsel,
 HASHES,
 MERGES
);

CREATE OPERATOR != (
 LEFTARG = tagvalue,
 RIGHTARG = tagvalue,
 PROCEDURE = tv_neq,
 commutator = !=,
 negator = =,
 RESTRICT = neqsel,
 JOIN = neqjoinsel
);

CREATE OR REPLACE FUNCTION tagvalue_cmp(tagvalue, tagvalue)
RETURNS integer AS $$
BEGIN
IF ($1).storedvalue < ($2).storedvalue THEN
 RETURN -1;
ELSEIF ($1).storedvalue > ($2).storedvalue THEN
 RETURN 1;
ELSE
 RETURN 0;
END IF;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION tagvalue_hash(tagvalue)
RETURNS integer AS $$
 SELECT hashtext(($1).storedvalue);
$$ LANGUAGE 'sql' STRICT IMMUTABLE;

CREATE OPERATOR CLASS tagvalue_btree_ops
    DEFAULT FOR TYPE tagvalue USING btree AS
        OPERATOR        1       < ,
        OPERATOR        2       <= ,
        OPERATOR        3       = ,
        OPERATOR        4       >= ,
        OPERATOR        5       > ,
        FUNCTION        1       tagvalue_cmp(tagvalue, tagvalue);
        
CREATE OPERATOR CLASS tagvalue_hash
    DEFAULT FOR TYPE tagvalue USING hash AS
        OPERATOR        1       =,
        FUNCTION        1       tagvalue_hash(tagvalue);

-- 8<-------

I use this on the following table:

CREATE TABLE tags (
       id       bigint       NOT NULL,
       name     text         NOT NULL,
       value    tagvalue     NOT NULL
  );

All the operators work as expected, excepted for > and >= :

xxx=> SELECT value FROM tags WHERE value < 3 LIMIT 1;
 value 
-------
 (2)
(1 row)

xxx=> SELECT value FROM tags WHERE value = 3 LIMIT 1;
 value 
-------
 (3)
(1 row)

xxx=> SELECT value FROM tags WHERE value > 3 LIMIT 1;
ERROR:  unsupported type: 17886



Obviously there's got to be something wrong with these operators, but
when I use the comparison function directly, it works fine :

xxx=> SELECT value FROM tags WHERE num_gt(value, 3) LIMIT 1;
 value 
-------
 (21)
(1 row)


I am at a loss of ideas about what causes this behavior. Any help
welcome !


Matthieu Huin


-- 
Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux