← 모두의 툴

SQL 압축기가 문자열 속 --를 만나면 쿼리를 통째로 잘라먹는다

가이드 · 2026.08.24 최종 확인

SQL을 한 줄로 압축하는 도구는 공백·줄바꿈·주석을 지워서 크기를 줄이는 단순한 작업처럼 보입니다. 하지만 "주석 제거"라는 한 단계가 문자열 리터럴 내부를 침범하면 결과가 조용히 틀리는 게 아니라 쿼리 자체가 깨질 수 있습니다. 이 글은 SQL 최소화 도구의 실제 코드를 그대로 읽고, 문제가 재현되는지 검증한 뒤 그 원인을 분해합니다.

1. SQL 주석 문법이 가진 근본적인 모호함

SQL에서 --는 그 뒤로 줄바꿈이 나올 때까지를 한 줄 주석으로 처리하고, /* ... */는 블록 주석입니다. 문제는 이 기호들이 문자열 리터럴 안에서도 똑같은 문자로 나타날 수 있다는 점입니다. WHERE note='A--B'처럼 하이픈 두 개가 우연히 문자열 값 안에 들어가는 경우는 URL(https://a--b.example.com), 코드 스니펫을 저장하는 컬럼, 자유 텍스트 필드 등에서 실제로 드물지 않게 발생합니다. 파서가 "지금 문자열 안에 있는가"를 모른 채 정규식만으로 -- 이후를 지워버리면, 문자열 경계라는 개념 자체가 무시됩니다.

2. 실제 코드로 확인: 처리 순서가 문제다

도구의 minify() 함수를 그대로 옮기면 핵심 로직은 이렇습니다.

if(rmComments){ sql=sql.replace(/\/\*[\s\S]*?\*\//g,' ').replace(/--[^\n]*/g,' '); }
// 문자열 리터럴 보호 (플레이스홀더 치환) — 이 시점에야 실행됨
const strings=[]; sql=sql.replace(/'[^']*'/g, m => { strings.push(m); return '__STR'+(strings.length-1)+'__'; });

공백 압축과 키워드 대문자화는 문자열을 __STR0__ 같은 플레이스홀더로 먼저 바꿔치기한 뒤 처리하고 마지막에 복원하므로 문자열 값을 절대 건드리지 않습니다. 그런데 주석 제거 코드는 이 보호 로직보다 먼저 실행됩니다. 즉 정규식 /--[^\n]*/g가 원본 SQL 문자열 전체를 훑을 때 어떤 --가 진짜 주석이고 어떤 게 문자열 값 내부인지 구분할 방법이 코드 안에 전혀 없습니다.

3. 재현: 실제로 쿼리가 끊긴다

주석 제거 옵션을 켠 채로 아래 입력을 넣으면 어떻게 되는지 실측한 결과입니다.

입력출력결과
WHERE note='A--B' AND x=1WHERE note='A따옴표 미종결, 뒤 조건 전부 소실
note='a/*b*/c'note='a c'따옴표는 닫혀 있어 오류는 안 나지만 값이 조용히 변조됨

첫 번째 케이스는 심각합니다. -- 이후 전체(B' AND x=1)가 "한 줄 주석"으로 취급되어 지워지고, 결과는 닫히지 않은 따옴표를 가진 문법 오류 SQL이 됩니다. 두 번째 케이스는 더 위험합니다 — 문법적으로는 멀쩡해 보이지만 저장하려던 문자열 값(a/*b*/c)이 a c로 조용히 바뀌어 있어서, 실행은 되지만 데이터가 손상됩니다. 두 케이스 모두 도구가 별도 오류 메시지를 띄우지 않기 때문에 눈으로 결과를 대조하지 않으면 알아채기 어렵습니다.

4. 왜 이런 설계가 나왔는가

이 순서 자체가 "설계 실수"라기보다는, SQL을 진짜로 토큰화(tokenize)하지 않고 정규식 치환만으로 압축을 구현할 때 거의 필연적으로 마주치는 함정입니다. 올바르게 처리하려면 문자열 리터럴을 가장 먼저 식별해 보호한 다음, 나머지 영역에서만 주석을 제거해야 합니다. 이 도구는 공백 압축·대문자화 단계에서는 이 순서를 지키고 있지만(그래서 그 두 기능은 안전합니다), 유독 주석 제거 단계만 문자열 보호보다 앞에 배치되어 있어 같은 파일 안에서도 기능별로 안전성이 다릅니다. SQL 검증기처럼 구문을 실제로 파싱하는 도구라면 이런 문제가 원천적으로 발생하지 않습니다.

5. 실무에서 안전하게 쓰는 방법

자주 묻는 질문

Q. 이 버그는 실제로 재현되나요, 아니면 이론상 가능성일 뿐인가요?

실제로 재현됩니다. 도구의 minify() 함수를 그대로 실행해보면 WHERE note='A--B' AND x=1 입력이 주석 제거 옵션 켠 상태에서 WHERE note='A로 잘려나가는 것을 직접 확인할 수 있습니다.

Q. 공백 압축이나 키워드 대문자화도 같은 문제가 있나요?

아니요. 이 두 기능은 문자열 리터럴을 플레이스홀더로 먼저 치환한 뒤 처리하고 마지막에 복원하므로 문자열 값을 건드리지 않습니다. 문제는 주석 제거 단계에서만 발생합니다.

Q. 이 문제를 피하려면 어떻게 해야 하나요?

SQL 문자열 값 안에 우연히 --/*가 들어갈 가능성이 있다면 주석 제거 옵션을 끄고 사용하거나, 압축 후 결과를 반드시 눈으로 대조 확인하세요.

Q. 블록 주석 기호가 문자열 안에 있을 때도 쿼리가 끊기나요?

끊기지는 않지만 값이 조용히 변조됩니다. note='a/*b*/c'note='a c'로 바뀌어 실행은 되지만 저장되는 데이터가 원본과 달라집니다.