Oracle PL/SQL: Обработка ошибок

Создадим пакет и в нем тестовую процедуру, которая будет генерировать исключение (спецификацию пакета я опускаю, т.к. она очевидна):

  create or replace package body VTESTPKG is

    procedure Test1

    is

    begin

      raise NO_DATA_FOUND;

    end Test1;

  end VTESTPKG;

Теперь, вызовем VTESTPKG.Test1 и запишем текст исключения в output:

  begin

    VTESTPKG.Test1;

  exception

    when others then

      dbms_output.put_line(sqlerrm);

  end;

Результат будет выглядеть так:

ORA-01403: данные не найдены

Код и текст ошибки в SQLERRM есть, однако нам бы очень хотелось увидеть место возникновения ошибки - в идеале номер строки и стек вызовов. Ниже приведен код функции ERR_WHENCE, которая возвращает место возникновения ошибки, и стандартный обработчик ошибок RaiseError, который я использую при обработке всех ошибок в моем коде на PL/SQL.

  function ERR_WHENCE return varchar2

  is

    l_back_trace varchar2(4096) default DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;

    l_pos integer;

  begin

    if substr(l_back_trace, length(l_back_trace), 1) = chr(10)

    then

      l_back_trace := substr(l_back_trace, 1, length(l_back_trace)-1);

    end if;

    l_pos := instr(l_back_trace, chr(10), -1);

    if l_pos > 0 then

      l_back_trace := substr(l_back_trace, l_pos+1);

    end if;

    return l_back_trace || chr(10);

  end ERR_WHENCE;

  procedure RaiseError(

    error_source varchar2,

    error_message varchar2 default ERR_WHENCE || sqlerrm,

    error_code number default -20001

  )

  is

  begin    

    if not error_source is null then

      raise_application_error(

        error_code, ‘error in ‘ || error_source || chr(10) || error_message);

    else

      raise_application_error(

        error_code, error_message);

    end if;

  end RaiseError;

Для демонстрации использования создадим процедуры Test2 и Test3, в которых используется обработчик ошибок RaiseError:

  procedure Test2

  is

  begin

    raise NO_DATA_FOUND;

  exception

    when others then

      RaiseError(‘Test2’);

  end Test2;

  procedure Test3

  is

  begin    

    Test2;

  exception

    when others then

      RaiseError(‘Test3’);

  end Test3;

Результат (в SQLERRM) вызова Test2:

ORA-20001: error in Test2

ORA-06512: на  “AIS.VTESTPKG”, line 44

ORA-01403: данные не найдены

Результат (в SQLERRM) вызова Test3:

ORA-20001: error in Test3

ORA-06512: на  “AIS.VTESTPKG”, line 53

ORA-20001: error in Test2

ORA-06512: на  “AIS.VTESTPKG”, line 44

ORA-01403: данные не найдены

===

Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Oracle SQL: INSERT WHEN

В Oracle SQL есть интересная конструкция “INSERT WHEN…”, о которой не все знают.

INSERT
WHEN ([Condition]) THEN
INTO [TableName] ([ColumnName])
VALUES ([VALUES])
ELSE
INTO [TableName] ([ColumnName])
VALUES ([VALUES])
SELECT [ColumnName] FROM [TableName];

Во первых, эта конструкция позволяет с помощью одной каманды INSERT вставлять данные в разные таблицы.

Во вторых, попробуем решить следующую задачу: пусть имеется таблица VTEST с полем A VARCHAR2(10) и нужно  написать команду INSERT, которая будет вставлять значение ‘AAA’, отсутствующее в этой таблице (если такое значение уже есть, то новую запись создавать не нужно). Решение этой задачи может выглядеть примерно так:

INSERT INTO VTEST (A)
  SELECT ‘AAA’ FROM dual
    WHERE NOT EXISTS (SELECT * FROM VTEST WHERE A=’AAA’)

Такая конструкция, конечно, работает. Но плохо в ней то, что значение ‘AAA’ фигурирует дважды: в SELECT ‘AAA’ FROM dual и в SELECT * FROM VTEST WHERE A=’AAA’.

А вот так выглядит та же операция, но с использованием INSERT WHEN:

INSERT
  WHEN NOT EXISTS (SELECT * FROM VTEST WHERE A=A0)
   THEN INTO VTEST (A) VALUES (A0)
  SELECT ‘AAA’ A0 FROM dual

Здесь ‘AAA’ присутствует только 1 раз.

===

Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Howto: запустить приложение на node.js в виде сервиса (linux)

1. Создаем файл ~/myapp.service:

[Unit]

Description=My App

After=network-online.target

[Service]

Restart=on-failure

WorkingDirectory=/var/mayapp

ExecStart=/usr/bin/node /var/myapp/index.js

[Install]

WantedBy=multi-user.target

2. cp ~/myapp.service /etc/systemd/system

3. systemctl start myapp.service

4. systemctl enable myapp.service

5. journalctl -u myapp

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Полезные ссылки (rpi, tinkerboard, linux, arm)

Полезные ссылки. Raspberry Pi, Tinker Board, Linux, ARM:

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru