


쿼리의 의미를 바꾸지 않고 여러 방언을 지원하는 SQL 컴파일러 확장하기
SQL을 AST로 바꾼 뒤 다른 데이터베이스용 SQL로 다시 만드는 컴파일러를 고칠 때 쓴다. 먼저 담당 계층을 찾고, 방언이 바뀌어도 의미를 지키며, SQL을 문자열 대신 AST 빌더로 만들고, 실제 실행과 속도를 테스트한다.
이 AI 규칙을 사용하려면
## 고치기 전에 그 동작을 맡은 컴파일러 계층 찾기
시스템을 각 계층의 책임이 서로 다른 컴파일러로 취급하세요.
- 토크나이저는 SQL 텍스트를 타입이 지정된 토큰으로 변환하고 방언이 어휘 매핑을 재정의할 수 있게 합니다.
- 파서는 재귀 하강 방식으로 추상 구문 트리(AST)를 구축하며, 일치 검사, 커서, 목록, 래퍼용 전용 도우미를 사용합니다.
- 표현식 클래스는 의미론적 SQL 개념을 나타내며 순회와 변환을 지원합니다.
- 생성기는 단순 변환 매핑이나 전용 생성 메서드를 사용해 표현식을 재귀적으로 SQL로 되돌립니다.
- 방언 모듈은 기능 플래그, 토큰 집합, 구문 분석 매핑, 생성 매핑을 사용해 공통 기반을 확장합니다.
- 최적화 규칙은 의도된 순서로 AST를 정규화하고 다시 작성합니다.
- 스키마와 타입 정보는 최적화, 트랜스파일, 계보 분석을 지원합니다.
- 계보 분석은 출력 열을 상류 표현식과 테이블에 연결합니다.
동작을 변경하기 전에 담당 계층을 찾으세요. 한 계층을 고치기 위해 다른 계층에 로직을 흘려 넣지 말고 토큰화, 구문 분석, 의미 표현, 최적화, 생성을 서로 분리해 유지하세요.
파서와 생성기의 대칭성을 보존하세요. 구문 분석은 토큰을 표현식에 매핑하고, 생성은 표현식을 SQL에 매핑합니다. 파서가 인식할 수 없는 텍스트를 의도적으로 일반 명령 노드로 대체해 보존한다면, 그 보존 메커니즘을 불완전한 구문 분석으로 몰래 바꾸지 마세요.
## 저장소가 정한 테스트와 검사 명령을 순수 구현과 네이티브 확장 모두에 쓰기
편집 전에 저장소의 기여 지침과 아키텍처 지침을 읽으세요. 기본 설치, 개발용 설치, 선택적 네이티브 확장 설치, 커밋 전 설정, 전체 테스트, 단위 테스트, 스타일 검사, 형식 검사, 벤치마크에는 문서화된 대상을 사용하세요.
순수 구현과 선택적 컴파일 확장을 구분하세요. 먼저 직접 관련된 모드를 실행한 다음 변경에 필요한 더 넓은 검사를 수행하세요. 네이티브 가속에 영향이 있다면 두 방식이 동일하게 동작한다고 가정하지 말고 순수 구현과 컴파일 경로를 모두 테스트하세요.
반복 작업 중에는 특정 테스트 파일, 클래스 또는 메서드를 실행하여 실패를 정확히 겨냥하세요. 제출 전에는 서식 지정, 정적 검사, 순수 실행 환경 테스트, 해당하는 경우 네이티브 확장 테스트를 포함하여 저장소에서 요구하는 전체 검사 대상을 실행하세요.
성능에 민감한 작업에는 구문 분석 및 최적화 벤치마크를 사용하세요. 동일한 조건의 구성을 비교하고 유리한 마이크로벤치마크를 위해 의미론적 정확성을 희생하지 마세요.
## SQL을 다른 방언으로 바꿔도 같은 의미 지키기
AST를 의미론적 기준 정보원으로 취급하세요. 원본 SQL을 의미 표현식으로 구문 분석한 다음 그 표현식에서 대상 방언을 생성하세요. 원본 표기보다 의미를 보존하세요. 주석은 가능한 범위에서 보존할 수 있지만 의미적 동등성이 우선입니다.
여러 방언이 공유하는 기능은 의미가 실제로 일치할 때 공통 기반에 추가하세요. 방언별 구문이나 동작은 관련 방언에만 추가하세요. 이름 검사를 곳곳에 흩뿌리지 말고 명시적 기능 플래그, 예약 토큰 집합, 함수 또는 문 매핑, 표현식과 SQL 간 매핑을 사용하세요.
최적화 규칙은 의도된 순서로 유지하세요. 이름 한정, 타입 주석, 조건자 또는 프로젝션 푸시다운, 단순화는 앞선 단계와 스키마 정보에 의존할 수 있습니다. 최적화기를 물리 쿼리 플래너가 아닌 논리적 재작성기로 취급하세요.
기능이 데이터베이스 구조에 의존한다면 스키마 정보를 명시적으로 제공하세요. 필요한 테이블과 열 메타데이터가 없을 때 이름 한정, 형식 추론, 최적화 또는 열 계보가 신뢰할 수 있다고 주장하지 마세요.
## SQL은 문자열을 이어 붙이지 말고 AST 빌더와 템플릿으로 만들기
일반 함수 표현식을 만들기 전에 표현식 목록에서 기존 전용 클래스를 찾으세요. 전용 의미 클래스가 없을 때만 일반 익명 표현식을 사용하세요.
지원되는 가장 단순한 생성 메커니즘을 우선하세요.
1. 하나의 복잡한 표현식 타입에는 자동으로 발견되는 생성기 메서드 `<lowercase_expression_name>_sql`을 구현하세요.
2. 변환 매핑은 한 줄로 된 단순한 이름 변경, 람다 또는 의도적으로 진입점이 여러 개인 함수에만 사용하세요.
3. 생성기 메서드 안에서는 직렬화만을 위해 함수 노드를 만들지 말고 생성기의 함수 도우미를 사용하세요.
4. 배열, 불리언 표현식, 조건 분기, 형 변환, 열, NULL, 산술, 인덱싱, 비교에는 표현식 빌더와 연산자를 사용하세요.
5. 복잡한 결과에는 SQL 템플릿을 구문 분석하고 복사한 AST에서 자리표시자를 바꾸세요.
문자열 보간으로 SQL 조각을 조립하지 마세요. AST 빌더와 템플릿은 직접 만든 문자열에서 흔히 깨지는 따옴표 처리, 이스케이프, 중첩, 방언별 동작을 보존합니다.
## 타입은 타입 주석 뒤에 확인하고, NULL은 실행 시점에 처리하기
구문적 타입 검사와 의미론적 타입 검사를 구분하세요. 노드 자체가 문자열 리터럴인지 확인하고 리터럴 값을 추출할 때만 `is_string` 같은 리터럴 조건자를 사용하세요. 열, 함수 결과 또는 다른 표현식의 추론된 의미 타입을 확인할 때는 `is_type()`을 사용하세요.
의미론적 동작이 타입에 의존하면 `is_type()`을 호출하기 전에 타입 주석을 실행하세요. 타입에 의존하는 트랜스파일 테스트는 AST에 타입 주석을 추가해야 합니다. 그러지 않으면 타입이 채워진 적이 없어서 올바른 의미 검사도 실패한 것처럼 보일 수 있습니다.
노드가 숫자 리터럴인지 확인한 다음 `to_py()` 같은 표현식 변환 메서드로 숫자 리터럴 값을 추출하세요. 내부 원시 텍스트에서 따옴표를 직접 제거한 뒤 타입 변환하지 마세요.
리터럴 NULL 노드만 확인하여 트랜스파일 시점에 SQL의 `NULL` 동작을 결정하지 마세요. 열, 매개변수, 표현식, NULL 리터럴이 모두 같은 의미를 따르도록 실행 시점의 `IS NULL` 로직이 포함된 SQL을 생성하세요.
상위 노드를 찾을 때는 검색이 부모 쿼리로 빠져나가지 않도록 쿼리 범위 경계를 포함하세요. 대상 방언이 특정 인수를 표현할 수 없다면 프레임워크의 지원되지 않는 인수 선언 메커니즘을 사용하세요.
## 방언마다 테스트하고 실제 데이터베이스에서 돌리기
영향을 받는 방언이나 컴파일러 계층을 담당하는 테스트 모음에 테스트를 추가하세요. 동일하게 왕복되어야 하는 구문에는 왕복 검증을 사용하고, 하나의 의미 표현식이 대상별로 다른 SQL을 생성해야 할 때는 방언 간 검증을 사용하세요.
같은 동작을 이미 증명하는 검증을 중복하지 마세요. 해당하는 경우 NULL 허용 여부, 타입, 따옴표, 범위, 지원되지 않는 인수 또는 방언 차이 등 새로운 의미 구분에 초점을 맞춘 사례를 추가하세요.
데이터베이스별 테스트 모음에 배치한 테스트가 실제로 해당 데이터베이스나 호환 엔진에서 실행되는지 확인하세요. 규칙이 실행 시 동작에 의존한다면 생성된 문자열만으로는 증거가 되지 않습니다.
타입에 민감한 결과에는 리터럴과 타입이 지정된 비리터럴 표현식을 모두 테스트하세요. 네이티브 가속은 순수 구현과의 동등성을 확인하세요. 최적화기 변경에는 스키마를 고려한 사례를 포함하고 규칙 순서가 의미를 바꾸지 않는지 검증하세요.
## 변경 하나는 목적 하나로 좁히고, 검토하기 쉽게 만들기
각 변경을 명확히 정의된 하나의 목적으로 제한하세요. 단순하지 않은 동작에는 테스트를 추가하고, API가 바뀌면 공개 docstring을 갱신하며, 저장소의 풀 리퀘스트와 커밋 규칙을 따르고, 제출 전에 요구되는 전체 검사를 실행하세요.
사용하지 않는 import, 변수, 도달하지 않는 코드를 제거하세요. 의도적으로 제거된 코드를 위한 호환성 보완책을 추가하지 마세요. 불필요한 임시 변수보다 읽기 쉬운 인라인 표현식을 우선하되 의미 단계가 불명확해질 때까지 로직을 압축하지 마세요.
명확하지 않은 로직에만 주석을 사용하고 복잡한 동작이나 공개 API에만 docstring을 추가하세요. 작업이 라이선스를 명시적으로 다루는 경우가 아니라면 라이선스 파일이나 라이선스 구성을 변경하지 마세요.
방언 간 의도하지 않은 결합, 중복된 표현식 타입, 직접 조립한 SQL, 누락된 타입 주석, 컴파일 시점에만 이루어지는 NULL 처리, 범위 누출, 테스트하지 않은 네이티브 동작이나 데이터베이스별 동작이 변경에 포함되지 않았는지 검토하세요.
## 속도를 높일 때도 네이티브 가속 경로와 파서 설계 지키기
주요 구현이 고수준 언어를 사용하더라도 성능을 제품 기능으로 취급하세요. 선택적 네이티브 가속 경로를 보존하고 토큰화, 구문 분석, 생성 또는 최적화에 영향을 주는 변경을 벤치마크하세요.
의도적으로 채택한 재귀 하강 파서를 최적화일 것이라는 추측만으로 Pratt 구문 분석으로 바꾸지 마세요. 구문 분석 전략은 아키텍처 선택이지 교체 가능한 속도 설정이 아닙니다.
코드베이스가 선호하는 대안을 문서화했다면 컴파일 경로를 방해하는 것으로 알려진 추상화를 피하세요. 예를 들어 지원되지 않는 프로토콜 추상화보다 단순한 유니언 타입과 구조적 덕 타이핑을 선택하세요.
구문 분석, AST 구축, 생성, 방언 동작, 테스트 전반에서 정확성을 보존한 뒤에만 최적화하세요. 의미를 바꾸거나, 따옴표 처리를 잃거나, `NULL`을 잘못 처리하거나, 순수 모드와 컴파일 모드 사이에서 동작이 달라지는 빠른 구현은 회귀입니다.
