티스토리 뷰
[Open source contribution] Apache Shardingsphere 오픈소스 기여 경험기 - ANTLR4 방언 문법과 DROP TABLE 한 줄 — Apache ShardingSphere 예제를 고친 기록
ebson 2026. 10. 6. 13:44작은 예제 파일에서 시작한 기여
오픈소스에 기여해 보고 싶다는 마음은 오래 있었지만, 막상 큰 프로젝트의 저장소를 열어보면 어디서부터 손을 대야 할지 막막했습니다. Apache ShardingSphere는 JDBC 드라이버와 프록시 형태로 데이터 샤딩·암호화·읽기쓰기 분리 같은 기능을 제공하는 분산 데이터베이스 생태계인데, 코드베이스가 넓고 모듈도 많습니다. 처음부터 커널이나 파서 엔진 같은 핵심을 건드릴 자신은 없어서, 저는 상대적으로 읽기 쉬운 examples 디렉터리부터 천천히 살펴보기로 했습니다.
examples/shardingsphere-parser-example는 ShardingSphere의 SQL 파서를 어떻게 쓰는지 보여주는 예제 모음입니다. 방언별로 예제 클래스가 나뉘어 있는데, 그중 Oracle용 예제인 OracleParserStatementExample을 읽던 중에 조금 이상한 부분이 눈에 들어왔습니다. DDL 문장을 상수로 선언해 두고 하나씩 파싱해 보여주는 구조였는데, DROP 문장이 이렇게 적혀 있었습니다.
private static final String DDL_DROP_SQL = "DROP TABLE table1, table2;";
콤마로 여러 테이블을 한 번에 지우는 형태였습니다. 처음에는 그냥 넘어갈 뻔했지만, 이게 Oracle에서 유효한 문장인지 확신이 서지 않아 멈춰 섰습니다. 확인해 보기 전에 넘겨짚지 않는 편이 낫다고 생각했습니다.
방언마다 다른 문법, 그리고 ANTLR4
ShardingSphere가 SQL을 다루는 방식을 조금 들여다보면 왜 이 문장이 문제가 되는지 이해할 수 있습니다. ShardingSphere의 SQL 파싱은 ANTLR4를 기반으로 합니다. 그런데 데이터베이스마다 SQL 문법이 조금씩 다르기 때문에, MySQL·Oracle·PostgreSQL 같은 방언별로 별도의 .g4 문법 파일을 두고 각자의 규칙에 맞춰 파싱합니다. 같은 DROP TABLE이라도 어떤 방언 문법을 통과시키느냐에 따라 허용되는 형태가 달라진다는 뜻입니다.
MySQL 계열에서는 DROP TABLE table1, table2 처럼 콤마로 여러 테이블을 나열해 한 번에 삭제하는 문법을 허용합니다. 반면 Oracle의 dropTable 문법은 단일 테이블만 받도록 되어 있습니다. 공식 저장소의 Oracle 문법 정의를 확인해 보면 이 규칙은 다음과 같습니다.
DROP TABLE tableName (CASCADE CONSTRAINTS)? (PURGE)?
여기에는 콤마로 여러 테이블을 이어 붙이는 경로가 없습니다. CASCADE CONSTRAINTS나 PURGE 같은 선택적 옵션은 붙일 수 있지만, 테이블 이름 자리에는 하나만 올 수 있습니다. 즉 DROP TABLE table1, table2;는 Oracle 방언 관점에서 문법에 맞지 않는 문장이었습니다.
파싱 실패가 예제 전체를 멈추게 한 지점
문제가 문법 위반에서 끝나지 않는다는 점이 이 변경을 올리기로 마음먹게 한 이유였습니다. OracleParserStatementExample의 main은 선언해 둔 SQL 상수들을 차례로 파싱하고 방문(visit)하면서 파서 동작을 보여주는 구조입니다. SELECT, INSERT, UPDATE, DELETE, CREATE TABLE을 거쳐 DROP TABLE, ALTER TABLE까지 순서대로 이어집니다.
그런데 Oracle 방언이 DROP TABLE table1, table2;를 파싱하지 못하고 예외를 던지면, 그 예외가 main의 흐름을 그 지점에서 끊어 버립니다. 결과적으로 DROP 데모는 실패로 끝나고, 그 뒤에 오는 ALTER TABLE 예제에는 도달조차 하지 못합니다. 예제를 그대로 실행해 본 사람은 파서가 정상적으로 동작하는 모습이 아니라 중간에 멈춘 스택 트레이스를 보게 되는 것입니다.
예제 코드는 라이브러리 사용법을 배우려는 사람이 가장 먼저 실행해 보는 자료입니다. 그렇기 때문에 예제에 담긴 SQL은 해당 방언의 파서가 실제로 받아들일 수 있는 형태여야 하고, 예제를 끝까지 실행했을 때 의도한 모든 문장 유형을 보여줄 수 있어야 한다고 생각했습니다.
고친 것은 한 줄
수정 자체는 아주 작았습니다. 콤마로 두 테이블을 나열하던 것을 단일 테이블 삭제로 바꾸었습니다.
private static final String DDL_DROP_SQL = "DROP TABLE table1;";
DROP TABLE table1;은 Oracle 문법이 받아들이는 유효한 형태이면서, 여전히 DROP TABLE이라는 문장 유형을 그대로 보여줍니다. 예제의 목적은 "여러 테이블을 한 번에 지우는 방법"을 보여주는 것이 아니라 "DROP TABLE 문장을 Oracle 파서가 어떻게 다루는지"를 보여주는 것이므로, 단일 테이블 형태로 충분했습니다.
이 한 줄을 바꾸자 예제는 SELECT, INSERT, UPDATE, DELETE, CREATE TABLE, DROP TABLE, ALTER TABLE까지 모든 문장을 예외 없이 파싱하고 방문하게 되었습니다. 동작 로직을 바꾼 것이 아니라 예제 데이터로 쓰인 문자열 하나를 방언에 맞게 바로잡은 것이라, 별도의 테스트를 추가하지는 않았습니다.
기여 규칙을 확인하며 알게 된 것들
변경이 작다고 해서 그냥 올릴 수 있는 것은 아니었습니다. ShardingSphere의 기여 규칙을 하나씩 확인하는 과정 자체가 저에게는 배움이었습니다.
먼저 기본 브랜치가 main이 아니라 master라는 점을 확인했습니다. 그리고 PR은 squash merge로 병합되기 때문에 PR 제목이 곧 커밋 제목이 됩니다. 그래서 제목을 명령형 동사구로, 접두사나 마침표 없이 첫 단어를 대문자로 써야 한다는 관례에 맞춰 Fix unparseable multi-table DROP TABLE in Oracle parser example로 정했습니다. 병합될 때 GitHub이 끝에 PR 번호를 자동으로 붙여 준다는 것도 이때 알게 됐습니다.
빌드는 Maven wrapper인 ./mvnw를 사용하고, 소스 문법은 JDK 8에 맞춰져 있습니다. 이번 변경은 문자열 상수 한 줄이라 이런 제약과 직접 부딪힐 일은 없었습니다. 이 수정은 단순한 예제 데이터 정정이라 RELEASE-NOTES.md에 항목을 더하지도 않았습니다.
PR 설명에는 무엇을 왜 바꿨는지 사실 그대로 적었습니다. 콤마로 여러 테이블을 지우는 형태가 MySQL 문법이라는 점, Oracle의 dropTable 문법은 단일 테이블만 허용한다는 점, 그래서 기존 문장이 파싱에 실패해 main이 DROP·ALTER 데모에 도달하기 전에 예외로 멈췄다는 점, 수정 후에는 모든 문장이 예외 없이 파싱된다는 점을 담았습니다. 리뷰어가 diff만 봐도 맥락을 잡을 수 있도록 배경을 갖춰 두려고 했습니다. 이 PR은 다음 링크에서 확인할 수 있습니다.
https://github.com/apache/shardingsphere/pull/39152
돌아보며
머지된 변경은 문자열 한 줄이었습니다. 규모로만 보면 내세울 것이 없는 기여입니다. 그렇지만 저에게 남은 것은 그 한 줄보다 조금 더 넓었습니다.
우선 "SQL은 다 같은 SQL"이라는 막연한 생각을 다시 보게 됐습니다. ShardingSphere가 방언마다 별도의 .g4 문법을 두고 각자의 규칙으로 파싱한다는 구조를 실제 코드로 확인하고 나니, MySQL에서 되던 문장이 Oracle에서 왜 막히는지를 문법 수준에서 이해할 수 있었습니다. 예제 파일 하나가 파서의 동작을 얼마나 정확히 대표해야 하는지도 실감했습니다. 잘못된 예제 데이터 하나가 예외로 흐름을 끊으면, 그 뒤의 멀쩡한 예제까지 사용자에게 보이지 않게 된다는 점을 실제 사례로 보게 된 것입니다.
또 하나는, 큰 프로젝트에 기여하는 일이 반드시 거창한 기능 추가일 필요는 없다는 감각입니다. 이상해 보이는 지점에서 넘겨짚지 않고 멈춰 서서 공식 문법 정의를 확인하고, 프로젝트의 규칙에 맞게 작은 변경을 다듬어 올리는 과정만으로도 배울 것이 많았습니다. 다음에는 조금 더 안쪽 모듈을 읽어 보고 싶다는 마음도 생겼습니다. 이번 기여는 그 방향으로 가는 첫걸음 정도로 기억해 두려고 합니다.
'OPEN SOURCE' 카테고리의 다른 글
- Total
- Today
- Yesterday
- 트래픽 처리
- Redis vs DB
- 백엔드 성능 설계
- Cache Avalanche
- 동시성처리
- 백엔드 아키텍처
- Eager Initialization
- Cache Penetration
- Initialization-on-Demand Holder Idiom
- 트랜잭션 관리
- 캐시 성능 비교
- mybatis
- Redis 성능 개선
- DB 트랜잭션
- 스레드 생명주기
- InterruptedException
- Spring Batch
- Hot Key 문제
- Cache Aside
- Redis 캐시 전략
- Enum 기반 싱글톤
- 캐시 장애
- Double-Checked Locking
- 백엔드 성능
- Java Performance
- TTL 설계
- spring batch 5
- 백엔드 성능 튜닝
- 캐시와 인덱스
- DB 인덱스 성능
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |

