diff --git a/app.text.js b/app.text.js
index 333f1ff..fe03322 100644
--- a/app.text.js
+++ b/app.text.js
@@ -15,7 +15,8 @@ export const TITLES = {
DEFAULT_PANELS_GROUP: "Без привязки к группе", //Заголовок группы панелей по умолчанию
DATA_SOURCE_CONFIG: "Настройка источника данных", //Заголовок для настройки источника данных
INSERT: "Добавление", //Заголовок для диалогов/форм добавления
- UPDATE: "Исправление" //Заголовок для диалогов/форм исправления
+ UPDATE: "Исправление", //Заголовок для диалогов/форм исправления
+ CONFIG: "Настройка" //Заголовок для диалога настройки
};
//Текст
diff --git a/app/panels/query_editor/components/inspector_query_ents/attr_setup_dialog.js b/app/panels/query_editor/components/inspector_query_ents/attr_setup_dialog.js
new file mode 100644
index 0000000..ca613d7
--- /dev/null
+++ b/app/panels/query_editor/components/inspector_query_ents/attr_setup_dialog.js
@@ -0,0 +1,73 @@
+/*
+ Парус 8 - Панели мониторинга - Редактор запросов
+ Компонент: Диалог настройки атрибута сущности
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import React from "react"; //Классы React
+import PropTypes from "prop-types"; //Контроль свойств компонента
+import { P8PDialog } from "../../../../components/p8p_dialog"; //Типовой диалог
+import { TITLES } from "../../../../../app.text"; //Общие текстовые ресурсы приложения
+import { DATA_TYPE } from "../../common"; //Общие константы редактора
+import { ATTRIBUTE_SHAPE } from "../attribute/attribute"; //Описание атрибута
+
+//-----------
+//Тело модуля
+//-----------
+
+//Диалог добавления/исправления аргумента запроса
+const AttrSetupDialog = ({ attr, onOk, onCancel }) => {
+ //Достанем необходимое из атрибута
+ const { name, title, dataType, alias } = attr;
+
+ //Нажатие на кнопку "Ok"
+ const handleOk = values => onOk && onOk({ ...values });
+
+ //Нажатие на кнопку "Отмена"
+ const handleCancel = () => onCancel && onCancel();
+
+ //Генерация содержимого
+ return (
+
+ );
+};
+
+//Контроль свойств - Диалог настройки атрибута сущности
+AttrSetupDialog.propTypes = {
+ attr: ATTRIBUTE_SHAPE.isRequired,
+ onOk: PropTypes.func,
+ onCancel: PropTypes.func
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { AttrSetupDialog };
diff --git a/app/panels/query_editor/components/inspector_query_ents/attrs_list.js b/app/panels/query_editor/components/inspector_query_ents/attrs_list.js
index 72ddbfd..7942003 100644
--- a/app/panels/query_editor/components/inspector_query_ents/attrs_list.js
+++ b/app/panels/query_editor/components/inspector_query_ents/attrs_list.js
@@ -30,7 +30,7 @@ const STYLES = {
//-----------
//Список атрибутов сущности
-const AttrsList = ({ attrs = [], onSelect = null, onShow = null } = {}) => {
+const AttrsList = ({ attrs = [], onSelect = null, onShow = null, onSetup = null } = {}) => {
//При выборе элемента списка
const handleSelectClick = attr => {
onSelect && onSelect(attr);
@@ -42,6 +42,12 @@ const AttrsList = ({ attrs = [], onSelect = null, onShow = null } = {}) => {
onShow && onShow(attr);
};
+ //При нажатии на кнопку настройки атрибута
+ const handleSetupClick = (e, attr) => {
+ e.stopPropagation();
+ onSetup && onSetup(attr);
+ };
+
//Формирование представления
return (
@@ -60,7 +66,7 @@ const AttrsList = ({ attrs = [], onSelect = null, onShow = null } = {}) => {
secondaryTypographyProps={{ component: "div" }}
secondary={
- {`${attr.alias || attr.name}`}
+ {`${attr.name}${attr.alias ? ` (${attr.alias})` : ""}`}
}
/>
@@ -68,6 +74,9 @@ const AttrsList = ({ attrs = [], onSelect = null, onShow = null } = {}) => {
handleShowClick(e, attr)} title={showTitle}>
{showIcon}
+ handleSetupClick(e, attr)} title={"Настроить"}>
+ settings
+
@@ -81,7 +90,8 @@ const AttrsList = ({ attrs = [], onSelect = null, onShow = null } = {}) => {
AttrsList.propTypes = {
attrs: PropTypes.arrayOf(ATTRIBUTE_SHAPE),
onSelect: PropTypes.func,
- onShow: PropTypes.func
+ onShow: PropTypes.func,
+ onSetup: PropTypes.func
};
//----------------
diff --git a/app/panels/query_editor/components/inspector_query_ents/entity_attrs_dialog.js b/app/panels/query_editor/components/inspector_query_ents/entity_attrs_dialog.js
index 11c0d14..a112047 100644
--- a/app/panels/query_editor/components/inspector_query_ents/entity_attrs_dialog.js
+++ b/app/panels/query_editor/components/inspector_query_ents/entity_attrs_dialog.js
@@ -13,6 +13,7 @@ import { Box, TextField, InputAdornment, Icon, IconButton } from "@mui/material"
import { P8PDialog, P8P_DIALOG_WIDTH } from "../../../../components/p8p_dialog"; //Типовой диалог
import { P8PComponentInlineMessage } from "../../../../components/editors/p8p_component_inline_message"; //Типовое встраиваемое сообщение
import { AttrsList } from "./attrs_list"; //Список атрибутов сущности
+import { AttrSetupDialog } from "./attr_setup_dialog"; //Диалог настройки атрибута
import { useEntityAttrs } from "./hooks"; //Хуки диалога настройки атрибутов сущности
//---------
@@ -36,6 +37,9 @@ const EntityAttrsDialog = ({ query, id, title, onOk, onCancel }) => {
//Собственное состояние - список атрибутов
const [attrs, setAttrs] = useState([]);
+ //Собственное состояние - настраиваемый атрибут
+ const [setupAttr, setSetupAttr] = useState(null);
+
//Хук для взаимодействия с сервером
const [srvAttrs, saveAttrs] = useEntityAttrs(query, id);
@@ -64,6 +68,21 @@ const EntityAttrsDialog = ({ query, id, title, onOk, onCancel }) => {
}))
);
+ //Настройка атрибута
+ const handleAttrSetup = attr => setSetupAttr({ ...attr });
+
+ //При закрытии диалога настройки атрибута по "ОК"
+ const handleAttrSetupOk = values => {
+ setAttrs(
+ attrs.map(a => ({
+ ...(a.id === setupAttr.id ? { ...a, use: 1, alias: values.alias } : a)
+ }))
+ );
+ setSetupAttr(null);
+ };
+
+ const handleAttrSetupCancel = () => setSetupAttr(null);
+
//При изменении значения фильтра
const handleFilterChange = e => setFilter(e.target.value);
@@ -87,6 +106,7 @@ const EntityAttrsDialog = ({ query, id, title, onOk, onCancel }) => {
//Генерация содержимого
return (
+ {setupAttr && }
{
}}
/>
- {displayAttrsList === true && }
+ {displayAttrsList === true && (
+
+ )}
{displayAttrsList === false && (
RENTS(NENT_INDEX).RATTRS, SCHECK_MSG => SCHECK_MSG);
+ if (SCHECK_MSG is not null) then
+ P_EXCEPTION(0, SCHECK_MSG);
+ end if;
/* Сохраняем обновленный набор сущностей */
PKG_P8PANELS_QE_BASE.QUERY_ENTS_SET(NRN => RQ.RN, RENTS => RENTS);
/* Сохраняем обновленный набор связей */
diff --git a/db/PKG_P8PANELS_QE_BASE.pck b/db/PKG_P8PANELS_QE_BASE.pck
index 42d1a69..56ba0f4 100644
--- a/db/PKG_P8PANELS_QE_BASE.pck
+++ b/db/PKG_P8PANELS_QE_BASE.pck
@@ -69,6 +69,13 @@ create or replace package PKG_P8PANELS_QE_BASE as
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
(
@@ -77,6 +84,13 @@ create or replace package PKG_P8PANELS_QE_BASE as
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
(
@@ -809,6 +823,36 @@ create or replace package body PKG_P8PANELS_QE_BASE as
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
(
@@ -929,6 +973,61 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Ничего не нашли */
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
@@ -995,6 +1094,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
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;
@@ -1108,24 +1208,61 @@ create or replace package body PKG_P8PANELS_QE_BASE as
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
(
- SNAME in varchar2, -- Имя сущности
+ STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*)
NNUMB in number -- Номер сущности в запросе
) return varchar2 -- Сформированный идентификатор
is
begin
/* Проверим параметры */
- if (SNAME is null) then
- P_EXCEPTION(0, 'Не указано имя сущности.');
+ if (STYPE is null) then
+ P_EXCEPTION(0, 'Не указан тип сущности.');
+ end if;
+ if (NNUMB is null) then
+ P_EXCEPTION(0, 'Не указан номер сущности в запросе.');
end if;
/* Соберем идентификатор */
- if (NNUMB is null) then
- return SNAME;
- else
- return SNAME || TO_CHAR(NNUMB);
- end if;
+ return SUBSTR(STYPE, 1, 1) || TO_CHAR(NNUMB);
end TENT_ID_MAKE;
/* Формирование описания сущности */
@@ -1154,7 +1291,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Получим описание представления */
RVIEW := PKG_OBJECT_DESC.DESC_VIEW(SVIEW_NAME => SNAME, BRAISE_ERROR => true);
/* Собираем заголовок сущности */
- RENT.SID := TENT_ID_MAKE(SNAME => RVIEW.VIEW_NAME, NNUMB => NNUMB);
+ 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;
@@ -1306,13 +1443,13 @@ create or replace package body PKG_P8PANELS_QE_BASE as
function TENTS_NEXT_NUMB
(
RENTS in TENTS, -- Коллекция сущностей
- SNAME in varchar2 -- Имя
+ 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(SNAME => SNAME, NNUMB => NNUMB)) is not null)
+ while (TENTS_INDEX_BY_ID(RENTS => RENTS, SID => TENT_ID_MAKE(STYPE => STYPE, NNUMB => NNUMB)) is not null)
loop
NNUMB := NNUMB + 1;
end loop;
@@ -1338,7 +1475,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Формируем пописание сущности */
RENT := TENT_MAKE(SNAME => SNAME,
STYPE => STYPE,
- NNUMB => TENTS_NEXT_NUMB(RENTS => RENTS, SNAME => SNAME),
+ NNUMB => TENTS_NEXT_NUMB(RENTS => RENTS, STYPE => STYPE),
NINIT_ATTRS => NINIT_ATTRS);
/* Добавляем её в коллекцию */
RENTS.EXTEND();
@@ -2580,6 +2717,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Если сущность одна - то она и главная */
if (RENTS.COUNT = 1) then
RENT := RENTS(RENTS.FIRST);
+ return;
end if;
/* Обходим все сущности */
for E in RENTS.FIRST .. RENTS.LAST
@@ -2590,13 +2728,15 @@ create or replace package body PKG_P8PANELS_QE_BASE as
for A in RENTS(E).RATTRS.FIRST .. RENTS(E).RATTRS.LAST
loop
/* Обойдем связи и поищем атрибут среди источников */
- 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;
+ 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;
@@ -2621,12 +2761,14 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Формирование части "select" */
procedure BUILD_SELECT
(
- RENTS TENTS, -- Сущности запроса
- SQRY in out varchar2 -- Буфер для запроса
+ RENTS TENTS, -- Сущности запроса
+ SQRY in out varchar2 -- Буфер для запроса
)
is
- SFIELD PKG_STD.TSTRING; -- Буфер для поля запроса
+ SFIELD PKG_STD.TSTRING; -- Буфер для поля запроса
+ BFOUND boolean := false; -- Флаг наличия визуализируемых атрибутов
begin
+ /* Формируем */
PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => 'select ');
for I in RENTS.FIRST .. RENTS.LAST
loop
@@ -2634,15 +2776,24 @@ create or replace package body PKG_P8PANELS_QE_BASE as
for J in RENTS(I).RATTRS.FIRST .. RENTS(I).RATTRS.LAST
loop
if (RENTS(I).RATTRS(J).NSHOW = 1) then
- SFIELD := RENTS(I).RATTRS(J).SID || ' ' || RENTS(I).RATTRS(J).SNAME || I || J;
- if (not ((I = RENTS.LAST) and (J = RENTS(I).RATTRS.LAST))) then
- SFIELD := SFIELD || ', ';
+ 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" */
@@ -2701,7 +2852,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
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.COUNT > 0) then
+ 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
@@ -2723,10 +2874,6 @@ create or replace package body PKG_P8PANELS_QE_BASE as
end if;
end BUILD_WHERE;
begin
- /*
- TODO: owner="root" created="09.09.2025"
- text="Контроль длины псевдонима таблицы и поля (максимум 30 символов)"
- */
/*
TODO: owner="root" created="10.09.2025"
text="Предусмотреть связям признак ""обязательность""
@@ -2746,14 +2893,14 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Читаем сущности запроса */
RENTS := QUERY_ENTS_GET(CENTS => RQ.ENTS);
/* Нет сущностей - нет запроса */
- if ((RENTS is null) and (RENTS.COUNT = 0)) then
+ if ((RENTS is null) or (RENTS.COUNT = 0)) then
SET_MSG(SMESSAGE => 'В запросе нет сущностей.');
return;
end if;
/* Читаем связи запроса */
RRLS := QUERY_RLS_GET(CRLS => RQ.RLS);
/* Нельзя построить запрос, если есть несвязанные сущности */
- if ((RENTS.COUNT > 1) and (RENTS.COUNT - 1 > RRLS.COUNT)) then
+ if ((RENTS.COUNT > 1) and ((RRLS is null) or (RENTS.COUNT - 1 > RRLS.COUNT))) then
SET_MSG(SMESSAGE => 'В запросе есть несвязанные сущности.');
return;
end if;
@@ -2766,7 +2913,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Собираем запрос - таблицы и связи */
BUILD_FROM(RENTS => RENTS, RRLS => RRLS, SQRY => SQRY);
/* Собираем запрос - условия */
- BUILD_WHERE(ROPT => ROPT, SQRY => SQRY);
+ BUILD_WHERE(ROPT => ROPT, SQRY => SQRY);
exception
when others then
PKG_STATE.DIAGNOSTICS_STACKED();