DROP PROCEDURE IF EXISTS sp_generateidforentity;
DROP FUNCTION IF EXISTS sp_generateidforentity;

CREATE PROCEDURE sp_generateidforentity
(
    "EntName" varchar(256),
    "FieldName" varchar(256) = 'PrimaryKey',
    "Count" integer = 1,
    INOUT _rc int = -1
)
AS
$BODY$
Declare
    _msg text;
    _eId integer;
Begin
    _msg := 'Ошибка генерации id для ' || "EntName";

    --LOCK TABLE T_ENTITY_IDS IN ACCESS EXCLUSIVE MODE;
    select id 
    from T_ENTITY_IDS
    into _rc 
    where EntName = "EntName" 
    and FieldName = "FieldName"
    for update;

    /*
        Исключение для генерации ключей VCLib.ENTITIES в доступных промежутках ввиду ограничения размера холдера.
        Генерируем после взятия блокировки в целях исключения пересечений и только при запросах для одной записи.
        Если выбрали все номера до текущего счётчика, резервируем номера по старому, изменение счётчика следует фиксировать.
    */
    if (_rc is not null and "EntName" = 'VCLib.ENTITIES' and "FieldName" = 'PrimaryKey' and "Count" = 1)
    then
    begin
        select COALESCE((select MIN(e.EntityID) from VCLib.T_ENTITIES e where not exists (select * from VCLib.T_ENTITIES e1 where e1.EntityID = e.EntityID + 1)), 0) + 1 into _eId;
        if (_rc > _eId)
        then
        begin
            _rc := _eId;
            return;
        end;
        end if;
    end;
    end if;

    if _rc is null  
    then  
        insert into T_ENTITY_IDS(id, EntName, FieldName) 
        values(1 + "Count", "EntName", "FieldName");
        _rc := 1;
    else   
        update T_ENTITY_IDS 
        set id = id + "Count" 
        where EntName = "EntName" 
        and FieldName = "FieldName";
    end if;
    return;
Exception
    WHEN Others 
    THEN Raise Exception Using Message = _msg;
_rc := -1;
Return;
End;
$BODY$
  LANGUAGE plpgsql;
