P8-ExchangeService/db/PKG_EXS.pck

2476 lines
112 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

create or replace package PKG_EXS as
/* Константы - идентификация сервера приложений в сессиях экземпляра БД */
SAPPSRV_PROGRAMM_NAME constant PKG_STD.TSTRING := 'node.exe'; -- Наименование исполняемого файла
SAPPSRV_MODULE_NAME constant PKG_STD.TSTRING := 'PARUS$ExchangeServer'; -- Наименование модуля
/* Константы - контейнеры контекста и процессов расчёта */
SCONT_MAIN constant PKG_STD.TSTRING := 'EXSCONT'; -- Глобальный префикс контейнера
SCONT_PRC constant PKG_STD.TSTRING := 'PRC'; -- Наименование контейнера для параметров процесса
/* Константы - поля контейнеров */
SCONT_FLD_SRESULT constant PKG_STD.TSTRING := 'SRESULT'; -- Наименование поля контейнера для кода результата обработки
SCONT_FLD_SMSG constant PKG_STD.TSTRING := 'SMSG'; -- Наименование поля контейнера для сообщения обработки
SCONT_FLD_BRESP constant PKG_STD.TSTRING := 'BRESP'; -- Наименование поля контейнера для результата обработки
SCONT_FLD_DCTX_EXP constant PKG_STD.TSTRING := 'DCTX_EXP'; -- Наименование поля контейнера для даты истечения контектса сервиса
SCONT_FLD_SCTX constant PKG_STD.TSTRING := 'SCTX'; -- Наименование поля контейнера для для контекста сервиса
/* Константы - типы сервисов */
NSRV_TYPE_SEND constant EXSSERVICE.SRV_TYPE%type := 0; -- Отправка сообщений
NSRV_TYPE_RECIVE constant EXSSERVICE.SRV_TYPE%type := 1; -- Получение сообщений
SSRV_TYPE_SEND constant varchar2(40) := 'SEND'; -- Отправка сообщений (строковый код)
SSRV_TYPE_RECIVE constant varchar2(40) := 'RECIVE'; -- Получение сообщений (строковый код)
/* Константы - типы функций сервиса */
NFN_TYPE_DATA constant EXSSERVICEFN.FN_TYPE%type := 0; -- Обмен данными
NFN_TYPE_LOGIN constant EXSSERVICEFN.FN_TYPE%type := 1; -- Начало сеанса
NFN_TYPE_LOGOUT constant EXSSERVICEFN.FN_TYPE%type := 2; -- Завершение сеанса
SFN_TYPE_DATA constant varchar2(40) := 'DATA'; -- Обмен данными (строковый код)
SFN_TYPE_LOGIN constant varchar2(40) := 'LOGIN'; -- Начало сеанса (строковый код)
SFN_TYPE_LOGOUT constant varchar2(40) := 'LOGOUT'; -- Завершение сеанса (строковый код)
/* Константы - способы передачи параметров функциям сервиса */
NFN_PRMS_TYPE_POST constant EXSSERVICEFN.FN_PRMS_TYPE%type := 0; -- POST-запрос
NFN_PRMS_TYPE_GET constant EXSSERVICEFN.FN_PRMS_TYPE%type := 1; -- GET-запрос
SFN_PRMS_TYPE_POST constant varchar2(40) := 'POST'; -- POST-запрос
SFN_PRMS_TYPE_GET constant varchar2(40) := 'GET'; -- GET-запрос
/* Константы - расписание повторного исполнения функции */
NRETRY_SCHEDULE_UNDEF constant EXSSERVICEFN.RETRY_SCHEDULE%type := 0; -- Не определено
NRETRY_SCHEDULE_SEC constant EXSSERVICEFN.RETRY_SCHEDULE%type := 1; -- Секунда
NRETRY_SCHEDULE_MIN constant EXSSERVICEFN.RETRY_SCHEDULE%type := 2; -- Минута
NRETRY_SCHEDULE_HOUR constant EXSSERVICEFN.RETRY_SCHEDULE%type := 3; -- Час
NRETRY_SCHEDULE_DAY constant EXSSERVICEFN.RETRY_SCHEDULE%type := 4; -- Сутки
NRETRY_SCHEDULE_WEEK constant EXSSERVICEFN.RETRY_SCHEDULE%type := 5; -- Неделя
NRETRY_SCHEDULE_MONTH constant EXSSERVICEFN.RETRY_SCHEDULE%type := 6; -- Месяц
SRETRY_SCHEDULE_UNDEF constant varchar2(40) := 'UNDEFINED'; -- Не определено (строковый код)
SRETRY_SCHEDULE_SEC constant varchar2(40) := 'SEC'; -- Секунда (строковый код)
SRETRY_SCHEDULE_MIN constant varchar2(40) := 'MIN'; -- Минута (строковый код)
SRETRY_SCHEDULE_HOUR constant varchar2(40) := 'HOUR'; -- Час (строковый код)
SRETRY_SCHEDULE_DAY constant varchar2(40) := 'DAY'; -- Сутки (строковый код)
SRETRY_SCHEDULE_WEEK constant varchar2(40) := 'WEEK'; -- Неделя (строковый код)
SRETRY_SCHEDULE_MONTH constant varchar2(40) := 'MONTH'; -- Месяц (строковый код)
/* Константы - признак оповещения о простое удаленного сервиса */
NUNAVLBL_NTF_SIGN_NO constant EXSSERVICE.UNAVLBL_NTF_SIGN%type := 0; -- Не оповещать о простое
NUNAVLBL_NTF_SIGN_YES constant EXSSERVICE.UNAVLBL_NTF_SIGN%type := 1; -- Оповещать о простое
SUNAVLBL_NTF_SIGN_NO constant varchar2(40) := 'UNAVLBL_NTF_NO'; -- Не оповещать о простое (строковый код)
SUNAVLBL_NTF_SIGN_YES constant varchar2(40) := 'UNAVLBL_NTF_YES'; -- Оповещать о простое (строковый код)
/* Константы - признак оповещения об ошибке исполнения сообщения очереди для функции обработки */
NERR_NTF_SIGN_NO constant EXSSERVICEFN.ERR_NTF_SIGN%type := 0; -- Не оповещать об ошибке исполнения
NERR_NTF_SIGN_YES constant EXSSERVICEFN.ERR_NTF_SIGN%type := 1; -- Оповещать об ошибке исполнения
SERR_NTF_SIGN_NO constant varchar2(40) := 'ERR_NTF_SIGN_NO'; -- Не оповещать об ошибке исполнения (строковый код)
SERR_NTF_SIGN_YES constant varchar2(40) := 'ERR_NTF_SIGN_YES'; -- Оповещать об ошибке исполнения (строковый код)
/* Константы - состояния записей журнала работы сервиса */
NLOG_STATE_INF constant EXSLOG.LOG_STATE%type := 0; -- Информация
NLOG_STATE_WRN constant EXSLOG.LOG_STATE%type := 1; -- Предупреждение
NLOG_STATE_ERR constant EXSLOG.LOG_STATE%type := 2; -- Ошибка
SLOG_STATE_INF constant varchar2(40) := 'INF'; -- Информация (строковый код)
SLOG_STATE_WRN constant varchar2(40) := 'WRN'; -- Предупреждение (строковый код)
SLOG_STATE_ERR constant varchar2(40) := 'ERR'; -- Ошибка (строковый код)
/* Константы - состояния исполнения записей очереди обмена */
NQUEUE_EXEC_STATE_INQUEUE constant EXSQUEUE.EXEC_STATE%type := 0; -- Поставлено в очередь
NQUEUE_EXEC_STATE_APP constant EXSQUEUE.EXEC_STATE%type := 1; -- Обрабатывается сервером приложений
NQUEUE_EXEC_STATE_APP_OK constant EXSQUEUE.EXEC_STATE%type := 2; -- Успешно обработано сервером приложений
NQUEUE_EXEC_STATE_APP_ERR constant EXSQUEUE.EXEC_STATE%type := 3; -- Ошибка обработки сервером приложений
NQUEUE_EXEC_STATE_DB constant EXSQUEUE.EXEC_STATE%type := 4; -- Обрабатывается СУБД
NQUEUE_EXEC_STATE_DB_OK constant EXSQUEUE.EXEC_STATE%type := 5; -- Успешно обработано СУБД
NQUEUE_EXEC_STATE_DB_ERR constant EXSQUEUE.EXEC_STATE%type := 6; -- Ошибка обработки СУБД
NQUEUE_EXEC_STATE_OK constant EXSQUEUE.EXEC_STATE%type := 7; -- Обработано успешно
NQUEUE_EXEC_STATE_ERR constant EXSQUEUE.EXEC_STATE%type := 8; -- Обработано с ошибками
SQUEUE_EXEC_STATE_INQUEUE constant varchar2(40) := 'INQUEUE'; -- Поставлено в очередь
SQUEUE_EXEC_STATE_APP constant varchar2(40) := 'APP'; -- Обрабатывается сервером приложений
SQUEUE_EXEC_STATE_APP_OK constant varchar2(40) := 'APP_OK'; -- Успешно обработано сервером приложений
SQUEUE_EXEC_STATE_APP_ERR constant varchar2(40) := 'APP_ERR'; -- Ошибка обработки сервером приложений
SQUEUE_EXEC_STATE_DB constant varchar2(40) := 'DB'; -- Обрабатывается СУБД
SQUEUE_EXEC_STATE_DB_OK constant varchar2(40) := 'DB_OK'; -- Успешно обработано СУБД
SQUEUE_EXEC_STATE_DB_ERR constant varchar2(40) := 'DB_ERR'; -- Ошибка обработки СУБД
SQUEUE_EXEC_STATE_OK constant varchar2(40) := 'OK'; -- Обработано успешно
SQUEUE_EXEC_STATE_ERR constant varchar2(40) := 'ERR'; -- Обработано с ошибками
/* Константы - признак инкремента количества попыток исполнения позиции очереди */
NINC_EXEC_CNT_NO constant number(1) := 0; -- Не инкрементировать
NINC_EXEC_CNT_YES constant number(1) := 1; -- Инкрементировать
/* Константы - признак необходимости исполнения позиции очереди */
NQUEUE_EXEC_NO constant number(1) := 0; -- Не исполнять
NQUEUE_EXEC_YES constant number(1) := 1; -- Исполнять
/* Константы - признак аутентифицированности сервиса */
NIS_AUTH_YES constant EXSSERVICE.IS_AUTH%type := 1; -- Аутентифицирован
NIS_AUTH_NO constant EXSSERVICE.IS_AUTH%type := 0; -- Неаутентифицирован
SIS_AUTH_YES constant varchar2(40) := 'IS_AUTH_YES'; -- Аутентифицирован (строковый код)
SIS_AUTH_NO constant varchar2(40) := 'IS_AUTH_NO'; -- Неаутентифицирован (строковый код)
/* Константы - признак необходимости аутентифицированности сервиса для исполнения функции */
NAUTH_ONLY_YES constant EXSSERVICEFN.AUTH_ONLY%type := 1; -- Требуется аутентификация
NAUTH_ONLY_NO constant EXSSERVICEFN.AUTH_ONLY%type := 0; -- Аутентификация не требуется
SAUTH_ONLY_YES constant varchar2(40) := 'AUTH_ONLY_YES'; -- Требуется аутентификация (строковый код)
SAUTH_ONLY_NO constant varchar2(40) := 'AUTH_ONLY_NO'; -- Аутентификация не требуется (строковый код)
/* Константы - коды результатов исполнения обработчика сообщения */
SPRC_RESP_RESULT_OK constant varchar2(40) := 'OK'; -- Обработано успешно
SPRC_RESP_RESULT_ERR constant varchar2(40) := 'ERR'; -- Ошибка обработки
SPRC_RESP_RESULT_UNAUTH constant varchar2(40) := 'UNAUTH'; -- Неаутентифицирован
/* Константы - признак сброса данных сообщения очереди */
NQUEUE_RESET_DATA_NO constant number(1) := 0; -- Не сбрасывать
NQUEUE_RESET_DATA_YES constant number(1) := 1; -- Сбрасывать
/* Константы - признак оригинала данных */
NIS_ORIGINAL_NO constant number(1) := 0; -- Оригинал
NIS_ORIGINAL_YES constant number(1) := 1; -- Не оригинал
/* Константы - ожидаемый интерфейс процедуры обработки сообщения очереди на стороне БД */
SPRC_RESP_ARGS constant varchar2(80) := 'NIDENT,IN,NUMBER;NEXSQUEUE,IN,NUMBER;'; -- Список параметров процедуры обработки
/* Проверка активности сервера приложений */
function UTL_APPSRV_IS_ACTIVE
return boolean; -- Флаг активности сервера приложений
/* Формирование ссылки на вызываемый хранимый объект */
function UTL_STORED_MAKE_LINK
(
SPROCEDURE in varchar2, -- Имя процедуры
SPACKAGE in varchar2 := null -- Имя пакета
) return varchar2; -- Ссылка на вызываемый хранимый объект
/* Проверка интерфейса хранимого объекта */
procedure UTL_STORED_CHECK
(
NFLAG_SMART in number, -- Признак генерации исключения (0 - да, 1 - нет)
SPKG in varchar2, -- Имя пакета
SPRC in varchar2, -- Имя процедуры
SARGS in varchar2, -- Список параметров (";" - разделитель аргументов, "," - разделитель атрибутов аргумента, формат: <АРГУМЕНТ>,<IN|OUT|IN OUT>,<ТИП ДАННЫХ ORACLE>;)
NRESULT out number -- Результат проверки (0 - ошибка, 1 - успех)
);
/* Формирование полного наименования контейнера для хранения окружения вызова процедуры */
function UTL_CONTAINER_MAKE_NAME
(
NIDENT in number, -- Идентификатор процесса
SSUB_CONTAINER in varchar2 := null -- Наименование контейнера второго уровня
) return varchar2; -- Полное наименование контейнера
/* Очистка контейнера для хранения окружения вызова процедуры */
procedure UTL_CONTAINER_PURGE
(
NIDENT in number, -- Идентификатор процесса
SSUB_CONTAINER in varchar2 := null -- Наименование контейнера второго уровня
);
/* Вычисление даты следующего запуска расписания */
function UTL_SCHED_CALC_NEXT_DATE
(
DEXEC_DATE in date, -- Дата предыдущего исполнения
NRETRY_SCHEDULE in number, -- График перезапуска (см. константы NRETRY_SCHEDULE_*)
NRETRY_STEP in number -- Шаг графика перезапуска
) return date; -- Дата следующего запуска
/* Выяснение необходимости запуска по расписанию */
function UTL_SCHED_CHECK_EXEC
(
DEXEC_DATE in date, -- Дата предыдущего исполнения
NRETRY_SCHEDULE in number, -- График перезапуска (см. константы NRETRY_SCHEDULE_*)
NRETRY_STEP in number, -- Шаг графика перезапуска
DEXEC in date := sysdate -- Дата, относительно которой необходимо выполнить проверку
) return boolean; -- Признак необходимости запуска
/* Установка значения типа строка параметра процедуры обработки сообщения обмена */
procedure PRC_RESP_ARG_STR_SET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2, -- Наименование параметра
SVALUE in varchar2 -- Значение параметра
);
/* Установка значения типа число параметра процедуры обработки сообщения обмена */
procedure PRC_RESP_ARG_NUM_SET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2, -- Наименование параметра
NVALUE in number -- Значение параметра
);
/* Установка значения типа дата параметра процедуры обработки сообщения обмена */
procedure PRC_RESP_ARG_DATE_SET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2, -- Наименование параметра
DVALUE in date -- Значение параметра
);
/* Установка значения типа BLOB параметра процедуры обработки сообщения обмена */
procedure PRC_RESP_ARG_BLOB_SET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2, -- Наименование параметра
BVALUE in blob -- Значение параметра
);
/* Считывание значения типа строка параметра процедуры обработки сообщения обмена */
function PRC_RESP_ARG_STR_GET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2 -- Наименование параметра
) return varchar2; -- Значение параметра
/* Считывание значения типа число параметра процедуры обработки сообщения обмена */
function PRC_RESP_ARG_NUM_GET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2 -- Наименование параметра
) return number; -- Значение параметра
/* Считывание значения типа дата параметра процедуры обработки сообщения обмена */
function PRC_RESP_ARG_DATE_GET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2 -- Наименование параметра
) return date; -- Значение параметра
/* Считывание значения типа BLOB параметра процедуры обработки сообщения обмена */
function PRC_RESP_ARG_BLOB_GET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2 -- Наименование параметра
) return blob; -- Значение параметра
/* Установка результата исполнения обработчика */
procedure PRC_RESP_RESULT_SET
(
NIDENT in number, -- Идентификатор процесса
SRESULT in varchar2 := SPRC_RESP_RESULT_OK, -- Код результата (см. константы SPRC_RESP_RESULT_*)
BRESP in blob := null, -- Результат обработки
SMSG in varchar2 := null, -- Сообщение обработчика
SCTX in varchar2 := null, -- Контекст
DCTX_EXP in date := null -- Дата истечения контекста
);
/* Считывание результата исполнения обработчика */
procedure PRC_RESP_RESULT_GET
(
NIDENT in number, -- Идентификатор процесса
SRESULT out varchar2, -- Код результата (см. константы SPRC_RESP_RESULT_*)
BRESP out blob, -- Результат обработки
SMSG out varchar2, -- Сообщение обработчика
SCTX out varchar2, -- Контекст
DCTX_EXP out date -- Дата истечения контекста
);
/* Базовое добавление в буфер отбора документов */
procedure RNLIST_BASE_INSERT
(
NIDENT in number, -- Идентификатор буфера
NDOCUMENT in number, -- Рег. номер записи документа
NRN out number -- Рег. номер добавленной записи буфера
);
/* Базовое удаление из буфера отбора документов */
procedure RNLINST_BASE_DELETE
(
NRN in number -- Рег. номер записи буфера
);
/* Базовая очистка буфера отбора документов */
procedure RNLIST_BASE_CLEAR
(
NIDENT in number -- Идентификатор буфера
);
/* Получение сервиса */
procedure SERVICE_GET
(
NIDENT in number, -- Идентификатор буфера
RCSERVICE out sys_refcursor -- Курсор со списком сервисов
);
/* Получение сервиса */
procedure SERVICE_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICE in number, -- Рег. номер записи сервиса
RCSERVICE out sys_refcursor -- Курсор со списком сервисов
);
/* Получение информации о просроченных сообщениях очереди для сервиса */
procedure SERVICE_QUEUE_EXPIRED_INFO_GET
(
NEXSSERVICE in number, -- Рег. номер записи сервиса
RCSERVICE_QUEUE_EXPIRED_INFO out sys_refcursor -- Курсор со сведениями о просроченных сообщениях сервиса
);
/* Получение контекста сервиса */
procedure SERVICE_CTX_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICE in number, -- Рег. номер записи сервиса
RCSERVICE_CTX out sys_refcursor -- Курсор со контектом сервиса
);
/* Установка контекста сервиса */
procedure SERVICE_CTX_SET
(
NEXSSERVICE in number, -- Рег. номер записи сервиса
SCTX in varchar2, -- Контекст
DCTX_EXP in date := null -- Дата истечения контекста
);
/* Очистка контекста сервиса */
procedure SERVICE_CTX_CLEAR
(
NEXSSERVICE in number -- Рег. номер записи сервиса
);
/* Проверка необходимости аутентификации */
function SERVICE_IS_AUTH
(
NEXSSERVICE in number -- Рег. номер записи сервиса
) return number; -- Флаг аутентификации (см. константы NIS_AUTH_*)
/* Поиск функции аутентификации (начала сеанса) для сервиса обмена */
procedure SERVICE_AUTH_FN_FIND
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICE in number, -- Рег. номер записи сервиса
REXSSERVICEFN out EXSSERVICEFN%rowtype -- Запись функции аутентификации
);
/* Поиск функции отмены аутентификации (завершения сеанса) для сервиса обмена */
procedure SERVICE_UNAUTH_FN_FIND
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICE in number, -- Рег. номер записи сервиса
REXSSERVICEFN out EXSSERVICEFN%rowtype -- Запись функции аутентификации
);
/* Помещение задания на аутентификацию (начало сеанса) сервиса в очередь обмена */
procedure SERVICE_AUTH_PUT_INQUEUE
(
NEXSSERVICE in number -- Рег. номер сервиса обмена
);
/* Помещение задания на отмену аутентификации (завершение сеанса) сервиса в очередь обмена */
procedure SERVICE_UNAUTH_PUT_INQUEUE
(
NEXSSERVICE in number -- Рег. номер сервиса обмена
);
/* Получение списка сервисов */
procedure SERVICES_GET
(
RCSERVICES out sys_refcursor -- Курсор со списком сервисов
);
/* Получение списка сервисов требующих аутентификации */
procedure SERVICES_AUTH_GET
(
RCSERVICES_AUTH out sys_refcursor -- Курсор со списком сервисов требующих аутентификации
);
/* Получение функции сервиса */
procedure SERVICEFN_GET
(
NIDENT in number, -- Идентификатор буфера
RCSERVICEFN out sys_refcursor -- Курсор со списком функций сервиса
);
/* Получение функции сервиса */
procedure SERVICEFN_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICEFN in number, -- Рег. номер функции сервиса
RCSERVICEFN out sys_refcursor -- Курсор со списком функций сервиса
);
/* Получение списка функций сервиса */
procedure SERVICEFNS_GET
(
NEXSSERVICE in number, -- Рег. номер записи сервиса
RCSERVICEFNS out sys_refcursor -- Курсор со списком функций
);
/* Поиск функции сервиса обмена по коду функции и коду сервиса */
function SERVICEFN_FIND_BY_SRVCODE
(
NFLAG_SMART in number, -- Признак генерации исключения (0 - да, 1 - нет)
SEXSSERVICE in varchar2, -- Мнемокод сервиса для обработки
SEXSSERVICEFN in varchar2 -- Мнемокод функции сервиса для обработки
) return number; -- Рег. номер функции сервиса обмена
/* Проверка наличия в очереди неисполненного задания для указанной функции сервиса обмена */
function SERVICEFN_CHECK_INCMPL_INQUEUE
(
NEXSSERVICEFN in number -- Рег. номер записи функции сервиса обмена
) return boolean; -- Результат проверки (true - в очереди есть неисполненные задания для данной функции, false - в очереди нет неисполненных заданий для данной функции)
/* Считывание записи журнала работы */
procedure LOG_GET
(
NIDENT in number, -- Идентификатор буфера
RCLOG out sys_refcursor -- Курсор со списком записей журнала работы
);
/* Считывание записи журнала работы */
procedure LOG_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSLOG in number, -- Рег. номер записи журнала
RCLOG out sys_refcursor -- Курсор со списком записей журнала работы
);
/* Добавление записи в журнал работы */
procedure LOG_PUT
(
NLOG_STATE in number, -- Тип записи (см. констнаты NLOG_STATE*)
SMSG in varchar2, -- Сообщение
NEXSSERVICE in number := null, -- Рег. номер связанного сервиса
NEXSSERVICEFN in number := null, -- Рег. номер связанной функции сервиса
NEXSQUEUE in number := null, -- Рег. номер связанной записи очереди
RCLOG out sys_refcursor -- Курсор со списком сервисов
);
/* Считывание сообщения очереди */
procedure QUEUE_GET
(
NIDENT in number, -- Идентификатор буфера
RCQUEUE out sys_refcursor -- Курсор с позицией очереди
);
/* Считывание сообщения из очереди */
procedure QUEUE_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSQUEUE in number, -- Рег. номер записи очереди
RCQUEUE out sys_refcursor -- Курсор с позицией очереди
);
/* Проверка необходимости исполнения исходящего сообщения очереди */
function QUEUE_SRV_TYPE_SEND_EXEC_CHECK
(
NEXSQUEUE in number -- Рег. номер записи очереди
) return number; -- Флаг необходимости исполнения позиции очереди (см. константы NQUEUE_EXEC_*)
/* Считывание очередной порции исходящих сообщений из очереди */
procedure QUEUE_SRV_TYPE_SEND_GET
(
NPORTION_SIZE in number, -- Количество выбираемых сообщений
RCQUEUES out sys_refcursor -- Курсор со списком позиций очереди
);
/* Установка состояние записи очереди */
procedure QUEUE_EXEC_STATE_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
NEXEC_STATE in number, -- Устанавливаемое состояние (см. констнаты NQUEUE_EXEC_STATE_*, null - не менять)
SEXEC_MSG in varchar2, -- Сообщение обработчика
NINC_EXEC_CNT in number, -- Флаг инкремента счётчика исполнений (см. констнаты NINC_EXEC_CNT_*, null - не менять)
NRESET_DATA in number, -- Флаг сброса данных сообщения (см. констатнты NQUEUE_RESET_DATA_NO*, null - не сбрасывать)
RCQUEUE out sys_refcursor -- Курсор с изменённой позицией очереди
);
/* Считывание данных результата обработки записи очереди */
procedure QUEUE_RESP_GET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
RCQUEUE_RESP out sys_refcursor -- Курсор с данными результата обработки записи очереди
);
/* Установка результата обработки записи очереди */
procedure QUEUE_RESP_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
BRESP in blob, -- Результат обработки
NIS_ORIGINAL in number := NIS_ORIGINAL_NO -- Признак передачи оригинального результата обработки (см. константы NIS_ORIGINAL*, null - не оригинал)
);
/* Установка результата обработки записи очереди (возвращает измененную позицию очереди) */
procedure QUEUE_RESP_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
BRESP in blob, -- Результат обработки
NIS_ORIGINAL in number := NIS_ORIGINAL_NO, -- Признак передачи оригинального результата обработки (см. константы NIS_ORIGINAL*, null - не оригинал)
RCQUEUE out sys_refcursor -- Курсор с изменённой позицией очереди
);
/* Считывание данных сообщения записи очереди */
procedure QUEUE_MSG_GET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
RCQUEUE_MSG out sys_refcursor -- Курсор с данными сообщения записи очереди
);
/* Установка сообщения записи очереди */
procedure QUEUE_MSG_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
BMSG in blob -- Результат обработки
);
/* Установка сообщения записи очереди (возвращает измененную позицию очереди) */
procedure QUEUE_MSG_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
BMSG in blob, -- Результат обработки
RCQUEUE out sys_refcursor -- Курсор с изменённой позицией очереди
);
/* Помещение сообщения обмена в очередь */
procedure QUEUE_PUT
(
NEXSSERVICEFN in number, -- Рег. номер функции обработки
BMSG in blob, -- Данные
NEXSQUEUE in number := null, -- Рег. номер связанной позиции очереди
NLNK_COMPANY in number := null, -- Рег. номер связанной организации
NLNK_DOCUMENT in number := null, -- Рег. номер связанной записи документа
SLNK_UNITCODE in varchar2 := null, -- Код связанного раздела
SOPTIONS in varchar2 := null, -- Параметры сообщения
NNEW_EXSQUEUE out number -- Рег. номер добавленной позиции очереди
);
/* Помещение сообщения обмена в очередь (возвращает курсор с добавленной записью) */
procedure QUEUE_PUT
(
NEXSSERVICEFN in number, -- Рег. номер функции обработки
BMSG in blob, -- Данные
NEXSQUEUE in number := null, -- Рег. номер связанной позиции очереди
NLNK_COMPANY in number := null, -- Рег. номер связанной организации
NLNK_DOCUMENT in number := null, -- Рег. номер связанной записи документа
SLNK_UNITCODE in varchar2 := null, -- Код связанного раздела
SOPTIONS in varchar2 := null, -- Параметры сообщения
RCQUEUE out sys_refcursor -- Курсор с добавленной позицией очереди
);
/* Помещение сообщения обмена в очередь (по коду сервиса и функции обрабоки) */
procedure QUEUE_PUT
(
SEXSSERVICE in varchar2, -- Мнемокод сервиса для обработки
SEXSSERVICEFN in varchar2, -- Мнемокод функции сервиса для обработки
BMSG in blob, -- Данные
NEXSQUEUE in number := null, -- Рег. номер связанной позиции очереди
NLNK_COMPANY in number := null, -- Рег. номер связанной организации
NLNK_DOCUMENT in number := null, -- Рег. номер связанной записи документа
SLNK_UNITCODE in varchar2 := null, -- Код связанного раздела
SOPTIONS in varchar2 := null, -- Параметры сообщения
NNEW_EXSQUEUE out number -- Рег. номер добавленной позиции очереди
);
/* Помещение сообщения обмена в очередь (по коду сервиса и функции обрабоки, возвращает курсор с добавленной записью) */
procedure QUEUE_PUT
(
SEXSSERVICE in varchar2, -- Мнемокод сервиса для обработки
SEXSSERVICEFN in varchar2, -- Мнемокод функции сервиса для обработки
BMSG in blob, -- Данные
NEXSQUEUE in number := null, -- Рег. номер связанной позиции очереди
NLNK_COMPANY in number := null, -- Рег. номер связанной организации
NLNK_DOCUMENT in number := null, -- Рег. номер связанной записи документа
SLNK_UNITCODE in varchar2 := null, -- Код связанного раздела
SOPTIONS in varchar2 := null, -- Параметры сообщения
RCQUEUE out sys_refcursor -- Курсор с добавленной позицией очереди
);
/* Исполнение обработчика для сообщения обмена */
procedure QUEUE_PRC
(
NEXSQUEUE in number, -- Рег. номер записи очереди
RCRESULT out sys_refcursor -- Курсор с результатами обработки
);
end;
/
create or replace package body PKG_EXS as
/* Проверка активности сервера приложений */
function UTL_APPSRV_IS_ACTIVE
return boolean -- Флаг активности сервера приложений
is
begin
/* Проверим наличие сеанса сервера приложений в сессиях */
for C in (select S.SID
from V$SESSION S
where UPPER(S.MODULE) = UPPER(SAPPSRV_MODULE_NAME)
and S.STATUS <> 'KILLED'
and UPPER(S.PROGRAM) = UPPER(SAPPSRV_PROGRAMM_NAME))
loop
return true;
end loop;
/* Сеанса нет */
return false;
end UTL_APPSRV_IS_ACTIVE;
/* Формирование ссылки на вызываемый хранимый объект */
function UTL_STORED_MAKE_LINK
(
SPROCEDURE in varchar2, -- Имя процедуры
SPACKAGE in varchar2 := null -- Имя пакета
) return varchar2 -- Ссылка на вызываемый хранимый объект
is
begin
/* Проверим параметры */
if (SPROCEDURE is null) then
P_EXCEPTION(0, 'Не указано наименование хранимой процедуры.');
end if;
/* Вернем результат */
return PKG_OBJECT_DESC.STORED_NAME(SPACKAGE_NAME => SPACKAGE, SSTORED_NAME => SPROCEDURE);
end UTL_STORED_MAKE_LINK;
/* Проверка интерфейса хранимого объекта */
procedure UTL_STORED_CHECK
(
NFLAG_SMART in number, -- Признак генерации исключения (0 - да, 1 - нет)
SPKG in varchar2, -- Имя пакета
SPRC in varchar2, -- Имя процедуры
SARGS in varchar2, -- Список параметров (";" - разделитель аргументов, "," - разделитель атрибутов аргумента, формат: <АРГУМЕНТ>,<IN|OUT|IN OUT>,<ТИП ДАННЫХ ORACLE>;)
NRESULT out number -- Результат проверки (0 - ошибка, 1 - успех)
)
is
/* Локальные типы данных - запись параметра */
type TARG is record
(
ARGUMENT_NAME varchar2(30), -- Имя параметра
DATA_TYPE varchar2(30), -- Тип данных
IN_OUT varchar2(9), -- Тип параметра
CORRECT number(1) -- Признак успешности проверки
);
/* Локальные типы данных - коллекция параметров */
type TARGS_LIST is table of TARG; -- Коллекция параметров
/* Локальные идентификаторы */
STORED PKG_OBJECT_DESC.TSTORED; -- Описание процедуры
STORED_ARGS PKG_OBJECT_DESC.TARGUMENTS; -- Коллекция описаний параметров процедуры
STORED_ARG PKG_OBJECT_DESC.TARGUMENT; -- Описание параметра процедуры
RARGS_LIST TARGS_LIST; -- Коллекция существующих параметров
RARGS_LIST_CUR TARGS_LIST; -- Коллекция переданных параметров
NARGS_LIST_CUR_CORRECT number(1); -- Признак успешности проверки переданных параметров
SARGS_LIST PKG_STD.TSTRING; -- Переданный список параметров
SARG PKG_STD.TSTRING; -- Переданный параметр процедуры
SARG_TYPE PKG_STD.TSTRING; -- Тип данных параметра
SARG_TYPE_NAME PKG_STD.TSTRING; -- Тип данных параметра (имя пользовательского типа данных)
SINTERFACE PKG_STD.TSTRING; -- Ожидаемый интерфейс процедуры
begin
/* Проверим параметры - имя процедры всегода должно быть указано */
if (SPRC is null) then
P_EXCEPTION(NFLAG_SMART, 'Не указано имя процедуры.');
return;
end if;
/* Проверим параметры - в списке параметров, если он есть, должны быть разделители */
if (SARGS is not null) then
if ((INSTR(SARGS, ';') = 0) or (INSTR(SARGS, ',') = 0)) then
P_EXCEPTION(NFLAG_SMART,
'Ошибочный формат списка аргументов: используйте ";" для разделения аргументов в списке и "," для разделения атрибутов аргумента: <АРГУМЕНТ>,<IN|OUT|IN OUT>,<ТИП ДАННЫХ ORACLE>;.');
return;
end if;
end if;
/* Инициализируем результат - есть ошибки */
NRESULT := 0;
/* Проверка объектов БД */
if (SPKG is not null) then
/* Поиск пакета */
if (PKG_OBJECT_DESC.EXISTS_PACKAGE(SPACKAGE_NAME => SPKG) = 0) then
P_EXCEPTION(NFLAG_SMART, 'Пакет "%s" не найден.', SPKG);
return;
end if;
/* Поиск процедуры в пакете*/
if (PKG_OBJECT_DESC.EXISTS_PROCEDURE(SPROCEDURE_NAME => UTL_STORED_MAKE_LINK(SPROCEDURE => SPRC, SPACKAGE => SPKG)) = 0) then
P_EXCEPTION(NFLAG_SMART, 'Процедура "%s" в пакете "%s" не найдена.', SPRC, SPKG);
return;
end if;
else
/* Поиск процедуры */
if (PKG_OBJECT_DESC.EXISTS_PROCEDURE(SPROCEDURE_NAME => SPRC) = 0) then
P_EXCEPTION(NFLAG_SMART,
'Процедура "%s" не найдена.',
UTL_STORED_MAKE_LINK(SPROCEDURE => SPRC, SPACKAGE => SPKG));
return;
end if;
end if;
/* Получаем описание процедуры */
begin
STORED := PKG_OBJECT_DESC.DESC_STORED(SSTORED_NAME => UTL_STORED_MAKE_LINK(SPROCEDURE => SPRC, SPACKAGE => SPKG),
BRAISE_ERROR => true);
exception
when others then
P_EXCEPTION(NFLAG_SMART, sqlerrm);
return;
end;
/* Проверяем валидность */
if (STORED.STATUS != 'VALID') then
P_EXCEPTION(NFLAG_SMART,
'Процедура "%s" неработоспособна.',
UTL_STORED_MAKE_LINK(SPROCEDURE => SPRC, SPACKAGE => SPKG));
return;
end if;
/* Получаем описание параметров процедуры */
begin
STORED_ARGS := PKG_OBJECT_DESC.DESC_ARGUMENTS(SSTORED_NAME => UTL_STORED_MAKE_LINK(SPROCEDURE => SPRC,
SPACKAGE => SPKG),
BRAISE_ERROR => true);
exception
when others then
P_EXCEPTION(NFLAG_SMART, sqlerrm);
return;
end;
/* Инициализируем локальную проверяемую коллекцию формальных параметров процедуры */
RARGS_LIST := TARGS_LIST();
for I in 1 .. PKG_OBJECT_DESC.COUNT_ARGUMENTS(RARGUMENTS => STORED_ARGS)
loop
/* Считываение очередного параметра из буфера */
STORED_ARG := PKG_OBJECT_DESC.FETCH_ARGUMENT(RARGUMENTS => STORED_ARGS, IINDEX => I);
/* Добавление эллемента в коллекцию */
RARGS_LIST.EXTEND();
/* Считывание имени параметра */
RARGS_LIST(RARGS_LIST.LAST).ARGUMENT_NAME := STORED_ARG.ARGUMENT_NAME;
/* Считывание типа параметра */
RARGS_LIST(RARGS_LIST.LAST).IN_OUT := STORED_ARG.DB_IN_OUT;
/* Считывание типа данных параметра */
RARGS_LIST(RARGS_LIST.LAST).DATA_TYPE := STORED_ARG.DB_DATA_TYPE;
if (RARGS_LIST(RARGS_LIST.LAST).DATA_TYPE in ('PL/SQL RECORD')) then
P_EXCEPTION(NFLAG_SMART,
'Невозможно проверить интерфейс пользовательской процедуры: поддерживаются только простые типы данных аргументов.');
return;
end if;
/* Установка признака - не проверено */
RARGS_LIST(RARGS_LIST.LAST).CORRECT := 0;
end loop;
/* Проверка переданных параметров */
if (SARGS is not null) then
/* Инициализируем коллекцию ожидаемого списка параметров процедуры */
SARGS_LIST := replace(UPPER(SARGS), ' ', '');
RARGS_LIST_CUR := TARGS_LIST();
/* Цикл по списку параметров */
loop
/* Считывание параметра из списка */
SARG := STRTOK(source => SARGS_LIST, DELIMETER => ';', ITEM => 1);
/* Если пусто - выход из цикла*/
if (SARG is null) then
exit;
end if;
/* Добавление эллемента в коллекцию */
RARGS_LIST_CUR.EXTEND();
/* Установка признака - не проверено */
RARGS_LIST_CUR(RARGS_LIST_CUR.LAST).CORRECT := 0;
/* Считывание имени параметра */
RARGS_LIST_CUR(RARGS_LIST_CUR.LAST).ARGUMENT_NAME := STRTOK(source => SARG, DELIMETER => ',', ITEM => 1);
/* Считывание типа параметра */
RARGS_LIST_CUR(RARGS_LIST_CUR.LAST).IN_OUT := STRTOK(source => SARG, DELIMETER => ',', ITEM => 2);
/* Считывание типа данных параметра */
SARG_TYPE := STRTOK(source => SARG, DELIMETER => ',', ITEM => 3);
SARG_TYPE_NAME := STRTOK(source => SARG_TYPE, DELIMETER => '.', ITEM => 2);
if (SARG_TYPE_NAME is not null) then
/* Если пользовательский тип данных */
P_EXCEPTION(NFLAG_SMART,
'Невозможно проверить интерфейс пользовательской процедуры: поддерживаются только простые типы данных.');
return;
else
/* Если стандартный тип данных */
RARGS_LIST_CUR(RARGS_LIST_CUR.LAST).DATA_TYPE := SARG_TYPE;
end if;
SARG_TYPE := null;
/* Удаление обработанного параметра из текущего списка */
SARGS_LIST := replace(SARGS_LIST, SARG || ';');
end loop;
/* Проверка параметров */
for I in RARGS_LIST_CUR.FIRST .. RARGS_LIST_CUR.LAST
loop
if (RARGS_LIST.COUNT > 0) then
for J in RARGS_LIST.FIRST .. RARGS_LIST.LAST
loop
if (RARGS_LIST_CUR(I).ARGUMENT_NAME = RARGS_LIST(J).ARGUMENT_NAME) then
if ((RARGS_LIST_CUR(I).IN_OUT = RARGS_LIST(J).IN_OUT) and
((RARGS_LIST_CUR(I).DATA_TYPE is null) or (RARGS_LIST_CUR(I).DATA_TYPE = RARGS_LIST(J).DATA_TYPE)) and
(RARGS_LIST(J).CORRECT = 0)) then
RARGS_LIST_CUR(I).CORRECT := 1;
RARGS_LIST(J).CORRECT := 1;
end if;
end if;
end loop;
end if;
end loop;
/* Если хотя бы один параметр не совпадает - ошибка */
NARGS_LIST_CUR_CORRECT := 1;
for I in RARGS_LIST_CUR.FIRST .. RARGS_LIST_CUR.LAST
loop
if (RARGS_LIST_CUR(I).CORRECT = 0) then
NARGS_LIST_CUR_CORRECT := 0;
end if;
end loop;
/* Проверим совпадение и по количеству */
if (RARGS_LIST.COUNT <> RARGS_LIST_CUR.COUNT) then
NARGS_LIST_CUR_CORRECT := 0;
end if;
/* Установка результата */
NRESULT := NARGS_LIST_CUR_CORRECT;
/* Установим сообщение об ожидаемом интерфейсе */
SINTERFACE := RTRIM(replace(replace(replace(UPPER(SARGS), ' ', ''), ',', ' '), ';', ';' || CHR(13)),
';' || CHR(13));
else
/* Если параметры не ожидались и их нет в списке формальных параметров процедуры */
if (RARGS_LIST.COUNT = 0) then
/* То проверка пройдена */
NRESULT := 1;
end if;
/* Установим сообщение об ожидаемом интерфейсе */
SINTERFACE := 'Без параметров';
end if;
/* Если проверка не пройдена */
if (NRESULT = 0) then
/* Выдаём сообщение об ошибке, если просили, с указанием ожидаемого интерфейса процедуры */
P_EXCEPTION(NFLAG_SMART,
'Для процедуры "%s" ожидался следующий интерфейс вызова: %s.',
UTL_STORED_MAKE_LINK(SPROCEDURE => SPRC, SPACKAGE => SPKG),
CHR(13) || SINTERFACE);
end if;
end UTL_STORED_CHECK;
/* Формирование полного наименования контейнера для хранения окружения вызова процедуры */
function UTL_CONTAINER_MAKE_NAME
(
NIDENT in number, -- Идентификатор процесса
SSUB_CONTAINER in varchar2 := null -- Наименование контейнера второго уровня
) return varchar2 -- Полное наименование контейнера
is
/* Формирование полного наименования контейнера */
function CONTAINER_MAKE_NAME
(
SCONT in varchar2, -- Наименование
SPREFIX in varchar2 := null -- Префикс
) return varchar2 -- Полное наименование контейнера
is
begin
/* Проверим параметры */
if (SCONT is null) then
P_EXCEPTION(0, 'Не указано наименование контейнера.');
end if;
/* Сформируем полное наименование с учётом префикса */
if (SPREFIX is null) then
return SCONT;
else
return SPREFIX || '.' || SCONT;
end if;
end;
begin
if (SSUB_CONTAINER is null) then
return TO_CHAR(NIDENT) || CONTAINER_MAKE_NAME(SCONT => SCONT_PRC, SPREFIX => SCONT_MAIN);
else
return TO_CHAR(NIDENT) || CONTAINER_MAKE_NAME(SCONT => SSUB_CONTAINER,
SPREFIX => CONTAINER_MAKE_NAME(SCONT => SCONT_PRC,
SPREFIX => SCONT_MAIN));
end if;
end UTL_CONTAINER_MAKE_NAME;
/* Очистка контейнера для хранения окружения вызова процедуры */
procedure UTL_CONTAINER_PURGE
(
NIDENT in number, -- Идентификатор процесса
SSUB_CONTAINER in varchar2 := null -- Наименование контейнера второго уровня
)
is
begin
PKG_CONTVARGLB.PURGE(SCONTAINER => UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT, SSUB_CONTAINER => SSUB_CONTAINER));
end UTL_CONTAINER_PURGE;
/* Вычисление даты следующего запуска расписания */
function UTL_SCHED_CALC_NEXT_DATE
(
DEXEC_DATE in date, -- Дата предыдущего исполнения
NRETRY_SCHEDULE in number, -- График перезапуска (см. константы NRETRY_SCHEDULE_*)
NRETRY_STEP in number -- Шаг графика перезапуска
) return date -- Дата следующего запуска
is
begin
/* Если нет даты предыдущего запуска или расписание не определено, то дата очередного запуска - это текущая дата */
if (DEXEC_DATE is null) or (NRETRY_SCHEDULE = NRETRY_SCHEDULE_UNDEF) then
/* Отнимим минутку - для верности */
return sysdate -(1 / (24 * 60));
else
/* Расчитаем в зависимости от типа расписания */
case NRETRY_SCHEDULE
/* Ежесекундно */
when NRETRY_SCHEDULE_SEC then
begin
return DEXEC_DATE +(1 / (24 * 60 * 60)) * NRETRY_STEP;
end;
/* Ежеминутно */
when NRETRY_SCHEDULE_MIN then
begin
return DEXEC_DATE +(1 / (24 * 60)) * NRETRY_STEP;
end;
/* Ежечасно */
when NRETRY_SCHEDULE_HOUR then
begin
return DEXEC_DATE +(1 / 24) * NRETRY_STEP;
end;
/* Ежедневно */
when NRETRY_SCHEDULE_DAY then
begin
return DEXEC_DATE + 1 * NRETRY_STEP;
end;
/* Еженедельно */
when NRETRY_SCHEDULE_WEEK then
begin
return DEXEC_DATE +(1 * 7) * NRETRY_STEP;
end;
/* Ежемесячно */
when NRETRY_SCHEDULE_MONTH then
begin
return ADD_MONTHS(DEXEC_DATE, NRETRY_STEP);
end;
/* Неподдерживаемый тип расписания */
else
return null;
end case;
end if;
return null;
exception
when others then
return null;
end UTL_SCHED_CALC_NEXT_DATE;
/* Выяснение необходимости запуска по расписанию */
function UTL_SCHED_CHECK_EXEC
(
DEXEC_DATE in date, -- Дата предыдущего исполнения
NRETRY_SCHEDULE in number, -- График перезапуска (см. константы NRETRY_SCHEDULE_*)
NRETRY_STEP in number, -- Шаг графика перезапуска
DEXEC in date := sysdate -- Дата, относительно которой необходимо выполнить проверку
) return boolean -- Признак необходимости запуска
is
DEXEC_NEXT date; -- Hасчетная дата следующего запуска
begin
/* Расчитаем дату следующего запуска */
DEXEC_NEXT := UTL_SCHED_CALC_NEXT_DATE(DEXEC_DATE => DEXEC_DATE,
NRETRY_SCHEDULE => NRETRY_SCHEDULE,
NRETRY_STEP => NRETRY_STEP);
/* Если не расчиталась - то запускать не можем */
if (DEXEC_NEXT is null) then
return false;
end if;
/* Если она раньше указанной - надо исполнять */
if (DEXEC_NEXT <= DEXEC) then
return true;
end if;
/* Исполять не надо */
return false;
exception
when others then
return false;
end UTL_SCHED_CHECK_EXEC;
/* Установка значения типа строка параметра процедуры обработки сообщения обмена */
procedure PRC_RESP_ARG_STR_SET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2, -- Наименование параметра
SVALUE in varchar2 -- Значение параметра
)
is
SCONTAINER PKG_STD.TSTRING; -- Наименование контейнера
begin
/* Сформируем наименование контейнера */
SCONTAINER := UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT);
/* Установим значение */
PKG_CONTVARGLB.PUTS(SCONTAINER => SCONTAINER, SNAME => SARG, SVALUE => SVALUE);
end PRC_RESP_ARG_STR_SET;
/* Установка значения типа число параметра процедуры обработки сообщения обмена */
procedure PRC_RESP_ARG_NUM_SET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2, -- Наименование параметра
NVALUE in number -- Значение параметра
)
is
SCONTAINER PKG_STD.TSTRING; -- Наименование контейнера
begin
/* Сформируем наименование контейнера */
SCONTAINER := UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT);
/* Установим значение */
PKG_CONTVARGLB.PUTN(SCONTAINER => SCONTAINER, SNAME => SARG, NVALUE => NVALUE);
end PRC_RESP_ARG_NUM_SET;
/* Установка значения типа дата параметра процедуры обработки сообщения обмена */
procedure PRC_RESP_ARG_DATE_SET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2, -- Наименование параметра
DVALUE in date -- Значение параметра
)
is
SCONTAINER PKG_STD.TSTRING; -- Наименование контейнера
begin
/* Сформируем наименование контейнера */
SCONTAINER := UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT);
/* Установим значение */
PKG_CONTVARGLB.PUTD(SCONTAINER => SCONTAINER, SNAME => SARG, DVALUE => DVALUE);
end PRC_RESP_ARG_DATE_SET;
/* Установка значения типа BLOB параметра процедуры обработки сообщения обмена */
procedure PRC_RESP_ARG_BLOB_SET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2, -- Наименование параметра
BVALUE in blob -- Значение параметра
)
is
NFILE_IDENT PKG_STD.TREF; -- Идентификатор буфера для хранения результата обработки
SCONTAINER PKG_STD.TSTRING; -- Наименование контейнера
begin
/* Сформируем наименование контейнера */
SCONTAINER := UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT);
/* Сохраним результаты обработки в файловый буфер */
NFILE_IDENT := GEN_IDENT();
P_FILE_BUFFER_INSERT(NIDENT => NFILE_IDENT, CFILENAME => NFILE_IDENT, CDATA => null, BLOBDATA => BVALUE);
/* Сохраним данные в контейнер */
PKG_CONTVARGLB.PUTN(SCONTAINER => SCONTAINER, SNAME => SARG, NVALUE => NFILE_IDENT);
end PRC_RESP_ARG_BLOB_SET;
/* Считывание значения типа строка параметра процедуры обработки сообщения обмена */
function PRC_RESP_ARG_STR_GET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2 -- Наименование параметра
) return varchar2 -- Значение параметра
is
SCONTAINER PKG_STD.TSTRING; -- Наименование контейнера
begin
/* Сформируем наименование контейнера */
SCONTAINER := UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT);
/* Считаем и вернём значение */
return PKG_CONTVARGLB.GETS(SCONTAINER => SCONTAINER, SNAME => SARG);
end PRC_RESP_ARG_STR_GET;
/* Считывание значения типа число параметра процедуры обработки сообщения обмена */
function PRC_RESP_ARG_NUM_GET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2 -- Наименование параметра
) return number -- Значение параметра
is
SCONTAINER PKG_STD.TSTRING; -- Наименование контейнера
begin
/* Сформируем наименование контейнера */
SCONTAINER := UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT);
/* Считаем и вернём значение */
return PKG_CONTVARGLB.GETN(SCONTAINER => SCONTAINER, SNAME => SARG);
end PRC_RESP_ARG_NUM_GET;
/* Считывание значения типа дата параметра процедуры обработки сообщения обмена */
function PRC_RESP_ARG_DATE_GET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2 -- Наименование параметра
) return date -- Значение параметра
is
SCONTAINER PKG_STD.TSTRING; -- Наименование контейнера
begin
/* Сформируем наименование контейнера */
SCONTAINER := UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT);
/* Считаем и вернём значение */
return PKG_CONTVARGLB.GETD(SCONTAINER => SCONTAINER, SNAME => SARG);
end PRC_RESP_ARG_DATE_GET;
/* Считывание значения типа BLOB параметра процедуры обработки сообщения обмена */
function PRC_RESP_ARG_BLOB_GET
(
NIDENT in number, -- Идентификатор процесса
SARG in varchar2 -- Наименование параметра
) return blob -- Значение параметра
is
NFILE_IDENT PKG_STD.TREF; -- Идентификатор буфера для хранения результата обработки
SCONTAINER PKG_STD.TSTRING; -- Наименование контейнера
BRESP blob; -- Буфер для значения
begin
/* Сформируем наименование контейнера */
SCONTAINER := UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT);
/* Считаем значение идентификатора буфера из контейнера */
NFILE_IDENT := PKG_CONTVARGLB.GETN(SCONTAINER => SCONTAINER, SNAME => SARG);
/* Если идентификатор буфера был в контейнере */
if (NFILE_IDENT is not null) then
/* Заберем результаты обработки из файлового буфера */
begin
select T.BDATA into BRESP from FILE_BUFFER T where T.IDENT = NFILE_IDENT;
exception
when NO_DATA_FOUND then
P_EXCEPTION(0,
'Результаты обработки не найдены в буфере (IDENT: %s).',
TO_CHAR(NFILE_IDENT));
when TOO_MANY_ROWS then
P_EXCEPTION(0,
'Результаты обработки не определены однозначно (IDENT: %s).',
TO_CHAR(NFILE_IDENT));
end;
/* Зачистим файловый буфер */
P_FILE_BUFFER_CLEAR(NIDENT => NFILE_IDENT);
else
/* Идентификатор буфера в контейнере отсутствовал - данных нет */
BRESP := null;
end if;
/* Вернём значение */
return BRESP;
end PRC_RESP_ARG_BLOB_GET;
/* Установка результата исполнения обработчика */
procedure PRC_RESP_RESULT_SET
(
NIDENT in number, -- Идентификатор процесса
SRESULT in varchar2 := SPRC_RESP_RESULT_OK, -- Код результата (см. константы SPRC_RESP_RESULT_*)
BRESP in blob := null, -- Данные ответа
SMSG in varchar2 := null, -- Сообщение обработчика
SCTX in varchar2 := null, -- Контекст
DCTX_EXP in date := null -- Дата истечения контекста
)
is
begin
/* Проверим параметры */
if (SRESULT is not null) then
if (SRESULT not in (SPRC_RESP_RESULT_OK, SPRC_RESP_RESULT_ERR, SPRC_RESP_RESULT_UNAUTH)) then
P_EXCEPTION(0,
'Код результата исполнения обработчика "%s" не поддерживается.',
SRESULT);
end if;
else
P_EXCEPTION(0, 'Не указан код результата исполнения обработчика.');
end if;
/* Сохраняем код результата */
PRC_RESP_ARG_STR_SET(NIDENT => NIDENT, SARG => SCONT_FLD_SRESULT, SVALUE => SRESULT);
/* Сохраняем данные ответа */
PRC_RESP_ARG_BLOB_SET(NIDENT => NIDENT, SARG => SCONT_FLD_BRESP, BVALUE => BRESP);
/* Сохраняем сообщение обработчика */
PRC_RESP_ARG_STR_SET(NIDENT => NIDENT, SARG => SCONT_FLD_SMSG, SVALUE => SMSG);
/* Сохраняем контекст */
PRC_RESP_ARG_STR_SET(NIDENT => NIDENT, SARG => SCONT_FLD_SCTX, SVALUE => SCTX);
/* Сохраняем дату истечения контекста */
PRC_RESP_ARG_DATE_SET(NIDENT => NIDENT, SARG => SCONT_FLD_DCTX_EXP, DVALUE => DCTX_EXP);
end PRC_RESP_RESULT_SET;
/* Считывание результата исполнения обработчика */
procedure PRC_RESP_RESULT_GET
(
NIDENT in number, -- Идентификатор процесса
SRESULT out varchar2, -- Код результата (см. константы SPRC_RESP_RESULT_*)
BRESP out blob, -- Данные ответа
SMSG out varchar2, -- Сообщение обработчика
SCTX out varchar2, -- Контекст
DCTX_EXP out date -- Дата истечения контекста
)
is
begin
/* Считаем код результата */
SRESULT := PRC_RESP_ARG_STR_GET(NIDENT => NIDENT, SARG => SCONT_FLD_SRESULT);
/* Считаем данные ответа */
BRESP := PRC_RESP_ARG_BLOB_GET(NIDENT => NIDENT, SARG => SCONT_FLD_BRESP);
/* Считаем сообщение обработчика */
SMSG := PRC_RESP_ARG_STR_GET(NIDENT => NIDENT, SARG => SCONT_FLD_SMSG);
/* Считаем контекст */
SCTX := PRC_RESP_ARG_STR_GET(NIDENT => NIDENT, SARG => SCONT_FLD_SCTX);
/* Считаем дату истечения контекста */
DCTX_EXP := PRC_RESP_ARG_DATE_GET(NIDENT => NIDENT, SARG => SCONT_FLD_DCTX_EXP);
end PRC_RESP_RESULT_GET;
/* Базовое добавление в буфер отбора документов */
procedure RNLIST_BASE_INSERT
(
NIDENT in number, -- Идентификатор буфера
NDOCUMENT in number, -- Рег. номер записи документа
NRN out number -- Рег. номер добавленной записи буфера
)
is
begin
/* Генерируем рег. номер */
NRN := GEN_ID();
/* Добавляем запись */
insert into EXSRNLIST (RN, IDENT, DOCUMENT) values (NRN, NIDENT, NDOCUMENT);
end RNLIST_BASE_INSERT;
/* Базовое удаление из буфера отбора документов */
procedure RNLINST_BASE_DELETE
(
NRN in number -- Рег. номер записи буфера
)
is
begin
/* Удалим запись */
delete from EXSRNLIST T where T.RN = NRN;
end RNLINST_BASE_DELETE;
/* Базовая очистка буфера отбора документов */
procedure RNLIST_BASE_CLEAR
(
NIDENT in number -- Идентификатор буфера
)
is
begin
/* Обходим буфер */
for C in (select T.RN from EXSRNLIST T where T.IDENT = NIDENT)
loop
/* Удаляем его записи */
RNLINST_BASE_DELETE(NRN => C.RN);
end loop;
end RNLIST_BASE_CLEAR;
/* Получение сервиса */
procedure SERVICE_GET
(
NIDENT in number, -- Идентификатор буфера
RCSERVICE out sys_refcursor -- Курсор со списком сервисов
)
is
begin
/* Отдаём список сервисов в виде курсора */
open RCSERVICE for
select T.RN "nId",
T.CODE "sCode",
T.NAME "sName",
T.SRV_TYPE "nSrvType",
DECODE(T.SRV_TYPE, NSRV_TYPE_SEND, SSRV_TYPE_SEND, NSRV_TYPE_RECIVE, SSRV_TYPE_RECIVE) "sSrvType",
T.SRV_ROOT "sSrvRoot",
T.SRV_USER "sSrvUser",
T.SRV_PASS "sSrvPass",
T.UNAVLBL_NTF_SIGN "nUnavlblNtfSign",
DECODE(T.UNAVLBL_NTF_SIGN,
NUNAVLBL_NTF_SIGN_NO,
SUNAVLBL_NTF_SIGN_NO,
NUNAVLBL_NTF_SIGN_YES,
SUNAVLBL_NTF_SIGN_YES) "sUnavlblNtfSign",
T.UNAVLBL_NTF_TIME "nUnavlblNtfTime",
T.UNAVLBL_NTF_MAIL "sUnavlblNtfMail"
from EXSSERVICE T
where T.RN in (select L.DOCUMENT from EXSRNLIST L where L.IDENT = NIDENT);
end SERVICE_GET;
/* Получение сервиса */
procedure SERVICE_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICE in number, -- Рег. номер записи сервиса
RCSERVICE out sys_refcursor -- Курсор со списком сервисов
)
is
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
NIDENT PKG_STD.TREF; -- Идентификатор буфера
NTMP PKG_STD.TREF; -- Рег. номер очередной записи буфера
begin
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => NFLAG_SMART, NRN => NEXSSERVICE);
/* Сформируем идентификатор буфера */
NIDENT := GEN_IDENT();
/* Положим рег. номер сервиса в буфер */
RNLIST_BASE_INSERT(NIDENT => NIDENT, NDOCUMENT => NVL(REXSSERVICE.RN, NEXSSERVICE), NRN => NTMP);
/* Забираем сервис в виде курсора */
SERVICE_GET(NIDENT => NIDENT, RCSERVICE => RCSERVICE);
/* Чистим буфер */
RNLIST_BASE_CLEAR(NIDENT => NIDENT);
end SERVICE_GET;
/* Получение информации о просроченных сообщениях очереди для сервиса */
procedure SERVICE_QUEUE_EXPIRED_INFO_GET
(
NEXSSERVICE in number, -- Рег. номер записи сервиса
RCSERVICE_QUEUE_EXPIRED_INFO out sys_refcursor -- Курсор со сведениями о просроченных сообщениях сервиса
)
is
/* Локальные константы */
NMAX_SINFO_LIST_LEN constant PKG_STD.TNUMBER := 4000; -- Максимальная длинна списка с информацией о просроченных сообщениях
SDELIM constant varchar2(10) := chr(10); -- Разделитель списка с информацией о просроченных сообщениях
/* Локальные переменные */
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
NCNT PKG_STD.TNUMBER := 0; -- Количество просроченных сообщений
SINFO_LIST PKG_STD.TSTRING; -- Список с информацией о просроченных сообщениях
SPREF PKG_STD.TSTRING; -- Возвращаемый префикс списка с информацией о просроченных сообщениях
SPREF_FULL PKG_STD.TSTRING; -- Префикс полного списка с информацией о просроченных сообщениях
SPREF_SOME PKG_STD.TSTRING; -- Префикс неполного (если не вся информация вошла) списка с информацией о просроченных сообщениях
begin
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => NEXSSERVICE);
/* Инициализируем префексы */
SPREF_FULL := 'Список просроченных сообщений обмена для сервиса "' || REXSSERVICE.CODE || '":' || CHR(10);
SPREF_SOME := 'Наиболее поздние сообщения обмена из числа просроченных для сервиса "' || REXSSERVICE.CODE || '":' ||
CHR(10);
SPREF := SPREF_FULL;
/* Обходим все сообщения в любом статусе, кроме финальных, для которых установлен лимит нахождения в очереди и он превышен */
for C in (select 'Р/н: ' || TO_CHAR(Q.RN) || ', ф-я: ' || FN.CODE || ', от ' ||
TO_CHAR(Q.IN_DATE, 'dd.mm.yyyy hh24:mi:ss') SINFO
from EXSSERVICEFN FN,
EXSMSGTYPE MT,
EXSQUEUE Q
where FN.PRN = REXSSERVICE.RN
and FN.EXSMSGTYPE = MT.RN
and FN.RN = Q.EXSSERVICEFN
and MT.MAX_IDLE > 0
and Q.EXEC_STATE not in (NQUEUE_EXEC_STATE_OK, NQUEUE_EXEC_STATE_ERR)
and ROUND(24 * 60 * (sysdate - Q.IN_DATE)) > MT.MAX_IDLE
order by Q.IN_DATE)
loop
/* Инкремент количества */
NCNT := NCNT + 1;
/* Собираем информацию в список */
if ((NVL(LENGTH(SINFO_LIST), 0) + LENGTH(C.SINFO) + LENGTH(SDELIM) +
GREATEST(NVL(LENGTH(SPREF_FULL), 0), NVL(LENGTH(SPREF_SOME), 0))) <= NMAX_SINFO_LIST_LEN) then
if (SINFO_LIST is null) then
SINFO_LIST := C.SINFO;
else
SINFO_LIST := SINFO_LIST || SDELIM || C.SINFO;
end if;
else
SPREF := SPREF_SOME;
end if;
end loop;
/* Возвращаем ответ в виде курсора */
open RCSERVICE_QUEUE_EXPIRED_INFO for
select REXSSERVICE.RN "nId",
NCNT "nCnt",
DECODE(NCNT, 0, null, SPREF || SINFO_LIST) "sInfoList"
from DUAL;
end SERVICE_QUEUE_EXPIRED_INFO_GET;
/* Получение контекста сервиса */
procedure SERVICE_CTX_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICE in number, -- Рег. номер записи сервиса
RCSERVICE_CTX out sys_refcursor -- Курсор со контектом сервиса
)
is
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
begin
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => NFLAG_SMART, NRN => NEXSSERVICE);
/* Открываем выходной курсор */
open RCSERVICE_CTX for
select T.RN "nId",
T.CTX "sCtx",
T.CTX_EXP "dCtxExp",
TO_CHAR(T.CTX_EXP, 'dd.mm.yyyy hh24:mi:ss') "sCtxExp",
T.IS_AUTH "nIsAuth",
DECODE(T.IS_AUTH, NIS_AUTH_YES, SIS_AUTH_YES, NIS_AUTH_NO, SIS_AUTH_NO) "sIsAuth"
from EXSSERVICE T
where T.RN = REXSSERVICE.RN;
end SERVICE_CTX_GET;
/* Установка контекста сервиса */
procedure SERVICE_CTX_SET
(
NEXSSERVICE in number, -- Рег. номер записи сервиса
SCTX in varchar2, -- Контекст
DCTX_EXP in date := null -- Дата истечения контекста
)
is
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
begin
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => NEXSSERVICE);
/* Проверим, что контекст есть */
if (SCTX is null) then
P_EXCEPTION(0, 'Не указан контекст работы сервиса.');
end if;
/* Устанавливаем контекст */
update EXSSERVICE T
set T.CTX = SCTX,
T.CTX_EXP = DCTX_EXP,
T.IS_AUTH = NIS_AUTH_YES
where T.RN = REXSSERVICE.RN;
end SERVICE_CTX_SET;
/* Очистка контекста сервиса */
procedure SERVICE_CTX_CLEAR
(
NEXSSERVICE in number -- Рег. номер записи сервиса
)
is
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
begin
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => NEXSSERVICE);
/* Устанавливаем контекст */
update EXSSERVICE T
set T.CTX = null,
T.CTX_EXP = null,
T.IS_AUTH = NIS_AUTH_NO
where T.RN = REXSSERVICE.RN;
end SERVICE_CTX_CLEAR;
/* Проверка аутентифицированности сервиса */
function SERVICE_IS_AUTH
(
NEXSSERVICE in number -- Рег. номер записи сервиса
) return number -- Флаг аутентификации (см. константы NIS_AUTH_*)
is
NRES PKG_STD.TNUMBER; -- Результат работы
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
begin
/* инициализируем результат */
NRES := NIS_AUTH_NO;
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => NEXSSERVICE);
/* Если сервис аутентифицирован */
if (REXSSERVICE.IS_AUTH = NIS_AUTH_YES) then
/* Если указана дата исчетечения аутентификации */
if (REXSSERVICE.CTX_EXP is not null) then
/* Если дата истечения ещё не наступила */
if (REXSSERVICE.CTX_EXP > sysdate) then
/* То он аутентифицирован */
NRES := NIS_AUTH_YES;
end if;
else
/* Даты нет - считаем его аутентифицированным */
NRES := NIS_AUTH_YES;
end if;
end if;
/* Вернем результат работы */
return NRES;
end SERVICE_IS_AUTH;
/* Поиск функции аутентификации (начала сеанса) для сервиса обмена */
procedure SERVICE_AUTH_FN_FIND
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICE in number, -- Рег. номер записи сервиса
REXSSERVICEFN out EXSSERVICEFN%rowtype -- Запись функции аутентификации
)
is
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
begin
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => NFLAG_SMART, NRN => NEXSSERVICE);
/* Если сервис считался */
if (REXSSERVICE.RN is not null) then
/* Ищем функцию */
begin
select T.*
into REXSSERVICEFN
from EXSSERVICEFN T
where T.PRN = REXSSERVICE.RN
and T.FN_TYPE = NFN_TYPE_LOGIN;
exception
when TOO_MANY_ROWS then
P_EXCEPTION(NFLAG_SMART,
'Для сервиса обмена "%s" функция аутентификации определена неоднозначно.',
REXSSERVICE.CODE);
when NO_DATA_FOUND then
P_EXCEPTION(NFLAG_SMART,
'Для сервиса обмена "%s" не определена функция аутентификации.',
REXSSERVICE.CODE);
end;
end if;
end SERVICE_AUTH_FN_FIND;
/* Поиск функции отмены аутентификации (завершения сеанса) для сервиса обмена */
procedure SERVICE_UNAUTH_FN_FIND
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICE in number, -- Рег. номер записи сервиса
REXSSERVICEFN out EXSSERVICEFN%rowtype -- Запись функции аутентификации
)
is
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
begin
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => NFLAG_SMART, NRN => NEXSSERVICE);
/* Если сервис считался */
if (REXSSERVICE.RN is not null) then
/* Ищем функцию */
begin
select T.*
into REXSSERVICEFN
from EXSSERVICEFN T
where T.PRN = REXSSERVICE.RN
and T.FN_TYPE = NFN_TYPE_LOGOUT;
exception
when TOO_MANY_ROWS then
P_EXCEPTION(NFLAG_SMART,
'Для сервиса обмена "%s" функция отмены аутентификации определена неоднозначно.',
REXSSERVICE.CODE);
when NO_DATA_FOUND then
P_EXCEPTION(NFLAG_SMART,
'Для сервиса обмена "%s" не определена функция отмены аутентификации.',
REXSSERVICE.CODE);
end;
end if;
end SERVICE_UNAUTH_FN_FIND;
/* Помещение задания на аутентификацию (начало сеанса) сервиса в очередь обмена */
procedure SERVICE_AUTH_PUT_INQUEUE
(
NEXSSERVICE in number -- Рег. номер сервиса обмена
)
is
pragma autonomous_transaction;
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
REXSSERVICEFN_AUTH EXSSERVICEFN%rowtype; -- Запись функции аутентификации
NAUTH_EXSQUEUE PKG_STD.TREF; -- Рег. номер позиции очереди для атуентификации
begin
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => NEXSSERVICE);
/* Работаем только для сервисов отправки сообщений */
if (REXSSERVICE.SRV_TYPE = NSRV_TYPE_SEND) then
/* Проверим, что сервис ещё не аутентифицирован */
if (SERVICE_IS_AUTH(NEXSSERVICE => REXSSERVICE.RN) = PKG_EXS.NIS_AUTH_NO) then
/* Ищем функцию осуществляющую аутентификацию */
SERVICE_AUTH_FN_FIND(NFLAG_SMART => 0, NEXSSERVICE => REXSSERVICE.RN, REXSSERVICEFN => REXSSERVICEFN_AUTH);
/* Проверяем, что в очереди ещё пока нет запросов на аутентификацию */
if (not SERVICEFN_CHECK_INCMPL_INQUEUE(NEXSSERVICEFN => REXSSERVICEFN_AUTH.RN)) then
/* Зачищаем текущий контекст сервиса */
SERVICE_CTX_CLEAR(NEXSSERVICE => REXSSERVICEFN_AUTH.PRN);
/* Регистрируем в очереди задание на аутентификацию */
QUEUE_PUT(NEXSSERVICEFN => REXSSERVICEFN_AUTH.RN, BMSG => null, NNEW_EXSQUEUE => NAUTH_EXSQUEUE);
end if;
commit;
else
P_EXCEPTION(0,
'Сервис уже аутентифицирован - сначала необходимо завершить текущий сеанс.');
end if;
else
P_EXCEPTION(0,
'Только удалённый клиент может начинать сеанс для сервиса типа "Приём сообщений".');
end if;
end SERVICE_AUTH_PUT_INQUEUE;
/* Помещение задания на отмену аутентификации (завершение сеанса) сервиса в очередь обмена */
procedure SERVICE_UNAUTH_PUT_INQUEUE
(
NEXSSERVICE in number -- Рег. номер сервиса обмена
)
is
pragma autonomous_transaction;
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса
REXSSERVICEFN_UNAUTH EXSSERVICEFN%rowtype; -- Запись функции отмены аутентификации
NUNAUTH_EXSQUEUE PKG_STD.TREF; -- Рег. номер позиции очереди для отмены атуентификации
begin
/* Считаем запись сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => NEXSSERVICE);
/* Работаем только для сервисов отправки сообщений */
if (REXSSERVICE.SRV_TYPE = NSRV_TYPE_SEND) then
/* Проверим, что сервис аутентифицирован */
if (SERVICE_IS_AUTH(NEXSSERVICE => REXSSERVICE.RN) = PKG_EXS.NIS_AUTH_YES) then
/* Ищем функцию осуществляющую отмену аутентификации */
SERVICE_UNAUTH_FN_FIND(NFLAG_SMART => 1, NEXSSERVICE => REXSSERVICE.RN, REXSSERVICEFN => REXSSERVICEFN_UNAUTH);
/* Если функция найдена */
if (REXSSERVICEFN_UNAUTH.RN is not null) then
/* Проверяем, что в очереди ещё пока нет запросов на отмену аутентификации */
if (not SERVICEFN_CHECK_INCMPL_INQUEUE(NEXSSERVICEFN => REXSSERVICEFN_UNAUTH.RN)) then
/* Регистрируем в очереди задание на отмену аутентификации */
QUEUE_PUT(NEXSSERVICEFN => REXSSERVICEFN_UNAUTH.RN, BMSG => null, NNEW_EXSQUEUE => NUNAUTH_EXSQUEUE);
end if;
else
/* Функции отмены аутентификации нет - просто зачищаем текущий контекст сервиса */
SERVICE_CTX_CLEAR(NEXSSERVICE => REXSSERVICE.RN);
end if;
commit;
else
P_EXCEPTION(0,
'Сервис не аутентифицирован - сначала необходимо начать сеанс.');
end if;
else
P_EXCEPTION(0,
'Только удалённый клиент может завершать сеанс для сервиса типа "Приём сообщений".');
end if;
end SERVICE_UNAUTH_PUT_INQUEUE;
/* Получение списка сервисов */
procedure SERVICES_GET
(
RCSERVICES out sys_refcursor -- Курсор со списком сервисов
)
is
NIDENT PKG_STD.TREF; -- Идентификатор буфера
NTMP PKG_STD.TREF; -- Рег. номер очередной записи буфера
begin
/* Сформируем идентификатор буфера */
NIDENT := GEN_IDENT();
/* Обходим нужные сервисы */
for C in (select T.RN from EXSSERVICE T)
loop
/* Запоминаем их рег. номера в буфере */
RNLIST_BASE_INSERT(NIDENT => NIDENT, NDOCUMENT => C.RN, NRN => NTMP);
end loop;
/* Забираем отобранные сервисы */
SERVICE_GET(NIDENT => NIDENT, RCSERVICE => RCSERVICES);
/* Чистим буфер */
RNLIST_BASE_CLEAR(NIDENT => NIDENT);
end SERVICES_GET;
/* Получение списка сервисов требующих аутентификации */
procedure SERVICES_AUTH_GET
(
RCSERVICES_AUTH out sys_refcursor -- Курсор со списком сервисов требующих аутентификации
)
is
NIDENT PKG_STD.TREF; -- Идентификатор буфера
NTMP PKG_STD.TREF; -- Рег. номер очередной записи буфера
begin
/* Сформируем идентификатор буфера */
NIDENT := GEN_IDENT();
/* Обходим нужные сервисы */
for C in (select T.RN
from EXSSERVICE T
where T.IS_AUTH = NIS_AUTH_NO
and exists (select FN.RN
from EXSSERVICEFN FN
where FN.PRN = T.RN
and FN.FN_TYPE = NFN_TYPE_LOGIN)
and exists (select FN.RN
from EXSSERVICEFN FN
where FN.PRN = T.RN
and FN.AUTH_ONLY = NAUTH_ONLY_YES
and FN.FN_TYPE <> NFN_TYPE_LOGIN))
loop
/* Запоминаем их рег. номера в буфере */
RNLIST_BASE_INSERT(NIDENT => NIDENT, NDOCUMENT => C.RN, NRN => NTMP);
end loop;
/* Забираем отобранные сервисы */
SERVICE_GET(NIDENT => NIDENT, RCSERVICE => RCSERVICES_AUTH);
/* Чистим буфер */
RNLIST_BASE_CLEAR(NIDENT => NIDENT);
end SERVICES_AUTH_GET;
/* Получение функции сервиса */
procedure SERVICEFN_GET
(
NIDENT in number, -- Идентификатор буфера
RCSERVICEFN out sys_refcursor -- Курсор со списком функций сервиса
)
is
begin
/* Отдаём список функций в виде курсора */
open RCSERVICEFN for
select T.RN "nId",
T.PRN "nServiceId",
T.CODE "sCode",
T.FN_TYPE "nFnType",
DECODE(T.FN_TYPE,
NFN_TYPE_DATA,
SFN_TYPE_DATA,
NFN_TYPE_LOGIN,
SFN_TYPE_LOGIN,
NFN_TYPE_LOGOUT,
SFN_TYPE_LOGOUT) "sFnType",
T.FN_URL "sFnURL",
T.FN_PRMS_TYPE "nFnPrmsType",
DECODE(T.FN_PRMS_TYPE, NFN_PRMS_TYPE_POST, SFN_PRMS_TYPE_POST, NFN_PRMS_TYPE_GET, SFN_PRMS_TYPE_GET) "sFnPrmsType",
T.RETRY_SCHEDULE "nRetrySchedule",
DECODE(T.RETRY_SCHEDULE,
NRETRY_SCHEDULE_UNDEF,
SRETRY_SCHEDULE_UNDEF,
NRETRY_SCHEDULE_SEC,
SRETRY_SCHEDULE_SEC,
NRETRY_SCHEDULE_MIN,
SRETRY_SCHEDULE_MIN,
NRETRY_SCHEDULE_HOUR,
SRETRY_SCHEDULE_HOUR,
NRETRY_SCHEDULE_DAY,
SRETRY_SCHEDULE_DAY,
NRETRY_SCHEDULE_WEEK,
SRETRY_SCHEDULE_WEEK,
NRETRY_SCHEDULE_MONTH,
SRETRY_SCHEDULE_MONTH) "sRetrySchedule",
T.EXSMSGTYPE "nMsgId",
M.CODE "sMsgCode",
DECODE(M.PRC_RESP, null, null, UTL_STORED_MAKE_LINK(M.PRC_RESP, M.PKG_RESP)) "sPrcResp",
M.APPSRV_BEFORE "sAppSrvBefore",
M.APPSRV_AFTER "sAppSrvAfter",
T.AUTH_ONLY "nAuthOnly",
DECODE(T.AUTH_ONLY, NAUTH_ONLY_NO, SAUTH_ONLY_NO, NAUTH_ONLY_YES, SAUTH_ONLY_YES) "sAuthOnly",
T.ERR_NTF_SIGN "nErrNtfSign",
DECODE(T.ERR_NTF_SIGN, NERR_NTF_SIGN_NO, SERR_NTF_SIGN_NO, NERR_NTF_SIGN_YES, SERR_NTF_SIGN_YES) "sErrNtfSign",
T.ERR_NTF_MAIL "sErrNtfMail"
from EXSSERVICEFN T,
EXSMSGTYPE M
where T.RN in (select L.DOCUMENT from EXSRNLIST L where L.IDENT = NIDENT)
and T.EXSMSGTYPE = M.RN;
end SERVICEFN_GET;
/* Получение функции сервиса */
procedure SERVICEFN_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSSERVICEFN in number, -- Рег. номер функции сервиса
RCSERVICEFN out sys_refcursor -- Курсор со списком функций сервиса
)
is
REXSSERVICEFN EXSSERVICEFN%rowtype; -- Запись функции сервиса
NIDENT PKG_STD.TREF; -- Идентификатор буфера
NTMP PKG_STD.TREF; -- Рег. номер очередной записи буфера
begin
/* Считаем запись функции сервиса */
REXSSERVICEFN := GET_EXSSERVICEFN_ID(NFLAG_SMART => NFLAG_SMART, NRN => NEXSSERVICEFN);
/* Сформируем идентификатор буфера */
NIDENT := GEN_IDENT();
/* Положим рег. номер функции сервиса в буфер */
RNLIST_BASE_INSERT(NIDENT => NIDENT, NDOCUMENT => NVL(REXSSERVICEFN.RN, NEXSSERVICEFN), NRN => NTMP);
/* Забираем сервис в виде курсора */
SERVICEFN_GET(NIDENT => NIDENT, RCSERVICEFN => RCSERVICEFN);
/* Чистим буфер */
RNLIST_BASE_CLEAR(NIDENT => NIDENT);
end SERVICEFN_GET;
/* Получение списка функций сервиса */
procedure SERVICEFNS_GET
(
NEXSSERVICE in number, -- Рег. номер записи сервиса
RCSERVICEFNS out sys_refcursor -- Курсор со списком функций
)
is
NIDENT PKG_STD.TREF; -- Идентификатор буфера
NTMP PKG_STD.TREF; -- Рег. номер очередной записи буфера
begin
/* Сформируем идентификатор буфера */
NIDENT := GEN_IDENT();
/* Обходим функции сервиса */
for C in (select T.RN from EXSSERVICEFN T where T.PRN = NEXSSERVICE)
loop
/* Запоминаем их рег. номера в буфере */
RNLIST_BASE_INSERT(NIDENT => NIDENT, NDOCUMENT => C.RN, NRN => NTMP);
end loop;
/* Забираем отобранные функции сервиса */
SERVICEFN_GET(NIDENT => NIDENT, RCSERVICEFN => RCSERVICEFNS);
/* Чистим буфер */
RNLIST_BASE_CLEAR(NIDENT => NIDENT);
end SERVICEFNS_GET;
/* Поиск функции сервиса обмена по коду функции и коду сервиса */
function SERVICEFN_FIND_BY_SRVCODE
(
NFLAG_SMART in number, -- Признак генерации исключения (0 - да, 1 - нет)
SEXSSERVICE in varchar2, -- Мнемокод сервиса для обработки
SEXSSERVICEFN in varchar2 -- Мнемокод функции сервиса для обработки
) return number -- Рег. номер функции сервиса обмена
is
NEXSSERVICE PKG_STD.TREF; -- Рег. номер сервиса обработки
NEXSSERVICEFN PKG_STD.TREF; -- Рег. номер функции сервиса обработки
begin
/* Найдем функцию сервиса обработки */
FIND_EXSSERVICE_CODE(NFLAG_SMART => NFLAG_SMART, NFLAG_OPTION => 0, SCODE => SEXSSERVICE, NRN => NEXSSERVICE);
/* Найдем функцию сервиса обработки */
FIND_EXSSERVICEFN_CODE(NFLAG_SMART => NFLAG_SMART,
NFLAG_OPTION => 0,
NEXSSERVICE => NEXSSERVICE,
SCODE => SEXSSERVICEFN,
NRN => NEXSSERVICEFN);
/* Вернем результат */
return NEXSSERVICEFN;
end SERVICEFN_FIND_BY_SRVCODE;
/* Проверка наличия в очереди неисполненного задания для указанной функции сервиса обмена */
function SERVICEFN_CHECK_INCMPL_INQUEUE
(
NEXSSERVICEFN in number -- Рег. номер записи функции сервиса обмена
) return boolean -- Результат проверки (true - в очереди есть неисполненные задания для данной функции, false - в очереди нет неисполненных заданий для данной функции)
is
NCNT PKG_STD.TNUMBER; -- Количество найденных записей очереди
begin
/* Проверим очередь */
select count(Q.RN)
into NCNT
from EXSQUEUE Q
where Q.EXSSERVICEFN = NEXSSERVICEFN
and Q.EXEC_STATE not in (NQUEUE_EXEC_STATE_OK, NQUEUE_EXEC_STATE_ERR);
/* Если не нашли ничего в очереди... */
if (NCNT = 0) then
/* ...скажем что заданий нет */
return false;
else
/* Если нашли - скажем что задания есть */
return true;
end if;
exception
when others then
P_EXCEPTION(0,
'Ошибка определения наличия в очереди заданий для функции (RN: %s) сервиса обмена: %s.',
TO_CHAR(NEXSSERVICEFN),
sqlerrm);
end SERVICEFN_CHECK_INCMPL_INQUEUE;
/* Считывание записи журнала работы */
procedure LOG_GET
(
NIDENT in number, -- Идентификатор буфера
RCLOG out sys_refcursor -- Курсор со списком записей журнала работы
)
is
begin
/* Отдаём запись в виде курсора */
open RCLOG for
select T.RN "nId",
T.LOG_DATE "dLogDate",
TO_CHAR(T.LOG_DATE, 'dd.mm.yyyy hh24:mi:ss') "sLogDate",
T.LOG_STATE "nLogState",
DECODE(T.LOG_STATE,
NLOG_STATE_INF,
SLOG_STATE_INF,
NLOG_STATE_WRN,
SLOG_STATE_WRN,
NLOG_STATE_ERR,
SLOG_STATE_ERR) "sLogState",
T.MSG "sMsg",
T.EXSSERVICE "nServiceId",
S.CODE "sServiceCode",
T.EXSSERVICEFN "nServiceFnId",
SFN.CODE "sServiceFnCode",
T.EXSQUEUE "nQueueId"
from EXSLOG T,
EXSSERVICE S,
EXSSERVICEFN SFN
where T.RN in (select L.DOCUMENT from EXSRNLIST L where L.IDENT = NIDENT)
and T.EXSSERVICE = S.RN(+)
and T.EXSSERVICEFN = SFN.RN(+);
end LOG_GET;
/* Считывание записи журнала работы */
procedure LOG_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSLOG in number, -- Рег. номер записи журнала
RCLOG out sys_refcursor -- Курсор со списком записей журнала работы
)
is
REXSLOG EXSLOG%rowtype; -- Запись журнала работы
NIDENT PKG_STD.TREF; -- Идентификатор буфера
NTMP PKG_STD.TREF; -- Рег. номер очередной записи буфера
begin
/* Считаем запись журнала работы */
REXSLOG := GET_EXSLOG_ID(NFLAG_SMART => NFLAG_SMART, NRN => NEXSLOG);
/* Сформируем идентификатор буфера */
NIDENT := GEN_IDENT();
/* Положим рег. номер записи журнала работы в буфер */
RNLIST_BASE_INSERT(NIDENT => NIDENT, NDOCUMENT => NVL(REXSLOG.RN, NEXSLOG), NRN => NTMP);
/* Забираем позицию очереди в виде курсора */
LOG_GET(NIDENT => NIDENT, RCLOG => RCLOG);
/* Чистим буфер */
RNLIST_BASE_CLEAR(NIDENT => NIDENT);
end LOG_GET;
/* Добавление записи в журнал работы */
procedure LOG_PUT
(
NLOG_STATE in number, -- Тип записи (см. констнаты NLOG_STATE*)
SMSG in varchar2, -- Сообщение
NEXSSERVICE in number := null, -- Рег. номер связанного сервиса
NEXSSERVICEFN in number := null, -- Рег. номер связанной функции сервиса
NEXSQUEUE in number := null, -- Рег. номер связанной записи очереди
RCLOG out sys_refcursor -- Курсор со списком сервисов
)
is
NEXSSERVICE_ EXSSERVICE.RN%type; -- Рег. номер связанного сервиса (для автоматического определения)
NEXSSERVICEFN_ EXSSERVICEFN.RN%type; -- Рег. номер связанной функции сервиса (для автоматического определения)
NEXSLOG PKG_STD.TREF; -- Рег. номер добавленной записи журнала
begin
/* Проинициализирем переопределенные функцию и сервис */
NEXSSERVICE_ := NEXSSERVICE;
NEXSSERVICEFN_ := NEXSSERVICEFN;
/* Если задана функция сервиса - определяем по ней сервис */
if (NEXSSERVICEFN is not null) then
begin
select T.PRN into NEXSSERVICE_ from EXSSERVICEFN T where T.RN = NEXSSERVICEFN;
exception
when NO_DATA_FOUND then
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEXSSERVICEFN, SUNIT_TABLE => 'EXSSERVICEFN');
end;
end if;
/* Если задана позиция очереди - определяем по ней и функцию и сервис */
if (NEXSQUEUE is not null) then
begin
select SFN.PRN,
SFN.RN
into NEXSSERVICE_,
NEXSSERVICEFN_
from EXSQUEUE T,
EXSSERVICEFN SFN
where T.RN = NEXSQUEUE
and T.EXSSERVICEFN = SFN.RN;
exception
when NO_DATA_FOUND then
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEXSQUEUE, SUNIT_TABLE => 'EXSQUEUE');
end;
end if;
/* Добавим запись в протокол работы */
P_EXSLOG_BASE_INSERT(DLOG_DATE => sysdate,
NLOG_STATE => NLOG_STATE,
SMSG => SMSG,
NEXSSERVICE => NEXSSERVICE_,
NEXSSERVICEFN => NEXSSERVICEFN_,
NEXSQUEUE => NEXSQUEUE,
NRN => NEXSLOG);
/* Вернем добавленную запись */
LOG_GET(NFLAG_SMART => 0, NEXSLOG => NEXSLOG, RCLOG => RCLOG);
end LOG_PUT;
/* Считывание сообщения из очереди */
procedure QUEUE_GET
(
NIDENT in number, -- Идентификатор буфера
RCQUEUE out sys_refcursor -- Курсор с позицией очереди
)
is
begin
open RCQUEUE for
select T.RN "nId",
T.IN_DATE "dInDate",
TO_CHAR(T.IN_DATE, 'dd.mm.yyyy hh24:mi:ss') "sInDate",
T.IN_AUTHID "sInAuth",
S.RN "nServiceId",
S.CODE "sServiceCode",
T.EXSSERVICEFN "nServiceFnId",
F.CODE "sServiceFnCode",
T.EXEC_DATE "dExecDate",
TO_CHAR(T.EXEC_DATE, 'dd.mm.yyyy hh24:mi:ss') "sExecDate",
T.EXEC_CNT "nExecCnt",
F.RETRY_ATTEMPTS "nRetryAttempts",
T.EXEC_STATE "nExecState",
DECODE(T.EXEC_STATE,
NQUEUE_EXEC_STATE_INQUEUE,
SQUEUE_EXEC_STATE_INQUEUE,
NQUEUE_EXEC_STATE_APP,
SQUEUE_EXEC_STATE_APP,
NQUEUE_EXEC_STATE_APP_OK,
SQUEUE_EXEC_STATE_APP_OK,
NQUEUE_EXEC_STATE_APP_ERR,
SQUEUE_EXEC_STATE_APP_ERR,
NQUEUE_EXEC_STATE_DB,
SQUEUE_EXEC_STATE_DB,
NQUEUE_EXEC_STATE_DB_OK,
SQUEUE_EXEC_STATE_DB_OK,
NQUEUE_EXEC_STATE_DB_ERR,
SQUEUE_EXEC_STATE_DB_ERR,
NQUEUE_EXEC_STATE_OK,
SQUEUE_EXEC_STATE_OK,
NQUEUE_EXEC_STATE_ERR,
SQUEUE_EXEC_STATE_ERR) "sExecState",
T.EXEC_MSG "sExecMsg",
T.EXSQUEUE "nQueueId"
from EXSQUEUE T,
EXSSERVICEFN F,
EXSSERVICE S
where T.RN in (select L.DOCUMENT from EXSRNLIST L where L.IDENT = NIDENT)
and T.EXSSERVICEFN = F.RN
and F.PRN = S.RN;
end QUEUE_GET;
/* Считывание сообщения из очереди */
procedure QUEUE_GET
(
NFLAG_SMART in number, -- Признак выдачи сообщения об ошибке
NEXSQUEUE in number, -- Рег. номер записи очереди
RCQUEUE out sys_refcursor -- Курсор с позицией очереди
)
is
REXSQUEUE EXSQUEUE%rowtype; -- Запись позиции очереди
NIDENT PKG_STD.TREF; -- Идентификатор буфера
NTMP PKG_STD.TREF; -- Рег. номер очередной записи буфера
begin
/* Считаем запись позиции очереди */
REXSQUEUE := GET_EXSQUEUE_ID(NFLAG_SMART => NFLAG_SMART, NRN => NEXSQUEUE);
/* Сформируем идентификатор буфера */
NIDENT := GEN_IDENT();
/* Положим рег. номер записи очереди в буфер */
RNLIST_BASE_INSERT(NIDENT => NIDENT, NDOCUMENT => NVL(REXSQUEUE.RN, NEXSQUEUE), NRN => NTMP);
/* Забираем позицию очереди в виде курсора */
QUEUE_GET(NIDENT => NIDENT, RCQUEUE => RCQUEUE);
/* Чистим буфер */
RNLIST_BASE_CLEAR(NIDENT => NIDENT);
end QUEUE_GET;
/* Проверка необходимости исполнения позиции очереди */
function QUEUE_SRV_TYPE_SEND_EXEC_CHECK
(
NEXSQUEUE in number -- Рег. номер записи очереди
) return number -- Флаг необходимости исполнения позиции очереди (см. константы NQUEUE_EXEC_*)
is
REXSQUEUE EXSQUEUE%rowtype; -- Запись позиции очереди
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса обработки
REXSSERVICEFN EXSSERVICEFN%rowtype; -- Запись функции обработки
NRESULT PKG_STD.TNUMBER; -- Результат работы
begin
/* Инициализируем результат */
NRESULT := NQUEUE_EXEC_NO;
begin
/* Считаем запись очереди */
REXSQUEUE := GET_EXSQUEUE_ID(NFLAG_SMART => 0, NRN => NEXSQUEUE);
/* Считаем запись функции обработки */
REXSSERVICEFN := GET_EXSSERVICEFN_ID(NFLAG_SMART => 0, NRN => REXSQUEUE.EXSSERVICEFN);
/* Считаем запись сервиса обработки */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => REXSSERVICEFN.PRN);
/* Проверим условия исполнения - исходящее, недоисполнено, и остались попытки, требует аутентификации и сервис аутентифицирован */
if ((REXSSERVICE.SRV_TYPE = NSRV_TYPE_SEND) and
(REXSQUEUE.EXEC_STATE not in
(NQUEUE_EXEC_STATE_OK, NQUEUE_EXEC_STATE_ERR, NQUEUE_EXEC_STATE_APP, NQUEUE_EXEC_STATE_DB)) and
(((REXSSERVICEFN.RETRY_SCHEDULE <> NRETRY_SCHEDULE_UNDEF) and
(REXSQUEUE.EXEC_CNT < REXSSERVICEFN.RETRY_ATTEMPTS)) or
((REXSSERVICEFN.RETRY_SCHEDULE = NRETRY_SCHEDULE_UNDEF) and (REXSQUEUE.EXEC_CNT = 0))) and
(UTL_SCHED_CHECK_EXEC(DEXEC_DATE => REXSQUEUE.EXEC_DATE,
NRETRY_SCHEDULE => REXSSERVICEFN.RETRY_SCHEDULE,
NRETRY_STEP => REXSSERVICEFN.RETRY_STEP)) and
((REXSSERVICEFN.AUTH_ONLY = NAUTH_ONLY_NO) or
((REXSSERVICEFN.AUTH_ONLY = NAUTH_ONLY_YES) and (REXSSERVICE.IS_AUTH = NIS_AUTH_YES)))) then
/* Надо исполнять */
NRESULT := NQUEUE_EXEC_YES;
end if;
exception
when others then
NRESULT := NQUEUE_EXEC_NO;
end;
/* Вернём результат */
return NRESULT;
end QUEUE_SRV_TYPE_SEND_EXEC_CHECK;
/* Считывание очередной порции исходящих сообщений из очереди */
procedure QUEUE_SRV_TYPE_SEND_GET
(
NPORTION_SIZE in number, -- Количество выбираемых сообщений
RCQUEUES out sys_refcursor -- Курсор со списком позиций очереди
)
is
NIDENT PKG_STD.TREF; -- Идентификатор буфера
NTMP PKG_STD.TREF; -- Рег. номер очередной записи буфера
begin
/* Сформируем идентификатор буфера */
NIDENT := GEN_IDENT();
/* Обходим требуемые исходящие сообщения */
for C in (select *
from (select T.RN
from EXSQUEUE T
where QUEUE_SRV_TYPE_SEND_EXEC_CHECK(T.RN) = NQUEUE_EXEC_YES
order by T.RN)
where ROWNUM <= NPORTION_SIZE)
loop
/* Запоминаем их рег. номера в буфере */
RNLIST_BASE_INSERT(NIDENT => NIDENT, NDOCUMENT => C.RN, NRN => NTMP);
end loop;
/* Забираем отобранные записи очереди */
QUEUE_GET(NIDENT => NIDENT, RCQUEUE => RCQUEUES);
/* Чистим буфер */
RNLIST_BASE_CLEAR(NIDENT => NIDENT);
end QUEUE_SRV_TYPE_SEND_GET;
/* Установка состояние записи очереди */
procedure QUEUE_EXEC_STATE_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
NEXEC_STATE in number, -- Устанавливаемое состояние (см. констнаты NQUEUE_EXEC_STATE_*, null - не менять)
SEXEC_MSG in varchar2, -- Сообщение обработчика
NINC_EXEC_CNT in number, -- Флаг инкремента счётчика исполнений (см. констнаты NINC_EXEC_CNT_*, null - не менять)
NRESET_DATA in number, -- Флаг сброса данных сообщения (см. констатнты NQUEUE_RESET_DATA_NO*, null - не сбрасывать)
RCQUEUE out sys_refcursor -- Курсор с изменённой позицией очереди
)
is
REXSQUEUE EXSQUEUE%rowtype; -- Запись позиции очереди
begin
/* Проверям параметры */
if (NEXSQUEUE is null) then
P_EXCEPTION(0,
'Не указан идентификатор позиции очереди для изменения состояния.');
end if;
if ((NEXEC_STATE is not null) and
(NEXEC_STATE not in (NQUEUE_EXEC_STATE_INQUEUE,
NQUEUE_EXEC_STATE_APP,
NQUEUE_EXEC_STATE_APP_OK,
NQUEUE_EXEC_STATE_APP_ERR,
NQUEUE_EXEC_STATE_DB,
NQUEUE_EXEC_STATE_DB_OK,
NQUEUE_EXEC_STATE_DB_ERR,
NQUEUE_EXEC_STATE_OK,
NQUEUE_EXEC_STATE_ERR))) then
P_EXCEPTION(0,
'Код состояния "%s" позиции очереди не поддерживается.',
TO_CHAR(NEXEC_STATE));
end if;
if (NVL(NINC_EXEC_CNT, NINC_EXEC_CNT_NO) not in (NINC_EXEC_CNT_YES, NINC_EXEC_CNT_NO)) then
P_EXCEPTION(0,
'Флаг икремента счетчика исполнений "%s" позиции очереди не поддерживается.',
TO_CHAR(NINC_EXEC_CNT));
end if;
/* Считаем запись очереди */
REXSQUEUE := GET_EXSQUEUE_ID(NFLAG_SMART => 0, NRN => NEXSQUEUE);
/* Увеличим счётчик количества попыток исполнения, если просили */
if (NVL(NINC_EXEC_CNT, NINC_EXEC_CNT_NO) = NINC_EXEC_CNT_YES) then
REXSQUEUE.EXEC_CNT := REXSQUEUE.EXEC_CNT + 1;
end if;
/* Выставим состояние */
update EXSQUEUE T
set T.EXEC_DATE = sysdate,
T.EXEC_STATE = NVL(NEXEC_STATE, T.EXEC_STATE),
T.EXEC_CNT = REXSQUEUE.EXEC_CNT,
T.EXEC_MSG = SEXEC_MSG,
T.MSG = DECODE(NVL(NRESET_DATA, NQUEUE_RESET_DATA_NO), NQUEUE_RESET_DATA_NO, T.MSG, T.MSG_ORIGINAL),
T.RESP = DECODE(NVL(NRESET_DATA, NQUEUE_RESET_DATA_NO), NQUEUE_RESET_DATA_NO, T.RESP, null)
where T.RN = NEXSQUEUE;
if (sql%rowcount = 0) then
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEXSQUEUE, SUNIT_TABLE => 'EXSQUEUE');
end if;
/* Вернем измененную позицию очереди */
QUEUE_GET(NFLAG_SMART => 0, NEXSQUEUE => NEXSQUEUE, RCQUEUE => RCQUEUE);
end QUEUE_EXEC_STATE_SET;
/* Считывание данных результата обработки записи очереди */
procedure QUEUE_RESP_GET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
RCQUEUE_RESP out sys_refcursor -- Курсор с данными результата обработки записи очереди
)
is
REXSQUEUE EXSQUEUE%rowtype; -- Запись позиции очереди
begin
/* Считаем запись очереди */
REXSQUEUE := GET_EXSQUEUE_ID(NFLAG_SMART => 0, NRN => NEXSQUEUE);
/* Вернем данные в виде курсора */
open RCQUEUE_RESP for
select REXSQUEUE.RESP "blResp" from DUAL;
end QUEUE_RESP_GET;
/* Установка результата обработки записи очереди */
procedure QUEUE_RESP_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
BRESP in blob, -- Результат обработки
NIS_ORIGINAL in number := NIS_ORIGINAL_NO -- Признак передачи оригинального результата обработки (см. константы NIS_ORIGINAL*, null - не оригинал)
)
is
begin
/* Выставим результат */
update EXSQUEUE T
set T.RESP = BRESP,
T.RESP_ORIGINAL = DECODE(NVL(NIS_ORIGINAL, NIS_ORIGINAL_NO), NIS_ORIGINAL_NO, T.RESP_ORIGINAL, BRESP)
where T.RN = NEXSQUEUE;
if (sql%rowcount = 0) then
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEXSQUEUE, SUNIT_TABLE => 'EXSQUEUE');
end if;
end QUEUE_RESP_SET;
/* Установка результата обработки записи очереди (возвращает измененную позицию очереди) */
procedure QUEUE_RESP_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
BRESP in blob, -- Результат обработки
NIS_ORIGINAL in number := NIS_ORIGINAL_NO, -- Признак передачи оригинального результата обработки (см. константы NIS_ORIGINAL*, null - не оригинал)
RCQUEUE out sys_refcursor -- Курсор с изменённой позицией очереди
)
is
begin
/* Выставим результат */
QUEUE_RESP_SET(NEXSQUEUE => NEXSQUEUE, BRESP => BRESP, NIS_ORIGINAL => NIS_ORIGINAL);
/* Вернем измененную позицию очереди */
QUEUE_GET(NFLAG_SMART => 0, NEXSQUEUE => NEXSQUEUE, RCQUEUE => RCQUEUE);
end QUEUE_RESP_SET;
/* Считывание данных сообщения записи очереди */
procedure QUEUE_MSG_GET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
RCQUEUE_MSG out sys_refcursor -- Курсор с данными сообщения записи очереди
)
is
REXSQUEUE EXSQUEUE%rowtype; -- Запись позиции очереди
begin
/* Считаем запись очереди */
REXSQUEUE := GET_EXSQUEUE_ID(NFLAG_SMART => 0, NRN => NEXSQUEUE);
/* Вернем данные в виде курсора */
open RCQUEUE_MSG for
select REXSQUEUE.MSG "blMsg" from DUAL;
end QUEUE_MSG_GET;
/* Установка сообщения записи очереди */
procedure QUEUE_MSG_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
BMSG in blob -- Результат обработки
)
is
begin
/* Выставим сообщение */
update EXSQUEUE T set T.MSG = BMSG where T.RN = NEXSQUEUE;
if (sql%rowcount = 0) then
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEXSQUEUE, SUNIT_TABLE => 'EXSQUEUE');
end if;
end QUEUE_MSG_SET;
/* Установка сообщения записи очереди (возвращает измененную позицию очереди) */
procedure QUEUE_MSG_SET
(
NEXSQUEUE in number, -- Рег. номер записи очереди
BMSG in blob, -- Результат обработки
RCQUEUE out sys_refcursor -- Курсор с изменённой позицией очереди
)
is
begin
/* Выставим сообщение */
QUEUE_MSG_SET(NEXSQUEUE => NEXSQUEUE, BMSG => BMSG);
/* Вернем измененную позицию очереди */
QUEUE_GET(NFLAG_SMART => 0, NEXSQUEUE => NEXSQUEUE, RCQUEUE => RCQUEUE);
end QUEUE_MSG_SET;
/* Помещение сообщения обмена в очередь */
procedure QUEUE_PUT
(
NEXSSERVICEFN in number, -- Рег. номер функции обработки
BMSG in blob, -- Данные
NEXSQUEUE in number := null, -- Рег. номер связанной позиции очереди
NLNK_COMPANY in number := null, -- Рег. номер связанной организации
NLNK_DOCUMENT in number := null, -- Рег. номер связанной записи документа
SLNK_UNITCODE in varchar2 := null, -- Код связанного раздела
SOPTIONS in varchar2 := null, -- Параметры сообщения
NNEW_EXSQUEUE out number -- Рег. номер добавленной позиции очереди
)
is
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса обработки
REXSSERVICEFN EXSSERVICEFN%rowtype; -- Запись функции обработки
begin
/* Проверяем параметры */
if (NEXSSERVICEFN is null) then
P_EXCEPTION(0, 'Не указан идентификатор функции сервиса обмена.');
end if;
/* Считаем запись функции обработки */
REXSSERVICEFN := GET_EXSSERVICEFN_ID(NFLAG_SMART => 0, NRN => NEXSSERVICEFN);
/* Считаем запись сервиса обработки */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => REXSSERVICEFN.PRN);
/* Если это исходящее сообщение и функция требует аутентификации */
if ((REXSSERVICE.SRV_TYPE = NSRV_TYPE_SEND) and (REXSSERVICEFN.AUTH_ONLY = NAUTH_ONLY_YES)) then
/* Проверим необходимость аутентификации */
if (SERVICE_IS_AUTH(NEXSSERVICE => REXSSERVICE.RN) = NIS_AUTH_NO) then
/* Нужна аутентификация - поставим в очередь задание для неё */
SERVICE_AUTH_PUT_INQUEUE(NEXSSERVICE => REXSSERVICE.RN);
end if;
end if;
/* Ставим запись в очередь */
P_EXSQUEUE_BASE_INSERT(DIN_DATE => sysdate,
SIN_AUTHID => UTILIZER(),
NEXSSERVICEFN => REXSSERVICEFN.RN,
DEXEC_DATE => null,
NEXEC_CNT => 0,
NEXEC_STATE => NQUEUE_EXEC_STATE_INQUEUE,
SEXEC_MSG => null,
BMSG => BMSG,
BRESP => null,
NEXSQUEUE => NEXSQUEUE,
NLNK_COMPANY => NLNK_COMPANY,
NLNK_DOCUMENT => NLNK_DOCUMENT,
SLNK_UNITCODE => SLNK_UNITCODE,
SOPTIONS => SOPTIONS,
NRN => NNEW_EXSQUEUE);
end QUEUE_PUT;
/* Помещение сообщения обмена в очередь (возвращает курсор с добавленной записью) */
procedure QUEUE_PUT
(
NEXSSERVICEFN in number, -- Рег. номер функции обработки
BMSG in blob, -- Данные
NEXSQUEUE in number := null, -- Рег. номер связанной позиции очереди
NLNK_COMPANY in number := null, -- Рег. номер связанной организации
NLNK_DOCUMENT in number := null, -- Рег. номер связанной записи документа
SLNK_UNITCODE in varchar2 := null, -- Код связанного раздела
SOPTIONS in varchar2 := null, -- Параметры сообщения
RCQUEUE out sys_refcursor -- Курсор с добавленной позицией очереди
)
is
NRN EXSQUEUE.RN%type; -- Рег. номер добавленной записи очереди
begin
/* Проверяем параметры */
QUEUE_PUT(NEXSSERVICEFN => NEXSSERVICEFN,
BMSG => BMSG,
NEXSQUEUE => NEXSQUEUE,
NLNK_COMPANY => NLNK_COMPANY,
NLNK_DOCUMENT => NLNK_DOCUMENT,
SLNK_UNITCODE => SLNK_UNITCODE,
SOPTIONS => SOPTIONS,
NNEW_EXSQUEUE => NRN);
/* Возвращаем добавленную позицию очереди */
QUEUE_GET(NFLAG_SMART => 0, NEXSQUEUE => NRN, RCQUEUE => RCQUEUE);
end QUEUE_PUT;
/* Помещение сообщения обмена в очередь (по коду сервиса и функции обрабоки) */
procedure QUEUE_PUT
(
SEXSSERVICE in varchar2, -- Мнемокод сервиса для обработки
SEXSSERVICEFN in varchar2, -- Мнемокод функции сервиса для обработки
BMSG in blob, -- Данные
NEXSQUEUE in number := null, -- Рег. номер связанной позиции очереди
NLNK_COMPANY in number := null, -- Рег. номер связанной организации
NLNK_DOCUMENT in number := null, -- Рег. номер связанной записи документа
SLNK_UNITCODE in varchar2 := null, -- Код связанного раздела
SOPTIONS in varchar2 := null, -- Параметры сообщения
NNEW_EXSQUEUE out number -- Рег. номер добавленной позиции очереди
)
is
NEXSSERVICEFN PKG_STD.TREF; -- Рег. номер функции сервиса обработки
begin
/* Проверяем параметры */
if (SEXSSERVICE is null) then
P_EXCEPTION(0, 'Не указан код сервиса обмена.');
end if;
if (SEXSSERVICEFN is null) then
P_EXCEPTION(0, 'Не указан код функции сервиса обмена.');
end if;
/* Разыменуем функцию сервиса */
NEXSSERVICEFN := SERVICEFN_FIND_BY_SRVCODE(NFLAG_SMART => 0,
SEXSSERVICE => SEXSSERVICE,
SEXSSERVICEFN => SEXSSERVICEFN);
/* Ставим запись в очередь */
QUEUE_PUT(NEXSSERVICEFN => NEXSSERVICEFN,
BMSG => BMSG,
NEXSQUEUE => NEXSQUEUE,
NLNK_COMPANY => NLNK_COMPANY,
NLNK_DOCUMENT => NLNK_DOCUMENT,
SLNK_UNITCODE => SLNK_UNITCODE,
SOPTIONS => SOPTIONS,
NNEW_EXSQUEUE => NNEW_EXSQUEUE);
end QUEUE_PUT;
/* Помещение сообщения обмена в очередь (по коду сервиса и функции обрабоки, возвращает курсор с добавленной записью) */
procedure QUEUE_PUT
(
SEXSSERVICE in varchar2, -- Мнемокод сервиса для обработки
SEXSSERVICEFN in varchar2, -- Мнемокод функции сервиса для обработки
BMSG in blob, -- Данные
NEXSQUEUE in number := null, -- Рег. номер связанной позиции очереди
NLNK_COMPANY in number := null, -- Рег. номер связанной организации
NLNK_DOCUMENT in number := null, -- Рег. номер связанной записи документа
SLNK_UNITCODE in varchar2 := null, -- Код связанного раздела
SOPTIONS in varchar2 := null, -- Параметры сообщения
RCQUEUE out sys_refcursor -- Курсор с добавленной позицией очереди
)
is
NRN EXSQUEUE.RN%type; -- Рег. номер добавленной записи очереди
begin
/* Ставим запись в очередь */
QUEUE_PUT(SEXSSERVICE => SEXSSERVICE,
SEXSSERVICEFN => SEXSSERVICEFN,
BMSG => BMSG,
NEXSQUEUE => NEXSQUEUE,
NLNK_COMPANY => NLNK_COMPANY,
NLNK_DOCUMENT => NLNK_DOCUMENT,
SLNK_UNITCODE => SLNK_UNITCODE,
SOPTIONS => SOPTIONS,
NNEW_EXSQUEUE => NRN);
/* Возвращаем добавленную позицию очереди */
QUEUE_GET(NFLAG_SMART => 0, NEXSQUEUE => NRN, RCQUEUE => RCQUEUE);
end QUEUE_PUT;
/* Исполнение обработчика для сообщения обмена */
procedure QUEUE_PRC
(
NEXSQUEUE in number, -- Рег. номер записи очереди
RCRESULT out sys_refcursor -- Курсор с результатами обработки
)
is
REXSQUEUE EXSQUEUE%rowtype; -- Запись позиции очереди
REXSSERVICE EXSSERVICE%rowtype; -- Запись сервиса обработки
REXSSERVICEFN EXSSERVICEFN%rowtype; -- Запись функции обработки
REXSMSGTYPE EXSMSGTYPE%rowtype; -- Запись типового сообщения обмена
NIDENT PKG_STD.TREF; -- Идентификатор процесса обработки
SRESULT PKG_STD.TSTRING; -- Буфер для результата: код результата
BRESP blob; -- Буфер для результата: данные ответа
SMSG PKG_STD.TSTRING; -- Буфер для результата: сообщение обработчика
SCTX PKG_STD.TSTRING; -- Буфер для результата: контекст
DCTX_EXP PKG_STD.TLDATE; -- Буфер для результата: дата истечения контекста
PRMS PKG_CONTPRMLOC.TCONTAINER; -- Контейнер для параметров процедуры обработки
begin
/* Считаем запись очереди */
REXSQUEUE := GET_EXSQUEUE_ID(NFLAG_SMART => 0, NRN => NEXSQUEUE);
/* Считаем запись функции обработки */
REXSSERVICEFN := GET_EXSSERVICEFN_ID(NFLAG_SMART => 0, NRN => REXSQUEUE.EXSSERVICEFN);
/* Считаем запись сервиса обработки */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => REXSSERVICEFN.PRN);
/* Считаем запись типового сообщения */
REXSMSGTYPE := GET_EXSMSGTYPE_ID(NFLAG_SMART => 0, NRN => REXSSERVICEFN.EXSMSGTYPE);
/* Запустим обработчик, если он есть */
if (REXSMSGTYPE.PRC_RESP is not null) then
begin
/* Проверяем интерфейс обработчика */
UTL_STORED_CHECK(NFLAG_SMART => 0,
SPKG => REXSMSGTYPE.PKG_RESP,
SPRC => REXSMSGTYPE.PRC_RESP,
SARGS => SPRC_RESP_ARGS,
NRESULT => NIDENT);
/* Формируем идентификатор процесса */
NIDENT := GEN_IDENT();
/* Установим значения фиксированных входных параметров */
PKG_CONTPRMLOC.APPENDN(RCONTAINER => PRMS,
SNAME => 'NIDENT',
NVALUE => NIDENT,
NIN_OUT => PKG_STD.IPARAM_TYPE_IN);
PKG_CONTPRMLOC.APPENDN(RCONTAINER => PRMS,
SNAME => 'NEXSQUEUE',
NVALUE => REXSQUEUE.RN,
NIN_OUT => PKG_STD.IPARAM_TYPE_IN);
/* Исполняем процедуру */
PKG_SQL_CALL.EXECUTE_STORED(SSTORED_NAME => UTL_STORED_MAKE_LINK(SPACKAGE => REXSMSGTYPE.PKG_RESP,
SPROCEDURE => REXSMSGTYPE.PRC_RESP),
RPARAM_CONTAINER => PRMS);
/* Очистим контейнер параметров */
PKG_CONTPRMLOC.PURGE(RCONTAINER => PRMS);
/* Забираем результаты */
PRC_RESP_RESULT_GET(NIDENT => NIDENT,
SRESULT => SRESULT,
BRESP => BRESP,
SMSG => SMSG,
SCTX => SCTX,
DCTX_EXP => DCTX_EXP);
/* Если код результата установлен */
if (SRESULT is not null) then
/* И если результат успешен - применим его */
if (SRESULT = SPRC_RESP_RESULT_OK) then
/* Зафиксируем результат обработки (для входящих - всегда, для исходящих - только если не пустой) */
if ((REXSSERVICE.SRV_TYPE = NSRV_TYPE_RECIVE) or
((REXSSERVICE.SRV_TYPE = NSRV_TYPE_SEND) and (BRESP is not null) and (DBMS_LOB.GETLENGTH(BRESP) > 0))) then
QUEUE_RESP_SET(NEXSQUEUE => REXSQUEUE.RN, BRESP => BRESP, NIS_ORIGINAL => NIS_ORIGINAL_NO);
end if;
/* Если это была функция начала сеанса */
if (REXSSERVICEFN.FN_TYPE = NFN_TYPE_LOGIN) then
/* Если обработчик вернул контекст */
if (SCTX is not null) then
/* Пропишем его сервису, вне зависимости от того, что там было до этого */
SERVICE_CTX_SET(NEXSSERVICE => REXSSERVICE.RN, SCTX => SCTX, DCTX_EXP => DCTX_EXP);
else
/* Обработчик не вернул контекста, проверим, есть ли он сейчас у сервиса */
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => REXSSERVICEFN.PRN);
if (REXSSERVICE.CTX is null) then
/* Обработчик не вернул контекст и сейчас он не установлен для сервиса, это проблема - больше обработок не будет значит мы не залогинились */
P_EXCEPTION(0,
'Функция начала сеанса "%s" не установила контекст работы для сервиса "%s".',
REXSSERVICEFN.CODE,
REXSSERVICE.CODE);
end if;
end if;
end if;
/* Если это была функция завершения сеанса */
if (REXSSERVICEFN.FN_TYPE = NFN_TYPE_LOGOUT) then
/* Удалим контекст сервиса */
SERVICE_CTX_CLEAR(NEXSSERVICE => REXSSERVICE.RN);
end if;
else
/* Во всех остальных случаях - откатываем транзакцию, т.к. есть какие-то ошибки обработки */
rollback;
end if;
else
/* Результат не установлен - это ошибка */
P_EXCEPTION(0,
'Процедура обработчик "%s" не вернула результат работы.',
UTL_STORED_MAKE_LINK(SPACKAGE => REXSMSGTYPE.PKG_RESP, SPROCEDURE => REXSMSGTYPE.PRC_RESP));
end if;
exception
when others then
rollback;
SRESULT := SPRC_RESP_RESULT_ERR;
SMSG := sqlerrm;
end;
else
/* Обработчика нет и нет проблем */
SRESULT := SPRC_RESP_RESULT_OK;
SMSG := null;
end if;
/* Возвращаем результат в виде курсора */
open RCRESULT for
select SRESULT "sResult",
DECODE(SRESULT,
SPRC_RESP_RESULT_OK,
null,
SPRC_RESP_RESULT_ERR,
NVL(SMSG, 'Неопределённая ошибка'),
SPRC_RESP_RESULT_UNAUTH,
NVL(SMSG, 'Нет аутентификации')) "sMsg"
from DUAL;
end QUEUE_PRC;
end;
/