CREATE OR REPLACE FUNCTION _snowflake_init(
  cluster_no_str text,
  island_no_str text
) RETURNS void
LANGUAGE plpgsql
SET search_path FROM CURRENT
AS $$
DECLARE
  cluster_no integer;
  island_no integer;
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM pg_proc
    JOIN pg_namespace ON pg_namespace.oid = pronamespace
    WHERE proname = 'snowflake_cluster_no' AND nspname = current_schema()
  ) THEN
    IF cluster_no_str IS NULL OR cluster_no_str !~ '^[0-9]+$' THEN
      RAISE EXCEPTION
        'PG_SNOWFLAKE_CLUSTER_NO=% environment variable must be a number. '
        'Alternatively, define snowflake_cluster_no() function manually.',
        quote_literal(cluster_no_str);
    END IF;
    EXECUTE _snowflake_template(
      $sql$
        CREATE OR REPLACE FUNCTION snowflake_cluster_no() RETURNS integer LANGUAGE sql SET search_path FROM CURRENT
        AS 'SELECT {SQL:cluster_no_str}'
      $sql$,
      'cluster_no_str', cluster_no_str
    );
    COMMENT ON FUNCTION snowflake_cluster_no()
      IS 'Returns the current cluster number.';
  END IF;

  IF NOT EXISTS (
    SELECT 1 FROM pg_proc
    JOIN pg_namespace ON pg_namespace.oid = pronamespace
    WHERE proname = 'snowflake_island_no' AND nspname = current_schema()
  ) THEN
    IF island_no_str IS NULL OR island_no_str !~ '^[0-9]+$' THEN
      RAISE EXCEPTION
        'PG_SNOWFLAKE_ISLAND_NO=% environment variable must be a number. '
        'Alternatively, define snowflake_island_no() function manually.',
        quote_literal(island_no_str);
    END IF;
    EXECUTE _snowflake_template(
      $sql$
        CREATE OR REPLACE FUNCTION snowflake_island_no() RETURNS integer LANGUAGE sql SET search_path FROM CURRENT
        AS 'SELECT {SQL:island_no_str}'
      $sql$,
      'island_no_str', island_no_str
    );
    COMMENT ON FUNCTION snowflake_island_no()
      IS 'Returns the current island number (machine id in the Snowflake ID format).';
  END IF;

  cluster_no := snowflake_cluster_no();
  IF cluster_no IS NULL OR cluster_no < 0 THEN
    RAISE EXCEPTION
      'snowflake_cluster_no() must return a natural number, but it returned %',
      cluster_no;
  END IF;

  island_no := snowflake_island_no();
  IF island_no IS NULL OR island_no < 0 THEN
    RAISE EXCEPTION
      'snowflake_island_no() must return a natural number, but it returned %',
      island_no;
  END IF;
END
$$;
