-- add recv/send functions

CREATE FUNCTION unit_recv(internal)
	RETURNS unit
	AS '$libdir/unit'
	LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION unit_send(unit)
	RETURNS bytea
	AS '$libdir/unit'
	LANGUAGE C IMMUTABLE STRICT;

UPDATE pg_type SET typreceive = 'unit_recv', typsend = 'unit_send'
	WHERE typname = 'unit' AND typnamespace = '@extschema@'::regnamespace;

INSERT INTO pg_depend (classid, objid, objsubid, refclassid, refobjid, refobjsubid, deptype)
	VALUES
		('pg_type'::regclass, 'unit'::regtype, 0, 'pg_proc'::regclass, 'unit_recv'::regproc, 0, 'n'),
		('pg_type'::regclass, 'unit'::regtype, 0, 'pg_proc'::regclass, 'unit_send'::regproc, 0, 'n');

-- convert @ from (unit, text)->cstring to (unit, text)->text

DROP OPERATOR @ (unit, text);
DROP FUNCTION unit_at(unit, text);

CREATE FUNCTION unit_at(unit, text)
	RETURNS text
	SET search_path = @extschema@
	AS '$libdir/unit', 'unit_at_text2'
	LANGUAGE C IMMUTABLE STRICT;

CREATE OPERATOR @ (
	leftarg = unit,
	rightarg = text,
	procedure = unit_at
);

-- strict comparisons

CREATE FUNCTION unit_strict_lt(unit, unit) RETURNS bool
   AS '$libdir/unit' LANGUAGE C IMMUTABLE STRICT;
CREATE FUNCTION unit_strict_le(unit, unit) RETURNS bool
   AS '$libdir/unit' LANGUAGE C IMMUTABLE STRICT;
CREATE FUNCTION unit_strict_eq(unit, unit) RETURNS bool
   AS '$libdir/unit' LANGUAGE C IMMUTABLE STRICT;
CREATE FUNCTION unit_strict_ne(unit, unit) RETURNS bool
   AS '$libdir/unit' LANGUAGE C IMMUTABLE STRICT;
CREATE FUNCTION unit_strict_ge(unit, unit) RETURNS bool
   AS '$libdir/unit' LANGUAGE C IMMUTABLE STRICT;
CREATE FUNCTION unit_strict_gt(unit, unit) RETURNS bool
   AS '$libdir/unit' LANGUAGE C IMMUTABLE STRICT;

CREATE OPERATOR << (
	leftarg = unit, rightarg = unit, procedure = unit_strict_lt,
	commutator = >> , negator = >>= ,
	restrict = scalarltsel, join = scalarltjoinsel
);
CREATE OPERATOR <<= (
	leftarg = unit, rightarg = unit, procedure = unit_strict_le,
	commutator = >>= , negator = >> ,
	restrict = scalarltsel, join = scalarltjoinsel
);
CREATE OPERATOR == (
	leftarg = unit, rightarg = unit, procedure = unit_strict_eq,
	commutator = == , negator = <<>> ,
	restrict = eqsel, join = eqjoinsel
);
CREATE OPERATOR <<>> (
	leftarg = unit, rightarg = unit, procedure = unit_strict_ne,
	commutator = <<>> , negator = == ,
	restrict = neqsel, join = neqjoinsel
);
CREATE OPERATOR >>= (
	leftarg = unit, rightarg = unit, procedure = unit_strict_ge,
	commutator = <<= , negator = << ,
	restrict = scalargtsel, join = scalargtjoinsel
);
CREATE OPERATOR >> (
	leftarg = unit, rightarg = unit, procedure = unit_strict_gt,
	commutator = << , negator = <<= ,
	restrict = scalargtsel, join = scalargtjoinsel
);

CREATE FUNCTION unit_strict_cmp(unit, unit)
	RETURNS int4
	AS '$libdir/unit'
	LANGUAGE C IMMUTABLE STRICT;

CREATE OPERATOR CLASS unit_strict_ops
	FOR TYPE unit USING btree AS
		OPERATOR 1 << ,
		OPERATOR 2 <<= ,
		OPERATOR 3 == ,
		OPERATOR 4 >>= ,
		OPERATOR 5 >> ,
		FUNCTION 1 unit_strict_cmp(unit, unit);

-- range type

CREATE FUNCTION unit_diff(unit, unit)
	RETURNS float8
	AS '$libdir/unit'
	LANGUAGE C IMMUTABLE STRICT;

COMMENT ON FUNCTION unit_diff(unit, unit) IS 'returns difference of two units as float8 for use in the unitrange type';

CREATE TYPE unitrange AS RANGE (
	SUBTYPE = unit,
	SUBTYPE_OPCLASS = unit_strict_ops,
	SUBTYPE_DIFF = unit_diff
);

-- load prefixes and units tables
SELECT unit_load();
