ЦИТК-979 - Формирование списка атрибутов сущности (сервер)

This commit is contained in:
Mikhail Chechnev 2025-08-08 19:09:59 +03:00
parent 6ff99591e2
commit 836a3db5e2
2 changed files with 240 additions and 29 deletions

View File

@ -59,6 +59,22 @@ create or replace package PKG_P8PANELS_QE as
NY in number -- Координата по оси ординат NY in number -- Координата по оси ординат
); );
/* Получение состава атрибутов сущности */
procedure QUERY_ENT_ATTRS_GET
(
NRN in number, -- Рег. номер запроса
SID in varchar2, -- Идентификатор сущности
COUT out clob -- Сериализованное описание атрибутов сущности
);
/* Установка состава атрибутов сущности */
procedure QUERY_ENT_ATTRS_SET
(
NRN in number, -- Рег. номер запроса
SID in varchar2, -- Идентификатор сущности
CATTRS in clob -- Сериализованное описание атрибутов сущности
);
/* Добавление связи в запрос */ /* Добавление связи в запрос */
procedure QUERY_RL_ADD procedure QUERY_RL_ADD
( (
@ -265,6 +281,33 @@ create or replace package body PKG_P8PANELS_QE as
end if; end if;
end QUERY_ENT_POSITION_SET; end QUERY_ENT_POSITION_SET;
/* Получение состава атрибутов сущности */
procedure QUERY_ENT_ATTRS_GET
(
NRN in number, -- Рег. номер запроса
SID in varchar2, -- Идентификатор сущности
COUT out clob -- Сериализованное описание атрибутов сущности
)
is
begin
/* Провим права доступа */
PKG_P8PANELS_QE_BASE.QUERY_ACCESS_MODIFY(NRN => NRN, SUSER => UTILIZER());
/* Сформируем описание атрибутов */
PKG_P8PANELS_QE_BASE.QUERY_ENT_ATTRS_GET(NRN => NRN, SID => SID, COUT => COUT);
end QUERY_ENT_ATTRS_GET;
/* Установка состава атрибутов сущности */
procedure QUERY_ENT_ATTRS_SET
(
NRN in number, -- Рег. номер запроса
SID in varchar2, -- Идентификатор сущности
CATTRS in clob -- Сериализованное описание атрибутов сущности
)
is
begin
null;
end QUERY_ENT_ATTRS_SET;
/* Добавление связи в запрос */ /* Добавление связи в запрос */
procedure QUERY_RL_ADD procedure QUERY_RL_ADD
( (
@ -337,6 +380,6 @@ create or replace package body PKG_P8PANELS_QE as
/* Базовая установка признака публичности */ /* Базовая установка признака публичности */
PKG_P8PANELS_QE_BASE.QUERY_PBL_SET(NRN => NRN, NPBL => NPBL); PKG_P8PANELS_QE_BASE.QUERY_PBL_SET(NRN => NRN, NPBL => NPBL);
end QUERY_PBL_SET; end QUERY_PBL_SET;
end PKG_P8PANELS_QE; end PKG_P8PANELS_QE;
/ /

View File

@ -10,7 +10,11 @@ create or replace package PKG_P8PANELS_QE_BASE as
SID PKG_STD.TSTRING, -- Уникальный идентификатор в запросе SID PKG_STD.TSTRING, -- Уникальный идентификатор в запросе
SNAME PKG_STD.TSTRING, -- Имя SNAME PKG_STD.TSTRING, -- Имя
STITLE PKG_STD.TSTRING, -- Заголовок STITLE PKG_STD.TSTRING, -- Заголовок
NDATA_TYPE PKG_STD.TNUMBER -- Тип данных (см. константы PKG_STD.DATA_TYPE_*) 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 - нет)
); );
/* Типы данных - Коллекция атрибутов сущности */ /* Типы данных - Коллекция атрибутов сущности */
@ -177,6 +181,14 @@ create or replace package PKG_P8PANELS_QE_BASE as
RENTS in TENTS -- Коллекция сущностей RENTS in TENTS -- Коллекция сущностей
); );
/* Получение состава атрибутов сущности */
procedure QUERY_ENT_ATTRS_GET
(
NRN in number, -- Рег. номер запроса
SID in varchar2, -- Идентификатор сущности
COUT out clob -- Сериализованное описание атрибутов сущности
);
/* Чтение связей запроса */ /* Чтение связей запроса */
function QUERY_RLS_GET function QUERY_RLS_GET
( (
@ -238,6 +250,10 @@ create or replace package body PKG_P8PANELS_QE_BASE as
SATTR_Y constant PKG_STD.TSTRING := 'y'; -- Координата по Y SATTR_Y constant PKG_STD.TSTRING := 'y'; -- Координата по Y
SATTR_SOURCE constant PKG_STD.TSTRING := 'source'; -- Источник SATTR_SOURCE constant PKG_STD.TSTRING := 'source'; -- Источник
SATTR_TARGET constant PKG_STD.TSTRING := 'target'; -- Приёмник 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'; -- Отображение в запросе
/* Получение заголовка представления из метаданных */ /* Получение заголовка представления из метаданных */
function DMSCLVIEWS_TITLE_GET function DMSCLVIEWS_TITLE_GET
@ -328,6 +344,10 @@ create or replace package body PKG_P8PANELS_QE_BASE as
PKG_XFAST.ATTR(SNAME => SATTR_NAME, SVALUE => RATTR.SNAME); PKG_XFAST.ATTR(SNAME => SATTR_NAME, SVALUE => RATTR.SNAME);
PKG_XFAST.ATTR(SNAME => SATTR_TITLE, SVALUE => RATTR.STITLE); 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_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(); PKG_XFAST.UP();
end TATTR_TO_XML; end TATTR_TO_XML;
@ -356,6 +376,10 @@ create or replace package body PKG_P8PANELS_QE_BASE as
RRES.SNAME := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_NAME); RRES.SNAME := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_NAME);
RRES.STITLE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_TITLE); RRES.STITLE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_TITLE);
RRES.NDATA_TYPE := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_DATA_TYPE); 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_SHOW);
RRES.NSHOW := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_SHOW);
/* Освободим документ */ /* Освободим документ */
PKG_XPATH.FREE(RDOCUMENT => XDOC); PKG_XPATH.FREE(RDOCUMENT => XDOC);
exception exception
@ -371,6 +395,119 @@ create or replace package body PKG_P8PANELS_QE_BASE as
return RRES; return RRES;
end TATTR_FROM_XML; end TATTR_FROM_XML;
/* Поиск индекса атрибута по имени */
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_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 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)) 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).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;
/* Если ранее в сущности вообще не было атрибутов - установим флаг применения в запросе (тогда атрибут будет отображен в диаграмме) */
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 procedure TATTRS_TO_XML
( (
@ -462,15 +599,13 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Формирование описания сущности */ /* Формирование описания сущности */
function TENT_MAKE function TENT_MAKE
( (
SNAME in varchar2, -- Имя SNAME in varchar2, -- Имя
STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*) STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*)
NNUMB in number -- Номер сущности NNUMB in number -- Номер сущности
) return TENT -- Описание сущности ) return TENT -- Описание сущности
is is
RENT TENT; -- Буфер для результата RENT TENT; -- Буфер для результата
RVIEW PKG_OBJECT_DESC.TVIEW; -- Описание представления RVIEW PKG_OBJECT_DESC.TVIEW; -- Описание представления
RVIEW_FIELDS PKG_OBJECT_DESC.TCOLUMNS; -- Коллекция описаний полей представления
RVIEW_FIELD PKG_OBJECT_DESC.TCOLUMN; -- Описание поля представления
begin begin
/* Проверим корректность типа сущности */ /* Проверим корректность типа сущности */
if (STYPE not in (SENT_TYPE_TABLE, SENT_TYPE_VIEW)) then if (STYPE not in (SENT_TYPE_TABLE, SENT_TYPE_VIEW)) then
@ -482,30 +617,13 @@ create or replace package body PKG_P8PANELS_QE_BASE as
if (STYPE = SENT_TYPE_VIEW) then if (STYPE = SENT_TYPE_VIEW) then
/* Получим описание представления */ /* Получим описание представления */
RVIEW := PKG_OBJECT_DESC.DESC_VIEW(SVIEW_NAME => SNAME, BRAISE_ERROR => true); RVIEW := PKG_OBJECT_DESC.DESC_VIEW(SVIEW_NAME => SNAME, BRAISE_ERROR => true);
/* Получим список полей представления */
RVIEW_FIELDS := PKG_OBJECT_DESC.DESC_SEL_COLUMNS(SSELECT_NAME => SNAME, BRAISE_ERROR => true);
/* Собираем заголовок сущности */ /* Собираем заголовок сущности */
RENT.SID := TENT_ID_MAKE(SNAME => RVIEW.VIEW_NAME, NNUMB => NNUMB); RENT.SID := TENT_ID_MAKE(SNAME => RVIEW.VIEW_NAME, NNUMB => NNUMB);
RENT.SNAME := RVIEW.VIEW_NAME; RENT.SNAME := RVIEW.VIEW_NAME;
RENT.STITLE := DMSCLVIEWS_TITLE_GET(SVIEW_NAME => RENT.SNAME); RENT.STITLE := DMSCLVIEWS_TITLE_GET(SVIEW_NAME => RENT.SNAME);
RENT.STYPE := SENT_TYPE_VIEW; RENT.STYPE := SENT_TYPE_VIEW;
RENT.RATTRS := TATTRS(); /* Формируем набор атрибутов */
/* Собираем атрибуты в ответ */ RENT.RATTRS := TATTRS_MAKE(RENT => RENT, NCOUNT => 10);
for I in 1 .. PKG_OBJECT_DESC.COUNT_COLUMNS(RCOLUMNS => RVIEW_FIELDS)
loop
/* По умолчанию - первые 10 */
exit when I > 10;
/* Считываем очередное поле из коллекции описания полей представления */
RVIEW_FIELD := PKG_OBJECT_DESC.FETCH_COLUMN(RCOLUMNS => RVIEW_FIELDS, IINDEX => I);
/* Формируем описание поля и добавляем в коллекцию атрибутов сущности */
RENT.RATTRS.EXTEND();
RENT.RATTRS(RENT.RATTRS.LAST).SID := TATTR_ID_MAKE(SENT_ID => RENT.SID, SNAME => RVIEW_FIELD.COLUMN_NAME);
RENT.RATTRS(RENT.RATTRS.LAST).SNAME := RVIEW_FIELD.COLUMN_NAME;
RENT.RATTRS(RENT.RATTRS.LAST).STITLE := DMSCLVIEWSATTRS_TITLE_GET(SVIEW_NAME => RENT.SNAME,
SATTR_NAME => RENT.RATTRS(RENT.RATTRS.LAST)
.SNAME);
RENT.RATTRS(RENT.RATTRS.LAST).NDATA_TYPE := RVIEW_FIELD.DATA_TYPE;
end loop;
end if; end if;
/* Если сущность это таблица */ /* Если сущность это таблица */
if (STYPE = SENT_TYPE_TABLE) then if (STYPE = SENT_TYPE_TABLE) then
@ -1483,6 +1601,56 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Обновим дату изменения запроса */ /* Обновим дату изменения запроса */
QUERY_CH_DATE_SYNC(NRN => NRN); QUERY_CH_DATE_SYNC(NRN => NRN);
end QUERY_ENTS_SET; 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 function QUERY_RLS_GET