3059 lines
142 KiB
SQL
3059 lines
142 KiB
SQL
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, -- Условия отбора
|
||
NSUBST_ARGS_VALS PKG_STD.TNUMBER -- Флаг подстановки значений аргументов в запрос (1 - да, 0 - нет)
|
||
);
|
||
|
||
/* Типы данных - Атрибут сущности */
|
||
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_REFRESH
|
||
(
|
||
NRN in number -- Рег. номер запроса
|
||
);
|
||
|
||
/* Формирование SQL запроса */
|
||
procedure QUERY_SQL_BUILD
|
||
(
|
||
NRN in number, -- Рег. номер запроса
|
||
SQRY out varchar2, -- SQL-выражение
|
||
SQRY_BND 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_SUBST_ARGS_VALS constant PKG_STD.TSTRING := 'XSUBST_ARGS_VALS'; -- Флаг подстановки значений аргументов в запрос
|
||
STAG_QRY constant PKG_STD.TSTRING := 'XQRY'; -- SQL-выражение запроса
|
||
STAG_QRY_BND constant PKG_STD.TSTRING := 'XQRY_BND'; -- 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;
|
||
for C in (select null from DUAL where not REGEXP_LIKE(SUBSTR(SNAME, 1, 1), '^[A-z]+$'))
|
||
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 (UPPER(RARGS(I).SNAME) = UPPER(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" уже существует.', UPPER(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.HERB(SNAME => STAG_SUBST_ARGS_VALS, NVALUE => ROPT.NSUBST_ARGS_VALS);
|
||
/* Закрываем описание настройки */
|
||
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.NSUBST_ARGS_VALS := PKG_XPATH.VALUE_NUM(RNODE => XNODE, SPATTERN => STAG_SUBST_ARGS_VALS);
|
||
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_BND, LCVALUE => RQ.QRY_BND);
|
||
/* Сообщение при формировании 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_BND in clob, -- SQL-выражение с подставленными значениями аргументов
|
||
CQRY_MSG in clob -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
|
||
)
|
||
is
|
||
begin
|
||
/* Сохраним её */
|
||
update P8PNL_QE_QUERY T
|
||
set T.QRY = CQRY,
|
||
T.QRY_BND = CQRY_BND,
|
||
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_QRY_REFRESH
|
||
(
|
||
NRN in number -- Рег. номер запроса
|
||
)
|
||
is
|
||
SQRY PKG_STD.TLSTRING; -- SQL-выражение запроса
|
||
SQRY_BND PKG_STD.TLSTRING; -- SQL-выражение запроса с подстановками
|
||
SQRY_MSG PKG_STD.TLSTRING; -- Сообщение при формировании SQL-выражения
|
||
begin
|
||
/* Сформируем SQL-выражение */
|
||
QUERY_SQL_BUILD(NRN => NRN, SQRY => SQRY, SQRY_BND => SQRY_BND, SQRY_MSG => SQRY_MSG);
|
||
/* Обновим его в запросе */
|
||
QUERY_QRY_SET(NRN => NRN, CQRY => SQRY, CQRY_BND => SQRY_BND, CQRY_MSG => SQRY_MSG);
|
||
end QUERY_QRY_REFRESH;
|
||
|
||
/* Формирование SQL запроса */
|
||
procedure QUERY_SQL_BUILD
|
||
(
|
||
NRN in number, -- Рег. номер запроса
|
||
SQRY out varchar2, -- SQL-выражение
|
||
SQRY_BND out varchar2, -- SQL-выражение с подставленными значениями аргументов
|
||
SQRY_MSG out varchar2 -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
|
||
)
|
||
is
|
||
RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса
|
||
RENTS TENTS; -- Сущности запроса
|
||
RRLS TRLS; -- Связи запроса
|
||
ROPT TOPT; -- Настройка запроса
|
||
|
||
/* Кумулятивная установка сообщения формирования запроса */
|
||
procedure ADD_QRY_MSG
|
||
(
|
||
SMESSAGE in varchar2, -- Текст сообщения
|
||
BCLEAR_QRY in boolean := true -- Флаг очистки сформированного запроса
|
||
)
|
||
is
|
||
begin
|
||
if (BCLEAR_QRY) then
|
||
SQRY := null;
|
||
SQRY_BND := 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 ADD_QRY_MSG;
|
||
|
||
/* Проверка соответствия условий запроса набору его аргументов */
|
||
procedure CHECK_COND_ARGS
|
||
(
|
||
ROPT TOPT -- Настройка запроса
|
||
)
|
||
is
|
||
RCOND_VARS PKG_CONTVARLOC.TCONTAINER; -- Коллекция переменных условия запроса
|
||
SCOND_VAR PKG_STD.TSTRING; -- Текущая переменная условия запроса
|
||
begin
|
||
/* Извлечен переменные из условия запроса */
|
||
RCOND_VARS := PKG_SQL_BUILD.VAR_LIST(SSQL => ROPT.SCOND);
|
||
/* Если переменные в условии есть */
|
||
if (PKG_CONTVARLOC.COUNT_(RCONTAINER => RCOND_VARS) > 0) then
|
||
/* Обходим их */
|
||
SCOND_VAR := PKG_CONTVARLOC.FIRST_(RCONTAINER => RCOND_VARS);
|
||
while (SCOND_VAR is not null)
|
||
loop
|
||
/* Проверяем вхождение текущей переменной в состав аргументов запроса */
|
||
if (TARGS_INDEX_BY_NAME(RARGS => ROPT.RARGS, SNAME => SCOND_VAR) is null) then
|
||
/* В аргументах такой нет - добавляем предупреждение */
|
||
ADD_QRY_MSG(SMESSAGE => 'Переменная условия запроса "' || SCOND_VAR ||
|
||
'" отсутствует в составе его аргументов.',
|
||
BCLEAR_QRY => false);
|
||
end if;
|
||
/* Ищем следующу */
|
||
SCOND_VAR := PKG_CONTVARLOC.NEXT_(RCONTAINER => RCOND_VARS, SNAME => SCOND_VAR);
|
||
end loop;
|
||
end if;
|
||
end CHECK_COND_ARGS;
|
||
|
||
/* Поиск корневой (не имеет связей по выходу - т.е. нигде не является источником) сущности запроса */
|
||
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
|
||
/* Корневую сущность не нашли */
|
||
ADD_QRY_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;
|
||
|
||
/* Подстановка отладочных значений в SQL-выражение */
|
||
procedure BOUND
|
||
(
|
||
ROPT TOPT, -- Настройка запроса
|
||
SQRY in varchar2, -- Сформированное SQL-выражение
|
||
SQRY_BND out varchar2 -- SQL-выражение с подстановками
|
||
)
|
||
is
|
||
begin
|
||
SQRY_BND := SQRY;
|
||
if ((ROPT.RARGS is not null) and (ROPT.RARGS.COUNT > 0)) then
|
||
for I in ROPT.RARGS.FIRST .. ROPT.RARGS.LAST
|
||
loop
|
||
begin
|
||
case
|
||
when ROPT.RARGS(I).NDATA_TYPE = PKG_STD.DATA_TYPE_STR then
|
||
SQRY_BND := PKG_SQL_BUILD.VAR_REPLACE_TO_STR(SSQL => SQRY_BND,
|
||
SNAME => ROPT.RARGS(I).SNAME,
|
||
SVALUE => ROPT.RARGS(I).SVALUE);
|
||
when ROPT.RARGS(I).NDATA_TYPE = PKG_STD.DATA_TYPE_NUM then
|
||
SQRY_BND := PKG_SQL_BUILD.VAR_REPLACE_TO_NUM(SSQL => SQRY_BND,
|
||
SNAME => ROPT.RARGS(I).SNAME,
|
||
NVALUE => TO_NUMBER(ROPT.RARGS(I).SVALUE));
|
||
when ROPT.RARGS(I).NDATA_TYPE = PKG_STD.DATA_TYPE_DATE then
|
||
SQRY_BND := PKG_SQL_BUILD.VAR_REPLACE_TO_DATE(SSQL => SQRY_BND,
|
||
SNAME => ROPT.RARGS(I).SNAME,
|
||
DVALUE => TO_DATE(ROPT.RARGS(I).SVALUE, 'yyyy-mm-dd'));
|
||
else
|
||
SQRY_BND := PKG_SQL_BUILD.VAR_REPLACE_TO_ANY(SSQL => SQRY_BND,
|
||
SNAME => ROPT.RARGS(I).SNAME,
|
||
SANY => ROPT.RARGS(I).SVALUE);
|
||
end case;
|
||
exception
|
||
when others then
|
||
ADD_QRY_MSG(SMESSAGE => 'Ошибка конвертации при подстановке значения "' || ROPT.RARGS(I).SVALUE ||
|
||
'" в аргумент запроса "' || ROPT.RARGS(I).SNAME || '".',
|
||
BCLEAR_QRY => false);
|
||
end;
|
||
end loop;
|
||
end if;
|
||
end BOUND;
|
||
begin
|
||
/* Читаем описание запроса */
|
||
RQ := QUERY_GET(NRN => NRN);
|
||
/* Читаем сущности запроса */
|
||
RENTS := QUERY_ENTS_GET(CENTS => RQ.ENTS);
|
||
/* Нет сущностей - нет запроса */
|
||
if ((RENTS is null) or (RENTS.COUNT = 0)) then
|
||
ADD_QRY_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
|
||
ADD_QRY_MSG(SMESSAGE => 'В запросе есть несвязанные сущности.');
|
||
return;
|
||
end if;
|
||
/* Читаем настройку запроса */
|
||
ROPT := QUERY_OPT_GET(COPT => RQ.OPT);
|
||
/* Проверяем параметры запроса */
|
||
CHECK_COND_ARGS(ROPT => ROPT);
|
||
/* Добавляем подсказку совместимости */
|
||
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);
|
||
/* Сделаем подстановки */
|
||
BOUND(ROPT => ROPT, SQRY => SQRY, SQRY_BND => SQRY_BND);
|
||
exception
|
||
when others then
|
||
PKG_STATE.DIAGNOSTICS_STACKED();
|
||
ADD_QRY_MSG(SMESSAGE => PKG_STATE.SQL_ERRM(), BCLEAR_QRY => false);
|
||
end QUERY_SQL_BUILD;
|
||
|
||
end PKG_P8PANELS_QE_BASE;
|
||
/
|