9.10.4 [SQL] SQL 파서를 이용한 문법 유효성 및 테이블 존재 여부 확인
최근의 거대 언어 모델(LLM)들은 Text-to-SQL 작업에서 놀라운 성과를 보여주며, 자연어 질문을 복잡한 RDBMS 쿼리로 변환하는 AI 데이터 애널리스트(AI Data Analyst)의 역할을 훌륭히 수행하고 있다. 그러나 SQL은 일반적인 프로그래밍 언어와 달리 코드가 실행될 ’데이터베이스 스키마(Schema)’라는 물리적 실체에 완벽하게 종속되어 있다는 치명적인 특징을 가진다.
아무리 JOIN 문법이 완벽하더라도, DB에 users 테이블이 없거나 created_at 컬럼의 타입이 다르다면 그 쿼리는 즉각적인 SyntaxError나 런타임 장애를 일으킨다. 이를 방지하기 위해 생성된 SQL 코드를 실제 운영 DB에 던져보기 전에(무거운 실행 비용 리스크 없이) 선제적으로 걸러낼 수 있는 안전한 SQL 전용 정적 오라클이 필수적이다.
1. 1차 관문: SQL 파서를 이용한 Dialect 특화 문법 검증
SQL은 표준(ANSI SQL)이 존재하지만, 실제 운영 환경에서는 PostgreSQL, MySQL, Oracle, SQL Server 등 각 벤더별 방언(Dialect)이 난무한다. LLM은 이 방언들을 종종 섞어서(Hallucination) 사용하는 실수를 범한다. (예: PostgreSQL 환경에서 MySQL의 전용 함수인 DATE_ADD를 사용하는 경우).
오라클 미들웨어는 sqlglot (Python) 또는 JSQLParser (Java)와 같은 강력한 정적 SQL 파서를 샌드박스에서 실행한다.
import sqlglot
from sqlglot.errors import ParseError
def validate_sql_syntax(ai_sql: str, target_dialect="postgres") -> tuple[bool, str]:
try:
# 방언(Dialect) 스펙에 맞추어 AST 파싱 및 재구성 검증
parsed = sqlglot.transpile(ai_sql, read=target_dialect, write=target_dialect)
return True, "Syntax OK"
except ParseError as e:
return False, f"SQL Syntax Error for {target_dialect}: {str(e)}"
이 검증은 쿼리를 실제 DB망에 흘려보내지 않고도 메모리 단에서 SyntaxError와 방언 불일치를 1ms 안에 잡아낸다.
2. 2차 관문: 메타데이터 스캐닝을 통한 테이블/컬럼 존재 검증
파싱을 통과한 SQL AST 트리에서 오라클은 쿼리에 사용된 모든 테이블 이름과 컬럼 식별자(Identifier)들을 추출(Extract)한다. 이후, 이 추출된 리스트를 메모리에 캐싱해 둔 **실제 데이터베이스의 스키마 메타데이터(Schema Metadata)**와 대조한다.
- Extract:
SELECT u.email, o.price FROM users u JOIN orders o ...➔ 추출된 테이블:[users, orders], 추출된 컬럼:[email, price]. - Verify:
users테이블이 존재하는가? 존재한다면email컬럼이 그 안에 존재하는가? - Reject: 존재하지 않는 테이블이나 컬럼(할루시네이션)이 발견되면, 오류 메시지를 구성하여 AI에게 반환.
“[Schema Oracle Reject] 귀하가 작성한 쿼리에 사용된
customer_profile테이블은 현재 데이터베이스 스키마에 존재하지 않습니다. 제공된 DDL(Data Definition Language) 컨텍스트를 다시 확인하고,users테이블을 활용하여 조인 쿼리를 재작성하십시오.”
3. 3차 관문: EXPLAIN / EXPLAIN PLAN을 활용한 실행 계획 검증
단순 SELECT 쿼리에 한해 적용할 수 있는 가장 고도화된 정적 검증 기법은 대상 DB의 실행 계획(Execution Plan) 생성 도구를 활용하는 것이다.
오라클은 생성된 안전한 SELECT 문 앞에 EXPLAIN 키워드를 붙여(Read-only 모드 데이터베이스에) 전송한다. EXPLAIN은 실제로 데이터를 풀 스캔하지 않고 컴파일 타임에 쿼리가 유효한지, 문법과 스키마가 일치하는지만을 검사하여 실행 경로를 반환한다.
만약 EXPLAIN 명령이 에러를 뱉는다면 앞선 두 개의 관문을 뚫고 들어온 복잡한 시멘틱 오류(Semantic Error, 예: 타입 불일치 비교 등)가 존재한다는 뜻이며, 이것이 피드백 루프로 직행한다.
이처럼 SQL 오라클은 파서(Parser)를 통한 문법 검증과 스키마 컨텍스트 대조, 그리고 리스크가 없는 EXPLAIN 메커니즘을 3중으로 겹쳐 구성함으로써, 데이터베이스의 퍼포먼스를 위협하지 않으면서도 가장 확실한 SQL 확정성을 보장한다.