@@ -4089,3 +4089,338 @@ registry helper를 사용하도록 바꾸고 production completion 재현 테스
40894089| ` cargo test ` | 전체 6,745 통과 · 235 ignored · 실패 0 · doc-test 실패 0 |
40904090| ` cargo clippy --locked --all-targets -- -D warnings -W clippy::perf -W clippy::complexity ` | 통과, 경고 0 |
40914091| ` cargo fmt --all -- --check ` / ` git diff --check ` | 통과 |
4092+
4093+ # 30차: 공식 매뉴얼 문법 final 3종 전수 인증 (2026-07-17)
4094+
4095+ ## 30-1. 신규 final 스크립트와 실제 실행
4096+
4097+ 기존 fixture를 재사용하지 않고 Oracle, MySQL, MariaDB 공식 매뉴얼의 문법군을 기준으로
4098+ 각 DB용 ` final.sql ` 을 새로 작성했다. 세 스크립트는 Space Query의 production 실행 경로로
4099+ 각 대상 DB에 실행해 모두 정상 완료를 확인했다.
4100+
4101+ - Oracle: ` test/final.sql `
4102+ - MySQL: ` test_mysql/final.sql `
4103+ - MariaDB: ` test_mariadb/final.sql `
4104+
4105+ ## 30-2. 하이라이팅과 인텔리센스 전수 검증
4106+
4107+ 하이라이팅 sweep은 66개 파일, 83,402단어를 검사했다. catalog 단어 45,625개 중
4108+ 45,081개는 직접 하이라이트되고 544개는 문맥상 식별자로 판정됐으며, object 4,480개는
4109+ 전부 하이라이트됐다. unexpected highlight 0, failure 0으로 production 수정이 필요한
4110+ 잔여 오류는 없었다.
4111+
4112+ 인텔리센스 final 리포트는 Oracle 4,819개, MySQL 1,117개, MariaDB 418개 추천 위치를
4113+ 검사해 모두 missing 0이었다. 전체 fixture sweep에서 발견한 MySQL ` DELIMITER ` 문맥
4114+ 차이는 재현 테스트를 먼저 추가하고 테스트가 production completion과 같은 흐름을
4115+ 사용하도록 맞췄다. 수정 후 해당 sweep은 707개 후보 missing 0이었다.
4116+
4117+ 100만 줄 이상 문서의 production/snapshot/shadow completion 성능 회귀 5건은 8.87초에
4118+ 모두 통과했다. completion은 전체 문서를 다시 순회하지 않고 상한이 있는 token window와
4119+ 국소 symbol snapshot만 사용한다.
4120+
4121+ ## 30-3. 포맷 sweep 66개·53,361줄 전수 육안 검토
4122+
4123+ ` formatting_sweep_all_files_generate_out_report ` 로 생성한 ` target/format-sweep ` 아래
4124+ 66개 ` .format.out ` , 최종 53,361줄을 처음부터 끝까지 검토했다. 자동 PASS를 그대로
4125+ 신뢰하지 않고 원문과 결과를 대조했으며, ` docs/auto_format_rule.md ` 의 frame 단일 깊이
4126+ 원천, 문법적 부모, first-child-inline, structural body frame, closing owner depth,
4127+ canonical/idempotent 원칙으로 판단했다.
4128+
4129+ 자동 검사만으로는 잡히지 않은 네 문법군을 육안 검토에서 발견했다. 각 오류는 먼저
4130+ 독립 재현 테스트를 추가해 실패를 확인한 뒤 production formatter의 문법 owner를
4131+ 수정했다.
4132+
4133+ ### Oracle PROPERTY GRAPH의 TABLES/KEY/PROPERTIES 소유 관계
4134+
4135+ AS-IS:
4136+
4137+ ``` sql
4138+ CREATE PROPERTY GRAPH graph_cert
4139+ VERTEX TABLES (graph_node KEY (node_id) LABEL node PROPERTIES (node_id, node_name))
4140+ EDGE TABLES (graph_edge KEY (edge_id) SOURCE KEY (source_node_id) REFERENCES graph_node (node_id) DESTINATION KEY (target_node_id) REFERENCES graph_node (node_id) LABEL owns PROPERTIES (edge_label, edge_weight));
4141+ ```
4142+
4143+ TO-BE:
4144+
4145+ ``` sql
4146+ CREATE PROPERTY GRAPH graph_cert
4147+ VERTEX TABLES (graph_node
4148+ KEY (node_id)
4149+ LABEL node
4150+ PROPERTIES (node_id,
4151+ node_name)
4152+ )
4153+ EDGE TABLES (graph_edge
4154+ KEY (edge_id)
4155+ SOURCE KEY (source_node_id) REFERENCES graph_node (node_id)
4156+ DESTINATION KEY (target_node_id) REFERENCES graph_node (node_id)
4157+ LABEL owns
4158+ PROPERTIES (edge_label,
4159+ edge_weight)
4160+ );
4161+ ```
4162+
4163+ ` VERTEX TABLES ` 와 ` EDGE TABLES ` 를 명시적 parenthesized owner로 추가하고,
4164+ ` KEY ` /` SOURCE KEY ` /` DESTINATION KEY ` /` LABEL ` /` PROPERTIES ` 를 그 자식으로 분류했다.
4165+ ` PROPERTIES ` 내부 comma-list도 별도 owner를 사용하므로 100만 줄 문서에서 주변 전체를
4166+ 재탐색하지 않는다.
4167+
4168+ ### Oracle MATERIALIZED VIEW LOG 절 소유 관계
4169+
4170+ AS-IS:
4171+
4172+ ``` sql
4173+ CREATE MATERIALIZED VIEW LOG
4174+ ON sq_oracle_manual_log WITH PRIMARY KEY ,
4175+ ROWID (category,
4176+ amount) INCLUDING NEW VALUES ;
4177+ ```
4178+
4179+ TO-BE:
4180+
4181+ ``` sql
4182+ CREATE MATERIALIZED VIEW LOG ON sq_oracle_manual_log
4183+ WITH PRIMARY KEY ,
4184+ ROWID (category,
4185+ amount)
4186+ INCLUDING NEW VALUES ;
4187+ ```
4188+
4189+ ` ON ` 은 CREATE header에 유지하고, ` WITH ` option-list와 ` INCLUDING ` 을 각각 동일 statement의
4190+ 명시적 clause로 만들었다.
4191+
4192+ ### MariaDB/MySQL VIEW의 ` ALGORITHM = MERGE `
4193+
4194+ AS-IS:
4195+
4196+ ``` sql
4197+ CREATE OR REPLACE ALGORITHM =
4198+ MERGE VIEW statement_log_v AS
4199+ SELECT id
4200+ FROM statement_log;
4201+ ```
4202+
4203+ TO-BE:
4204+
4205+ ``` sql
4206+ CREATE OR REPLACE ALGORITHM = MERGE VIEW statement_log_v AS
4207+ SELECT id
4208+ FROM statement_log;
4209+ ```
4210+
4211+ ` MERGE ` 가 ` ALGORITHM = ` 의 값일 때는 독립 MERGE DML opener가 아니므로 structural break를
4212+ 만들지 않게 했다.
4213+
4214+ ### MariaDB/MySQL EVENT의 ` DO ` 본문
4215+
4216+ AS-IS:
4217+
4218+ ``` sql
4219+ CREATE EVENT syntax_event
4220+ ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
4221+ ON COMPLETION PRESERVE DISABLE COMMENT ' disabled event' DO UPDATE statement_log
4222+ SET amount = amount
4223+ WHERE id = - 1 ;
4224+ ```
4225+
4226+ TO-BE:
4227+
4228+ ``` sql
4229+ CREATE EVENT syntax_event
4230+ ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
4231+ ON COMPLETION PRESERVE DISABLE
4232+ COMMENT ' disabled event'
4233+ DO
4234+ UPDATE statement_log
4235+ SET amount = amount
4236+ WHERE id = - 1 ;
4237+ ```
4238+
4239+ CREATE EVENT를 명시적 construct로 추적하고 ` COMMENT ` /` DO ` 를 event clause로,
4240+ ` DO ` 뒤 실제 SQL을 structural body frame으로 관리한다.
4241+
4242+ ## 30-4. 추가 자동 포맷 회귀 수정
4243+
4244+ final 3종의 1차 sweep에서 발견한 나머지 문법도 모두 재현 테스트를 먼저 추가했다.
4245+
4246+ ### prepared ` EXECUTE ... USING ` , transaction/XA/SHOW
4247+
4248+ AS-IS:
4249+
4250+ ``` sql
4251+ EXECUTE prepared_select
4252+ USING @prepared_amount, @prepared_category;
4253+ START
4254+ TRANSACTION READ WRITE;
4255+ COMMIT AND
4256+ NO CHAIN;
4257+ XA
4258+ START ' sq-final-xa' ;
4259+ ```
4260+
4261+ TO-BE:
4262+
4263+ ``` sql
4264+ EXECUTE prepared_select USING @prepared_amount, @prepared_category;
4265+ START TRANSACTION READ WRITE;
4266+ COMMIT AND NO CHAIN;
4267+ XA START ' sq-final-xa' ;
4268+ ```
4269+
4270+ prepared EXECUTE의 USING-list를 production list owner에 연결했다. MySQL/MariaDB의
4271+ ` START TRANSACTION ` , ` SHOW CREATE ` , ` XA START/END ` 는 client tool/control opener가 아니라
4272+ server SQL 문법으로 판정하고, ` COMMIT AND [NO] CHAIN ` 은 boolean condition으로 분리하지
4273+ 않게 했다.
4274+
4275+ ### Oracle ` EXEC ` bind, ` EXPLAIN PLAN `
4276+
4277+ AS-IS:
4278+
4279+ ``` sql
4280+ EXEC
4281+ :b_inout := 10 ;
4282+
4283+ EXPLAIN PLAN SET STATEMENT_ID = ' SQ_ORACLE_FINAL'
4284+ FOR
4285+ SELECT category, SUM (amount)
4286+ FROM sq_oracle_manual_log
4287+ GROUP BY category;
4288+ ```
4289+
4290+ TO-BE:
4291+
4292+ ``` sql
4293+ EXEC :b_inout := 10 ;
4294+
4295+ EXPLAIN PLAN SET STATEMENT_ID = ' SQ_ORACLE_FINAL'
4296+ FOR SELECT category,
4297+ SUM (amount)
4298+ FROM sq_oracle_manual_log
4299+ GROUP BY category;
4300+ ```
4301+
4302+ Oracle bind assignment의 ` EXEC :name ` 은 줄 단위 tool command 자동 종결 대상에서 제외했다.
4303+ ` EXPLAIN PLAN ... FOR ` 는 procedural FOR-loop가 아니라 explain statement의 clause로
4304+ 판정하고 뒤 SELECT의 query/list owner를 정상 생성한다.
4305+
4306+ ## 30-5. 최종 포맷 결과
4307+
4308+ 요청된 명령을 그대로 실행한 최종 포맷 sweep은 1 passed, 0 failed였다. 생성된
4309+ 66개 ` .format.out ` 모두 ` status: PASS ` , issue 0이며, 수정된 파일의 재생성 결과까지
4310+ 다시 육안 대조해 최종 검토 수는 66개·53,361줄이다.
4311+
4312+ ## 30-6. 전체 테스트에서 발견한 production 경로 정합성 수정
4313+
4314+ 전체 ` cargo test ` 는 개별 sweep이 놓칠 수 있는 inventory와 production 조합을 추가로
4315+ 검사했다. 실패 건은 기존 테스트 또는 새 재현 테스트로 먼저 고정한 다음 수정했다.
4316+
4317+ ### Oracle ` SET TRANSACTION ` 의 선택적 ` NAME `
4318+
4319+ AS-IS:
4320+
4321+ ``` sql
4322+ SET TRANSACTION READ WRITE |;
4323+ -- suggestions: []
4324+ ```
4325+
4326+ TO-BE:
4327+
4328+ ``` sql
4329+ SET TRANSACTION READ WRITE NAME ' batch_tx' ;
4330+ -- suggestions at |: [NAME]
4331+ ```
4332+
4333+ Oracle 공식 문법에 따라 ` READ ONLY ` , ` READ WRITE ` , ` ISOLATION LEVEL SERIALIZABLE ` ,
4334+ ` ISOLATION LEVEL READ COMMITTED ` 뒤에 선택적인 ` NAME ` 을 production grammar table에서
4335+ 추천한다. prefix가 비어 있을 때와 입력 중일 때 동일한 경로를 사용한다.
4336+
4337+ ### MySQL/MariaDB DATABASE 대상과 qualified-member 차단
4338+
4339+ AS-IS:
4340+
4341+ ``` sql
4342+ DROP DATABASE IF EXISTS qt_m|;
4343+ -- suggestions: []
4344+
4345+ SHOW CREATE DATABASE app.|;
4346+ -- suggestions: [EMP, EMP_VIEW, EMP_PROC, ...]
4347+ ```
4348+
4349+ TO-BE:
4350+
4351+ ``` sql
4352+ DROP DATABASE IF EXISTS qt_mysql_final_boss;
4353+ -- suggestions at qt_m|: [qt_mysql_final_boss]
4354+
4355+ SHOW CREATE DATABASE app.|;
4356+ -- suggestions: []
4357+ ```
4358+
4359+ ` ALTER/DROP/SHOW CREATE DATABASE|SCHEMA ` 의 대상은 전용 ` Database ` object kind로
4360+ 분류한다. 따라서 현재 파일과 database catalog의 이름은 추천하지만, 점 뒤에는
4361+ schema의 테이블·뷰·루틴 멤버를 열지 않는다. 테스트와 production 모두 동일한
4362+ qualified-completion entry를 사용한다.
4363+
4364+ ### SQL* Plus slash와 REMARK의 원자적 분할
4365+
4366+ AS-IS:
4367+
4368+ ``` sql
4369+ END
4370+ / remark execute block
4371+ SELECT 1 FROM DUAL;
4372+ ```
4373+
4374+ ``` text
4375+ Statement("CREATE PROCEDURE ... END")
4376+ Slash
4377+ Statement("remark execute block")
4378+ Statement("SELECT 1 FROM DUAL")
4379+ ```
4380+
4381+ TO-BE:
4382+
4383+ ``` text
4384+ Statement("CREATE PROCEDURE ... END")
4385+ Slash
4386+ Statement("SELECT 1 FROM DUAL")
4387+ ```
4388+
4389+ slash 뒤 ` REM ` /` REMARK ` 는 parser engine이 이미 하나의 slash terminator/comment로
4390+ 분류한다. concatenated-command 복구가 이를 다시 ` / ` 와 SQL 조각으로 나누지 않도록
4391+ shared slash classifier를 먼저 적용한다.
4392+
4393+ ### MySQL session setting의 typed residue
4394+
4395+ AS-IS:
4396+
4397+ ``` sql
4398+ SET autocommit = 1 , sql_notes = 0 ;
4399+ -- sql_notes를 unknown session state로만 기록
4400+ ```
4401+
4402+ TO-BE:
4403+
4404+ ``` sql
4405+ SET autocommit = 1 , sql_notes = 0 ;
4406+ -- autocommit 상태와 session setting residue를 각각 typed state로 기록
4407+ ```
4408+
4409+ 일반 세션 설정을 ` may_have_session_setting ` 으로 분리해 물리 세션 보존 판단은 유지하면서
4410+ unknown 상태의 의미를 좁혔다. ` SET ` 의 우변에 등장한 ` @var ` 는 assignment target이
4411+ 아니므로 user-variable residue로 잘못 기록하지 않는다.
4412+
4413+ ## 30-7. 최종 품질 게이트
4414+
4415+ | 검증 | 결과 |
4416+ | --- | --- |
4417+ | Space Query 실제 실행 | Oracle/MySQL/MariaDB ` final.sql ` 3개 모두 정상 완료 |
4418+ | ` syntax_highlighting_sweep_all_files_generate_out_report ` | 66개 파일 · 83,402단어 · unexpected 0 · failure 0 |
4419+ | final 인텔리센스 리포트 | Oracle 4,819개 · MySQL 1,117개 · MariaDB 418개, missing 0 |
4420+ | 전체 fixture 인텔리센스 회귀 | MySQL-family 보강 707개 후보, missing 0 |
4421+ | ` million_line_ ` | production/snapshot/shadow 5건 통과, 8.87초 |
4422+ | ` formatting_sweep_all_files_generate_out_report ` | 통과, 66개 ` .format.out ` · issue 0 |
4423+ | 전수 상세 검토 | 66개 · 53,361줄 · 잔여 오류 0 |
4424+ | ` cargo test ` | library 6,623 통과 · 234 ignored · 통합/가드/doc-test 실패 0 |
4425+ | ` cargo clippy --locked --all-targets -- -D warnings -W clippy::perf -W clippy::complexity ` | 통과, 경고 0 |
4426+ | ` cargo fmt --all -- --check ` / ` git diff --check ` | 통과 |
0 commit comments