-- User type charNN: space saving replacement for char(NN)

CREATE FUNCTION charNN_in(opaque)
    RETURNS charNN
    AS '$libdir/fixchar'
    LANGUAGE 'c';

CREATE FUNCTION charNN_out(opaque)
    RETURNS opaque
    AS '$libdir/fixchar'
    LANGUAGE 'c';

CREATE TYPE charNN (
    INPUT = charNN_in,
    OUTPUT = charNN_out,
    INTERNALLENGTH = NN,
    ALIGNMENT = char
);

-- Operators
CREATE FUNCTION charNN_lt(charNN, charNN)
    RETURNS boolean
    AS '$libdir/fixchar'
    LANGUAGE 'c';

CREATE FUNCTION charNN_le(charNN, charNN)
    RETURNS boolean
    AS '$libdir/fixchar'
    LANGUAGE 'c';

CREATE FUNCTION charNN_eq(charNN, charNN)
    RETURNS boolean
    AS '$libdir/fixchar'
    LANGUAGE 'c';

CREATE FUNCTION charNN_ge(charNN, charNN)
    RETURNS boolean
    AS '$libdir/fixchar'
    LANGUAGE 'c';

CREATE FUNCTION charNN_gt(charNN, charNN)
    RETURNS boolean
    AS '$libdir/fixchar'
    LANGUAGE 'c';

CREATE FUNCTION charNN_ne(charNN, charNN)
    RETURNS boolean
    AS '$libdir/fixchar'
    LANGUAGE 'c';

CREATE OPERATOR < ( LEFTARG = charNN, RIGHTARG = charNN,
    PROCEDURE = charNN_lt,
	COMMUTATOR = >,
	NEGATOR = >=,
    RESTRICT = scalarltsel, JOIN = scalarltjoinsel
);

CREATE OPERATOR <= ( LEFTARG = charNN, RIGHTARG = charNN,
    PROCEDURE = charNN_le,
	COMMUTATOR = >=,
	NEGATOR = >,
    RESTRICT = scalarltsel, JOIN = scalarltjoinsel
);

CREATE OPERATOR = ( LEFTARG = charNN, RIGHTARG = charNN,
    PROCEDURE = charNN_eq,
	COMMUTATOR = =,
	NEGATOR = !=,
    RESTRICT = eqsel, JOIN = eqjoinsel
);

CREATE OPERATOR >= ( LEFTARG = charNN, RIGHTARG = charNN,
    PROCEDURE = charNN_ge,
	COMMUTATOR = <=,
	NEGATOR = <,
    RESTRICT = scalargtsel, JOIN = scalargtjoinsel
);

CREATE OPERATOR > ( LEFTARG = charNN, RIGHTARG = charNN,
    PROCEDURE = charNN_gt,
	COMMUTATOR = <,
	NEGATOR = <=,
    RESTRICT = scalargtsel, JOIN = scalargtjoinsel
);

CREATE OPERATOR != ( LEFTARG = charNN, RIGHTARG = charNN,
    PROCEDURE = charNN_ne,
	COMMUTATOR = !=,
	NEGATOR = =,
    RESTRICT = neqsel, JOIN = neqjoinsel
);

-- btree opclass
INSERT INTO pg_opclass (opcamid, opcname, opcintype, opcdefault, opckeytype)
    SELECT a.oid, 'charNN_ops', t.oid, true, 0
      FROM pg_am a, pg_type t
     WHERE a.amname = 'btree'
       AND t.typname = 'charNN';

--btree strategies
CREATE TEMP TABLE charNN_strat (
    strat smallint,
    opr name
);

INSERT INTO charNN_strat VALUES (1, '<');
INSERT INTO charNN_strat VALUES (2, '<=');
INSERT INTO charNN_strat VALUES (3, '=');
INSERT INTO charNN_strat VALUES (4, '>=');
INSERT INTO charNN_strat VALUES (5, '>');

SELECT o.oid AS opoid, s.strat
  INTO TEMP TABLE charNN_ops_tmp
  FROM pg_operator o, pg_type t, charNN_strat s
 WHERE t.typname = 'charNN'
   AND o.oprleft = t.oid
   AND o.oprright = t.oid
   AND o.oprname = s.opr;

INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
    SELECT oc.oid, c.strat, false, c.opoid
      FROM pg_opclass oc, charNN_ops_tmp c, pg_am a
     WHERE opcamid = a.oid
       AND opcname = 'charNN_ops' 
       AND a.amname = 'btree';


-- support routine
CREATE FUNCTION charNN_cmp(charNN, charNN)
    RETURNS integer
    AS '$libdir/fixchar'
    LANGUAGE 'c';

INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
    SELECT oc.oid, 1, p.oid
      FROM pg_opclass oc, pg_proc p, pg_am a
     WHERE a.amname = 'btree'
       AND oc.opcamid = a.oid
       AND oc.opcname = 'charNN_ops'
       AND p.proname = 'charNN_cmp';

