P8-Panels/db/PKG_P8PANELS_QE_BASE.pck

2960 lines
136 KiB
SQL
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_P8PANELS_QE_BASE as
/* Типы данных - Аргумент */
type TARG is record
(
SNAME PKG_STD.TSTRING, -- Имя
STITLE PKG_STD.TSTRING, -- Заголовок
NDATA_TYPE PKG_STD.TNUMBER, -- Тип данных (см. константы PKG_STD.DATA_TYPE_*)
NMANDATORY PKG_STD.TNUMBER, -- Флаг обязательности (1 - да, 0 - нет)
SVALUE PKG_STD.TLSTRING -- Значение для отладки (строковое представление для всех типов данных)
);
/* Типы данных - Коллекция аргументов */
type TARGS is table of TARG;
/* Типы данных - Настройка запроса */
type TOPT is record
(
RARGS TARGS, -- Аргументы
SCOND PKG_STD.TSTRING -- Условия отбора
);
/* Типы данных - Атрибут сущности */
type TATTR is record
(
SID PKG_STD.TSTRING, -- Уникальный идентификатор в запросе
SPARENT_ENTITY PKG_STD.TSTRING, -- Идентификатор родительской сущности
SNAME PKG_STD.TSTRING, -- Имя
STITLE PKG_STD.TSTRING, -- Заголовок
NDATA_TYPE PKG_STD.TNUMBER, -- Тип данных (см. константы PKG_STD.DATA_TYPE_*)
SAGG PKG_STD.TSTRING, -- Агрегатная функция
SALIAS PKG_STD.TSTRING, -- Псевдоним в выборке
NUSE PKG_STD.TNUMBER, -- Флаг применения в запросе (1 - да, 0 - нет)
NSHOW PKG_STD.TNUMBER -- Флаг отображения в выборке (1 - да, 0 - нет)
);
/* Типы данных - Коллекция атрибутов сущности */
type TATTRS is table of TATTR;
/* Типы данных - Сущность */
type TENT is record
(
SID PKG_STD.TSTRING, -- Уникальный идентификатор в запросе
SNAME PKG_STD.TSTRING, -- Имя
STITLE PKG_STD.TSTRING, -- Заголовок
STYPE PKG_STD.TSTRING, -- Тип (см. константы SENT_TYPE_*)
NX PKG_STD.TNUMBER := 0, -- Координата по оси абсцисс
NY PKG_STD.TNUMBER := 0, -- Координата по оси ординат
RATTRS TATTRS -- Атрибуты
);
/* Типы данных - Коллекция сущностей */
type TENTS is table of TENT;
/* Типы данных - Отношение */
type TRL is record
(
SID PKG_STD.TSTRING, -- Уникальный идентификатор в запросе
SSOURCE PKG_STD.TSTRING, -- Идентификатор атрибута-источника
STARGET PKG_STD.TSTRING, -- Идентификатор атрибута-приёмника
NMANDATORY PKG_STD.TNUMBER -- Флаг обязательности (1 - да, 0 - нет)
);
/* Типы данных - Коллекция отношений */
type TRLS is table of TRL;
/* Получение заголовка представления из метаданных */
function DMSCLVIEWS_TITLE_GET
(
SVIEW_NAME in varchar2 -- Имя представления
) return varchar2; -- Заголовок представления из метаданных
/* Поиск индекса атрибута по псевдониму */
function TATTRS_INDEX_BY_ALIAS
(
RATTRS in TATTRS, -- Коллекция атрибутов
SALIAS in varchar2 -- Искомый псевдоним
) return number; -- Индекс найденного атрибута (null - если не найдено)
/* Десериализация коллекции атрибутов сущности (из BASE64) */
function TATTRS_FROM_XML_BASE64
(
CXML in clob, -- XML-описание коллекции атрибутов сущности (BASE64)
SCHARSET in varchar2, -- Кодировка, в которой XML-данные были упакованы в BASE64
BADD_ROOT in boolean := false -- Флаг необходимости добавления корневого тэга (false - нет, true - да)
) return TATTRS; -- Коллекция атрибутов сущности
/* Проверка корректности атрибутов сущности */
procedure TATTRS_CHECK
(
RATTRS in TATTRS, -- Коллекция атрибутов сущности
SCHECK_MSG out varchar2 -- Сообщения проверки (null - ошибок нет)
);
/* Поиск индекса аргумента по имени */
function TARGS_INDEX_BY_NAME
(
RARGS in TARGS, -- Коллекция аргументов
SNAME in varchar2 -- Искомое имя
) return number; -- Индекс найденного аргумента (null - если не найдено)
/* Добавление аргумента в коллекцию */
procedure TARGS_ADD
(
RARGS in out nocopy TARGS, -- Изменяемая коллекция
SNAME in varchar2, -- Имя
STITLE in varchar2, -- Заголовок
NDATA_TYPE in number, -- Тип данных (см. константы PKG_STD.DATA_TYPE_*)
NMANDATORY in number, -- Флаг обязательности (1 - да, 0 - нет)
SVALUE in varchar2 -- Значение для отладки (строковое представление для всех типов данных)
);
/* Изменение аргумента в коллекции */
procedure TARGS_EDIT
(
RARGS in out nocopy TARGS, -- Изменяемая коллекция
NINDEX in number, -- Индекс изменяемого аргумента
SNAME in varchar2, -- Имя
STITLE in varchar2, -- Заголовок
NDATA_TYPE in number, -- Тип данных (см. константы PKG_STD.DATA_TYPE_*)
NMANDATORY in number, -- Флаг обязательности (1 - да, 0 - нет)
SVALUE in varchar2 -- Значение для отладки (строковое представление для всех типов данных)
);
/* Удаление аргумента из коллекции */
procedure TARGS_REMOVE
(
RARGS in out nocopy TARGS, -- Изменяемая коллекция
SNAME in varchar2 -- Имя удаляемого аргумента
);
/* Поиск индекса сущности по идентификатору */
function TENTS_INDEX_BY_ID
(
RENTS in TENTS, -- Коллекция сущностей
SID in varchar2 -- Искомый идентификатор
) return number; -- Индекс найденной сущности (null - если не найдено)
/* Добавление сущности в коллекцию */
procedure TENTS_ADD
(
RENTS in out nocopy TENTS, -- Изменяемая коллекция
SNAME in varchar2, -- Имя
STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*)
NINIT_ATTRS in number := 1 -- Флаг инициализации атрибутов сущности (0 - нет, 1 - да)
);
/* Удаление сущности из коллекции */
procedure TENTS_REMOVE
(
RENTS in out nocopy TENTS, -- Изменяемая коллекция
SID in varchar2 -- Идентификатор удялемой сущности
);
/* Установка координат сущности в коллекции */
procedure TENTS_POSITION_SET
(
RENTS in out nocopy TENTS, -- Изменяемая коллекция
SID in varchar2, -- Идентификатор сущности
NX in number, -- Координата по оси абсцисс
NY in number -- Координата по оси ординат
);
/* Добавление связи в коллекцию */
procedure TRLS_ADD
(
RRLS in out nocopy TRLS, -- Изменяемая коллекция
SSOURCE in varchar2, -- Источник
STARGET in varchar2, -- Приёмник
NMANDATORY in number -- Флаг обязательности (1 - да, 0 - нет)
);
/* Удаление связи из коллекции */
procedure TRLS_REMOVE
(
RRLS in out nocopy TRLS, -- Изменяемая коллекция
SID in varchar2 -- Идентификатор удялемой связи
);
/* Установка признака обязательности связи в коллекции */
procedure TRLS_MANDATORY_SET
(
RRLS in out nocopy TRLS, -- Изменяемая коллекция
SID in varchar2, -- Идентификатор связи
NMANDATORY in number -- Флаг обязательности (1 - да, 0 - нет)
);
/* Подчистка коллекции связей по атрибуту */
procedure TRLS_CLEANUP_BY_ATTR
(
RRLS in out nocopy TRLS, -- Изменяемая коллекция
SATTR_ID in varchar2 -- Идентификатор атрибута
);
/* Формирование списка доступных сущностей */
function ENTITY_LIST
(
SSEARCH in varchar2, -- Поисковый запрос
NBRIEF in number, -- Флаг формирования описания сущности в кратком формате (0 - нет, 1 - да)
NINCLUDE_ATTRS in number -- Флаг включения в ответ атрибутов сущности (0 - нет, 1 - да)
) return clob; -- Список сущностей
/* Считывание записи запроса */
function QUERY_GET
(
NRN in number -- Рег. номер запроса
) return P8PNL_QE_QUERY%rowtype; -- Запись запроса
/* Получение признака возможности изменения запроса */
function QUERY_ACCESS_SIGN_MODIFY
(
NRN in number, -- Рег. номер запроса
SUSER in varchar2 -- Имя пользователя
) return number; -- Признак возможности изменения запроса (0 - нет, 1 - да)
/* Проверка возможности изменения запроса */
procedure QUERY_ACCESS_MODIFY
(
NRN in number, -- Рег. номер запроса
SUSER in varchar2 -- Имя пользователя
);
/* Получение признака возможности просмотра запроса */
function QUERY_ACCESS_SIGN_VIEW
(
NRN in number, -- Рег. номер запроса
SUSER in varchar2 -- Имя пользователя
) return number; -- Признак возможности просмотра запроса (0 - нет, 1 - да)
/* Проверка возможности просмотра запроса */
procedure QUERY_ACCESS_VIEW
(
NRN in number, -- Рег. номер запроса
SUSER in varchar2 -- Имя пользователя
);
/* Формирование описания запроса */
function QUERY
(
NRN in number -- Рег. номер запроса
) return clob; -- XML-описание
/* Формирование списка запросов */
function QUERY_LIST
(
SUSER in varchar2 -- Имя пользователя
) return clob; -- Список запросов
/* Добавление запроса */
procedure QUERY_INSERT
(
SCODE in varchar2, -- Мнемокод
SNAME in varchar2, -- Наименование
NRN out number -- Рег. номер добавленного запроса
);
/* Исправление запроса */
procedure QUERY_UPDATE
(
NRN in number, -- Рег. номер запроса
SCODE in varchar2, -- Мнемокод
SNAME in varchar2 -- Наименование
);
/* Удаление запроса */
procedure QUERY_DELETE
(
NRN in number -- Рег. номер запроса
);
/* Чтение сущностей запроса */
function QUERY_ENTS_GET
(
CENTS in clob -- Сериализованное описание сущностей
) return TENTS; -- Коллекция сущностей
/* Запись сущностей запроса */
procedure QUERY_ENTS_SET
(
NRN in number, -- Рег. номер запроса
RENTS in TENTS -- Коллекция сущностей
);
/* Получение состава атрибутов сущности */
procedure QUERY_ENT_ATTRS_GET
(
NRN in number, -- Рег. номер запроса
SID in varchar2, -- Идентификатор сущности
COUT out clob -- Сериализованное описание атрибутов сущности
);
/* Чтение связей запроса */
function QUERY_RLS_GET
(
CRLS in clob -- Сериализованное описание связей
) return TRLS; -- Коллекция связей
/* Запись связей запроса */
procedure QUERY_RLS_SET
(
NRN in number, -- Рег. номер запроса
RRLS in TRLS -- Коллекция связей
);
/* Установка признака "готовности" запроса */
procedure QUERY_READY_SET
(
NRN in number, -- Рег. номер запроса
NREADY in number -- Флаг готовности к использованию (0 - нет, 1 - да)
);
/* Установка признака "публичности" запроса */
procedure QUERY_PBL_SET
(
NRN in number, -- Рег. номер запроса
NPBL in number -- Флаг публичности (0 - приватный, 1 - публичный)
);
/* Чтение настройки запроса */
function QUERY_OPT_GET
(
COPT in clob -- Сериализованное описание настройки запроса
) return TOPT; -- Настройка запроса
/* Запись настройки запроса */
procedure QUERY_OPT_SET
(
NRN in number, -- Рег. номер запроса
ROPT in TOPT -- Настройка запроса
);
/* Запись SQL-выражения запроса */
procedure QUERY_QRY_SET
(
NRN in number, -- Рег. номер запроса
CQRY in clob, -- SQL-выражение
CQRY_MSG in clob -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
);
/* Формирование SQL запроса */
procedure QUERY_SQL_BUILD
(
NRN in number, -- Рег. номер запроса
SQRY out varchar2, -- SQL-выражение
SQRY_MSG out varchar2 -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
);
end PKG_P8PANELS_QE_BASE;
/
create or replace package body PKG_P8PANELS_QE_BASE as
/* Константы - Типы сущностей */
SENT_TYPE_TABLE constant PKG_STD.TSTRING := 'TABLE'; -- Таблица
SENT_TYPE_VIEW constant PKG_STD.TSTRING := 'VIEW'; -- Представление
/* Константы - Теги для сериализации */
STAG_DATA constant PKG_STD.TSTRING := 'XDATA'; -- Данные
STAG_QUERIES constant PKG_STD.TSTRING := 'XQUERIES'; -- Запросы
STAG_QUERY constant PKG_STD.TSTRING := 'XQUERY'; -- Запрос
STAG_ARGS constant PKG_STD.TSTRING := 'XARGS'; -- Аргументы запроса
STAG_ARG constant PKG_STD.TSTRING := 'XARG'; -- Аргумент запроса
STAG_ATTRS constant PKG_STD.TSTRING := 'XATTRS'; -- Атрибуты сущности
STAG_ATTR constant PKG_STD.TSTRING := 'XATTR'; -- Атрибут сущности
STAG_ENTS constant PKG_STD.TSTRING := 'XENTS'; -- Сущности
STAG_ENT constant PKG_STD.TSTRING := 'XENT'; -- Сущность
STAG_RLS constant PKG_STD.TSTRING := 'XRLS'; -- Связи
STAG_RL constant PKG_STD.TSTRING := 'XRL'; -- Связь
STAG_OPT constant PKG_STD.TSTRING := 'XOPT'; -- Настройка запроса
STAG_COND constant PKG_STD.TSTRING := 'XCOND'; -- Условия запроса
STAG_QRY constant PKG_STD.TSTRING := 'XQRY'; -- SQL-выражение запроса
STAG_QRY_MSG constant PKG_STD.TSTRING := 'XQRY_MSG'; -- Сообщение при формировании запроса
/* Константы - Атрибуты для сериализации */
SATTR_ID constant PKG_STD.TSTRING := 'id'; -- Идентификатор
SATTR_RN constant PKG_STD.TSTRING := 'rn'; -- Регистрационный номер
SATTR_CODE constant PKG_STD.TSTRING := 'code'; -- Код
SATTR_NAME constant PKG_STD.TSTRING := 'name'; -- Имя
SATTR_AUTHOR constant PKG_STD.TSTRING := 'author'; -- Автор
SATTR_CH_DATE constant PKG_STD.TSTRING := 'chDate'; -- Дата изменения
SATTR_READY constant PKG_STD.TSTRING := 'ready'; -- Готовность к использованию
SATTR_PBL constant PKG_STD.TSTRING := 'pbl'; -- Публичность
SATTR_MODIFY constant PKG_STD.TSTRING := 'modify'; -- Изменяемость
SATTR_TITLE constant PKG_STD.TSTRING := 'title'; -- Заголовок
SATTR_TYPE constant PKG_STD.TSTRING := 'type'; -- Тип
SATTR_DATA_TYPE constant PKG_STD.TSTRING := 'dataType'; -- Тип данных
SATTR_MANDATORY constant PKG_STD.TSTRING := 'mandatory'; -- Обязательность
SATTR_X constant PKG_STD.TSTRING := 'x'; -- Координата по X
SATTR_Y constant PKG_STD.TSTRING := 'y'; -- Координата по Y
SATTR_SOURCE constant PKG_STD.TSTRING := 'source'; -- Источник
SATTR_TARGET constant PKG_STD.TSTRING := 'target'; -- Приёмник
SATTR_AGG constant PKG_STD.TSTRING := 'agg'; -- Агрегатная функция
SATTR_ALIAS constant PKG_STD.TSTRING := 'alias'; -- Псевдоним
SATTR_USE constant PKG_STD.TSTRING := 'use'; -- Применение в запросе
SATTR_SHOW constant PKG_STD.TSTRING := 'show'; -- Отображение в запросе
SATTR_PARENT_ENTITY constant PKG_STD.TSTRING := 'parentEntity'; -- Идентификатор родительской сущности
SATTR_VALUE constant PKG_STD.TSTRING := 'value'; -- Значение
/* Константы - зарезервированные имена рагументов */
SARG_NAME_PAGE constant PKG_STD.TSTRING := 'NPAGE'; -- Номер страницы
SARG_NAME_PAGE_SIZE constant PKG_STD.TSTRING := 'NPAGE_SIZE'; -- Размер страницы (записей)
/* Получение заголовка представления из метаданных */
function DMSCLVIEWS_TITLE_GET
(
SVIEW_NAME in varchar2 -- Имя представления
) return varchar2 -- Заголовок представления из метаданных
is
begin
/* Обратимся к метаописанию представления */
for V in (select T.VIEW_NOTE,
UL.UNITNAME
from DMSCLVIEWS T,
UNITLIST UL
where T.VIEW_NAME = SVIEW_NAME
and T.CUSTOM_QUERY = 0
and T.PRN = UL.RN)
loop
if (V.VIEW_NOTE = SVIEW_NAME) then
return V.UNITNAME;
else
return V.VIEW_NOTE;
end if;
end loop;
/* Ничего не нашли - вернём обычное имя */
return SVIEW_NAME;
end DMSCLVIEWS_TITLE_GET;
/* Получение заголовка атрибута представления из метаданных */
function DMSCLVIEWSATTRS_TITLE_GET
(
SVIEW_NAME in varchar2, -- Имя представления
SATTR_NAME in varchar2 -- Имя атрибута
) return varchar2 -- Заголовок атрибута представления из метаданных
is
begin
/* Обратимся к метаописанию представления */
for V in (select T.RN
from DMSCLVIEWS T
where T.VIEW_NAME = SVIEW_NAME
and T.CUSTOM_QUERY = 0)
loop
/* Обходим поля найденного представления */
for F in (select A.CAPTION
from DMSCLVIEWSATTRS T,
DMSCLATTRS A
where T.PRN = V.RN
and T.COLUMN_NAME = SATTR_NAME
and T.ATTR = A.RN)
loop
return F.CAPTION;
end loop;
end loop;
/* Ничего не нашли - вернём обычное имя */
return SATTR_NAME;
end DMSCLVIEWSATTRS_TITLE_GET;
/* Формирование аргумента */
function TARG_MAKE
(
SNAME in varchar2, -- Имя
STITLE in varchar2, -- Заголовок
NDATA_TYPE in number, -- Тип данных (см. константы PKG_STD.DATA_TYPE_*)
NMANDATORY in number, -- Флаг обязательности (1 - да, 0 - нет)
SVALUE in varchar2 -- Значение для отладки (строковое представление для всех типов данных)
) return TARG -- Описание аргумента
is
RARG TARG; -- Буфер для результата
begin
/* Проверим имя */
if (SNAME is null) then
P_EXCEPTION(0, 'Имя аргумента не указано.');
end if;
for C in (select null from DUAL where not REGEXP_LIKE(SNAME, '^[A-z0-9_]+$'))
loop
P_EXCEPTION(0,
'Имя аргумента содержит недопустимые символы (разрешены латинские буквы, цифры и символ нижнего подчеркивания).');
end loop;
if (UPPER(SNAME) in (UPPER(SARG_NAME_PAGE), UPPER(SARG_NAME_PAGE_SIZE))) then
P_EXCEPTION(0, 'Это имя аргумента зарезервировано Системой.');
end if;
/* Проверим заголовок */
if (STITLE is null) then
P_EXCEPTION(0, 'Не указан заголовок аргумента.');
end if;
/* Проверим корректность типа сущности */
if (NDATA_TYPE is null) then
P_EXCEPTION(0, 'Не указан тип данных аргумента.');
end if;
if (NDATA_TYPE not in (PKG_STD.DATA_TYPE_STR, PKG_STD.DATA_TYPE_NUM, PKG_STD.DATA_TYPE_DATE)) then
P_EXCEPTION(0,
'Аргументы типа "%s" не поддерживаются.',
COALESCE(TO_CHAR(NDATA_TYPE), '<НЕ УКАЗАН>'));
end if;
/* Проверим корректность флага обязательности */
if (NMANDATORY is null) then
P_EXCEPTION(0, 'Не указан признак обязательности аргумента.');
end if;
if (NMANDATORY not in (0, 1)) then
P_EXCEPTION(0,
'Некорректно указан признак обязательности аргумента.');
end if;
/* Собираем аргумент */
RARG.SNAME := UPPER(SNAME);
RARG.STITLE := STITLE;
RARG.NDATA_TYPE := NDATA_TYPE;
RARG.NMANDATORY := NMANDATORY;
RARG.SVALUE := SVALUE;
/* Вернем полученное */
return RARG;
end TARG_MAKE;
/* Сериализация аргумента */
procedure TARG_TO_XML
(
RARG in TARG -- Аргумент
)
is
begin
/* Открываем описание аргумента */
PKG_XFAST.DOWN_NODE(SNAME => STAG_ARG);
/* Аргумент */
PKG_XFAST.ATTR(SNAME => SATTR_NAME, SVALUE => RARG.SNAME);
PKG_XFAST.ATTR(SNAME => SATTR_TITLE, SVALUE => RARG.STITLE);
PKG_XFAST.ATTR(SNAME => SATTR_DATA_TYPE, NVALUE => RARG.NDATA_TYPE);
PKG_XFAST.ATTR(SNAME => SATTR_MANDATORY, NVALUE => RARG.NMANDATORY);
PKG_XFAST.ATTR(SNAME => SATTR_VALUE, SVALUE => RARG.SVALUE);
/* Закрываем описание аргумента */
PKG_XFAST.UP();
end TARG_TO_XML;
/* Десериализация аргумента */
function TARG_FROM_XML
(
CXML in clob -- XML-описание аргумента
) return TARG -- Аргумент
is
RRES TARG; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
begin
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
XNODE := PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_ARG);
/* Получаем значения */
RRES.SNAME := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_NAME);
RRES.STITLE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_TITLE);
RRES.NDATA_TYPE := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_DATA_TYPE);
RRES.NMANDATORY := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_MANDATORY);
RRES.SVALUE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_VALUE);
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём результат */
return RRES;
end TARG_FROM_XML;
/* Поиск индекса аргумента по имени */
function TARGS_INDEX_BY_NAME
(
RARGS in TARGS, -- Коллекция аргументов
SNAME in varchar2 -- Искомое имя
) return number -- Индекс найденного аргумента (null - если не найдено)
is
begin
/* Обходим коллекцию */
if ((RARGS is not null) and (RARGS.COUNT > 0)) then
for I in RARGS.FIRST .. RARGS.LAST
loop
begin
/* Возвращаем найденный индекс */
if (RARGS(I).SNAME = SNAME) then
return I;
end if;
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Ничего не нашли */
return null;
end TARGS_INDEX_BY_NAME;
/* Добавление аргумента в коллекцию */
procedure TARGS_ADD
(
RARGS in out nocopy TARGS, -- Изменяемая коллекция
SNAME in varchar2, -- Имя
STITLE in varchar2, -- Заголовок
NDATA_TYPE in number, -- Тип данных (см. константы PKG_STD.DATA_TYPE_*)
NMANDATORY in number, -- Флаг обязательности (1 - да, 0 - нет)
SVALUE in varchar2 -- Значение для отладки (строковое представление для всех типов данных)
)
is
RARG TARG; -- Добавляемый аргумент
begin
/* Инициализируем коллекцию если необходимо */
if (RARGS is null) then
RARGS := TARGS();
end if;
/* Проверим уникальность имени */
if ((SNAME is not null) and (TARGS_INDEX_BY_NAME(RARGS => RARGS, SNAME => SNAME) is not null)) then
P_EXCEPTION(0, 'Аргумент с именем "%s" уже существует.', SNAME);
end if;
/* Формируем аргумент */
RARG := TARG_MAKE(SNAME => SNAME,
STITLE => STITLE,
NDATA_TYPE => NDATA_TYPE,
NMANDATORY => NMANDATORY,
SVALUE => SVALUE);
/* Добавляем его в коллекцию */
RARGS.EXTEND();
RARGS(RARGS.LAST) := RARG;
end TARGS_ADD;
/* Изменение аргумента в коллекции */
procedure TARGS_EDIT
(
RARGS in out nocopy TARGS, -- Изменяемая коллекция
NINDEX in number, -- Индекс изменяемого аргумента
SNAME in varchar2, -- Имя
STITLE in varchar2, -- Заголовок
NDATA_TYPE in number, -- Тип данных (см. константы PKG_STD.DATA_TYPE_*)
NMANDATORY in number, -- Флаг обязательности (1 - да, 0 - нет)
SVALUE in varchar2 -- Значение для отладки (строковое представление для всех типов данных)
)
is
RARG TARG; -- Добавляемый аргумент
begin
/* Проверим коллекцию */
if ((RARGS is null) or (RARGS.COUNT = 0)) then
P_EXCEPTION(0,
'Коллекция аргументов пуста. Изменение аргумента невозможно.');
end if;
/* Проверим индекс изменяемого аргумента */
if (NINDEX is null) then
P_EXCEPTION(0, 'Не указан индекс изменяемого аргумента.');
end if;
/* Формируем аргумент */
RARG := TARG_MAKE(SNAME => SNAME,
STITLE => STITLE,
NDATA_TYPE => NDATA_TYPE,
NMANDATORY => NMANDATORY,
SVALUE => SVALUE);
/* Обновляем аргумент в коллекции */
begin
RARGS(NINDEX) := RARG;
exception
when others then
P_EXCEPTION(0, 'Изменяемый аргумент отсутствует в коллекции.');
end;
end TARGS_EDIT;
/* Удаление аргумента из коллекции */
procedure TARGS_REMOVE
(
RARGS in out nocopy TARGS, -- Изменяемая коллекция
SNAME in varchar2 -- Имя удаляемого аргумента
)
is
NIND PKG_STD.TNUMBER; -- Индекс аргумента коллекции
begin
/* Найдем индекс аргумента в коллекции */
NIND := TARGS_INDEX_BY_NAME(RARGS => RARGS, SNAME => SNAME);
/* Удалим его, если нашли */
if (NIND is not null) then
RARGS.DELETE(NIND);
end if;
end TARGS_REMOVE;
/* Сериализация коллекции аргументов */
procedure TARGS_TO_XML
(
RARGS in TARGS -- Коллекция аргументов
)
is
begin
/* Открываем описание аргументов */
PKG_XFAST.DOWN_NODE(SNAME => STAG_ARGS);
/* Обходим аргументы из коллекции */
if ((RARGS is not null) and (RARGS.COUNT > 0)) then
for I in RARGS.FIRST .. RARGS.LAST
loop
begin
/* Добавляем описание аргумента */
TARG_TO_XML(RARG => RARGS(I));
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Закрываем описание аргумента */
PKG_XFAST.UP();
end TARGS_TO_XML;
/* Десериализация коллекции аргументов */
function TARGS_FROM_XML
(
CXML in clob -- XML-описание коллекции аргументов
) return TARGS -- Коллекция аргументов
is
RRES TARGS; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
XNODES PKG_XPATH.TNODES; -- Буфер коллекции узлов документа
begin
/* Инициализируем результат */
RRES := TARGS();
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считывание списка аргументов */
XNODES := PKG_XPATH.LIST_NODES(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_ARGS || '/' || STAG_ARG);
/* Цикл по списку аргументов */
for I in 1 .. PKG_XPATH.COUNT_NODES(RNODES => XNODES)
loop
/* Считаем элемент по его номеру */
XNODE := PKG_XPATH.ITEM_NODE(RNODES => XNODES, INUMBER => I);
/* Сериализуем и добавим его в коллекцию */
RRES.EXTEND();
RRES(RRES.LAST) := TARG_FROM_XML(CXML => PKG_XPATH.SERIALIZE_TO_CLOB(RNODE => XNODE));
end loop;
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём результат */
return RRES;
end TARGS_FROM_XML;
/* Сериализация настройки */
procedure TOPT_TO_XML
(
ROPT in TOPT -- Настройка
)
is
begin
/* Открываем описание настройки */
PKG_XFAST.DOWN_NODE(SNAME => STAG_OPT);
/* Аргументы */
TARGS_TO_XML(RARGS => ROPT.RARGS);
/* Условия отбора */
PKG_XFAST.HERB(SNAME => STAG_COND, SVALUE => ROPT.SCOND);
/* Закрываем описание настройки */
PKG_XFAST.UP();
end TOPT_TO_XML;
/* Десериализация настройки */
function TOPT_FROM_XML
(
CXML in clob -- XML-описание настройки
) return TOPT -- Настройка
is
RRES TOPT; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
begin
/* Инициализируем настройку */
RRES.RARGS := TARGS();
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считаваем узел настройки */
XNODE := PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_OPT);
/* Получаем значения */
RRES.SCOND := PKG_XPATH.VALUE(RNODE => XNODE, SPATTERN => STAG_COND);
RRES.RARGS := TARGS_FROM_XML(CXML => PKG_XPATH.SERIALIZE_TO_CLOB(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XNODE,
SPATTERN => STAG_ARGS)));
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём результат */
return RRES;
end TOPT_FROM_XML;
/* Формирование идентификатора атрибута сущности */
function TATTR_ID_MAKE
(
SENT_ID in varchar2, -- Уникальный идентификатор родительской сущности
SNAME in varchar2 -- Имя атрибута
) return varchar2 -- Сформированный идентификатор
is
begin
/* Проверим параметры */
if (SNAME is null) then
P_EXCEPTION(0, 'Не указано имя атрибута сущности.');
end if;
if (SENT_ID is null) then
P_EXCEPTION(0,
'Не указан идентификатор родительской сущности атрибута.');
end if;
/* Соберем идентификатор */
return SENT_ID || '.' || SNAME;
end TATTR_ID_MAKE;
/* Формирование псевдонима атрибута сущности */
function TATTR_ALIAS_MAKE
(
SENT_ID in varchar2, -- Уникальный идентификатор родительской сущности
RATTRS in TATTRS, -- Коллекция уже существующих атрибутов
NINDEX in number -- Индекс элемента, для которого формируется псевдоним
) return varchar2 -- Сформированный идентификатор
is
SRES PKG_STD.TSTRING; -- Буфер для результата
NCNT PKG_STD.TNUMBER := 0; -- Текущая попытка
NMAX_CNT PKG_STD.TNUMBER := 1000; -- Предельное количество попыток
NATTR_INDEX PKG_STD.TNUMBER := 0; -- Индекс поля в коллекции атрибутов сущности, при проверке уникальности псевдонима
begin
/* Подбираем псевдоним */
while ((NATTR_INDEX is not null) and (NCNT < NMAX_CNT))
loop
SRES := SENT_ID || TO_CHAR(NINDEX + NCNT);
NATTR_INDEX := TATTRS_INDEX_BY_ALIAS(RATTRS => RATTRS, SALIAS => SRES);
NCNT := NCNT + 1;
end loop;
/* Если так и не смогли сформировать уникальный псевдоним */
if ((NATTR_INDEX is not null) and (NCNT >= NMAX_CNT)) then
P_EXCEPTION(0,
'Не удалось сформировать уникальный псевдоним для атрибута сущности "%s".',
SENT_ID);
end if;
/* Вернём полученный псевдоним */
return SRES;
end TATTR_ALIAS_MAKE;
/* Сериализация атрибута сущности */
procedure TATTR_TO_XML
(
RATTR in TATTR -- Атрибут сущности
)
is
begin
/* Открываем описание атрибута сущности */
PKG_XFAST.DOWN_NODE(SNAME => STAG_ATTR);
/* Атрибут */
PKG_XFAST.ATTR(SNAME => SATTR_ID, SVALUE => RATTR.SID);
PKG_XFAST.ATTR(SNAME => SATTR_PARENT_ENTITY, SVALUE => RATTR.SPARENT_ENTITY);
PKG_XFAST.ATTR(SNAME => SATTR_NAME, SVALUE => RATTR.SNAME);
PKG_XFAST.ATTR(SNAME => SATTR_TITLE, SVALUE => RATTR.STITLE);
PKG_XFAST.ATTR(SNAME => SATTR_DATA_TYPE, NVALUE => RATTR.NDATA_TYPE);
PKG_XFAST.ATTR(SNAME => SATTR_AGG, SVALUE => RATTR.SAGG);
PKG_XFAST.ATTR(SNAME => SATTR_ALIAS, SVALUE => RATTR.SALIAS);
PKG_XFAST.ATTR(SNAME => SATTR_USE, NVALUE => RATTR.NUSE);
PKG_XFAST.ATTR(SNAME => SATTR_SHOW, NVALUE => RATTR.NSHOW);
/* Закрываем описание атрибута сущности */
PKG_XFAST.UP();
end TATTR_TO_XML;
/* Десериализация атрибута сущности */
function TATTR_FROM_XML
(
CXML in clob -- XML-описание атрибута сущности
) return TATTR -- Атрибут сущности
is
RRES TATTR; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
begin
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
XNODE := PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_ATTR);
/* Получаем значения */
RRES.SID := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_ID);
RRES.SPARENT_ENTITY := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_PARENT_ENTITY);
RRES.SNAME := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_NAME);
RRES.STITLE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_TITLE);
RRES.NDATA_TYPE := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_DATA_TYPE);
RRES.SAGG := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_AGG);
RRES.SALIAS := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_ALIAS);
RRES.NUSE := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_USE);
RRES.NSHOW := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_SHOW);
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём результат */
return RRES;
end TATTR_FROM_XML;
/* Поиск индекса атрибута по идентификатору */
function TATTRS_INDEX_BY_ID
(
RATTRS in TATTRS, -- Коллекция атрибутов
SID in varchar2 -- Искомый идентификатор
) return number -- Индекс найденного атрибута (null - если не найдено)
is
begin
/* Обходим коллекцию */
if ((RATTRS is not null) and (RATTRS.COUNT > 0)) then
for I in RATTRS.FIRST .. RATTRS.LAST
loop
begin
/* Возвращаем найденный индекс */
if (RATTRS(I).SID = SID) then
return I;
end if;
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Ничего не нашли */
return null;
end TATTRS_INDEX_BY_ID;
/* Поиск индекса атрибута по имени */
function TATTRS_INDEX_BY_NAME
(
RATTRS in TATTRS, -- Коллекция атрибутов
SNAME in varchar2 -- Искомое имя
) return number -- Индекс найденного атрибута (null - если не найдено)
is
begin
/* Обходим коллекцию */
if ((RATTRS is not null) and (RATTRS.COUNT > 0)) then
for I in RATTRS.FIRST .. RATTRS.LAST
loop
begin
/* Возвращаем найденный индекс */
if (RATTRS(I).SNAME = SNAME) then
return I;
end if;
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Ничего не нашли */
return null;
end TATTRS_INDEX_BY_NAME;
/* Поиск индекса атрибута по псевдониму */
function TATTRS_INDEX_BY_ALIAS
(
RATTRS in TATTRS, -- Коллекция атрибутов
SALIAS in varchar2 -- Искомый псевдоним
) return number -- Индекс найденного атрибута (null - если не найдено)
is
begin
/* Обходим коллекцию */
if ((RATTRS is not null) and (RATTRS.COUNT > 0)) then
for I in RATTRS.FIRST .. RATTRS.LAST
loop
begin
/* Возвращаем найденный индекс */
if (RATTRS(I).SALIAS = SALIAS) then
return I;
end if;
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Ничего не нашли */
return null;
end TATTRS_INDEX_BY_ALIAS;
/* Подсчет количества атрибутов по псевдониму */
function TATTRS_COUNT_BY_ALIAS
(
RATTRS in TATTRS, -- Коллекция атрибутов
SALIAS in varchar2 -- Искомый псевдоним
) return number -- Количество найденных атрибутов
is
NRES PKG_STD.TNUMBER := 0; --Буфер для расчета
begin
/* Обходим коллекцию */
if ((RATTRS is not null) and (RATTRS.COUNT > 0)) then
for I in RATTRS.FIRST .. RATTRS.LAST
loop
begin
/* Увеличиваем счетчик, если наш клиент */
if (RATTRS(I).SALIAS = SALIAS) then
NRES := NRES + 1;
end if;
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Вернем количество найденных */
return NRES;
end TATTRS_COUNT_BY_ALIAS;
/* Формирование списка атрибутов сущности */
function TATTRS_MAKE
(
RENT in TENT, -- Родительская сущность
NCOUNT in number := null -- Количество атрибутов (null - все)
) return TATTRS -- Коллекция атрибутов сущности
is
RRES TATTRS; -- Буфер для результата
RVIEW_FIELDS PKG_OBJECT_DESC.TCOLUMNS; -- Коллекция описаний полей представления
RVIEW_FIELD PKG_OBJECT_DESC.TCOLUMN; -- Описание поля представления
NATTR_INDEX PKG_STD.TNUMBER; -- Индекс поля в коллекции атрибутов сущности
BINIT boolean := false; -- Признак инициализации атрибутов сущности
begin
/* Проверим корректность типа сущности */
if (RENT.STYPE is null) then
P_EXCEPTION(0, 'Не указан тип сущности.');
end if;
if (RENT.STYPE not in (SENT_TYPE_TABLE, SENT_TYPE_VIEW)) then
P_EXCEPTION(0,
'Сущности типа "%s" не поддерживаются.',
COALESCE(RENT.STYPE, '<НЕ УКАЗАН>'));
end if;
/* Проверим, что у сущности задан идентификатор */
if (RENT.SID is null) then
P_EXCEPTION(0,
'Ошибка формирования атрибутов - не задан идентификатор сущности.');
end if;
/* Проверим, что у сущности задано имя */
if (RENT.SNAME is null) then
P_EXCEPTION(0,
'Ошибка формирования атрибутов - не задано имя сущности.');
end if;
/* Инициализируем результат */
RRES := TATTRS();
/* Установим флаг инициализации - в сущности нет атрибутов и нас просили ограничить количество */
if (((RENT.RATTRS is null) or (RENT.RATTRS.COUNT = 0)) and (NCOUNT is not null)) then
BINIT := true;
end if;
/* Если сущность это представление */
if (RENT.STYPE = SENT_TYPE_VIEW) then
/* Получим список полей представления */
RVIEW_FIELDS := PKG_OBJECT_DESC.DESC_SEL_COLUMNS(SSELECT_NAME => RENT.SNAME, BRAISE_ERROR => true);
/* Собираем атрибуты в ответ */
for I in 1 .. PKG_OBJECT_DESC.COUNT_COLUMNS(RCOLUMNS => RVIEW_FIELDS)
loop
/* Считываем очередное поле из коллекции описания полей представления */
RVIEW_FIELD := PKG_OBJECT_DESC.FETCH_COLUMN(RCOLUMNS => RVIEW_FIELDS, IINDEX => I);
/* Если поле поддерживаемого типа */
if (RVIEW_FIELD.DATA_TYPE in (PKG_STD.DATA_TYPE_STR(), PKG_STD.DATA_TYPE_NUM(), PKG_STD.DATA_TYPE_DATE())) then
/* Добавляем элемент в результирующую коллекцию */
RRES.EXTEND();
/* Ищем такой атрибут в родительской сущности */
NATTR_INDEX := TATTRS_INDEX_BY_NAME(RATTRS => RENT.RATTRS, SNAME => RVIEW_FIELD.COLUMN_NAME);
/* Если это поле уже есть в коллекции атрибутов родительской сущности */
if (NATTR_INDEX is not null) then
/* Возьмём элемент оттуда */
RRES(RRES.LAST) := RENT.RATTRS(NATTR_INDEX);
else
/* Такого элемента нет - берем из представления */
RRES(RRES.LAST).SID := TATTR_ID_MAKE(SENT_ID => RENT.SID, SNAME => RVIEW_FIELD.COLUMN_NAME);
RRES(RRES.LAST).SPARENT_ENTITY := RENT.SID;
RRES(RRES.LAST).SNAME := RVIEW_FIELD.COLUMN_NAME;
RRES(RRES.LAST).STITLE := DMSCLVIEWSATTRS_TITLE_GET(SVIEW_NAME => RENT.SNAME,
SATTR_NAME => RRES(RRES.LAST).SNAME);
RRES(RRES.LAST).NDATA_TYPE := RVIEW_FIELD.DATA_TYPE;
RRES(RRES.LAST).SALIAS := TATTR_ALIAS_MAKE(SENT_ID => RENT.SID, RATTRS => RRES, NINDEX => RRES.LAST);
/* Если это инициализиция сущности - установим флаг применения в запросе (тогда атрибут будет отображен в диаграмме) */
if (BINIT) then
RRES(RRES.LAST).NUSE := 1;
RRES(RRES.LAST).NSHOW := 1;
else
RRES(RRES.LAST).NUSE := 0;
RRES(RRES.LAST).NSHOW := 0;
end if;
end if;
/* Ограничим объем коллекции если необходимо */
if (NCOUNT is not null) then
exit when RRES.LAST = NCOUNT;
end if;
end if;
end loop;
end if;
/* Если сущность это таблица */
if (RENT.STYPE = SENT_TYPE_TABLE) then
P_EXCEPTION(0,
'Поддержка формирования атрибутов для сущностей типа "Таблица" ещё не реализована.');
end if;
/* Возвращаем результат */
return RRES;
end TATTRS_MAKE;
/* Сериализация коллекции атрибутов сущности */
procedure TATTRS_TO_XML
(
RATTRS in TATTRS -- Коллекция атрибутов сущности
)
is
begin
/* Открываем описание атрибутов сущности */
PKG_XFAST.DOWN_NODE(SNAME => STAG_ATTRS);
/* Обходим атрибуты из коллекции */
if ((RATTRS is not null) and (RATTRS.COUNT > 0)) then
for I in RATTRS.FIRST .. RATTRS.LAST
loop
/* Добавляем описание атрибута сущности */
TATTR_TO_XML(RATTR => RATTRS(I));
end loop;
end if;
/* Закрываем описание атрибутов сущности */
PKG_XFAST.UP();
end TATTRS_TO_XML;
/* Десериализация коллекции атрибутов сущности */
function TATTRS_FROM_XML
(
CXML in clob -- XML-описание коллекции атрибутов сущности
) return TATTRS -- Коллекция атрибутов сущности
is
RRES TATTRS; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
XNODES PKG_XPATH.TNODES; -- Буфер коллекции узлов документа
begin
/* Инициализируем результат */
RRES := TATTRS();
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считывание списка атрибутов */
XNODES := PKG_XPATH.LIST_NODES(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_ATTRS || '/' || STAG_ATTR);
/* Цикл по списку атрибутов */
for I in 1 .. PKG_XPATH.COUNT_NODES(RNODES => XNODES)
loop
/* Считаем элемент по его номеру */
XNODE := PKG_XPATH.ITEM_NODE(RNODES => XNODES, INUMBER => I);
/* Сериализуем и добавим его в коллекцию */
RRES.EXTEND();
RRES(RRES.LAST) := TATTR_FROM_XML(CXML => PKG_XPATH.SERIALIZE_TO_CLOB(RNODE => XNODE));
end loop;
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём результат */
return RRES;
end TATTRS_FROM_XML;
/* Десериализация коллекции атрибутов сущности (из BASE64) */
function TATTRS_FROM_XML_BASE64
(
CXML in clob, -- XML-описание коллекции атрибутов сущности (BASE64)
SCHARSET in varchar2, -- Кодировка, в которой XML-данные были упакованы в BASE64
BADD_ROOT in boolean := false -- Флаг необходимости добавления корневого тэга (false - нет, true - да)
) return TATTRS -- Коллекция атрибутов сущности
is
CTMP clob; -- Буфер для преобразований
begin
/* Избавимся от BASE64 */
CTMP := BLOB2CLOB(LBDATA => BASE64_DECODE(LCSRCE => CXML), SCHARSET => SCHARSET);
/* Если надо - добавим корень */
if (BADD_ROOT) then
CTMP := '<' || STAG_ATTRS || '>' || CTMP || '</' || STAG_ATTRS || '>';
end if;
/* Десериализуем */
return TATTRS_FROM_XML(CXML => CTMP);
end TATTRS_FROM_XML_BASE64;
/* Проверка корректности атрибутов сущности */
procedure TATTRS_CHECK
(
RATTRS in TATTRS, -- Коллекция атрибутов сущности
SCHECK_MSG out varchar2 -- Сообщения проверки (null - ошибок нет)
)
is
begin
/* Обходим коллекцию */
if ((RATTRS is not null) and (RATTRS.COUNT > 0)) then
for I in RATTRS.FIRST .. RATTRS.LAST
loop
/* Псевдоним должен быть задан */
if (RATTRS(I).SALIAS is null) then
SCHECK_MSG := SCHECK_MSG || 'Для атрибута "' || RATTRS(I).SNAME || '" не задан псевдоним; ';
else
/* А если задан - должен соответствовать по длине */
if (LENGTH(RATTRS(I).SALIAS) > 30) then
SCHECK_MSG := SCHECK_MSG || 'Длина псевдонима атрибута "' || RATTRS(I).SNAME ||
'" превышает максимально допустимую (30 символов); ';
end if;
/* Набору символов */
if (INSTR(RATTRS(I).SALIAS, '"') <> 0) then
SCHECK_MSG := SCHECK_MSG || 'Псевдоним атрибута "' || RATTRS(I).SNAME ||
'" содержит недопустимые символы; ';
end if;
/* Быть уникальным */
if (TATTRS_COUNT_BY_ALIAS(RATTRS => RATTRS, SALIAS => RATTRS(I).SALIAS) > 1) then
SCHECK_MSG := SCHECK_MSG || 'Нарушение уникальности псевдонима атрибута "' || RATTRS(I).SNAME || '"; ';
end if;
end if;
end loop;
end if;
if (SCHECK_MSG is not null) then
SCHECK_MSG := RTRIM(SCHECK_MSG, '; ');
end if;
end TATTRS_CHECK;
/* Формирование идентификатора сущности */
function TENT_ID_MAKE
(
STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*)
NNUMB in number -- Номер сущности в запросе
) return varchar2 -- Сформированный идентификатор
is
begin
/* Проверим параметры */
if (STYPE is null) then
P_EXCEPTION(0, 'Не указан тип сущности.');
end if;
if (NNUMB is null) then
P_EXCEPTION(0, 'Не указан номер сущности в запросе.');
end if;
/* Соберем идентификатор */
return SUBSTR(STYPE, 1, 1) || TO_CHAR(NNUMB);
end TENT_ID_MAKE;
/* Формирование описания сущности */
function TENT_MAKE
(
SNAME in varchar2, -- Имя
STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*)
NNUMB in number, -- Номер сущности
NINIT_ATTRS in number := 1 -- Флаг инициализации атрибутов сущности (0 - нет, 1 - да)
) return TENT -- Описание сущности
is
RENT TENT; -- Буфер для результата
RVIEW PKG_OBJECT_DESC.TVIEW; -- Описание представления
begin
/* Проверим корректность типа сущности */
if (STYPE is null) then
P_EXCEPTION(0, 'Не указан тип сущности.');
end if;
if (STYPE not in (SENT_TYPE_TABLE, SENT_TYPE_VIEW)) then
P_EXCEPTION(0,
'Сущности типа "%s" не поддерживаются.',
COALESCE(STYPE, '<НЕ УКАЗАН>'));
end if;
/* Если сущность это представление */
if (STYPE = SENT_TYPE_VIEW) then
/* Получим описание представления */
RVIEW := PKG_OBJECT_DESC.DESC_VIEW(SVIEW_NAME => SNAME, BRAISE_ERROR => true);
/* Собираем заголовок сущности */
RENT.SID := TENT_ID_MAKE(STYPE => STYPE, NNUMB => NNUMB);
RENT.SNAME := RVIEW.VIEW_NAME;
RENT.STITLE := DMSCLVIEWS_TITLE_GET(SVIEW_NAME => RENT.SNAME);
RENT.STYPE := SENT_TYPE_VIEW;
/* Формируем набор атрибутов */
if (NINIT_ATTRS = 1) then
RENT.RATTRS := TATTRS_MAKE(RENT => RENT, NCOUNT => 10);
else
RENT.RATTRS := TATTRS();
end if;
end if;
/* Если сущность это таблица */
if (STYPE = SENT_TYPE_TABLE) then
P_EXCEPTION(0,
'Поддержка сущностей типа "Таблица" ещё не реализована.');
end if;
/* Вернем полученное */
return RENT;
end TENT_MAKE;
/* Сериализация сущности */
procedure TENT_TO_XML
(
RENT in TENT, -- Сущность
NBRIEF in number := 0, -- Флаг формирования описания сущности в кратком формате (0 - нет, 1 - да)
NINCLUDE_ATTRS in number := 1 -- Флаг включения атрибутов в описание (0 - нет, 1 - да)
)
is
begin
/* Открываем описание сущности */
PKG_XFAST.DOWN_NODE(SNAME => STAG_ENT);
/* Cущность */
if (NBRIEF = 0) then
PKG_XFAST.ATTR(SNAME => SATTR_ID, SVALUE => RENT.SID);
PKG_XFAST.ATTR(SNAME => SATTR_X, NVALUE => RENT.NX);
PKG_XFAST.ATTR(SNAME => SATTR_Y, NVALUE => RENT.NY);
end if;
PKG_XFAST.ATTR(SNAME => SATTR_NAME, SVALUE => RENT.SNAME);
PKG_XFAST.ATTR(SNAME => SATTR_TITLE, SVALUE => RENT.STITLE);
PKG_XFAST.ATTR(SNAME => SATTR_TYPE, SVALUE => RENT.STYPE);
/* Атрибуты */
if (NINCLUDE_ATTRS = 1) then
TATTRS_TO_XML(RATTRS => RENT.RATTRS);
end if;
/* Закрываем описание сущности */
PKG_XFAST.UP();
end TENT_TO_XML;
/* Десериализация сущности */
function TENT_FROM_XML
(
CXML in clob -- XML-описание сущности
) return TENT -- Сущность
is
RRES TENT; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
begin
/* Инициализируем сущность */
RRES.RATTRS := TATTRS();
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считаваем узел сущности */
XNODE := PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_ENT);
/* Получаем значения */
RRES.SID := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_ID);
RRES.SNAME := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_NAME);
RRES.STITLE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_TITLE);
RRES.STYPE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_TYPE);
RRES.NX := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_X);
RRES.NY := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_Y);
RRES.RATTRS := TATTRS_FROM_XML(CXML => PKG_XPATH.SERIALIZE_TO_CLOB(RNODE => PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XNODE,
SPATTERN => STAG_ATTRS)));
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём результат */
return RRES;
end TENT_FROM_XML;
/* Поиск индекса сущности по идентификатору */
function TENTS_INDEX_BY_ID
(
RENTS in TENTS, -- Коллекция сущностей
SID in varchar2 -- Искомый идентификатор
) return number -- Индекс найденной сущности (null - если не найдено)
is
begin
/* Обходим коллекцию */
if ((RENTS is not null) and (RENTS.COUNT > 0)) then
for I in RENTS.FIRST .. RENTS.LAST
loop
begin
/* Возвращаем найденный индекс */
if (RENTS(I).SID = SID) then
return I;
end if;
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Ничего не нашли */
return null;
end TENTS_INDEX_BY_ID;
/* Поиск индекса сущности по идентификатору атрибута */
function TENTS_INDEX_BY_ATTR_ID
(
RENTS in TENTS, -- Коллекция сущностей
SATTR_ID in varchar2 -- Искомый идентификатор атрибута
) return number -- Индекс найденной сущности (null - если не найдено)
is
begin
/* Обходим коллекцию */
if ((RENTS is not null) and (RENTS.COUNT > 0)) then
for I in RENTS.FIRST .. RENTS.LAST
loop
begin
/* Возвращаем найденный индекс */
if (TATTRS_INDEX_BY_ID(RATTRS => RENTS(I).RATTRS, SID => SATTR_ID) is not null) then
return I;
end if;
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Ничего не нашли */
return null;
end TENTS_INDEX_BY_ATTR_ID;
/* Поиск номера сущности в коллекции */
function TENTS_NEXT_NUMB
(
RENTS in TENTS, -- Коллекция сущностей
STYPE in varchar2 -- Тип (см. константы SENT_TYPE_*)
) return number -- Номер сущности в коллекции
is
NNUMB PKG_STD.TNUMBER := 0; -- Буфер для результата
begin
/* Подбираем первый свободный номер */
while (TENTS_INDEX_BY_ID(RENTS => RENTS, SID => TENT_ID_MAKE(STYPE => STYPE, NNUMB => NNUMB)) is not null)
loop
NNUMB := NNUMB + 1;
end loop;
/* Возвращаем его */
return NNUMB;
end TENTS_NEXT_NUMB;
/* Добавление сущности в коллекцию */
procedure TENTS_ADD
(
RENTS in out nocopy TENTS, -- Изменяемая коллекция
SNAME in varchar2, -- Имя
STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*)
NINIT_ATTRS in number := 1 -- Флаг инициализации атрибутов сущности (0 - нет, 1 - да)
)
is
RENT TENT; -- Добавляемая сущность
begin
/* Инициализируем коллекцию если необходимо */
if (RENTS is null) then
RENTS := TENTS();
end if;
/* Формируем пописание сущности */
RENT := TENT_MAKE(SNAME => SNAME,
STYPE => STYPE,
NNUMB => TENTS_NEXT_NUMB(RENTS => RENTS, STYPE => STYPE),
NINIT_ATTRS => NINIT_ATTRS);
/* Добавляем её в коллекцию */
RENTS.EXTEND();
RENTS(RENTS.LAST) := RENT;
end TENTS_ADD;
/* Удаление сущности из коллекции */
procedure TENTS_REMOVE
(
RENTS in out nocopy TENTS, -- Изменяемая коллекция
SID in varchar2 -- Идентификатор удялемой сущности
)
is
NIND PKG_STD.TNUMBER; -- Индекс сущности в коллекции
begin
/* Найдем индекс сущности в коллекции */
NIND := TENTS_INDEX_BY_ID(RENTS => RENTS, SID => SID);
/* Удалим её, если нашли */
if (NIND is not null) then
RENTS.DELETE(NIND);
end if;
end TENTS_REMOVE;
/* Установка координат сущности в коллекции */
procedure TENTS_POSITION_SET
(
RENTS in out nocopy TENTS, -- Изменяемая коллекция
SID in varchar2, -- Идентификатор сущности
NX in number, -- Координата по оси абсцисс
NY in number -- Координата по оси ординат
)
is
NIND PKG_STD.TNUMBER; -- Индекс сущности в коллекции
begin
NIND := TENTS_INDEX_BY_ID(RENTS => RENTS, SID => SID);
if (NIND is not null) then
RENTS(NIND).NX := NX;
RENTS(NIND).NY := NY;
end if;
end TENTS_POSITION_SET;
/* Формирование списка сущностей */
function TENTS_MAKE
(
SSEARCH in varchar2, -- Поисковый запрос
NINIT_ATTRS in number -- Флаг инициализации атрибутов сущности (0 - нет, 1 - да)
) return TENTS -- Коллекция сущностей
is
RRES TENTS; -- Буфер для результата
SSEARCH_ PKG_STD.TSTRING; -- Строка поиска, предобразованная для применения в запросе
begin
/* Инициализируем результат */
RRES := TENTS();
/* Формируем список представлений */
PKG_OBJECT_DESC.SNAP_VIEWS(NACCESS_TYPE => 1);
/* Подготовим поисковую фразу */
if (SSEARCH is not null) then
SSEARCH_ := '%' || LOWER(replace(SSEARCH, ' ', '%')) || '%';
else
SSEARCH_ := null;
end if;
/* Обходим полученный список */
for C in (select T.VIEW_NAME
from SNAP_VIEWS T
where ((SSEARCH_ is null) or ((SSEARCH_ is not null) and ((LOWER(T.VIEW_NAME) like SSEARCH_) or (LOWER(DMSCLVIEWS_TITLE_GET(T.VIEW_NAME)) like
SSEARCH_)))))
loop
/* Добавляем представления в коллекцию */
TENTS_ADD(RENTS => RRES, SNAME => C.VIEW_NAME, STYPE => SENT_TYPE_VIEW, NINIT_ATTRS => NINIT_ATTRS);
end loop;
/* Вернём полученный список */
return RRES;
end TENTS_MAKE;
/* Сериализация коллекции сущностей */
procedure TENTS_TO_XML
(
RENTS in TENTS, -- Коллекция сущностей
NBRIEF in number := 0, -- Флаг формирования описания сущности в кратком формате (0 - нет, 1 - да)
NINCLUDE_ATTRS in number := 1 -- Флаг включения атрибутов в описание (0 - нет, 1 - да)
)
is
begin
/* Открываем описание сущностей */
PKG_XFAST.DOWN_NODE(SNAME => STAG_ENTS);
/* Обходим сущности из коллекции */
if ((RENTS is not null) and (RENTS.COUNT > 0)) then
for I in RENTS.FIRST .. RENTS.LAST
loop
begin
/* Добавляем описание сущности */
TENT_TO_XML(RENT => RENTS(I), NBRIEF => NBRIEF, NINCLUDE_ATTRS => NINCLUDE_ATTRS);
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Закрываем описание сущностей */
PKG_XFAST.UP();
end TENTS_TO_XML;
/* Десериализация коллекции сущностей */
function TENTS_FROM_XML
(
CXML in clob -- XML-описание коллекции сущностей
) return TENTS -- Коллекция сущностей
is
RRES TENTS; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
XNODES PKG_XPATH.TNODES; -- Буфер коллекции узлов документа
begin
/* Инициализируем результат */
RRES := TENTS();
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считывание списка сущностей */
XNODES := PKG_XPATH.LIST_NODES(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_ENTS || '/' || STAG_ENT);
/* Цикл по списку сущностей */
for I in 1 .. PKG_XPATH.COUNT_NODES(RNODES => XNODES)
loop
/* Считаем элемент по его номеру */
XNODE := PKG_XPATH.ITEM_NODE(RNODES => XNODES, INUMBER => I);
/* Сериализуем и добавим его в коллекцию */
RRES.EXTEND();
RRES(RRES.LAST) := TENT_FROM_XML(CXML => PKG_XPATH.SERIALIZE_TO_CLOB(RNODE => XNODE));
end loop;
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём результат */
return RRES;
end TENTS_FROM_XML;
/* Формирование идентификатора связи */
function TRL_ID_MAKE
(
SSOURCE in varchar2, -- Источник
STARGET in varchar2 -- Приёмник
) return varchar2 -- Сформированный идентификатор
is
begin
/* Проверим параметры */
if (SSOURCE is null) then
P_EXCEPTION(0, 'Не указан источник связи.');
end if;
if (STARGET is null) then
P_EXCEPTION(0, 'Не указан приёмник связи.');
end if;
/* Соберем идентификатор */
return SSOURCE || '-' || STARGET;
end TRL_ID_MAKE;
/* Формирование описания связи */
function TRL_MAKE
(
SID in varchar2 := null, -- Идентификатор (null - автоформирование)
SSOURCE in varchar2, -- Источник
STARGET in varchar2, -- Приёмник
NMANDATORY in number -- Флаг обязательности (1 - да, 0 - нет)
) return TRL -- Описание связи
is
RRL TRL; -- Буфер для результата
begin
/* Собираем описание связи */
RRL.SID := COALESCE(SID, TRL_ID_MAKE(SSOURCE => SSOURCE, STARGET => STARGET));
RRL.SSOURCE := SSOURCE;
RRL.STARGET := STARGET;
RRL.NMANDATORY := NMANDATORY;
/* Вернем полученное */
return RRL;
end TRL_MAKE;
/* Сериализация связи */
procedure TRL_TO_XML
(
RRL in TRL -- Связь
)
is
begin
/* Открываем описание связи */
PKG_XFAST.DOWN_NODE(SNAME => STAG_RL);
/* Связь */
PKG_XFAST.ATTR(SNAME => SATTR_ID, SVALUE => RRL.SID);
PKG_XFAST.ATTR(SNAME => SATTR_SOURCE, SVALUE => RRL.SSOURCE);
PKG_XFAST.ATTR(SNAME => SATTR_TARGET, SVALUE => RRL.STARGET);
PKG_XFAST.ATTR(SNAME => SATTR_MANDATORY, NVALUE => RRL.NMANDATORY);
/* Закрываем описание связи */
PKG_XFAST.UP();
end TRL_TO_XML;
/* Десериализация связи */
function TRL_FROM_XML
(
CXML in clob -- XML-описание связи
) return TRL -- Связь
is
RRES TRL; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
begin
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считаваем узел связи */
XNODE := PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_RL);
/* Получаем значения */
RRES.SID := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_ID);
RRES.SSOURCE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_SOURCE);
RRES.STARGET := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_TARGET);
RRES.NMANDATORY := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_MANDATORY);
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём результат */
return RRES;
end TRL_FROM_XML;
/* Поиск индекса связи по идентификатору */
function TRLS_INDEX_BY_ID
(
RRLS in TRLS, -- Коллекция связей
SID in varchar2 -- Искомый идентификатор
) return number -- Индекс найденной связи (null - если не найдено)
is
begin
/* Обходим коллекцию */
if ((RRLS is not null) and (RRLS.COUNT > 0)) then
for I in RRLS.FIRST .. RRLS.LAST
loop
begin
/* Возвращаем найденный индекс */
if (RRLS(I).SID = SID) then
return I;
end if;
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Ничего не нашли */
return null;
end TRLS_INDEX_BY_ID;
/* Формирование коллекции связей по источнику/приёмнику */
function TRLS_LIST_BY_ST
(
RRLS in TRLS, -- Коллекция связей
SSOURCE_TARGET in varchar2, -- Идентификатор источника/приёмкника
NLIST_TYPE in number -- Тип формирования коллекции (0 - по источнику, 1 - по приёмнику
) return TRLS -- Сформированная коллекция
is
RRES TRLS; -- Буфер для результата
begin
/* Инициализируем результат */
RRES := TRLS();
/* Обходим входную коллекцию */
if ((RRLS is not null) and (RRLS.COUNT > 0)) then
for I in RRLS.FIRST .. RRLS.LAST
loop
begin
/* Формируем выходную коллекцию */
if (((NLIST_TYPE = 0) and (RRLS(I).SSOURCE = SSOURCE_TARGET)) or
((NLIST_TYPE = 1) and (RRLS(I).STARGET = SSOURCE_TARGET))) then
RRES.EXTEND();
RRES(RRES.LAST) := TRL_MAKE(SID => RRLS(I).SID,
SSOURCE => RRLS(I).SSOURCE,
STARGET => RRLS(I).STARGET,
NMANDATORY => RRLS(I).NMANDATORY);
end if;
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Вернем результат */
return RRES;
end TRLS_LIST_BY_ST;
/* Добавление связи в коллекцию */
procedure TRLS_ADD
(
RRLS in out nocopy TRLS, -- Изменяемая коллекция
SSOURCE in varchar2, -- Источник
STARGET in varchar2, -- Приёмник
NMANDATORY in number -- Флаг обязательности (1 - да, 0 - нет)
)
is
RRL TRL; -- Добавляемая связь
begin
/* Инициализируем коллекцию если необходимо */
if (RRLS is null) then
RRLS := TRLS();
end if;
/* Формируем пописание связи */
RRL := TRL_MAKE(SSOURCE => SSOURCE, STARGET => STARGET, NMANDATORY => NMANDATORY);
/* Добавляем её в коллекцию */
RRLS.EXTEND();
RRLS(RRLS.LAST) := RRL;
end TRLS_ADD;
/* Удаление связи из коллекции */
procedure TRLS_REMOVE
(
RRLS in out nocopy TRLS, -- Изменяемая коллекция
SID in varchar2 -- Идентификатор удялемой связи
)
is
NIND PKG_STD.TNUMBER; -- Индекс связи в коллекции
begin
/* Найдем индекс связи в коллекции */
NIND := TRLS_INDEX_BY_ID(RRLS => RRLS, SID => SID);
/* Удалим её, если нашли */
if (NIND is not null) then
RRLS.DELETE(NIND);
end if;
end TRLS_REMOVE;
/* Установка признака обязательности связи в коллекции */
procedure TRLS_MANDATORY_SET
(
RRLS in out nocopy TRLS, -- Изменяемая коллекция
SID in varchar2, -- Идентификатор связи
NMANDATORY in number -- Флаг обязательности (1 - да, 0 - нет)
)
is
NIND PKG_STD.TNUMBER; -- Индекс связи в коллекции
begin
NIND := TRLS_INDEX_BY_ID(RRLS => RRLS, SID => SID);
if (NIND is not null) then
RRLS(NIND).NMANDATORY := NMANDATORY;
end if;
end TRLS_MANDATORY_SET;
/* Подчистка коллекции связей по атрибуту */
procedure TRLS_CLEANUP_BY_ATTR
(
RRLS in out nocopy TRLS, -- Изменяемая коллекция
SATTR_ID in varchar2 -- Идентификатор атрибута
)
is
RRLS_TMP PKG_P8PANELS_QE_BASE.TRLS; -- Буфер для коллекции удаляемых связей
begin
/* Если атрибут есть в связях (как источник или как приёмник) */
for J in 0 .. 1
loop
RRLS_TMP := TRLS_LIST_BY_ST(RRLS => RRLS, SSOURCE_TARGET => SATTR_ID, NLIST_TYPE => J);
/* То связь должна быть удалена */
if ((RRLS_TMP is not null) and (RRLS_TMP.COUNT > 0)) then
for K in RRLS_TMP.FIRST .. RRLS_TMP.LAST
loop
TRLS_REMOVE(RRLS => RRLS, SID => RRLS_TMP(K).SID);
end loop;
end if;
end loop;
end TRLS_CLEANUP_BY_ATTR;
/* Сериализация коллекции связей */
procedure TRLS_TO_XML
(
RRLS in TRLS -- Коллекция связей
)
is
begin
/* Открываем описание связей */
PKG_XFAST.DOWN_NODE(SNAME => STAG_RLS);
/* Обходим связи из коллекции */
if ((RRLS is not null) and (RRLS.COUNT > 0)) then
for I in RRLS.FIRST .. RRLS.LAST
loop
begin
/* Добавляем описание связи */
TRL_TO_XML(RRL => RRLS(I));
exception
when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* Закрываем описание связей */
PKG_XFAST.UP();
end TRLS_TO_XML;
/* Десериализация коллекции связей */
function TRLS_FROM_XML
(
CXML in clob -- XML-описание коллекции связей
) return TRLS -- Коллекция связей
is
RRES TRLS; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
XNODES PKG_XPATH.TNODES; -- Буфер коллекции узлов документа
begin
/* Инициализируем результат */
RRES := TRLS();
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считывание списка связей */
XNODES := PKG_XPATH.LIST_NODES(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_RLS || '/' || STAG_RL);
/* Цикл по списку связей */
for I in 1 .. PKG_XPATH.COUNT_NODES(RNODES => XNODES)
loop
/* Считаем элемент по его номеру */
XNODE := PKG_XPATH.ITEM_NODE(RNODES => XNODES, INUMBER => I);
/* Сериализуем и добавим его в коллекцию */
RRES.EXTEND();
RRES(RRES.LAST) := TRL_FROM_XML(CXML => PKG_XPATH.SERIALIZE_TO_CLOB(RNODE => XNODE));
end loop;
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём результат */
return RRES;
end TRLS_FROM_XML;
/* Формирование списка доступных сущностей */
function ENTITY_LIST
(
SSEARCH in varchar2, -- Поисковый запрос
NBRIEF in number, -- Флаг формирования описания сущности в кратком формате (0 - нет, 1 - да)
NINCLUDE_ATTRS in number -- Флаг включения в ответ атрибутов сущности (0 - нет, 1 - да)
) return clob -- Список сущностей
is
CRES clob; -- Буфер для сериализации
begin
/* Начинаем формирование XML */
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_, BALINE => true, BINDENT => true);
/* Открываем корень */
PKG_XFAST.DOWN_NODE(SNAME => STAG_DATA);
/* Строим и сериализуем список доступных сущностей */
TENTS_TO_XML(RENTS => TENTS_MAKE(SSEARCH => SSEARCH, NINIT_ATTRS => NINCLUDE_ATTRS),
NBRIEF => NBRIEF,
NINCLUDE_ATTRS => NINCLUDE_ATTRS);
/* Закрываем корень */
PKG_XFAST.UP();
/* Сериализуем */
CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Возвращаем результат */
return CRES;
exception
when others then
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end ENTITY_LIST;
/* Считывание записи запроса */
function QUERY_GET
(
NRN in number -- Рег. номер запроса
) return P8PNL_QE_QUERY%rowtype -- Запись запроса
is
RRES P8PNL_QE_QUERY%rowtype; -- Буфер для результата
begin
select T.* into RRES from P8PNL_QE_QUERY T where T.RN = NRN;
return RRES;
exception
when NO_DATA_FOUND then
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end QUERY_GET;
/* Получение признака возможности изменения запроса */
function QUERY_ACCESS_SIGN_MODIFY
(
NRN in number, -- Рег. номер запроса
SUSER in varchar2 -- Имя пользователя
) return number -- Признак возможности изменения запроса (0 - нет, 1 - да)
is
RQ P8PNL_QE_QUERY%rowtype; -- Проверяемая запись запроса
begin
/* Читаем запрос */
RQ := QUERY_GET(NRN => NRN);
/* Менять можно только свой запрос */
if (RQ.AUTHOR = SUSER) then
return 1;
end if;
/* Проверки не пройдены - менять нельзя */
return 0;
end QUERY_ACCESS_SIGN_MODIFY;
/* Проверка возможности изменения запроса */
procedure QUERY_ACCESS_MODIFY
(
NRN in number, -- Рег. номер запроса
SUSER in varchar2 -- Имя пользователя
)
is
begin
/* Получим признак возможности измнения */
if (QUERY_ACCESS_SIGN_MODIFY(NRN => NRN, SUSER => SUSER) = 0) then
/* Менять нельзя */
P_EXCEPTION(0, 'У Вас нет прав доступа для измнения запроса.');
end if;
end QUERY_ACCESS_MODIFY;
/* Получение признака возможности просмотра запроса */
function QUERY_ACCESS_SIGN_VIEW
(
NRN in number, -- Рег. номер запроса
SUSER in varchar2 -- Имя пользователя
) return number -- Признак возможности просмотра запроса (0 - нет, 1 - да)
is
RQ P8PNL_QE_QUERY%rowtype; -- Проверяемая запись запроса
begin
/* Читаем запрос */
RQ := QUERY_GET(NRN => NRN);
/* Смотреть можно только свой или публичный запрос */
if ((RQ.PBL = 1) or (RQ.AUTHOR = SUSER)) then
return 1;
end if;
/* Проверки не пройдены - нельзя смотреть */
return 0;
end QUERY_ACCESS_SIGN_VIEW;
/* Проверка возможности просмотра запроса */
procedure QUERY_ACCESS_VIEW
(
NRN in number, -- Рег. номер запроса
SUSER in varchar2 -- Имя пользователя
)
is
begin
/* Получим признак возможности просмотра */
if (QUERY_ACCESS_SIGN_VIEW(NRN => NRN, SUSER => SUSER) = 0) then
/* Смотреть нельзя */
P_EXCEPTION(0, 'У Вас нет прав доступа для просмотра запроса.');
end if;
end QUERY_ACCESS_VIEW;
/* Проверка атрибутов запроса */
procedure QUERY_CHECK
(
SCODE in varchar2, -- Мнемокод
SNAME in varchar2 -- Наименование
)
is
begin
/* Мнемокод должен быть задан */
if (SCODE is null) then
P_EXCEPTION(0, 'Не задан мнемокод запроса.');
end if;
/* Наименование должно быть задано */
if (SNAME is null) then
P_EXCEPTION(0, 'Не задано наименование запроса.');
end if;
end QUERY_CHECK;
/* Синхронизация даты изменения запроса с текущим временем */
procedure QUERY_CH_DATE_SYNC
(
NRN in number -- Рег. номер запроса
)
is
begin
/* Установим текущую дату изменения */
update P8PNL_QE_QUERY T set T.CH_DATE = sysdate where T.RN = NRN;
/* Контроль изменения данных */
if (sql%notfound) then
PKG_MSG.RECORD_NOT_FOUND(NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end if;
end QUERY_CH_DATE_SYNC;
/* Сериализация сущностей запроса */
function QUERY_ENTS_TO_XML
(
RENTS in TENTS -- Коллекция сущностей
) return clob -- XML-описание
is
CRES clob; -- Буфер для результата
begin
/* Если сущности есть */
if ((RENTS is not null) and (RENTS.COUNT > 0)) then
/* Начинаем формирование XML */
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
/* Добавляем сущности */
TENTS_TO_XML(RENTS => RENTS);
/* Сериализуем */
CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
else
CRES := null;
end if;
/* Возвращаем полученное */
return CRES;
exception
when others then
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end QUERY_ENTS_TO_XML;
/* Десериализация сущностей запроса */
function QUERY_ENTS_FROM_XML
(
CXML in clob -- XML-описание коллекции сущностей запроса
) return TENTS -- Коллекция сущностей
is
RENTS TENTS; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
begin
/* Инициализируем результат */
RENTS := TENTS();
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считываем узел сущностей */
XNODE := PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_ENTS);
/* Десериализуем его */
RENTS := TENTS_FROM_XML(CXML => PKG_XPATH.SERIALIZE_TO_CLOB(RNODE => XNODE));
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём сформированное */
return RENTS;
end QUERY_ENTS_FROM_XML;
/* Сериализация связей запроса */
function QUERY_RLS_TO_XML
(
RRLS in TRLS -- Коллекция связей
) return clob -- XML-описание
is
CRES clob; -- Буфер для результата
begin
/* Если связи есть */
if ((RRLS is not null) and (RRLS.COUNT > 0)) then
/* Начинаем формирование XML */
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
/* Добавляем связи */
TRLS_TO_XML(RRLS => RRLS);
/* Сериализуем */
CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
else
CRES := null;
end if;
/* Возвращаем полученное */
return CRES;
exception
when others then
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end QUERY_RLS_TO_XML;
/* Десериализация связей запроса */
function QUERY_RLS_FROM_XML
(
CXML in clob -- XML-описание коллекции связей запроса
) return TRLS -- Коллекция связей
is
RRLS TRLS; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
begin
/* Инициализируем результат */
RRLS := TRLS();
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считываем узел связей */
XNODE := PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_RLS);
/* Десериализуем его */
RRLS := TRLS_FROM_XML(CXML => PKG_XPATH.SERIALIZE_TO_CLOB(RNODE => XNODE));
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём сформированное */
return RRLS;
end QUERY_RLS_FROM_XML;
/* Сериализация настройки запроса */
function QUERY_OPT_TO_XML
(
ROPT in TOPT -- Настройка
) return clob -- XML-описание
is
CRES clob; -- Буфер для результата
begin
/* Начинаем формирование XML */
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_);
/* Формируем XML настройки */
TOPT_TO_XML(ROPT => ROPT);
/* Сериализуем */
CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Возвращаем полученное */
return CRES;
exception
when others then
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end QUERY_OPT_TO_XML;
/* Десериализация настройки запроса */
function QUERY_OPT_FROM_XML
(
CXML in clob -- XML-описание настройки запроса
) return TOPT -- Настройка
is
ROPT TOPT; -- Буфер для результата
XDOC PKG_XPATH.TDOCUMENT; -- Документ XML
XROOT PKG_XPATH.TNODE; -- Корень документа XML
XNODE PKG_XPATH.TNODE; -- Буфер узла документа
begin
/* Инициализируем результат */
ROPT.RARGS := TARGS();
/* Если данные есть */
if (CXML is not null) then
begin
/* Разбираем XML */
XDOC := PKG_XPATH.PARSE_FROM_CLOB(LCXML => CXML);
/* Считываем корневой узел */
XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC);
/* Считываем узел настройки */
XNODE := PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_OPT);
/* Десериализуем его */
ROPT := TOPT_FROM_XML(CXML => PKG_XPATH.SERIALIZE_TO_CLOB(RNODE => XNODE));
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception
when others then
/* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC);
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end;
end if;
/* Вернём сформированное */
return ROPT;
end QUERY_OPT_FROM_XML;
/* Сериализация запроса */
function QUERY_TO_XML
(
NRN in number -- Рег. номер запроса
) return clob -- XML-описание
is
RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса
CRES clob; -- Буфер для сериализации
begin
/* Читаем запрос */
RQ := QUERY_GET(NRN => NRN);
/* Начинаем формирование XML */
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_, BALINE => true, BINDENT => true);
/* Открываем корень */
PKG_XFAST.DOWN_NODE(SNAME => STAG_DATA);
/* Настройка */
if (RQ.OPT is not null) then
TOPT_TO_XML(ROPT => QUERY_OPT_FROM_XML(CXML => RQ.OPT));
end if;
/* Сущности (можно использовать просто PKG_XFAST.VALUE_XML и сразу отдать готовый XML из RQ.ENTS, но это приводит к формированию некорректного документа с лишней ">" между группами) */
if (RQ.ENTS is not null) then
TENTS_TO_XML(RENTS => QUERY_ENTS_FROM_XML(CXML => RQ.ENTS));
end if;
/* Связи (можно использовать просто PKG_XFAST.VALUE_XML и сразу отдать готовый XML из RQ.RLS, но это приводит к формированию некорректного документа с лишней ">" между группами) */
if (RQ.RLS is not null) then
TRLS_TO_XML(RRLS => QUERY_RLS_FROM_XML(CXML => RQ.RLS));
end if;
/* SQL-выражение */
PKG_XFAST.HERB(SNAME => STAG_QRY, LCVALUE => RQ.QRY);
/* Сообщение при формировании SQL-выражения */
PKG_XFAST.HERB(SNAME => STAG_QRY_MSG, LCVALUE => RQ.QRY_MSG);
/* Закрываем корень */
PKG_XFAST.UP();
/* Сериализуем */
CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Возвращаем результат */
return CRES;
exception
when others then
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end QUERY_TO_XML;
/* Формирование описания запроса */
function QUERY
(
NRN in number -- Рег. номер запроса
) return clob -- XML-описание
is
begin
/* Сериализуем запрос */
return QUERY_TO_XML(NRN => NRN);
end QUERY;
/* Формирование списка запросов */
function QUERY_LIST
(
SUSER in varchar2 -- Имя пользователя
) return clob -- Список запросов
is
CRES clob; -- Буфер для сериализации
begin
/* Начинаем формирование XML */
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_, BALINE => true, BINDENT => true);
/* Открываем корень */
PKG_XFAST.DOWN_NODE(SNAME => STAG_DATA);
/* Открываем список запросов */
PKG_XFAST.DOWN_NODE(SNAME => STAG_QUERIES);
/* Обходим запросы - данного пользователя и публичные */
for C in (select T.RN NRN,
T.CODE SCODE,
T.NAME SNAME,
UL.NAME SAUTHOR,
TO_CHAR(T.CH_DATE, 'dd.mm.yyyy hh24:mi:ss') SCH_DATE,
T.READY NREADY,
T.PBL NPBL,
QUERY_ACCESS_SIGN_MODIFY(T.RN, SUSER) NMODIFY
from P8PNL_QE_QUERY T,
USERLIST UL
where T.AUTHOR = UL.AUTHID
and QUERY_ACCESS_SIGN_VIEW(T.RN, SUSER) = 1
order by T.CODE)
loop
/* Открываем описание запроса */
PKG_XFAST.DOWN_NODE(SNAME => STAG_QUERY);
/* Запрос */
PKG_XFAST.ATTR(SNAME => SATTR_RN, NVALUE => C.NRN);
PKG_XFAST.ATTR(SNAME => SATTR_CODE, SVALUE => C.SCODE);
PKG_XFAST.ATTR(SNAME => SATTR_NAME, SVALUE => C.SNAME);
PKG_XFAST.ATTR(SNAME => SATTR_AUTHOR, SVALUE => C.SAUTHOR);
PKG_XFAST.ATTR(SNAME => SATTR_CH_DATE, SVALUE => C.SCH_DATE);
PKG_XFAST.ATTR(SNAME => SATTR_READY, NVALUE => C.NREADY);
PKG_XFAST.ATTR(SNAME => SATTR_PBL, NVALUE => C.NPBL);
PKG_XFAST.ATTR(SNAME => SATTR_MODIFY, NVALUE => C.NMODIFY);
/* Закрываем описание запроса */
PKG_XFAST.UP();
end loop;
/* Закрываем список запросов */
PKG_XFAST.UP();
/* Закрываем корень */
PKG_XFAST.UP();
/* Сериализуем */
CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Возвращаем результат */
return CRES;
exception
when others then
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end QUERY_LIST;
/* Добавление запроса */
procedure QUERY_INSERT
(
SCODE in varchar2, -- Мнемокод
SNAME in varchar2, -- Наименование
NRN out number -- Рег. номер добавленного запроса
)
is
begin
/* Проверим параметры */
QUERY_CHECK(SCODE => SCODE, SNAME => SNAME);
/* Формируем рег. номер */
NRN := GEN_ID();
/* Добавляем данные */
insert into P8PNL_QE_QUERY
(RN, CODE, name, AUTHOR, CH_DATE, READY, PBL)
values
(NRN, SCODE, SNAME, UTILIZER(), sysdate, 0, 0);
end QUERY_INSERT;
/* Исправление запроса */
procedure QUERY_UPDATE
(
NRN in number, -- Рег. номер запроса
SCODE in varchar2, -- Мнемокод
SNAME in varchar2 -- Наименование
)
is
begin
/* Проверим параметры */
QUERY_CHECK(SCODE => SCODE, SNAME => SNAME);
/* Изменяем данные */
update P8PNL_QE_QUERY T
set T.CODE = SCODE,
T.NAME = SNAME
where T.RN = NRN;
/* Контроль изменения данных */
if (sql%notfound) then
PKG_MSG.RECORD_NOT_FOUND(NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end if;
/* Обновим дату изменения запроса */
QUERY_CH_DATE_SYNC(NRN => NRN);
end QUERY_UPDATE;
/* Удаление запроса */
procedure QUERY_DELETE
(
NRN in number -- Рег. номер запроса
)
is
begin
/* Удаляем запись */
delete from P8PNL_QE_QUERY T where T.RN = NRN;
/* Контроль изменения данных */
if (sql%notfound) then
PKG_MSG.RECORD_NOT_FOUND(NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end if;
end QUERY_DELETE;
/* Чтение сущностей запроса */
function QUERY_ENTS_GET
(
CENTS in clob -- Сериализованное описание сущностей
) return TENTS -- Коллекция сущностей
is
begin
/* Десериализуем */
return QUERY_ENTS_FROM_XML(CXML => CENTS);
end QUERY_ENTS_GET;
/* Запись сущностей запроса */
procedure QUERY_ENTS_SET
(
NRN in number, -- Рег. номер запроса
RENTS in TENTS -- Коллекция сущностей
)
is
CENTS clob; -- Буфер для сериализации
begin
/* Сериализуем полученную коллекцию сущностей */
CENTS := QUERY_ENTS_TO_XML(RENTS => RENTS);
/* Сохраним её */
update P8PNL_QE_QUERY T set T.ENTS = CENTS where T.RN = NRN;
/* Контроль изменения данных */
if (sql%notfound) then
PKG_MSG.RECORD_NOT_FOUND(NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end if;
/* Обновим дату изменения запроса */
QUERY_CH_DATE_SYNC(NRN => NRN);
end QUERY_ENTS_SET;
/* Получение состава атрибутов сущности */
procedure QUERY_ENT_ATTRS_GET
(
NRN in number, -- Рег. номер запроса
SID in varchar2, -- Идентификатор сущности
COUT out clob -- Сериализованное описание атрибутов сущности
)
is
RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса
NENT_INDEX PKG_STD.TNUMBER; -- Индекс изменяемой сущности в коллекции
RENTS TENTS; -- Коллекция существующих сущностей
RENT TENT; -- Изменяемая сущность
RATTRS TATTRS; -- Коллекция атрибутов изменяемой сущности
begin
/* Читаем запись запроса */
RQ := QUERY_GET(NRN => NRN);
/* Читаем существующие сущности */
RENTS := QUERY_ENTS_GET(CENTS => RQ.ENTS);
/* Читаем изменяемую сущность */
NENT_INDEX := TENTS_INDEX_BY_ID(RENTS => RENTS, SID => SID);
if (NENT_INDEX is not null) then
RENT := RENTS(NENT_INDEX);
else
P_EXCEPTION(0,
'Сущность с идентификатором "%s" не определена.',
COALESCE(SID, '<НЕ УКАЗАН>'));
end if;
/* Получим полный набор атрибутов сущности */
RATTRS := TATTRS_MAKE(RENT => RENT);
/* Начинаем формирование XML */
PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_, BALINE => true, BINDENT => true);
/* Открываем корень */
PKG_XFAST.DOWN_NODE(SNAME => STAG_DATA);
/* Формируем описание тарибутов */
TATTRS_TO_XML(RATTRS => RATTRS);
/* Закрываем корень */
PKG_XFAST.UP();
/* Сериализуем */
COUT := PKG_XFAST.SERIALIZE_TO_CLOB();
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
exception
when others then
/* Завершаем формирование XML */
PKG_XFAST.EPILOGUE();
/* Вернем ошибку */
PKG_STATE.DIAGNOSTICS_STACKED();
P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
end QUERY_ENT_ATTRS_GET;
/* Чтение связей запроса */
function QUERY_RLS_GET
(
CRLS in clob -- Сериализованное описание связей
) return TRLS -- Коллекция связей
is
begin
/* Десериализуем */
return QUERY_RLS_FROM_XML(CXML => CRLS);
end QUERY_RLS_GET;
/* Запись связей запроса */
procedure QUERY_RLS_SET
(
NRN in number, -- Рег. номер запроса
RRLS in TRLS -- Коллекция связей
)
is
CRLS clob; -- Буфер для сериализации
begin
/* Сериализуем полученную коллекцию связей */
CRLS := QUERY_RLS_TO_XML(RRLS => RRLS);
/* Сохраним её */
update P8PNL_QE_QUERY T set T.RLS = CRLS where T.RN = NRN;
/* Контроль изменения данных */
if (sql%notfound) then
PKG_MSG.RECORD_NOT_FOUND(NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end if;
/* Обновим дату изменения запроса */
QUERY_CH_DATE_SYNC(NRN => NRN);
end QUERY_RLS_SET;
/* Установка признака "готовности" запроса */
procedure QUERY_READY_SET
(
NRN in number, -- Рег. номер запроса
NREADY in number -- Флаг готовности к использованию (0 - нет, 1 - да)
)
is
begin
/* Проверим параметры */
if (NREADY is null) then
P_EXCEPTION(0,
'Не задано значение признака готовности запроса к использованию.');
end if;
if (NREADY not in (0, 1)) then
P_EXCEPTION(0,
'Значение признака готовности запроса к использованию задано некорректно (ожидалось 0 или 1).');
end if;
/* Установим флаг готовности к использованию */
update P8PNL_QE_QUERY T set T.READY = NREADY where T.RN = NRN;
/* Контроль изменения данных */
if (sql%notfound) then
PKG_MSG.RECORD_NOT_FOUND(NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end if;
/* Обновим дату изменения запроса */
QUERY_CH_DATE_SYNC(NRN => NRN);
end QUERY_READY_SET;
/* Установка признака "публичности" запроса */
procedure QUERY_PBL_SET
(
NRN in number, -- Рег. номер запроса
NPBL in number -- Флаг публичности (0 - приватный, 1 - публичный)
)
is
begin
/* Проверим параметры */
if (NPBL is null) then
P_EXCEPTION(0, 'Не задано значение признака публичности запроса.');
end if;
if (NPBL not in (0, 1)) then
P_EXCEPTION(0,
'Значение признака публичноти запроса задано некорректно (ожидалось 0 или 1).');
end if;
/* Установим флаг публичности */
update P8PNL_QE_QUERY T set T.PBL = NPBL where T.RN = NRN;
/* Контроль изменения данных */
if (sql%notfound) then
PKG_MSG.RECORD_NOT_FOUND(NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end if;
/* Обновим дату изменения запроса */
QUERY_CH_DATE_SYNC(NRN => NRN);
end QUERY_PBL_SET;
/* Чтение настройки запроса */
function QUERY_OPT_GET
(
COPT in clob -- Сериализованное описание настройки запроса
) return TOPT -- Настройка запроса
is
begin
/* Десериализуем */
return QUERY_OPT_FROM_XML(CXML => COPT);
end QUERY_OPT_GET;
/* Запись настройки запроса */
procedure QUERY_OPT_SET
(
NRN in number, -- Рег. номер запроса
ROPT in TOPT -- Настройка запроса
)
is
COPT clob; -- Буфер для сериализации
begin
/* Сериализуем настройку */
COPT := QUERY_OPT_TO_XML(ROPT => ROPT);
/* Сохраним её */
update P8PNL_QE_QUERY T set T.OPT = COPT where T.RN = NRN;
/* Контроль изменения данных */
if (sql%notfound) then
PKG_MSG.RECORD_NOT_FOUND(NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end if;
/* Обновим дату изменения запроса */
QUERY_CH_DATE_SYNC(NRN => NRN);
end QUERY_OPT_SET;
/* Запись SQL-выражения запроса */
procedure QUERY_QRY_SET
(
NRN in number, -- Рег. номер запроса
CQRY in clob, -- SQL-выражение
CQRY_MSG in clob -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
)
is
begin
/* Сохраним её */
update P8PNL_QE_QUERY T
set T.QRY = CQRY,
T.QRY_MSG = CQRY_MSG
where T.RN = NRN;
/* Контроль изменения данных */
if (sql%notfound) then
PKG_MSG.RECORD_NOT_FOUND(NDOCUMENT => NRN, SUNIT_TABLE => 'P8PNL_QE_QUERY');
end if;
/* Обновим дату изменения запроса */
QUERY_CH_DATE_SYNC(NRN => NRN);
end QUERY_QRY_SET;
/* Формирование SQL запроса */
procedure QUERY_SQL_BUILD
(
NRN in number, -- Рег. номер запроса
SQRY out varchar2, -- SQL-выражение
SQRY_MSG out varchar2 -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
)
is
RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса
RENTS TENTS; -- Сущности запроса
RRLS TRLS; -- Связи запроса
ROPT TOPT; -- Настройка запроса
/* Кумулятивная установка сообщения формирования запроса */
procedure SET_MSG
(
SMESSAGE in varchar2, -- Текст сообщения
BCLEAR_QRY in boolean := true -- Флаг очистки сформированного запроса
)
is
begin
if (BCLEAR_QRY) then
SQRY := null;
end if;
if (SQRY_MSG is null) then
SQRY_MSG := SMESSAGE;
else
SQRY_MSG := SQRY_MSG || CHR(10) || CHR(13) || SMESSAGE;
end if;
end SET_MSG;
/* Поиск корневой (не имеет связей по выходу - т.е. нигде не является источником) сущности запроса */
procedure FIND_ROOT_ENT
(
RENTS TENTS, -- Сущности запроса
RRLS TRLS, -- Связи запроса
RENT out TENT, -- Найденная корневая сущность
SMESSAGE out varchar2 -- Сообщение от алгоритма поиска
)
is
BFOUND boolean; -- Флаг наличия атрибута сущности в составе источникв связей запроса
begin
/* Если сущность одна - то она и главная */
if (RENTS.COUNT = 1) then
RENT := RENTS(RENTS.FIRST);
return;
end if;
/* Обходим все сущности */
for E in RENTS.FIRST .. RENTS.LAST
loop
/* Сброс флага наличия атрибутов в источниках связей */
BFOUND := false;
/* Обходим атрибуты сущности */
for A in RENTS(E).RATTRS.FIRST .. RENTS(E).RATTRS.LAST
loop
/* Обойдем связи и поищем атрибут среди источников */
if ((RRLS is not null) and (RRLS.COUNT > 0)) then
for R in RRLS.FIRST .. RRLS.LAST
loop
if (RRLS(R).SSOURCE = RENTS(E).RATTRS(A).SID) then
BFOUND := true;
exit;
end if;
end loop;
end if;
/* Если хоть один атрибут сущности есть среди источников - дальше можно атрибуты этой сущности не рассматривать */
exit when BFOUND = true;
end loop;
/* Если ни один из атрибутов не был источником - сущность наш клиент */
if (not BFOUND) then
/* Если мы ещё не находили корневую сущность ранее */
if (RENT.SID is null) then
RENT := RENTS(E);
else
/* Ранее была найдена корневая сущность */
SMESSAGE := 'В запросе более одной корневой (без выходных связей) сущности.';
return;
end if;
end if;
end loop;
/* Проверим, что хоть что-то нашли */
if (RENT.SID is null) then
SMESSAGE := 'В запросе нет корневой (без выходных связей) сущности.';
end if;
end FIND_ROOT_ENT;
/* Формирование части "select" */
procedure BUILD_SELECT
(
RENTS TENTS, -- Сущности запроса
SQRY in out varchar2 -- Буфер для запроса
)
is
SFIELD PKG_STD.TSTRING; -- Буфер для поля запроса
BFOUND boolean := false; -- Флаг наличия визуализируемых атрибутов
begin
/* Формируем */
PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => 'select ');
for I in RENTS.FIRST .. RENTS.LAST
loop
if ((RENTS(I).RATTRS is not null) and (RENTS(I).RATTRS.COUNT > 0)) then
for J in RENTS(I).RATTRS.FIRST .. RENTS(I).RATTRS.LAST
loop
if (RENTS(I).RATTRS(J).NSHOW = 1) then
if (RENTS(I).RATTRS(J).SALIAS is null) then
P_EXCEPTION(0,
'Для атрибута ("%s") не задан севдоним.',
RENTS(I).RATTRS(J).SID);
end if;
SFIELD := RENTS(I).RATTRS(J).SID || ' "' || RENTS(I).RATTRS(J).SALIAS || '", ';
PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => SFIELD);
BFOUND := true;
end if;
end loop;
end if;
end loop;
SQRY := RTRIM(SQRY, ', ');
/* Если не нашли ни одного атрибута */
if (not BFOUND) then
P_EXCEPTION(0,
'Для запроса не определено ни одного визуализируемого атрибута.');
end if;
end BUILD_SELECT;
/* Формирование иерархии связей в секции "from" */
procedure BUILD_FROM_HIER
(
RENT_START TENT, -- Начало ветки
RENTS TENTS, -- Сущности запроса
RRLS TRLS, -- Связи запроса
SQRY in out varchar2 -- Буфер для запроса
)
is
NENT_SRC PKG_STD.TNUMBER; -- Индекс сущности-источника связи
SJOIN PKG_STD.TSTRING; -- Буфер для операции объединения
STABLE PKG_STD.TSTRING; -- Буфер для таблицы запроса
begin
/* Обходим связи */
for I in RRLS.FIRST .. RRLS.LAST
loop
/* Если это связь, в которой приёмником является стартовая сущность */
if (TATTRS_INDEX_BY_ID(RATTRS => RENT_START.RATTRS, SID => RRLS(I).STARGET) is not null) then
/* Найдем сущность-источник связи по атрибуту-источнику связи */
NENT_SRC := TENTS_INDEX_BY_ATTR_ID(RENTS => RENTS, SATTR_ID => RRLS(I).SSOURCE);
if (NENT_SRC is null) then
P_EXCEPTION(0,
'Для связи "%s - %s" не удалось определить сущность-источник.',
RRLS (I)
.SSOURCE,
RRLS (I)
.STARGET);
end if;
/* Определим тип объединения */
if (RRLS(I).NMANDATORY = 1) then
SJOIN := 'join';
else
SJOIN := 'left join';
end if;
/* Соберем выражение и добавим его в запрос */
STABLE := SJOIN || ' ' || RENTS(NENT_SRC).SNAME || ' ' || RENTS(NENT_SRC).SID || ' on ' || RRLS(I).STARGET ||
' = ' || RRLS(I).SSOURCE;
PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => STABLE);
/* Добавим связи сущности-источника */
BUILD_FROM_HIER(RENT_START => RENTS(NENT_SRC), RENTS => RENTS, RRLS => RRLS, SQRY => SQRY);
end if;
end loop;
end BUILD_FROM_HIER;
/* Формирование части "from" */
procedure BUILD_FROM
(
RENTS TENTS, -- Сущности запроса
RRLS TRLS, -- Связи запроса
SQRY in out varchar2 -- Буфер для запроса
)
is
RENT_ROOT TENT; -- Корневая сущность запроса
STABLE PKG_STD.TSTRING; -- Буфер для таблицы запроса
SMESSAGE PKG_STD.TSTRING; -- Буфер для сообщений
begin
/* Определяем корневую сущность запроса */
FIND_ROOT_ENT(RENTS => RENTS, RRLS => RRLS, RENT => RENT_ROOT, SMESSAGE => SMESSAGE);
/* Продолжаем только если корневую успешно определили */
if ((RENT_ROOT.SID is not null) and (SMESSAGE is null)) then
PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => 'from ');
STABLE := RENT_ROOT.SNAME || ' ' || RENT_ROOT.SID;
PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => STABLE);
if ((RRLS is not null) and (RRLS.COUNT > 0)) then
BUILD_FROM_HIER(RENT_START => RENT_ROOT, RENTS => RENTS, RRLS => RRLS, SQRY => SQRY);
end if;
else
/* Корневую сущность не нашли */
SET_MSG(SMESSAGE => SMESSAGE, BCLEAR_QRY => false);
end if;
end BUILD_FROM;
/* Формирование части "where" */
procedure BUILD_WHERE
(
ROPT TOPT, -- Настройка запроса
SQRY in out varchar2 -- Буфер для запроса
)
is
begin
if (ROPT.SCOND is not null) then
PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => 'where ' || ROPT.SCOND);
end if;
end BUILD_WHERE;
begin
/*
TODO: owner="root" created="10.09.2025"
text="Предусмотреть отладочные значения для аргументов запроса"
*/
/*
TODO: owner="root" created="11.09.2025"
text="Проверять соответствие условий отбора запроса набору его аргументов"
*/
/* Читаем описание запроса */
RQ := QUERY_GET(NRN => NRN);
/* Читаем сущности запроса */
RENTS := QUERY_ENTS_GET(CENTS => RQ.ENTS);
/* Нет сущностей - нет запроса */
if ((RENTS is null) or (RENTS.COUNT = 0)) then
SET_MSG(SMESSAGE => 'В запросе нет сущностей.');
return;
end if;
/* Читаем связи запроса */
RRLS := QUERY_RLS_GET(CRLS => RQ.RLS);
/* Нельзя построить запрос, если есть несвязанные сущности */
if ((RENTS.COUNT > 1) and ((RRLS is null) or (RENTS.COUNT - 1 > RRLS.COUNT))) then
SET_MSG(SMESSAGE => 'В запросе есть несвязанные сущности.');
return;
end if;
/* Читаем настройку запроса */
ROPT := QUERY_OPT_GET(COPT => RQ.OPT);
/* Добавляем подсказку совместимости */
SQRY := PKG_SQL_BUILD.COMPATIBLE(SSQL => SQRY);
/* Собираем запрос - поля */
BUILD_SELECT(RENTS => RENTS, SQRY => SQRY);
/* Собираем запрос - таблицы и связи */
BUILD_FROM(RENTS => RENTS, RRLS => RRLS, SQRY => SQRY);
/* Собираем запрос - условия */
BUILD_WHERE(ROPT => ROPT, SQRY => SQRY);
exception
when others then
PKG_STATE.DIAGNOSTICS_STACKED();
SET_MSG(SMESSAGE => PKG_STATE.SQL_ERRM(), BCLEAR_QRY => false);
end QUERY_SQL_BUILD;
end PKG_P8PANELS_QE_BASE;
/