\set DIGITS_BIGINT 19
\set DIGITS_MAX_SAFE_INTEGER 16

SELECT _id_template(
  $sql$
    DROP FUNCTION IF EXISTS {I:func_name}();

    CREATE OR REPLACE FUNCTION {I:func_name}(seq_name regclass = NULL) RETURNS bigint
    LANGUAGE plpgsql
    SET search_path FROM CURRENT
    AS $$
    -- Generates next globally-unique monotonic id, e.g.:
    --   EssssNNNNN...
    -- where decimal positions are:
    -- a) E is environment number (e.g. 1..8)
    -- b) s is microshard number (e.g. 0..9999)
    -- c) N is monotonic sequence (e.g. up to 10^14)
    DECLARE
      seq regclass;
      plain_id bigint;
      id bigint;
    BEGIN
      seq := COALESCE(seq_name, (quote_ident({current_schema}) || '.id_monotonic_seq')::regclass);
      plain_id := nextval(seq);
      IF plain_id < 0 OR plain_id >= {rnd_mul} THEN
        RAISE EXCEPTION 'Too many ids generated by %: % (max %)', seq, plain_id, {rnd_mul};
      END IF;
      id := {I:current_schema}.id_env_no();
      id := id * {CONST_SHARD_MUL} + {I:current_schema}.id_shard_no();
      id := id * {rnd_mul} + plain_id;
      RETURN id;
    END
    $$;

    COMMENT ON FUNCTION {I:func_name}(regclass) IS
      'Generates the next globally-unique monotonic id. Monotonic ids are '
      'more friendly to heavy INSERTs since they maximize the chance for '
      'btree index to reuse the newly created leaf pages.';
  $sql$,
  'CONST_SHARD_MUL', :'CONST_SHARD_MUL',
  'func_name', func_name,
  'rnd_mul', round(10::numeric ^ digits / :'CONST_ENV_MUL' / :'CONST_SHARD_MUL')::text,
  'current_schema', current_schema
)
FROM (VALUES
  (:'DIGITS_BIGINT'::integer, 'id_gen_monotonic'),
  (:'DIGITS_MAX_SAFE_INTEGER'::integer, 'id_gen_monotonic_max_safe_integer')
) AS t(digits, func_name)
\gexec

