diff --git a/src/script/mysql/ddl/privacy.mber_nm_view_hash_cutover_mysql.sql b/src/script/mysql/ddl/privacy.mber_nm_view_hash_cutover_mysql.sql new file mode 100644 index 0000000..ef255db --- /dev/null +++ b/src/script/mysql/ddl/privacy.mber_nm_view_hash_cutover_mysql.sql @@ -0,0 +1,160 @@ +-- 개인정보보호 기능개선 사업 추가제안 Action4 (2026-08-11) +-- comvnusermaster / comvnuserinfo 뷰 재정의: GNR 분기를 암호문(MBER_NM_ENC)으로 전환하고 +-- 검색용 해시 컬럼(USER_NM_HASH)을 추가한다. +-- +-- 주의: 이 스크립트는 기존 뷰의 정확한 바이트 내용(특히 comvnuserinfo의 한글 리터럴 +-- USER_GUBUN_NM 값)을 절대 재입력하지 않는다 — information_schema.views.VIEW_DEFINITION을 +-- 서버 사이드에서 REPLACE()로 최소 치환만 하고, 결과를 다시 CREATE OR REPLACE VIEW로 +-- 반영한다(PREPARE/EXECUTE 동적 SQL). 클라이언트 터미널 인코딩 문제로 한글이 깨져 +-- 보이는 현상과 무관하게 안전하다. +-- +-- VIEW_DEFINITION은 테이블명을 스키마 한정자(`csv`.`table`)로 저장한다는 점에 +-- 주의(SHOW CREATE VIEW의 표시와 다름) — 2026-08-11 dryrun으로 실측 확인. +-- +-- 사전조건: 이 스크립트를 실행하기 전에 comvnusermaster/comvnuserinfo를 소비하는 +-- 모든 구문(66개 표시 + 검색 전환분, 2026-08-11 커밋 545b49d)이 이미 반영되어 있어야 +-- 한다 — all-or-nothing 게이트. 되돌리려면 아래 백업 섹션의 CREATE OR REPLACE VIEW로 복원한다. + +-- ============================================================ +-- 0. 백업: 현재 뷰 정의를 별도 테이블에 저장(롤백용) +-- ============================================================ +CREATE TABLE IF NOT EXISTS privacy_view_def_backup ( + view_name VARCHAR(64) NOT NULL, + backup_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + view_definition MEDIUMTEXT NOT NULL, + PRIMARY KEY (view_name, backup_at) +); + +INSERT INTO privacy_view_def_backup (view_name, view_definition) +SELECT 'comvnusermaster', VIEW_DEFINITION +FROM information_schema.views +WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'comvnusermaster'; + +INSERT INTO privacy_view_def_backup (view_name, view_definition) +SELECT 'comvnuserinfo', VIEW_DEFINITION +FROM information_schema.views +WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'comvnuserinfo'; + +SELECT view_name, COUNT(*) AS backup_count FROM privacy_view_def_backup GROUP BY view_name; + +-- ============================================================ +-- 1. comvnusermaster 재정의 +-- ============================================================ +SET @def_master = ( + SELECT VIEW_DEFINITION FROM information_schema.views + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'comvnusermaster' +); + +SET @def_master = REPLACE( + @def_master, + '`comtngnrlmber`.`MBER_NM` AS `USER_NM`', + '`comtngnrlmber`.`MBER_NM_ENC` AS `USER_NM`' +); + +SET @def_master = REPLACE( + @def_master, + 'end) AS `ADULT` from `csv`.`comtngnrlmber` where', + 'end) AS `ADULT`,`csv`.`comtngnrlmber`.`MBER_NM_HASH` AS `USER_NM_HASH` from `csv`.`comtngnrlmber` where' +); + +SET @def_master = REPLACE( + @def_master, + '\'N\' AS `ADULT` from `csv`.`comtnemplyrinfo` union all', + '\'N\' AS `ADULT`,NULL AS `USER_NM_HASH` from `csv`.`comtnemplyrinfo` union all' +); + +SET @def_master = REPLACE( + @def_master, + '\'N\' AS `ADULT` from `csv`.`comtnentrprsmber` where', + '\'N\' AS `ADULT`,NULL AS `USER_NM_HASH` from `csv`.`comtnentrprsmber` where' +); + +SET @def_master = REPLACE( + @def_master, + '\'N\' AS `ADULT` from `csv`.`biz_group` where', + '\'N\' AS `ADULT`,NULL AS `USER_NM_HASH` from `csv`.`biz_group` where' +); + +-- 안전장치: 치환이 정확히 4건(분기당 1건)이 아니면 실행을 중단시킨다(0으로 나누기 강제 에러). +SELECT CASE WHEN + (LENGTH(@def_master) - LENGTH(REPLACE(@def_master, 'USER_NM_HASH', ''))) / LENGTH('USER_NM_HASH') = 4 + AND @def_master LIKE '%MBER_NM_ENC%' + AND @def_master NOT LIKE '%`comtngnrlmber`.`MBER_NM` AS `USER_NM`%' + THEN 1 ELSE 1/0 END AS master_assertion_ok; + +SET @sql_master = CONCAT('CREATE OR REPLACE VIEW comvnusermaster AS ', @def_master); +PREPARE stmt_master FROM @sql_master; +EXECUTE stmt_master; +DEALLOCATE PREPARE stmt_master; + +-- ============================================================ +-- 2. comvnuserinfo 재정의 +-- ============================================================ +SET @def_info = ( + SELECT VIEW_DEFINITION FROM information_schema.views + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'comvnuserinfo' +); + +SET @def_info = REPLACE( + @def_info, + '`comtngnrlmber`.`MBER_NM` AS `USER_NM`', + '`comtngnrlmber`.`MBER_NM_ENC` AS `USER_NM`' +); + +SET @def_info = REPLACE( + @def_info, + '`comtngnrlmber`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT` from `csv`.`comtngnrlmber` union all', + '`comtngnrlmber`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT`,`csv`.`comtngnrlmber`.`MBER_NM_HASH` AS `USER_NM_HASH` from `csv`.`comtngnrlmber` union all' +); + +SET @def_info = REPLACE( + @def_info, + '`biz_group`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT` from `csv`.`biz_group` union all', + '`biz_group`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT`,NULL AS `USER_NM_HASH` from `csv`.`biz_group` union all' +); + +SET @def_info = REPLACE( + @def_info, + '`comtnentrprsmber`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT` from `csv`.`comtnentrprsmber` union all', + '`comtnentrprsmber`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT`,NULL AS `USER_NM_HASH` from `csv`.`comtnentrprsmber` union all' +); + +SET @def_info = REPLACE( + @def_info, + '`comtnemplyrinfo`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT` from `csv`.`comtnemplyrinfo`', + '`comtnemplyrinfo`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT`,NULL AS `USER_NM_HASH` from `csv`.`comtnemplyrinfo`' +); + +SELECT CASE WHEN + (LENGTH(@def_info) - LENGTH(REPLACE(@def_info, 'USER_NM_HASH', ''))) / LENGTH('USER_NM_HASH') = 4 + AND @def_info LIKE '%MBER_NM_ENC%' + AND @def_info NOT LIKE '%`comtngnrlmber`.`MBER_NM` AS `USER_NM`%' + THEN 1 ELSE 1/0 END AS info_assertion_ok; + +SET @sql_info = CONCAT('CREATE OR REPLACE VIEW comvnuserinfo AS ', @def_info); +PREPARE stmt_info FROM @sql_info; +EXECUTE stmt_info; +DEALLOCATE PREPARE stmt_info; + +-- ============================================================ +-- 3. 반영 후 검증 +-- ============================================================ +SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION +FROM information_schema.columns +WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME IN ('comvnusermaster', 'comvnuserinfo') + AND COLUMN_NAME IN ('USER_NM', 'USER_SE', 'USER_GUBUN', 'USER_NM_HASH') +ORDER BY TABLE_NAME, ORDINAL_POSITION; + +SELECT USER_ID, USER_SE, LEFT(USER_NM, 20) AS user_nm_sample, LEFT(USER_NM_HASH, 20) AS hash_sample +FROM comvnusermaster WHERE USER_SE = 'GNR' LIMIT 1; + +SELECT USER_ID, USER_SE, LEFT(USER_NM, 20) AS user_nm_sample, USER_NM_HASH +FROM comvnusermaster WHERE USER_SE = 'USR' LIMIT 1; + +SELECT USER_SE, COUNT(*) FROM comvnusermaster GROUP BY USER_SE; + +SELECT USER_GUBUN, LEFT(USER_NM, 20) AS user_nm_sample, LEFT(USER_NM_HASH, 20) AS hash_sample +FROM comvnuserinfo WHERE USER_GUBUN = 'GNR' LIMIT 1; + +SELECT USER_GUBUN, COUNT(*) FROM comvnuserinfo GROUP BY USER_GUBUN;