쿼리 편집기 — 무엇을 돌렸는지, 컬럼이 무엇인지, 늘 뜨는 경고

## 돌린 SQL 을 창 안에서 볼 수 있다

치환을 마친 문장을 필드에 담아 두기만 하고(진단용) 화면에는 안 내보냈다.
0행이 나왔을 때 <b>치환이 NULL 이라 조건이 사라진 것</b>인지
<b>이 환자에게 자료가 없는 것</b>인지 가르는 유일한 수단이 그 문장인데, 볼 방법이 없었다.

요약 줄에 '돌린 SQL 보기' 를 두고 읽기 전용으로 펼친다(SQL 복사도 함께 —
데이터소스 결과 창과 같은 구성이다). <b>실패했으면 자동으로 펼친다</b> —
표가 어차피 없고, 오라클 오류 문구만으로는 어디가 틀렸는지 알 수 없다.

## 0행이어도 컬럼 머리글을 남긴다

전에는 0행이면 표를 통째로 접었다. 그런데 <b>컬럼 이름은 이미 알고 있고</b>,
그것이 배선 필드 칸에 옮겨 적을 값이다. 접어 버리면 방금 조회한 컬럼명을 알아내려고
쿼리를 또 돌려야 한다 — 0행은 배선 작업에서 드문 상태도 아니다.

## 늘 뜨던 경고를 조건부로

'변수 NULL — 구문만 검사' 가 <b>치환 대상이 하나도 없는 쿼리에도</b> 붙었다.
치환할 것이 없으니 NULL 로 바뀐 것도 없는데 거짓 꼬리표가 상시로 달려서,
정작 진짜 경고가 붙은 날에도 눈에 들어오지 않았다. 늘 뜨는 경고는 경고가 아니다.
치환 시도가 실제로 있었을 때만 붙인다.

## 같은 창이 진입 경로에 따라 달랐다

데이터소스 아이콘에서 편집기를 열면 《컨트롤명》 치환 칩이 나오는데
인스펙터의 쿼리 행에서 열면 그 칩이 <b>통째로 사라졌다</b> — 호출부가 컨트롤 이름을 안 넘겼다.
같은 창이 어디서 열렸는지에 따라 능력이 다르면 안 된다. 인스펙터도 넘기게 했다.

## 판정

- 단위 시험 388 · edit-smoke 405건 전건 통과
- --query-popup(자동완성 팝업 진단) 전건 통과
- --dialog-shots 69장 전건 통과 — 03b 샷에서 치환 변수 없는 쿼리의 거짓 꼬리표가
  사라진 것을 눈으로 확인했다
- --modal-check · --maxrect · --scale-budget 전건 통과
- --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변

'돌린 SQL' 펼침과 실패 시 자동 펼침은 DB 가 붙은 단말에서 실제 실패 쿼리로 한 번 확인하는 것이 좋다 —
진단은 성공 경로만 찍는다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-21 09:27:27 +09:00
co-authored by Claude Fable 5
parent 4b400b94e0
commit 3e75bdc9b9
4 changed files with 113 additions and 4 deletions
@@ -323,9 +323,33 @@
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,8">
<Button DockPanel.Dock="Right" Content="닫기"
Style="{StaticResource LinkBtn}" Click="OnCloseTrial"/>
<!--
무엇을 돌렸는지 보여 준다. 0행이 나왔을 때
'치환이 NULL 이라 조건이 사라진 건지, 이 환자에게 자료가 없는 건지'를
창을 나가지 않고 가르는 유일한 수단이다 — 치환을 마친 문장이 답을 갖고 있다.
-->
<Button x:Name="ShowTrialSqlButton" DockPanel.Dock="Right"
Content="돌린 SQL 보기" Margin="0,0,10,0"
Style="{StaticResource LinkBtn}" Click="OnToggleTrialSql"/>
<TextBlock x:Name="TrialSummary" FontSize="12.5" TextWrapping="Wrap"
VerticalAlignment="Center"/>
</DockPanel>
<!-- 돌린 SQL 원문 — 읽기 전용. 08c 데이터소스 결과 창과 같은 구성이다 -->
<Border x:Name="TrialSqlPane" DockPanel.Dock="Top" Visibility="Collapsed"
Margin="0,0,0,8" BorderThickness="1"
BorderBrush="{DynamicResource B.Line2}"
Background="{DynamicResource B.Input}">
<DockPanel>
<Button DockPanel.Dock="Right" Content="SQL 복사" VerticalAlignment="Top"
Margin="6,4,6,4" Style="{StaticResource LinkBtn}"
Click="OnCopyTrialSql"/>
<TextBox x:Name="TrialSqlText" IsReadOnly="True" BorderThickness="0"
Background="Transparent" FontFamily="Consolas" FontSize="12"
TextWrapping="Wrap" MaxHeight="120" Padding="8,6"
VerticalScrollBarVisibility="Auto"
AutomationProperties.Name="돌린 SQL"/>
</DockPanel>
</Border>
<!-- 표를 감싸는 테두리 — 표 자체는 테두리를 그리지 않는다(위 스타일) -->
<Border BorderThickness="1" BorderBrush="{DynamicResource B.Line2}">
<DataGrid x:Name="TrialGrid" Style="{StaticResource ResultGrid}" MaxHeight="200"
@@ -575,7 +575,11 @@ public partial class QueryEditorWindow : Window
// 같은 정보를 두 군데 적으면 요약이 두 줄로 늘어 결과 표를 밀어내고,
// 화면에 환자 이름이 필요 이상으로 여러 번 남는다.
// 환자가 있을 때 필요한 말은 이미 버튼이 하고 있으므로 여기서는 침묵한다.
var basis = variables is not null ? string.Empty : "변수 NULL — 구문만 검사";
// 치환 대상이 <b>하나도 없는</b> 쿼리에 '변수 NULL' 을 적으면 거짓이다 —
// 치환할 것이 없으니 NULL 로 바뀐 것도 없다. 그런데 그 꼬리표가 늘 붙어 있어서
// 정작 진짜 경고가 붙은 날에도 눈에 안 들어왔다. 늘 뜨는 경고는 경고가 아니다.
var hasSubstitution = converted.Hits.Count > 0;
var basis = variables is null && hasSubstitution ? "변수 NULL — 구문만 검사" : string.Empty;
var notes = new List<string>();
// 환자를 안 골랐으면 <b>모든</b> 변수가 Unknown 이다 — 그것을 "아직 옮기지 않았다"고 적으면
// 거짓이 된다(ChtNum 은 옮겨져 있다). 그 사유는 위 basis 줄이 이미 말한다.
@@ -611,8 +615,11 @@ public partial class QueryEditorWindow : Window
// 빈 조각은 버린다 — 안 버리면 "성공 · · 경고" 처럼 가운뎃점이 떠 있는다
TrialSummary.Text = string.Join(" · ",
new[] { head, basis }.Concat(notes).Where(s => s.Length > 0));
// 0행이어도 표를 띄운다 — <b>컬럼 이름</b>은 이미 알고 있고, 그것이 배선 필드 칸에
// 옮겨 적을 값이다. 표를 접으면 방금 조회한 컬럼명을 다시 알아내려고
// 쿼리를 또 돌려야 한다(0행이 배선 작업에서 드문 상태도 아니다).
TrialGrid.ItemsSource = ToGridRows(result);
TrialGrid.Visibility = result.Rows.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
TrialGrid.Visibility = result.Columns.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
}
else
{
@@ -621,6 +628,9 @@ public partial class QueryEditorWindow : Window
new[] { "실패 — " + result.Error, basis }.Concat(notes).Where(s => s.Length > 0));
TrialGrid.ItemsSource = null;
TrialGrid.Visibility = Visibility.Collapsed;
// 실패했으면 표가 어차피 없다 — 그 자리에 돌린 문장을 바로 보여 준다.
// 오라클 오류 문구만으로는 어디가 틀렸는지 알 수 없고, 답은 치환된 문장에 있다.
SetTrialSqlVisible(true);
}
}
@@ -773,6 +783,37 @@ public partial class QueryEditorWindow : Window
/// <summary>검증 이후 SQL 이 바뀌었을 때 요약 앞에 붙는 표시</summary>
private const string StaleMark = "(수정됨 — 다시 실행하세요) ";
/// <summary>
/// '돌린 SQL' 접기/펴기 — 치환을 마친 문장을 창 안에서 확인한다.
///
/// 0행이 나왔을 때 <b>치환이 NULL 이라 조건이 사라진 것</b>인지
/// <b>이 환자에게 자료가 없는 것</b>인지 가르는 유일한 수단이다. 그 답은 돌린 문장에 있다.
/// 전에는 그 문장을 필드에 담아 두기만 하고(진단용) 화면에는 내보내지 않았다.
/// </summary>
private void OnToggleTrialSql(object sender, RoutedEventArgs e)
{
var show = TrialSqlPane.Visibility != Visibility.Visible;
SetTrialSqlVisible(show);
}
private void SetTrialSqlVisible(bool show)
{
TrialSqlPane.Visibility = show ? Visibility.Visible : Visibility.Collapsed;
ShowTrialSqlButton.Content = show ? "돌린 SQL 숨기기" : "돌린 SQL 보기";
if (show)
{
TrialSqlText.Text = lastTrialSql;
}
}
private void OnCopyTrialSql(object sender, RoutedEventArgs e)
{
if (lastTrialSql.Length > 0)
{
Clipboard.SetText(lastTrialSql);
}
}
/// <summary>줄·열 표시 — 오류 메시지의 위치를 찾아갈 때 쓴다</summary>
private void UpdateCaretText()
{