CREATE OR REPLACE VIEW range_type AS
  SELECT
      rngtypid::regtype AS range_type, rtn.nspname AS range_type_schema, rt.typname AS range_type_name
      , rngsubtype::regtype AS range_subtype, stn.nspname AS range_subtype_schema, st.typname AS range_subtype_name
      , rngcollation AS range_type_collation_oid, cn.nspname AS range_type_collation_schema, c.collname AS range_type_collation_name
      , rngsubopc AS range_type_operator_class_oid, oc.opcname AS range_type_operator_class_name, ocn.nspname AS range_type_operator_class_schema
      , rngcanonical AS range_type_canonical_function
      , rngsubdiff::regprocedure AS range_type_subdiff_function
    FROM pg_range r
      LEFT JOIN pg_type rt ON rt.oid = rngtypid
      LEFT JOIN pg_namespace rtn ON rtn.oid = rt.typnamespace
      LEFT JOIN pg_type st ON st.oid = rngsubtype
      LEFT JOIN pg_namespace stn ON stn.oid = st.typnamespace
      LEFT JOIN pg_collation c ON c.oid = rngcollation
      LEFT JOIN pg_namespace cn ON cn.oid = c.collnamespace
      LEFT JOIN pg_opclass oc ON oc.oid = rngsubopc
      LEFT JOIN pg_namespace ocn ON ocn.oid = oc.opcnamespace
;

CREATE OR REPLACE FUNCTION _range_from_array__create(
  range_type regtype
) RETURNS regprocedure LANGUAGE plpgsql
-- Do NOT set search_path here! Function needs to run with the calling search_path
AS $_range_from_array__create$
DECLARE
  subtype regtype;
  creation_function regproc;

  c_template CONSTANT text := $template$
-- This is a template!
CREATE OR REPLACE FUNCTION range_from_array(
    a %2$s[] -- 2:range_subtype
) RETURNS %1$s -- 1:range_type
LANGUAGE sql IMMUTABLE STRICT
SET search_path FROM CURRENT -- Make sure search path is same as when creation function was called
AS $range_from_array$
SELECT %3$s( -- 3:creation_function
      min(u)
      , max(u)
      , '[]'
    )
  FROM unnest(a) u
$range_from_array$;
$template$;
  
  sql text;
BEGIN
  SELECT INTO subtype, creation_function
      range_subtype
      , format(
        $$%1$s(%2$s, %2$s, text)$$
        , t.range_type -- Blindly assume function has same name as the range type
        , range_subtype
      )::regprocedure -- Note that this gets cast back to regproc
    FROM @extschema@.range_type t
    WHERE t.range_type = _range_from_array__create.range_type
  ;
  IF NOT FOUND THEN
    /*
     * Since range_type is of type regtype it must be a valid type, but it
     * might not be a range type. If we get here either it's not a range type
     * or our view is broken. :)
     */
    RAISE 'type "%" is not a range type', range_type
      USING ERRCODE = 'undefined_object'
    ;
  END IF;

  sql := format(
    c_template
    , range_type
    , subtype
    , creation_function
  );
  RAISE DEBUG 'executing sql: %', sql;
  EXECUTE sql;

  RETURN format( 'range_from_array(%s[])', subtype )::regprocedure;
END
$_range_from_array__create$;

SELECT _range_from_array__create(range_type)
  FROM range_type
  WHERE range_type_schema = 'pg_catalog'
;

-- vi: expandtab ts=2 sw=2
