Инструменти за потребители

Инструменти за сайта


kak_da:spravki_scriptove

Разлики

Тук са показани разликите между избраната и текущата версия на страницата.

Препратка към сравнението на версиите

Both sides previous revisionПредходна версия
Следваща версия
Предходна версия
kak_da:spravki_scriptove [2019/01/02 15:36] t.lalovakak_da:spravki_scriptove [2020/07/31 10:59] (текуща) – [Системна процедура SYS$SLEEP] t.lalova
Ред 1301: Ред 1301:
 </code> </code>
  
 +===== Системна процедура SYS$SLEEP =====
 +
 +Функция **SYS$SLEEP** служи за прекъсване на изпълнението на процедура, блок или тригер за определен брой милисекунди.
 +Може да се използва в случай на заключване на записи и изчакване за последващото освобождаване.
 +
 +Пример 1: Използване на процедурата в стейтмънт за извличане на номер от автоматична номерация (кочан).
 +
 +<code pascal>
 + NEW_DOC_NUMBER = null;
 +    if (DOC_NUM_GENERATOR_REF is not null) then
 +    begin
 +      STMT = 'execute block
 +      (
 +        WRH_DOC_TYPE_REF DM_REF = :WRH_DOC_TYPE_REF,
 +        DOC_NUM_GENERATOR_REF DM_REF = :DOC_NUM_GENERATOR_REF,
 +        WRH_DOC_DATE DM_DATE = :WRH_DOC_DATE
 +      )
 +      returns
 +      (
 +        NEW_DOC_NUMBER DM_REF
 +      )
 +      as
 +      declare variable MIN_RANGE DM_BIGINT;
 +      declare variable MAX_RANGE DM_BIGINT;
 +      declare variable CHECK_LAST_INVOICES_DATE DM_INT;
 +      declare variable LAST_INVOICE_DATE DM_DATE;
 +      declare variable LAST_INVOICE_YEAR DM_INT;
 +      declare variable LAST_INVOICE_MONTH DM_INT;
 +      declare variable LAST_INVOICE_DAY DM_INT;
 +      declare variable repeat_count DM_123;
 +      begin
 +         MIN_RANGE = null;
 +         MAX_RANGE = null;
 +         select
 +           DNG.RANGE_MIN, DNG.RANGE_MAX
 +         from
 +           NOM$DOC_NUM_GENERATORS DNG
 +           join NOM$DOC_NUM_GENERATOR_TYPES DNGT on DNGT.DOC_NUM_GENERATORS_REF = DNG.ID
 +           join CONFIG C on C.CURRENT_COM_ID = DNG.CURRENT_COM_REF
 +         where
 +           DNG.ID = :DOC_NUM_GENERATOR_REF and
 +           DNGT.GENERATOR_DOC_TYPE = :WRH_DOC_TYPE_REF and
 +           DNG.GENERATOR_TYPE = 1
 +         into :MIN_RANGE, :MAX_RANGE;
 +     
 +         repeat_count = 0;
 +         NEW_DOC_NUMBER = null;
 +         while ((repeat_count < 5) and (NEW_DOC_NUMBER is null)) do
 +         begin
 +            repeat_count = repeat_count + 1;
 +            NEW_DOC_NUMBER = null;
 +            update
 +              NOM$DOC_NUM_GENERATORS G
 +            set
 +              G.CURRENT_VALUE = G.CURRENT_VALUE + 1
 +            where
 +              G.ID = :DOC_NUM_GENERATOR_REF
 +            returning
 +              G.CURRENT_VALUE - 1
 +            into
 +              :NEW_DOC_NUMBER;
 +            when any do
 +            begin
 +              execute procedure SYS$SLEEP(200);
 +              NEW_DOC_NUMBER = null;
 +            end
 +          end
 +          if (NEW_DOC_NUMBER is null) then
 +              exception CLEAN_TEXT_ERROR ''There was a problem getting an invoice number for the warehouse document!'';  
 +        
 +          if (((MAX_RANGE is not null) and (NEW_DOC_NUMBER >= MAX_RANGE)) or
 +             ((MIN_RANGE is not null) and (NEW_DOC_NUMBER < MIN_RANGE))) then
 +          begin
 +            -- exausted range of the generator
 +            execute procedure SYS$EXCEPTION_CLEAN(64);
 +          end
 +
 +           CHECK_LAST_INVOICES_DATE = null;
 +           select
 +             WDT2.CHECK_LAST_INVOICES_DATE
 +           from
 +             WRH$DOC_TYPES2 WDT2
 +           where
 +             WDT2.ID = :WRH_DOC_TYPE_REF
 +           into
 +             :CHECK_LAST_INVOICES_DATE;
 +
 +           if ((CHECK_LAST_INVOICES_DATE is not null) and (CHECK_LAST_INVOICES_DATE > 0)) then
 +           begin
 +             -- check if the date of the previous invoice is not past the date of the current invoice
 +             LAST_INVOICE_DATE = null;
 +             select
 +               first 1
 +               WD.DOC_DATE, extract(year from WD.DOC_DATE), extract(month from WD.DOC_DATE),
 +               extract(day from WD.DOC_DATE)
 +             from
 +               WRH$DOCS WD
 +             where
 +               (WD.DOC_NUMBER < :NEW_DOC_NUMBER) and
 +               (WD.DOC_NUMBER >= (:NEW_DOC_NUMBER - :CHECK_LAST_INVOICES_DATE)) and
 +               (WD.DOC_STATUS >= 0) and
 +               (WD.DOC_NUM_GENERATOR_REF = :DOC_NUM_GENERATOR_REF)
 +             order by
 +               WD.DOC_NUMBER desc
 +             into
 +               :LAST_INVOICE_DATE, :LAST_INVOICE_YEAR, LAST_INVOICE_MONTH, :LAST_INVOICE_DAY;
 +
 +             if ((LAST_INVOICE_DATE is not null) and
 +                (LAST_INVOICE_DATE > :WRH_DOC_DATE)) then
 +             begin
 +               execute procedure SYS$EXCEPTION_CLEAN(71,
 +               '' '' || LAST_INVOICE_DAY || ''.'' || LAST_INVOICE_MONTH || ''.'' || LAST_INVOICE_YEAR);
 +             end
 +           end
 +         suspend;
 +      end';
 +      
 +      
 +      execute statement (STMT) (WRH_DOC_TYPE_REF := WRH_DOC_TYPE_REF, DOC_NUM_GENERATOR_REF := :DOC_NUM_GENERATOR_REF, WRH_DOC_DATE := :WRH_DOC_DATE) WITH AUTONOMOUS TRANSACTION
 +      into
 +        :NEW_DOC_NUMBER;
 +
 +</code>
 +
 +Пример 2: Показва изпълнението само в случая за изтегляне на номер и изчакването за следващ опит. Този пример е част от горната процедура. 
 +
 +При изтегляне на номер на фактура от кочан се извършва ъпдейт и изтегляне на номера в една транзакция. Ако транзакцията продължи около 1 секунда, то през това време, никой друг не може да достъпи същия кочан и да изтегли пореден номер.
 +
 +В този случай при грешка можем да изчакаме определено време (колкото преценим, че е добре) и да опитаме отново.
 +Пример за точно такова изчакване е в следващия пример:
 +
 +<code pascal>
 +         repeat_count = 0;
 +         NEW_DOC_NUMBER = null;
 +         while ((repeat_count < 5) and (NEW_DOC_NUMBER is null)) do
 +         begin
 +            repeat_count = repeat_count + 1;
 +            NEW_DOC_NUMBER = null;
 +            update
 +              NOM$DOC_NUM_GENERATORS G
 +            set
 +              G.CURRENT_VALUE = G.CURRENT_VALUE + 1
 +            where
 +              G.ID = :DOC_NUM_GENERATOR_REF
 +            returning
 +              G.CURRENT_VALUE - 1
 +            into
 +              :NEW_DOC_NUMBER;
 +            when any do
 +            begin
 +              execute procedure SYS$SLEEP(200); -- ако поискаме повече от 200 мс трябва да поставим съответното време за изчакване тук!
 +              NEW_DOC_NUMBER = null;
 +            end
 +          end
 +          if (NEW_DOC_NUMBER is null) then
 +              exception CLEAN_TEXT_ERROR ''There was a problem getting an invoice number for the warehouse document!'';  
 +
 +</code>   
kak_da/spravki_scriptove.1546443364.txt.gz · Последна промяна: 2019/01/02 15:36 от t.lalova