ЦИТК-979 - Редактор условия запроса - раздельное хранение канонического SQL-выражения и выражения с подстановками

This commit is contained in:
Mikhail Chechnev 2025-10-14 19:21:18 +03:00
parent 6efbb8508c
commit d446fd96ab
5 changed files with 65 additions and 35 deletions

View File

@ -34,6 +34,7 @@ const Inspector = ({
cond = null, cond = null,
substArgsVals = 0, substArgsVals = 0,
qry = "", qry = "",
qryBnd = "",
qryMsg = "", qryMsg = "",
onOptionsChanged = null onOptionsChanged = null
}) => { }) => {
@ -55,7 +56,7 @@ const Inspector = ({
<InspectorQueryRelations query={query} relation={relation} onOptionsChanged={handleOptionsChanged} /> <InspectorQueryRelations query={query} relation={relation} onOptionsChanged={handleOptionsChanged} />
</> </>
)} )}
<InspectorQueryArea query={query} substArgsVals={substArgsVals} qry={qry} qryMsg={qryMsg} onOptionsChanged={handleOptionsChanged} /> <InspectorQueryArea query={query} substArgsVals={substArgsVals} qry={qry} qryBnd={qryBnd} qryMsg={qryMsg} />
</P8PEditorBox> </P8PEditorBox>
); );
}; };
@ -70,6 +71,7 @@ Inspector.propTypes = {
cond: PropTypes.string, cond: PropTypes.string,
substArgsVals: PropTypes.number, substArgsVals: PropTypes.number,
qry: PropTypes.string, qry: PropTypes.string,
qryBnd: PropTypes.string,
qryMsg: PropTypes.string, qryMsg: PropTypes.string,
onOptionsChanged: PropTypes.func onOptionsChanged: PropTypes.func
}; };

View File

@ -7,7 +7,7 @@
//Подключение библиотек //Подключение библиотек
//--------------------- //---------------------
import React, { useState } from "react"; //Классы React import React, { useState, useEffect } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента import PropTypes from "prop-types"; //Контроль свойств компонента
import { Fab, Icon, Drawer, IconButton, TextField, Stack, Box, Snackbar, Alert } from "@mui/material"; //Компоненты MUI import { Fab, Icon, Drawer, IconButton, TextField, Stack, Box, Snackbar, Alert } from "@mui/material"; //Компоненты MUI
import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы приложения import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы приложения
@ -40,7 +40,10 @@ const SNACK_BAR_MESSAGE_INIT = { text: null, type: null };
//----------- //-----------
//Область SQL-выражения //Область SQL-выражения
const InspectorQueryArea = ({ query, substArgsVals = 0, qry = "", qryMsg = "", onOptionsChanged }) => { const InspectorQueryArea = ({ query, substArgsVals = 0, qry = "", qryBnd = "", qryMsg = "" }) => {
//Собственное состояние - отображение запроса с подстановками
const [showQryBnd, setShowQryBnd] = useState(substArgsVals);
//Собственное состояние - текст всплывающего сообщения //Собственное состояние - текст всплывающего сообщения
const [snackBarMessage, setSnackBarMessage] = useState(SNACK_BAR_MESSAGE_INIT); const [snackBarMessage, setSnackBarMessage] = useState(SNACK_BAR_MESSAGE_INIT);
@ -53,13 +56,10 @@ const InspectorQueryArea = ({ query, substArgsVals = 0, qry = "", qryMsg = "", o
//Работа с SQL-выражением //Работа с SQL-выражением
const { toggleSubstArgsVals } = useQuerySQLExpr(query); const { toggleSubstArgsVals } = useQuerySQLExpr(query);
//Уведомление родителя об изменении свойств
const notifyOptionsChanged = () => onOptionsChanged && onOptionsChanged();
//При нажатии на кнопку отображения/сокрытия значений аргументов в SQL-выражении запроса //При нажатии на кнопку отображения/сокрытия значений аргументов в SQL-выражении запроса
const handleToggleSubstArgsValsClick = async () => { const handleToggleSubstArgsValsClick = async () => {
await toggleSubstArgsVals(); await toggleSubstArgsVals();
notifyOptionsChanged(); setShowQryBnd(showQryBnd === 1 ? 0 : 1);
}; };
//При нажатии на кнопку копирования текста запроса //При нажатии на кнопку копирования текста запроса
@ -87,6 +87,13 @@ const InspectorQueryArea = ({ query, substArgsVals = 0, qry = "", qryMsg = "", o
//Расчет размеров тектовых полей //Расчет размеров тектовых полей
const [qryRows, qryMsgRows] = expanded ? [15, 6] : [5, 3]; const [qryRows, qryMsgRows] = expanded ? [15, 6] : [5, 3];
//Расчет параметров отображения запроса
const [dispQry, qryViewTitle, qryViewIcon] =
showQryBnd === 0 ? [qry, "Отобразить значения аргументов", "code"] : [qryBnd, "Скрыть значения аргументов", "code_off"];
//При изменении состояние отображения подстановок в запросе
useEffect(() => setShowQryBnd(substArgsVals), [substArgsVals]);
//Генерация содержимого //Генерация содержимого
return ( return (
<> <>
@ -101,11 +108,8 @@ const InspectorQueryArea = ({ query, substArgsVals = 0, qry = "", qryMsg = "", o
<Stack direction={"row"} justifyContent={"right"} spacing={2}> <Stack direction={"row"} justifyContent={"right"} spacing={2}>
{qry && ( {qry && (
<> <>
<IconButton <IconButton onClick={handleToggleSubstArgsValsClick} title={qryViewTitle}>
onClick={handleToggleSubstArgsValsClick} <Icon>{qryViewIcon}</Icon>
title={substArgsVals === 1 ? "Скрыть значения аргументов" : "Отобразить значения аргументов"}
>
<Icon>{substArgsVals === 1 ? "code_off" : "code"}</Icon>
</IconButton> </IconButton>
<IconButton onClick={handleCopyClick} title={"Скопировать текст запроса"}> <IconButton onClick={handleCopyClick} title={"Скопировать текст запроса"}>
<Icon>content_copy</Icon> <Icon>content_copy</Icon>
@ -120,12 +124,12 @@ const InspectorQueryArea = ({ query, substArgsVals = 0, qry = "", qryMsg = "", o
</IconButton> </IconButton>
</Stack> </Stack>
<Stack direction={"column"} spacing={2}> <Stack direction={"column"} spacing={2}>
{qry && ( {dispQry && (
<TextField <TextField
label={"Текст запроса"} label={"Текст запроса"}
multiline multiline
fullWidth fullWidth
value={qry} value={dispQry}
minRows={qryRows} minRows={qryRows}
maxRows={qryRows} maxRows={qryRows}
variant={"standard"} variant={"standard"}
@ -165,8 +169,8 @@ InspectorQueryArea.propTypes = {
query: PropTypes.number.isRequired, query: PropTypes.number.isRequired,
substArgsVals: PropTypes.number, substArgsVals: PropTypes.number,
qry: PropTypes.string, qry: PropTypes.string,
qryMsg: PropTypes.string, qryBnd: PropTypes.string,
onOptionsChanged: PropTypes.func qryMsg: PropTypes.string
}; };
//---------------- //----------------

View File

@ -144,7 +144,7 @@ const useQuery = query => {
cond: data?.XOPT?.XCOND || null, cond: data?.XOPT?.XCOND || null,
substArgsVals: data?.XOPT?.XSUBST_ARGS_VALS || 0 substArgsVals: data?.XOPT?.XSUBST_ARGS_VALS || 0
}); });
setQuerySQL({ qry: data?.XQRY, qryMsg: data?.XQRY_MSG }); setQuerySQL({ qry: data?.XQRY, qryBnd: data?.XQRY_BND, qryMsg: data?.XQRY_MSG });
setInit(true); setInit(true);
} finally { } finally {
setRefresh(false); setRefresh(false);

View File

@ -15,6 +15,7 @@ create table P8PNL_QE_QUERY
ENTS clob, -- Сущности запроса ENTS clob, -- Сущности запроса
RLS clob, -- Отношения сущностей запроса RLS clob, -- Отношения сущностей запроса
QRY clob, -- Запрос (SQL выражение) QRY clob, -- Запрос (SQL выражение)
QRY_BND clob, -- Запрос (SQL выражение) с подставленными значениями аргументов
QRY_MSG clob, -- Сообщение при формировании запроса (предупреждения и ошибки формирования) QRY_MSG clob, -- Сообщение при формировании запроса (предупреждения и ошибки формирования)
constraint C_P8PNL_QE_QUERY_RN_PK primary key (RN), 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_CODE_NB check (rtrim(CODE) is not null),

View File

@ -341,6 +341,7 @@ create or replace package PKG_P8PANELS_QE_BASE as
( (
NRN in number, -- Рег. номер запроса NRN in number, -- Рег. номер запроса
SQRY out varchar2, -- SQL-выражение SQRY out varchar2, -- SQL-выражение
SQRY_BND out varchar2, -- SQL-выражение с подставленными значениями аргументов
SQRY_MSG out varchar2 -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования) SQRY_MSG out varchar2 -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
); );
@ -368,6 +369,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
STAG_COND constant PKG_STD.TSTRING := 'XCOND'; -- Условия запроса STAG_COND constant PKG_STD.TSTRING := 'XCOND'; -- Условия запроса
STAG_SUBST_ARGS_VALS constant PKG_STD.TSTRING := 'XSUBST_ARGS_VALS'; -- Флаг подстановки значений аргументов в запрос STAG_SUBST_ARGS_VALS constant PKG_STD.TSTRING := 'XSUBST_ARGS_VALS'; -- Флаг подстановки значений аргументов в запрос
STAG_QRY constant PKG_STD.TSTRING := 'XQRY'; -- SQL-выражение запроса 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'; -- Сообщение при формировании запроса STAG_QRY_MSG constant PKG_STD.TSTRING := 'XQRY_MSG'; -- Сообщение при формировании запроса
/* Константы - Атрибуты для сериализации */ /* Константы - Атрибуты для сериализации */
@ -2341,6 +2343,8 @@ create or replace package body PKG_P8PANELS_QE_BASE as
end if; end if;
/* SQL-выражение */ /* SQL-выражение */
PKG_XFAST.HERB(SNAME => STAG_QRY, LCVALUE => RQ.QRY); PKG_XFAST.HERB(SNAME => STAG_QRY, LCVALUE => RQ.QRY);
/* SQL-выражение с подстановками */
PKG_XFAST.HERB(SNAME => STAG_QRY_BND, LCVALUE => RQ.QRY_BND);
/* Сообщение при формировании SQL-выражения */ /* Сообщение при формировании SQL-выражения */
PKG_XFAST.HERB(SNAME => STAG_QRY_MSG, LCVALUE => RQ.QRY_MSG); PKG_XFAST.HERB(SNAME => STAG_QRY_MSG, LCVALUE => RQ.QRY_MSG);
/* Закрываем корень */ /* Закрываем корень */
@ -2696,6 +2700,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
( (
NRN in number, -- Рег. номер запроса NRN in number, -- Рег. номер запроса
CQRY in clob, -- SQL-выражение CQRY in clob, -- SQL-выражение
CQRY_BND in clob, -- SQL-выражение с подставленными значениями аргументов
CQRY_MSG in clob -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования) CQRY_MSG in clob -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
) )
is is
@ -2703,6 +2708,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Сохраним её */ /* Сохраним её */
update P8PNL_QE_QUERY T update P8PNL_QE_QUERY T
set T.QRY = CQRY, set T.QRY = CQRY,
T.QRY_BND = CQRY_BND,
T.QRY_MSG = CQRY_MSG T.QRY_MSG = CQRY_MSG
where T.RN = NRN; where T.RN = NRN;
/* Контроль изменения данных */ /* Контроль изменения данных */
@ -2720,12 +2726,13 @@ create or replace package body PKG_P8PANELS_QE_BASE as
) )
is is
SQRY PKG_STD.TLSTRING; -- SQL-выражение запроса SQRY PKG_STD.TLSTRING; -- SQL-выражение запроса
SQRY_BND PKG_STD.TLSTRING; -- SQL-выражение запроса с подстановками
SQRY_MSG PKG_STD.TLSTRING; -- Сообщение при формировании SQL-выражения SQRY_MSG PKG_STD.TLSTRING; -- Сообщение при формировании SQL-выражения
begin begin
/* Сформируем SQL-выражение */ /* Сформируем SQL-выражение */
QUERY_SQL_BUILD(NRN => NRN, SQRY => SQRY, SQRY_MSG => SQRY_MSG); QUERY_SQL_BUILD(NRN => NRN, SQRY => SQRY, SQRY_BND => SQRY_BND, SQRY_MSG => SQRY_MSG);
/* Обновим его в запросе */ /* Обновим его в запросе */
QUERY_QRY_SET(NRN => NRN, CQRY => SQRY, CQRY_MSG => SQRY_MSG); QUERY_QRY_SET(NRN => NRN, CQRY => SQRY, CQRY_BND => SQRY_BND, CQRY_MSG => SQRY_MSG);
end QUERY_QRY_REFRESH; end QUERY_QRY_REFRESH;
/* Формирование SQL запроса */ /* Формирование SQL запроса */
@ -2733,6 +2740,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
( (
NRN in number, -- Рег. номер запроса NRN in number, -- Рег. номер запроса
SQRY out varchar2, -- SQL-выражение SQRY out varchar2, -- SQL-выражение
SQRY_BND out varchar2, -- SQL-выражение с подставленными значениями аргументов
SQRY_MSG out varchar2 -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования) SQRY_MSG out varchar2 -- Сообщение при формировании SQL-выражения (предупреждения и ошибки формирования)
) )
is is
@ -2751,6 +2759,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
begin begin
if (BCLEAR_QRY) then if (BCLEAR_QRY) then
SQRY := null; SQRY := null;
SQRY_BND := null;
end if; end if;
if (SQRY_MSG is null) then if (SQRY_MSG is null) then
SQRY_MSG := SMESSAGE; SQRY_MSG := SMESSAGE;
@ -2965,25 +2974,37 @@ create or replace package body PKG_P8PANELS_QE_BASE as
if (ROPT.SCOND is not null) then if (ROPT.SCOND is not null) then
PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => 'where ' || ROPT.SCOND); PKG_SQL_BUILD.APPEND(SSQL => SQRY, SELEMENT1 => 'where ' || ROPT.SCOND);
end if; end if;
if ((ROPT.NSUBST_ARGS_VALS = 1) and (ROPT.RARGS is not null) and (ROPT.RARGS.COUNT > 0)) then 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 for I in ROPT.RARGS.FIRST .. ROPT.RARGS.LAST
loop loop
begin begin
case case
when ROPT.RARGS(I).NDATA_TYPE = PKG_STD.DATA_TYPE_STR then when ROPT.RARGS(I).NDATA_TYPE = PKG_STD.DATA_TYPE_STR then
SQRY := PKG_SQL_BUILD.VAR_REPLACE_TO_STR(SSQL => SQRY, SQRY_BND := PKG_SQL_BUILD.VAR_REPLACE_TO_STR(SSQL => SQRY_BND,
SNAME => ROPT.RARGS(I).SNAME, SNAME => ROPT.RARGS(I).SNAME,
SVALUE => ROPT.RARGS(I).SVALUE); SVALUE => ROPT.RARGS(I).SVALUE);
when ROPT.RARGS(I).NDATA_TYPE = PKG_STD.DATA_TYPE_NUM then when ROPT.RARGS(I).NDATA_TYPE = PKG_STD.DATA_TYPE_NUM then
SQRY := PKG_SQL_BUILD.VAR_REPLACE_TO_NUM(SSQL => SQRY, SQRY_BND := PKG_SQL_BUILD.VAR_REPLACE_TO_NUM(SSQL => SQRY_BND,
SNAME => ROPT.RARGS(I).SNAME, SNAME => ROPT.RARGS(I).SNAME,
NVALUE => TO_NUMBER(ROPT.RARGS(I).SVALUE)); NVALUE => TO_NUMBER(ROPT.RARGS(I).SVALUE));
when ROPT.RARGS(I).NDATA_TYPE = PKG_STD.DATA_TYPE_DATE then when ROPT.RARGS(I).NDATA_TYPE = PKG_STD.DATA_TYPE_DATE then
SQRY := PKG_SQL_BUILD.VAR_REPLACE_TO_DATE(SSQL => SQRY, SQRY_BND := PKG_SQL_BUILD.VAR_REPLACE_TO_DATE(SSQL => SQRY_BND,
SNAME => ROPT.RARGS(I).SNAME, SNAME => ROPT.RARGS(I).SNAME,
DVALUE => TO_DATE(ROPT.RARGS(I).SVALUE, 'yyyy-mm-dd')); DVALUE => TO_DATE(ROPT.RARGS(I).SVALUE, 'yyyy-mm-dd'));
else else
SQRY := PKG_SQL_BUILD.VAR_REPLACE_TO_ANY(SSQL => SQRY, SQRY_BND := PKG_SQL_BUILD.VAR_REPLACE_TO_ANY(SSQL => SQRY_BND,
SNAME => ROPT.RARGS(I).SNAME, SNAME => ROPT.RARGS(I).SNAME,
SANY => ROPT.RARGS(I).SVALUE); SANY => ROPT.RARGS(I).SVALUE);
end case; end case;
@ -2995,7 +3016,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
end; end;
end loop; end loop;
end if; end if;
end BUILD_WHERE; end BOUND;
begin begin
/* Читаем описание запроса */ /* Читаем описание запроса */
RQ := QUERY_GET(NRN => NRN); RQ := QUERY_GET(NRN => NRN);
@ -3025,6 +3046,8 @@ create or replace package body PKG_P8PANELS_QE_BASE as
BUILD_FROM(RENTS => RENTS, RRLS => RRLS, SQRY => SQRY); BUILD_FROM(RENTS => RENTS, RRLS => RRLS, SQRY => SQRY);
/* Собираем запрос - условия */ /* Собираем запрос - условия */
BUILD_WHERE(ROPT => ROPT, SQRY => SQRY); BUILD_WHERE(ROPT => ROPT, SQRY => SQRY);
/* Сделаем подстановки */
BOUND(ROPT => ROPT, SQRY => SQRY, SQRY_BND => SQRY_BND);
exception exception
when others then when others then
PKG_STATE.DIAGNOSTICS_STACKED(); PKG_STATE.DIAGNOSTICS_STACKED();