Re: [GENERAL] no primary key on self designed type - Mailing list pgsql-general

From Gene Selkov Jr.
Subject Re: [GENERAL] no primary key on self designed type
Date
Msg-id 199912072049.OAA22473@mail.xnet.com
Whole thread Raw
In response to no primary key on self designed type  (Thomas Drillich <drillich@uniserve.de>)
List pgsql-general
> Hello,
>
> create type inrecord (
>     internallength=VARIABLE,
>     input=inr_in,
>     output=inr_out
> );
>
> create table test (
>     data    inrecord not null primary key
> );
> ... result ...
> ERROR:  Can't find a default operator class for type 268128.
>
> how can I define the default operator class ??
> --

The short answer is,

INSERT INTO pg_opclass (opcname, opcdeftype)
   SELECT 'inrecord_ops', oid
   FROM pg_type
   WHERE typname = 'inrecord';

But you won't get away with just that. You probably want a non-empty
opclass. For example, if your type, inrecord, needs a btree opclass,
you'll want to do:


SELECT o.oid AS opoid, o.oprname
   INTO TABLE inrecord_ops_tmp
   FROM pg_operator o, pg_type t
   WHERE o.oprleft = t.oid and o.oprright = t.oid
      and t.typname = 'inrecord';

INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy,
                     amopselect, amopnpages)
   SELECT am.oid, opcl.oid, c.opoid, 1,
        'btreesel'::regproc, 'btreenpage'::regproc
   FROM pg_am am, pg_opclass opcl, inrecord_ops_tmp c
   WHERE amname = 'btree' and opcname = 'inrecord_ops'
      and c.oprname = '<';

INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy,
                     amopselect, amopnpages)
   SELECT am.oid, opcl.oid, c.opoid, 2,
        'btreesel'::regproc, 'btreenpage'::regproc
   FROM pg_am am, pg_opclass opcl, inrecord_ops_tmp c
   WHERE amname = 'btree' and opcname = 'inrecord_ops'
      and c.oprname = '<=';

INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy,
                     amopselect, amopnpages)
   SELECT am.oid, opcl.oid, c.opoid, 3,
        'btreesel'::regproc, 'btreenpage'::regproc
   FROM pg_am am, pg_opclass opcl, inrecord_ops_tmp c
   WHERE amname = 'btree' and opcname = 'inrecord_ops'
      and c.oprname = '=';

INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy,
                     amopselect, amopnpages)
   SELECT am.oid, opcl.oid, c.opoid, 4,
        'btreesel'::regproc, 'btreenpage'::regproc
   FROM pg_am am, pg_opclass opcl, inrecord_ops_tmp c
   WHERE amname = 'btree' and opcname = 'inrecord_ops'
      and c.oprname = '>=';

INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy,
                     amopselect, amopnpages)
   SELECT am.oid, opcl.oid, c.opoid, 5,
        'btreesel'::regproc, 'btreenpage'::regproc
   FROM pg_am am, pg_opclass opcl, inrecord_ops_tmp c
   WHERE amname = 'btree' and opcname = 'inrecord_ops'
      and c.oprname = '>';

DROP table inrecord_ops_tmp;


Which isn't all yet. The code above assumes that you have defined the
operators, '=', '>=', etc.:

CREATE OPERATOR = (
    leftarg = inrecord, rightarg = inrecord_code, procedure = inrecord_eq,
   restrict = eqsel, join = eqjoinsel
);

If that didn't make you sick already, you also need to define the
procedures, such as inrecord_eq in this example, and possibly write
some c code for them:

CREATE FUNCTION inrecord_eq(inrecord, inrecord) RETURNS bool
AS '${LIBDIR}/inrecord.so' LANGUAGE 'c';

INSERT INTO pg_description (objoid, description)
   SELECT oid, 'equals'::text
   FROM pg_proc
   WHERE proname = 'inrecord_eq'::name;

Thar's, in short, what is required to build a completely new type. One
might as well attempt to borrow some code or the whole opclass from
existing similar types, but I would hesitate to even consider doing that
without the thorough knowledge of the current postgres schema, which
is unfortunately not yet covered by the contemporary docs.


--Gene

pgsql-general by date:

Previous
From: ymartin
Date:
Subject: help
Next
From: Lamar Owen
Date:
Subject: Re: Postgresql in win9x