From 836a3db5e2c7eca54ec19b99f1af0dffe25ef88f Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Fri, 8 Aug 2025 19:09:59 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-979=20-=20=D0=A4=D0=BE?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B0=D1=82=D1=80=D0=B8?= =?UTF-8?q?=D0=B1=D1=83=D1=82=D0=BE=D0=B2=20=D1=81=D1=83=D1=89=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20(=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/PKG_P8PANELS_QE.pck | 45 +++++++- db/PKG_P8PANELS_QE_BASE.pck | 224 +++++++++++++++++++++++++++++++----- 2 files changed, 240 insertions(+), 29 deletions(-) diff --git a/db/PKG_P8PANELS_QE.pck b/db/PKG_P8PANELS_QE.pck index a0f68c6..dca717c 100644 --- a/db/PKG_P8PANELS_QE.pck +++ b/db/PKG_P8PANELS_QE.pck @@ -59,6 +59,22 @@ create or replace package PKG_P8PANELS_QE as 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 ( @@ -265,6 +281,33 @@ create or replace package body PKG_P8PANELS_QE as end if; 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 ( @@ -337,6 +380,6 @@ create or replace package body PKG_P8PANELS_QE as /* Базовая установка признака публичности */ PKG_P8PANELS_QE_BASE.QUERY_PBL_SET(NRN => NRN, NPBL => NPBL); end QUERY_PBL_SET; - + end PKG_P8PANELS_QE; / diff --git a/db/PKG_P8PANELS_QE_BASE.pck b/db/PKG_P8PANELS_QE_BASE.pck index 2e30f80..bb7b051 100644 --- a/db/PKG_P8PANELS_QE_BASE.pck +++ b/db/PKG_P8PANELS_QE_BASE.pck @@ -10,7 +10,11 @@ create or replace package PKG_P8PANELS_QE_BASE as SID PKG_STD.TSTRING, -- Уникальный идентификатор в запросе SNAME 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 -- Коллекция сущностей ); + /* Получение состава атрибутов сущности */ + procedure QUERY_ENT_ATTRS_GET + ( + NRN in number, -- Рег. номер запроса + SID in varchar2, -- Идентификатор сущности + COUT out clob -- Сериализованное описание атрибутов сущности + ); + /* Чтение связей запроса */ 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_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'; -- Отображение в запросе /* Получение заголовка представления из метаданных */ 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_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; @@ -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.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_SHOW); + RRES.NSHOW := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_SHOW); /* Освободим документ */ PKG_XPATH.FREE(RDOCUMENT => XDOC); exception @@ -371,6 +395,119 @@ create or replace package body PKG_P8PANELS_QE_BASE as return RRES; 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 ( @@ -462,15 +599,13 @@ create or replace package body PKG_P8PANELS_QE_BASE as /* Формирование описания сущности */ function TENT_MAKE ( - SNAME in varchar2, -- Имя - STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*) - NNUMB in number -- Номер сущности - ) return TENT -- Описание сущности + SNAME in varchar2, -- Имя + STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*) + NNUMB in number -- Номер сущности + ) return TENT -- Описание сущности is - RENT TENT; -- Буфер для результата - RVIEW PKG_OBJECT_DESC.TVIEW; -- Описание представления - RVIEW_FIELDS PKG_OBJECT_DESC.TCOLUMNS; -- Коллекция описаний полей представления - RVIEW_FIELD PKG_OBJECT_DESC.TCOLUMN; -- Описание поля представления + RENT TENT; -- Буфер для результата + RVIEW PKG_OBJECT_DESC.TVIEW; -- Описание представления begin /* Проверим корректность типа сущности */ 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 /* Получим описание представления */ 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.SNAME := RVIEW.VIEW_NAME; RENT.STITLE := DMSCLVIEWS_TITLE_GET(SVIEW_NAME => RENT.SNAME); RENT.STYPE := SENT_TYPE_VIEW; - RENT.RATTRS := TATTRS(); - /* Собираем атрибуты в ответ */ - 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; + /* Формируем набор атрибутов */ + RENT.RATTRS := TATTRS_MAKE(RENT => RENT, NCOUNT => 10); end if; /* Если сущность это таблица */ 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); 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