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; -- Сбрасывать /* Константы - ожидаемый интерфейс процедуры обработки сообщения очереди на стороне БД */ 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, -- Список параметров (";" - разделитель аргументов, "," - разделитель атрибутов аргумента, формат: <АРГУМЕНТ>,,<ТИП ДАННЫХ 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_GET ( NEXSSERVICE in number, -- Рег. номер записи сервиса RCSERVICE_QUEUE_EXPIRED 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_AUTH_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 -- Результат обработки ); /* Установка результата обработки записи очереди (возвращает измененную позицию очереди) */ procedure QUEUE_RESP_SET ( NEXSQUEUE in number, -- Рег. номер записи очереди BRESP in blob, -- Результат обработки 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, -- Список параметров (";" - разделитель аргументов, "," - разделитель атрибутов аргумента, формат: <АРГУМЕНТ>,,<ТИП ДАННЫХ 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, 'Ошибочный формат списка аргументов: используйте ";" для разделения аргументов в списке и "," для разделения атрибутов аргумента: <АРГУМЕНТ>,,<ТИП ДАННЫХ 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_GET ( NEXSSERVICE in number, -- Рег. номер записи сервиса RCSERVICE_QUEUE_EXPIRED 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 for select NCNT "nCnt", DECODE(NCNT, 0, null, SPREF || SINFO_LIST) "sInfoList" from DUAL; end SERVICE_QUEUE_EXPIRED_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_AUTH_PUT_INQUEUE ( NEXSSERVICE in number -- Рег. номер сервиса обмена ) is pragma autonomous_transaction; REXSSERVICEFN_AUTH EXSSERVICEFN%rowtype; -- Запись функции аутентификации NAUTH_EXSQUEUE PKG_STD.TREF; -- Рег. номер позиции очереди для атуентификации begin /* Ищем функцию её осуществляющую аутентификацию */ SERVICE_AUTH_FN_FIND(NFLAG_SMART => 0, NEXSSERVICE => NEXSSERVICE, REXSSERVICEFN => REXSSERVICEFN_AUTH); /* Проверяем, что в очереди ещё пока нет запросов на аутентификацию */ if (not SERVICEFN_CHECK_INCMPL_INQUEUE(NEXSSERVICEFN => REXSSERVICEFN_AUTH.RN)) then /* Зачищаем текущий контекст сервиса */ SERVICE_CTX_CLEAR(NEXSSERVICE => REXSSERVICEFN_AUTH.PRN); /* Регистрируем в очереди задание на аутентификацию */ P_EXSQUEUE_BASE_INSERT(DIN_DATE => sysdate, SIN_AUTHID => UTILIZER(), NEXSSERVICEFN => REXSSERVICEFN_AUTH.RN, DEXEC_DATE => null, NEXEC_CNT => 0, NEXEC_STATE => NQUEUE_EXEC_STATE_INQUEUE, SEXEC_MSG => null, BMSG => null, BRESP => null, NEXSQUEUE => null, NLNK_COMPANY => null, NLNK_DOCUMENT => null, SLNK_UNITCODE => null, SOPTIONS => null, NRN => NAUTH_EXSQUEUE); end if; commit; end SERVICE_AUTH_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 -- Результат обработки ) is begin /* Выставим результат */ update EXSQUEUE T set T.RESP = 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, -- Результат обработки RCQUEUE out sys_refcursor -- Курсор с изменённой позицией очереди ) is begin /* Выставим результат */ QUEUE_RESP_SET(NEXSQUEUE => NEXSQUEUE, BRESP => BRESP); /* Вернем измененную позицию очереди */ 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); 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; /