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_QRY_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 || ''; 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_QRY_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_QRY_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_QRY_BUILD; end PKG_P8PANELS_QE_BASE; /