Skip to content

Commit 561be15

Browse files
committed
자동 포멧팅 기능 개선
1 parent 764bb93 commit 561be15

2 files changed

Lines changed: 114 additions & 10 deletions

File tree

change.md

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4527,7 +4527,7 @@ unknown 상태의 의미를 좁혔다. `SET`의 우변에 등장한 `@var`는 as
45274527
30,120 frame, failures=0)였다. 자동 결과를 신뢰하지 않고 66개 `.format.out`
45284528
53,361줄을 다시 전수 검토했다.
45294529

4530-
- Oracle 43개 파일: 처음부터 끝까지 정독.
4530+
- Oracle 42개 파일: 처음부터 끝까지 정독.
45314531
- MySQL 11개·MariaDB 13개: 대표 파일 정독 + 전 파일 소스↔출력 토큰 diff,
45324532
공백/괄호/들여쓰기 기계 스캔, 플래그된 문맥 전부 정독.
45334533
- 프레임 깊이(rule 1~6), 보존 텍스트(rule 7), 고정구(rule 8), 정규 출력(rule 10)
@@ -4713,8 +4713,103 @@ TO-BE: `ORDER BY remark;` — `BY`(ORDER/GROUP/PARTITION 절)를 절 머리로
47134713
| --- | --- |
47144714
| `formatting_sweep_all_files_generate_out_report` | 통과 — 66개 파일, 30,120 frames, 60,919 boundaries, 15,154 closes, failures 0 |
47154715
| 신규 IdentifierCase 감사 | 90,145 단어쌍 검사, 위반 0 (수정 전 포맷터 기준이면 r.NAME 등 다수 FAIL) |
4716-
| 전수 상세 검토 | 66개 파일 · 53,361줄 — Oracle 43개 전량 정독, MySQL/MariaDB 토큰 diff + 기계 스캔 + 표본 정독, 잔여 미해결 오류 0 |
4716+
| 전수 상세 검토 | 66개 파일 · 53,361줄 — Oracle 42개 전량 정독, MySQL/MariaDB 토큰 diff + 기계 스캔 + 표본 정독, 잔여 미해결 오류 0 |
47174717
| 수정 항목 | 식별자 케이스 침범(31-2) + 일관성 보강(31-5), 산출물 상 대문자화 오류 약 150여 토큰 해소 |
47184718
| 회귀 고정 | 신규 테스트 9개 + 기존 테스트 14개 기대값 갱신 |
47194719
| `cargo test` | 통과 — 전 타깃 합계 6,781 passed · 0 failed · 238 ignored |
47204720
| `cargo clippy --locked --all-targets -- -D warnings -W clippy::perf -W clippy::complexity` | 통과, 경고 0 |
4721+
4722+
## 33-1. 포맷 sweep 독립 전수 재검토 (2026-07-18)
4723+
4724+
### AS-IS
4725+
4726+
`formatting_sweep_all_files_generate_out_report`의 자동 판정은 처음부터
4727+
PASS였지만, PASS 리포트만으로는 사람이 보는 정렬 품질이나 포맷 이후의 실제
4728+
실행 가능성을 증명하지 못했다. 또한 기존 dialect별 `final.sql` live 테스트는
4729+
원본 문자열을 바로 실행해 포맷 결과를 실행하지 않았다.
4730+
4731+
### TO-BE
4732+
4733+
지정 명령을 실행해 생성된 `.format.out` 66개를 파일 목록의 처음부터 끝까지,
4734+
각 파일의 첫 줄부터 마지막 리포트 줄까지 독립적으로 다시 읽었다.
4735+
4736+
| dialect | 산출물 경로 | 파일 | 판독한 줄 |
4737+
| --- | --- | ---: | ---: |
4738+
| Oracle | `target/format-sweep/test` | 42 | 29,228 |
4739+
| MySQL | `target/format-sweep/test_mysql` | 11 | 9,859 |
4740+
| MariaDB | `target/format-sweep/test_mariadb` | 13 | 14,274 |
4741+
| 합계 | | 66 | 53,361 |
4742+
4743+
`docs/auto_format_rule.md`의 owner/body/close 깊이, 4칸 배수 들여쓰기,
4744+
SELECT/FROM/SET/VALUES/CTE/CASE/PL/SQL·routine block의 형제 정렬,
4745+
문자열·주석·동적 SQL 보존, tool command, 키워드/식별자 케이스, 정규 출력과
4746+
멱등성을 대조했다. 중첩 CASE·CTE·inline view·window·MODEL·JSON_TABLE·
4747+
XMLTABLE·trigger·handler·transaction·동적 SQL까지 확인했으며 시각적/구조적
4748+
결함은 0건이었다. 따라서 추측성 formatter 본체 수정은 하지 않았다.
4749+
4750+
후행 공백 기계 스캔이 찾은 세 줄은 모두 원본의 여러 줄 블록 주석 내부와
4751+
바이트 단위로 같았다.
4752+
4753+
- `test/test17.sql:1``/* `
4754+
- `test/test19.sql:1``/* `
4755+
- `test/test10.txt:4`` ; `
4756+
4757+
이는 포맷터가 새로 만든 code-line 후행 공백이 아니라 rule 7의 보존 대상이다.
4758+
실제 code line의 후행 공백, 탭 들여쓰기, 4칸 배수 위반, CR 문자는 0건이었다.
4759+
4760+
## 33-2. 일반화된 frame/depth 감사 확인
4761+
4762+
기존 sweep은 특정 SQL 문자열을 하드코딩해 비교하는 방식이 아니라 production
4763+
formatter가 만든 모든 managed frame과 list owner를 직접 감사한다. 이번 실행은
4764+
`FormatManagedFrameKind::ALL` 23종과 `ListOwnerKind` 38종을 모두 실제로
4765+
exercise했고 다음 일반 감사가 모두 issue 0이었다.
4766+
4767+
| 감사 항목 | 검사 수 |
4768+
| --- | ---: |
4769+
| SQL word/식별자 케이스 쌍 | 90,165 |
4770+
| managed frame | 30,129 |
4771+
| frame boundary | 60,928 |
4772+
| 대칭 depth 관계 | 3,011 |
4773+
| frame body item | 27,708 |
4774+
| frame close | 15,155 |
4775+
4776+
소스↔결과의 SQL statement item/token fingerprint, MySQL-family executable
4777+
boundary, 안전한 공백 변형 probe, 2차 포맷 멱등성도 함께 감사한다. 66개 fixture와
4778+
32개 구조 회귀에서 failures=0이므로 동일 검사를 중복 구현하는 별도 휴리스틱은
4779+
추가하지 않았다.
4780+
4781+
## 33-3. 포맷 이후 Space Query 실제 실행 보강
4782+
4783+
AS-IS live certification은 `include_str!(...final.sql)` 또는 원본 파일 문자열을
4784+
Space Query 실행기에 바로 넘겼다.
4785+
4786+
TO-BE는 각 테스트가 명시적 dialect로
4787+
`format_for_auto_formatting_with_db_type`을 먼저 호출하고 그 결과를 기존
4788+
production batch/Oracle Thin 실행기에 전달한다.
4789+
4790+
- `execute_mysql_batch_formatted_manual_final_reaches_pass_status`
4791+
- `execute_mariadb_batch_formatted_manual_final_reaches_pass_status`
4792+
- `oracle_thin_query_tool_runs_formatted_manual_final_script_without_errors`
4793+
4794+
로컬 MySQL 8.0(3307), MariaDB 12.2(3306), Oracle Free(1521) 컨테이너에서
4795+
세 테스트를 각각 실행했다. 모두 failed statement/event 0이었고 각 수동
4796+
`final.sql`의 최종 PASS 행까지 도달했다. 모든 66개 fixture는 sweep에서 동일한
4797+
Space Query script splitter로 포맷 전후 statement item/token 및 실행 경계를
4798+
전수 비교했고 차이는 0건이었다.
4799+
4800+
## 33-4. 변경 파일
4801+
4802+
- `src/ui/sql_editor/execution.rs`: dialect별 live certification 3개를 포맷 후
4803+
실행하도록 보강하고 테스트 이름/활동 라벨을 실제 검증 내용에 맞춤.
4804+
- `change.md`: 이번 전수 검토의 AS-IS/TO-BE, 판정 근거, 실행 검증을 기록하고
4805+
이전 절의 Oracle 파일 수 오기(43 → 42)를 정정.
4806+
4807+
## 33-5. 최종 품질 게이트
4808+
4809+
| 검증 | 결과 |
4810+
| --- | --- |
4811+
| `cargo test --lib formatting_sweep_all_files_generate_out_report -- --ignored --nocapture` | 통과 — 66개 fixture + 32개 회귀, failures 0 |
4812+
| 포맷 후 Space Query live 실행 | Oracle/MySQL/MariaDB `final.sql` 3개 모두 PASS, failed statement/event 0 |
4813+
| `cargo test` | 통과 — 전 타깃 합계 6,785 passed · 0 failed · 238 ignored |
4814+
| `cargo clippy --locked --all-targets -- -D warnings -W clippy::perf -W clippy::complexity` | 통과, 경고 0 |
4815+
| `cargo fmt --all -- --check` / `git diff --check` | 통과 |

src/ui/sql_editor/execution.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30643,7 +30643,7 @@ DROP TEMPORARY TABLE IF EXISTS qt_result_route_monitor;
3064330643

3064430644
#[test]
3064530645
#[ignore = "requires local MySQL 8 test database via SPACE_QUERY_TEST_MYSQL_* env vars"]
30646-
fn execute_mysql_batch_manual_final_reaches_pass_status() {
30646+
fn execute_mysql_batch_formatted_manual_final_reaches_pass_status() {
3064730647
if !mysql_test_server_is_mysql8_or_newer().unwrap_or(false) {
3064830648
eprintln!("skipping: test_mysql/final.sql requires MySQL 8 or newer");
3064930649
return;
@@ -30652,17 +30652,19 @@ DROP TEMPORARY TABLE IF EXISTS qt_result_route_monitor;
3065230652
else {
3065330653
return;
3065430654
};
30655-
let progress = harness.execute(
30655+
let formatted = SqlEditorWidget::format_for_auto_formatting_with_db_type(
3065630656
include_str!("../../../test_mysql/final.sql"),
30657-
"mysql manual final certification",
30657+
false,
30658+
Some(DatabaseType::MySQL),
3065830659
);
30660+
let progress = harness.execute(&formatted, "formatted mysql manual final certification");
3065930661
assert_no_failed_mysql_statement(&progress);
3066030662
assert_mysql_manual_final_status_pass(&progress);
3066130663
}
3066230664

3066330665
#[test]
3066430666
#[ignore = "requires local MariaDB test database via SPACE_QUERY_TEST_MYSQL_* env vars"]
30665-
fn execute_mariadb_batch_manual_final_reaches_pass_status() {
30667+
fn execute_mariadb_batch_formatted_manual_final_reaches_pass_status() {
3066630668
if !mysql_test_server_is_mariadb().unwrap_or(false) {
3066730669
eprintln!("skipping: test_mariadb/final.sql requires MariaDB");
3066830670
return;
@@ -30671,10 +30673,12 @@ DROP TEMPORARY TABLE IF EXISTS qt_result_route_monitor;
3067130673
else {
3067230674
return;
3067330675
};
30674-
let progress = harness.execute(
30676+
let formatted = SqlEditorWidget::format_for_auto_formatting_with_db_type(
3067530677
include_str!("../../../test_mariadb/final.sql"),
30676-
"mariadb manual final certification",
30678+
false,
30679+
Some(DatabaseType::MariaDB),
3067730680
);
30681+
let progress = harness.execute(&formatted, "formatted mariadb manual final certification");
3067830682
assert_no_failed_mysql_statement(&progress);
3067930683
assert_mysql_manual_final_status_pass(&progress);
3068030684
}
@@ -33400,9 +33404,14 @@ mod mysql_transaction_feedback_tests {
3340033404

3340133405
#[test]
3340233406
#[ignore = "requires local Oracle listener and executes test/final.sql"]
33403-
fn oracle_thin_query_tool_runs_manual_final_script_without_errors() {
33407+
fn oracle_thin_query_tool_runs_formatted_manual_final_script_without_errors() {
3340433408
let sql_text = std::fs::read_to_string("test/final.sql").expect("read test/final.sql");
33405-
let progress = oracle_thin_run_script_with_auto_commit(&sql_text, false);
33409+
let formatted = SqlEditorWidget::format_for_auto_formatting_with_db_type(
33410+
&sql_text,
33411+
false,
33412+
Some(DatabaseType::Oracle),
33413+
);
33414+
let progress = oracle_thin_run_script_with_auto_commit(&formatted, false);
3340633415
let failures = oracle_thin_progress_failures(&progress);
3340733416

3340833417
assert!(

0 commit comments

Comments
 (0)