ЦИТК-979 - Формирование SQL-выражения для запроса (сервер, начало)

This commit is contained in:
Mikhail Chechnev 2025-09-11 18:29:06 +03:00
parent 5706d59a92
commit aa9568c2fa
3 changed files with 369 additions and 2 deletions

View File

@ -14,7 +14,8 @@ create table P8PNL_QE_QUERY
OPT clob, -- Настройка запроса
ENTS clob, -- Сущности запроса
RLS clob, -- Отношения сущностей запроса
QRY clob, -- Запрос
QRY clob, -- Запрос (SQL выражение)
QRY_MSG clob, -- Сообщение при формировании запроса (предупреждения и ошибки формирования)
constraint C_P8PNL_QE_QUERY_RN_PK primary key (RN),
constraint C_P8PNL_QE_QUERY_CODE_NB check (rtrim(CODE) is not null),
constraint C_P8PNL_QE_QUERY_NAME_NB check (rtrim(NAME) is not null),

View File

@ -271,6 +271,8 @@ create or replace package body PKG_P8PANELS_QE as
is
RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса
RENTS PKG_P8PANELS_QE_BASE.TENTS; -- Коллекция существующих сущностей
SQRY PKG_STD.TLSTRING; -- SQL-выражение запроса
SQRY_MSG PKG_STD.TLSTRING; -- Сообщение при формировании SQL-выражения
begin
/* Провим права доступа */
PKG_P8PANELS_QE_BASE.QUERY_ACCESS_MODIFY(NRN => NRN, SUSER => UTILIZER());
@ -282,6 +284,9 @@ create or replace package body PKG_P8PANELS_QE as
PKG_P8PANELS_QE_BASE.TENTS_ADD(RENTS => RENTS, SNAME => SNAME, STYPE => STYPE);
/* Сохраняем обновленный набор сущностей */
PKG_P8PANELS_QE_BASE.QUERY_ENTS_SET(NRN => RQ.RN, RENTS => RENTS);
/* Переформируем SQL-выражение */
PKG_P8PANELS_QE_BASE.QUERY_SQL_BUILD(NRN => RQ.RN, SQRY => SQRY, SQRY_MSG => SQRY_MSG);
PKG_P8PANELS_QE_BASE.QUERY_QRY_SET(NRN => RQ.RN, CQRY => SQRY, CQRY_MSG => SQRY_MSG);
end QUERY_ENT_ADD;
/* Удаление сущности из запроса */
@ -295,6 +300,8 @@ create or replace package body PKG_P8PANELS_QE as
RENTS PKG_P8PANELS_QE_BASE.TENTS; -- Коллекция существующих сущностей
RENT PKG_P8PANELS_QE_BASE.TENT; -- Удаляемая сущность
RRLS PKG_P8PANELS_QE_BASE.TRLS; -- Коллекция существующих связей
SQRY PKG_STD.TLSTRING; -- SQL-выражение запроса
SQRY_MSG PKG_STD.TLSTRING; -- Сообщение при формировании SQL-выражения
begin
/* Провим права доступа */
PKG_P8PANELS_QE_BASE.QUERY_ACCESS_MODIFY(NRN => NRN, SUSER => UTILIZER());
@ -328,6 +335,9 @@ create or replace package body PKG_P8PANELS_QE as
PKG_P8PANELS_QE_BASE.QUERY_ENTS_SET(NRN => RQ.RN, RENTS => RENTS);
/* Сохраняем обновленный набор связей */
PKG_P8PANELS_QE_BASE.QUERY_RLS_SET(NRN => RQ.RN, RRLS => RRLS);
/* Переформируем SQL-выражение */
PKG_P8PANELS_QE_BASE.QUERY_SQL_BUILD(NRN => RQ.RN, SQRY => SQRY, SQRY_MSG => SQRY_MSG);
PKG_P8PANELS_QE_BASE.QUERY_QRY_SET(NRN => RQ.RN, CQRY => SQRY, CQRY_MSG => SQRY_MSG);
end QUERY_ENT_REMOVE;
/* Установка координат сущности в редакторе диаграммы запроса */
@ -382,7 +392,9 @@ create or replace package body PKG_P8PANELS_QE as
RENTS PKG_P8PANELS_QE_BASE.TENTS; -- Коллекция существующих сущностей
NENT_INDEX PKG_STD.TNUMBER; -- Индекс изменяемой сущности
RATTRS PKG_P8PANELS_QE_BASE.TATTRS; -- Коллекция полученных атриубтов
RRLS PKG_P8PANELS_QE_BASE.TRLS; -- Коллекция существующих связей
RRLS PKG_P8PANELS_QE_BASE.TRLS; -- Коллекция существующих связей
SQRY PKG_STD.TLSTRING; -- SQL-выражение запроса
SQRY_MSG PKG_STD.TLSTRING; -- Сообщение при формировании SQL-выражения
begin
/* Провим права доступа */
PKG_P8PANELS_QE_BASE.QUERY_ACCESS_MODIFY(NRN => NRN, SUSER => UTILIZER());
@ -424,6 +436,9 @@ create or replace package body PKG_P8PANELS_QE as
PKG_P8PANELS_QE_BASE.QUERY_ENTS_SET(NRN => RQ.RN, RENTS => RENTS);
/* Сохраняем обновленный набор связей */
PKG_P8PANELS_QE_BASE.QUERY_RLS_SET(NRN => RQ.RN, RRLS => RRLS);
/* Переформируем SQL-выражение */
PKG_P8PANELS_QE_BASE.QUERY_SQL_BUILD(NRN => RQ.RN, SQRY => SQRY, SQRY_MSG => SQRY_MSG);
PKG_P8PANELS_QE_BASE.QUERY_QRY_SET(NRN => RQ.RN, CQRY => SQRY, CQRY_MSG => SQRY_MSG);
end QUERY_ENT_ATTRS_SET;
/* Добавление связи в запрос */
@ -436,6 +451,8 @@ create or replace package body PKG_P8PANELS_QE as
is
RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса
RRLS PKG_P8PANELS_QE_BASE.TRLS; -- Коллекция существующих связей
SQRY PKG_STD.TLSTRING; -- SQL-выражение запроса
SQRY_MSG PKG_STD.TLSTRING; -- Сообщение при формировании SQL-выражения
begin
/* Провим права доступа */
PKG_P8PANELS_QE_BASE.QUERY_ACCESS_MODIFY(NRN => NRN, SUSER => UTILIZER());
@ -447,6 +464,9 @@ create or replace package body PKG_P8PANELS_QE as
PKG_P8PANELS_QE_BASE.TRLS_ADD(RRLS => RRLS, SSOURCE => SSOURCE, STARGET => STARGET);
/* Сохраняем обновленный набор связей */
PKG_P8PANELS_QE_BASE.QUERY_RLS_SET(NRN => RQ.RN, RRLS => RRLS);
/* Переформируем SQL-выражение */
PKG_P8PANELS_QE_BASE.QUERY_SQL_BUILD(NRN => RQ.RN, SQRY => SQRY, SQRY_MSG => SQRY_MSG);
PKG_P8PANELS_QE_BASE.QUERY_QRY_SET(NRN => RQ.RN, CQRY => SQRY, CQRY_MSG => SQRY_MSG);
end QUERY_RL_ADD;
/* Удаление связи из запроса */
@ -458,6 +478,8 @@ create or replace package body PKG_P8PANELS_QE as
is
RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса
RRLS PKG_P8PANELS_QE_BASE.TRLS; -- Коллекция существующих связей
SQRY PKG_STD.TLSTRING; -- SQL-выражение запроса
SQRY_MSG PKG_STD.TLSTRING; -- Сообщение при формировании SQL-выражения
begin
/* Провим права доступа */
PKG_P8PANELS_QE_BASE.QUERY_ACCESS_MODIFY(NRN => NRN, SUSER => UTILIZER());
@ -469,6 +491,9 @@ create or replace package body PKG_P8PANELS_QE as
PKG_P8PANELS_QE_BASE.TRLS_REMOVE(RRLS => RRLS, SID => SID);
/* Сохраняем обновленный набор связей */
PKG_P8PANELS_QE_BASE.QUERY_RLS_SET(NRN => RQ.RN, RRLS => RRLS);
/* Переформируем SQL-выражение */
PKG_P8PANELS_QE_BASE.QUERY_SQL_BUILD(NRN => RQ.RN, SQRY => SQRY, SQRY_MSG => SQRY_MSG);
PKG_P8PANELS_QE_BASE.QUERY_QRY_SET(NRN => RQ.RN, CQRY => SQRY, CQRY_MSG => SQRY_MSG);
end QUERY_RL_REMOVE;
/* Добавление аргумента запроса */
@ -577,6 +602,8 @@ create or replace package body PKG_P8PANELS_QE as
is
RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса
ROPT PKG_P8PANELS_QE_BASE.TOPT; -- Настройка запроса
SQRY PKG_STD.TLSTRING; -- SQL-выражение запроса
SQRY_MSG PKG_STD.TLSTRING; -- Сообщение при формировании SQL-выражения
begin
/* Провим права доступа */
PKG_P8PANELS_QE_BASE.QUERY_ACCESS_MODIFY(NRN => NRN, SUSER => UTILIZER());
@ -588,6 +615,9 @@ create or replace package body PKG_P8PANELS_QE as
ROPT.SCOND := SCOND;
/* Сохраняем обновленную настройку */
PKG_P8PANELS_QE_BASE.QUERY_OPT_SET(NRN => RQ.RN, ROPT => ROPT);
/* Переформируем SQL-выражение */
PKG_P8PANELS_QE_BASE.QUERY_SQL_BUILD(NRN => RQ.RN, SQRY => SQRY, SQRY_MSG => SQRY_MSG);
PKG_P8PANELS_QE_BASE.QUERY_QRY_SET(NRN => RQ.RN, CQRY => SQRY, CQRY_MSG => SQRY_MSG);
end QUERY_OPT_COND_SET;
end PKG_P8PANELS_QE;

View File

@ -301,6 +301,22 @@ create or replace package PKG_P8PANELS_QE_BASE as
NRN in number, -- Рег. номер запроса
ROPT in TOPT -- Настройка запроса
);
/* Запись SQL-выражения запроса */
procedure QUERY_QRY_SET
(
NRN in number, -- Рег. номер запроса
CQRY in clob, -- SQL-выражение
CQRY_MSG in clob -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
);
/* Формирование SQL запроса */
procedure QUERY_SQL_BUILD
(
NRN in number, -- Рег. номер запроса
SQRY out varchar2, -- SQL-выражение
SQRY_MSG out varchar2 -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
);
end PKG_P8PANELS_QE_BASE;
/
@ -324,6 +340,8 @@ create or replace package body PKG_P8PANELS_QE_BASE as
STAG_RL constant PKG_STD.TSTRING := 'XRL'; -- Связь
STAG_OPT constant PKG_STD.TSTRING := 'XOPT'; -- Настройка запроса
STAG_COND constant PKG_STD.TSTRING := 'XCOND'; -- Условия запроса
STAG_QRY constant PKG_STD.TSTRING := 'XQRY'; -- SQL-выражение запроса
STAG_QRY_MSG constant PKG_STD.TSTRING := 'XQRY_MSG'; -- Сообщение при формировании запроса
/* Константы - Атрибуты для сериализации */
SATTR_ID constant PKG_STD.TSTRING := 'id'; -- Идентификатор
@ -839,6 +857,33 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Вернём результат */
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
@ -1212,6 +1257,33 @@ create or replace package body PKG_P8PANELS_QE_BASE as
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
(
@ -2071,6 +2143,10 @@ create or replace package body PKG_P8PANELS_QE_BASE as
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_MSG, LCVALUE => RQ.QRY_MSG);
/* Закрываем корень */
PKG_XFAST.UP();
/* Сериализуем */
@ -2419,5 +2495,265 @@ create or replace package body PKG_P8PANELS_QE_BASE as
QUERY_CH_DATE_SYNC(NRN => NRN);
end QUERY_OPT_SET;
/* Запись SQL-выражения запроса */
procedure QUERY_QRY_SET
(
NRN in number, -- Рег. номер запроса
CQRY in clob, -- SQL-выражение
CQRY_MSG in clob -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
)
is
begin
/* Сохраним её */
update P8PNL_QE_QUERY T
set T.QRY = CQRY,
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_SQL_BUILD
(
NRN in number, -- Рег. номер запроса
SQRY out varchar2, -- SQL-выражение
SQRY_MSG out varchar2 -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
)
is
RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса
RENTS TENTS; -- Сущности запроса
RRLS TRLS; -- Связи запроса
ROPT TOPT; -- Настройка запроса
/* Кумулятивная установка сообщения формирования запроса */
procedure SET_MSG
(
SMESSAGE in varchar2, -- Текст сообщения
BCLEAR_QRY in boolean := true -- Флаг очистки сформированного запроса
)
is
begin
if (BCLEAR_QRY) then
SQRY := 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 SET_MSG;
/* Поиск корневой (не имеет связей по выходу - т.е. нигде не является источником) сущности запроса */
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);
end if;
/* Обходим все сущности */
for E in RENTS.FIRST .. RENTS.LAST
loop
/* Сброс флага наличия атрибутов в источниках связей */
BFOUND := false;
/* Обходим атрибуты сущности */
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;
/* Если хоть один атрибут сущности есть среди источников - дальше можно атрибуты этой сущности не рассматривать */
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; -- Буфер для поля запроса
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
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 || ', ';
end if;
PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => SFIELD);
end if;
end loop;
end if;
end loop;
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; -- Индекс сущности-источника связи
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;
/* Соберем выражение и добавим его в запрос */
STABLE := 'left join ' || 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.COUNT > 0) then
BUILD_FROM_HIER(RENT_START => RENT_ROOT, RENTS => RENTS, RRLS => RRLS, SQRY => SQRY);
end if;
else
/* Корневую сущность не нашли */
SET_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;
begin
/*
TODO: owner="root" created="09.09.2025"
text="Контроль длины псевдонима таблицы и поля (максимум 30 символов)"
*/
/*
TODO: owner="root" created="10.09.2025"
text="Предусмотреть связям признак ""обязательность""
с ним - join
без него - left join"
*/
/*
TODO: owner="root" created="10.09.2025"
text="Предусмотреть отладочные значения для аргументов запроса"
*/
/*
TODO: owner="root" created="11.09.2025"
text="Проверять соответствие условий отбора запроса набору его аргументов"
*/
/* Читаем описание запроса */
RQ := QUERY_GET(NRN => NRN);
/* Читаем сущности запроса */
RENTS := QUERY_ENTS_GET(CENTS => RQ.ENTS);
/* Нет сущностей - нет запроса */
if ((RENTS is null) and (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
SET_MSG(SMESSAGE => 'В запросе есть несвязанные сущности.');
return;
end if;
/* Читаем настройку запроса */
ROPT := QUERY_OPT_GET(COPT => RQ.OPT);
/* Добавляем подсказку совместимости */
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);
exception
when others then
PKG_STATE.DIAGNOSTICS_STACKED();
SET_MSG(SMESSAGE => PKG_STATE.SQL_ERRM(), BCLEAR_QRY => false);
end QUERY_SQL_BUILD;
end PKG_P8PANELS_QE_BASE;
/