개요
VillageSQL의 확장 프레임워크(VEF)를 사용하면 데이터베이스 서버에 사용자 정의 기능을 추가할 수 있습니다. 이 가이드에서는 C++ SDK와 확장 템플릿을 사용하여 C++로 확장을 빌드하는 과정을 안내합니다. 인수 및 결과 유형, 집계, 시스템 변수, 파라미터화된 유형 등 VDF 구현을 심층적으로 다루는 내용은 개발 가이드를 참조하세요.Rust를 선호한다면 Rust로 확장 만들기를 참조하세요.
VillageSQL 확장이란 무엇인가요?
VillageSQL 확장은 VEB 파일(VillageSQL Extension Bundle)로 패키지화되어 있습니다. 이 파일에는 다음이 포함됩니다:- 매니페스트 - 확장에 대한 메타데이터(이름, 버전, 설명)
- 공유 라이브러리 - 기능을 구현하는 컴파일된 C++ 코드
- 선택적 메타데이터 - 추가 리소스 또는 구성
- 유형과 함수 정의를 위한 C++ API
- SQL 스크립트 없이 자동 등록
- 유형 안전한 인수 및 결과 유형
- 확장 정의를 위한 빌더 패턴
VDF vs 기존 UDF: VEF를 통해 등록된 함수는 VDF(VillageSQL Defined Functions)라고 불립니다. VillageSQL은
CREATE FUNCTION ... SONAME을 통해 등록되는 기존 MySQL UDF도 지원하지만, 새로운 확장에는 VDF를 권장합니다.SQL에서 VDF 호출
VDF는 확장 접두사를 붙이거나 붙이지 않고 호출할 수 있습니다:- 시스템 함수(내장 MySQL 함수, 예:
NOW(),CONCAT()) - UDFs(기존 MySQL 사용자 정의 함수)
- VDFs(확장 함수) - 해당 이름의 함수가 정확히 하나만 존재할 경우에만
- 저장 함수(
CREATE FUNCTION으로 생성된 함수)
- 여러 확장이 동일한 이름의 함수를 제공할 때
extension.function_name사용 - 모호성이 없을 때 깔끔한 코드를 위해 접두사 없는 이름 사용
- 단일 확장만 해당 함수 이름을 제공할 때는 접두사가 필요하지 않음
- 사용자 정의 함수(VDFs) - 자동 유형 검사 및 검증을 갖춘 SQL 함수
- 사용자 정의 데이터 유형 - ORDER BY 및 인덱스와 함께 작동하는 COMPLEX, UUID, VECTOR와 같은 새 열 유형
- 유형 연산 - 사용자 정의 유형에 대한 인코딩, 디코딩, 비교, 해시 함수
사전 요구 사항
시작하기 전에 VillageSQL을 소스에서 빌드해야 합니다. 확장은 서버의 SDK 헤더와 빌드 트리에 연결됩니다. 먼저 소스에서 빌드하기 가이드를 따르세요. 다음도 필요합니다:- Git - 복제 및 버전 관리
- CMake 3.18 이상 - 빌드 시스템
- C++ 컴파일러 - GCC 8+, Clang 8+, 또는 C++17 지원이 있는 MSVC 2019+
- 기본 C++ 지식 - C++ 및 함수 포인터 이해
단계 1: 확장 템플릿 가져오기
확장 템플릿을 두 가지 방법으로 시작할 수 있습니다:옵션 A: VillageSQL 소스에서 템플릿 사용
VillageSQL 소스 코드가 있는 경우 템플릿이 포함되어 있습니다:옵션 B: GitHub에서 포크하기
먼저 VillageSQL 확장 템플릿 리포지토리를 포크하세요:-
GitHub에서 템플릿 리포지토리 방문:
- “포크(Fork)” 버튼 클릭하여 복사본 생성
-
로컬에 포크 복제:
단계 2: 매니페스트 업데이트
manifest.json을 편집하여 확장 메타데이터 정의:
$schema 필드는 선택 사항이지만, 모든 매니페스트 필드에 대한 IDE 자동 완성과 인라인 검증을 가능하게 합니다.
manifest.json 스키마
검증 규칙:
name: 알파벳으로 시작하고 알파벳 또는 숫자로 끝나야 합니다. 소문자 알파벳, 숫자, 언더스코어, 하이픈을 포함할 수 있습니다. 최대 64자. 언더스코어 사용 — 하이픈은 SQL에서 백틱으로 인용해야 합니다.version: 시맨틱 버전 규칙 준수(예: 1.0.0, 0.2.1)- 유효하지 않은 매니페스트는
INSTALL EXTENSION을 실패시킵니다.
단계 3: C++ SDK로 확장 구현
C++ SDK는 플루언트 빌더 패턴을 사용하여 확장을 정의하는 C++ API를 제공합니다:- 컴파일 타임 검사를 통한 유형 안전한 함수 정의
- 자동 인수 검증 및 유형 변환
- 비교/해시 함수를 가진 사용자 정의 유형 지원(ORDER BY 및 인덱스 가능)
VillageSQL 헤더 포함
주 확장 파일(예:src/extension.cc)을 만들고 C++ SDK 헤더 포함:
<villagesql/vsql.h> 헤더는 유형 빌더, 함수 빌더, 확장 빌더를 가져오고 일반적으로 사용되는 기호를 vsql 네임스페이스로 재내보냅니다.
확장 정의
VEF_GENERATE_ENTRY_POINTS() 매크로를 사용하여 확장 정의:
make_func<&impl>("name")- 구현 포인터로 함수 생성.returns(type)- 반환 유형 설정(STRING, INT, REAL 또는 사용자 정의 유형 이름).param(type)- 인수 추가(최대 8개 인수).buffer_size(size_t)- STRING/CUSTOM 반환 시 특정 출력 버퍼 크기 요청.max_result_length(size_t)- STRING 반환 시 결과 열의 크기를 지정하여 구체화된 결과가 인수 폭에서 잘리지 않도록 합니다.VEF_MAX_RESULT_LENGTH(16 MiB)를 초과하는 값은 서버에 의해 제한됩니다. STRING에만 해당하며, 먼저.returns(STRING)을 호출해야 합니다. Protocol 4(개발 ABI)가 필요합니다..deterministic(bool = true)- 동일한 입력에 항상 동일한 출력을 반환하고 부작용이 없음을 선언. 기본은 비결정적입니다..prerun<func>()- 문장별 설정 함수 설정(옵션).postrun<func>()- 문장별 정리 함수 설정(옵션).build()- 최종 함수 등록
인수 제한: 함수는 최대 8개의 인수를 지원합니다(
kMaxParams로 정의). 더 많은 인수가 필요하면 구조화된 유형 또는 여러 함수를 고려하세요.사용자 정의 유형 인수 및 반환 값을 가진 VDF
VDF는 빌더에서.param(TYPE_NAME) 및 .returns(TYPE_NAME)을 사용하여 사용자 정의 유형 값을 입력 및 반환할 수 있습니다. 구현은 입력에 CustomArg, 출력에 CustomResult를 사용합니다 — 유형 연산에 사용되는 동일한 인수 및 결과 유형입니다:
.param(COMPLEX) 및 .returns(COMPLEX)로 등록:
CustomArg/CustomResult API(파라미터화된 유형을 위한 CustomArgWith<P> 및 CustomResultWith<P>)는 개발 가이드를 참조하세요.
결정적 함수
기본적으로 VDF는 비결정적으로 등록됩니다. 비결정적 함수는 생성된 열, CHECK 제약 조건, 표현식 기본값(DEFAULT (expr) 열) 세 가지 SQL 컨텍스트에서 차단됩니다. 비결정적 VDF를 이러한 기능과 함께 사용하면 오류가 반환됩니다. 함수가 동일한 입력에 항상 동일한 출력을 생성하고 부작용이 없으면 빌더 체인에 .deterministic()을 추가하여 결정적이라고 선언할 수 있습니다.
최적화기는 이 정보를 사용하여 문장당 한 번만 함수를 평가하고 행 간에 결과를 재사용할 수 있습니다. 비결정적 함수를 잘못 결정적으로 표시하면 서버가 실제로 다른 출력을 생성해야 하는 입력에 대해 동일한 결과를 반환할 수 있습니다. 외부 상태, 난수, 시간에 의존하지 않는 경우에만 .deterministic()을 추가하세요.
빌더 서명: .deterministic(bool d = true) — 인수 없이 사용하면 기본값이 true입니다.
예시:
complex_add가 결정적이라고 선언되었으므로 생성된 열 정의에서 사용할 수 있습니다:
사용자 정의 버퍼 크기
변수 길이 데이터를 반환하는 함수의 경우 특정 버퍼 크기 요청:buffer()와 set_length()로 값을 직접 빌드할 때 버퍼는 buffer().size() 바이트로 고정됩니다 — 그 이상으로 쓰면 메모리가 오버플로되므로 넘어 쓰지 않도록 방지하세요:
out.set(sv)는 snprintf 스타일 오버플로 계약을 따릅니다. 즉, 버퍼에 들어가는 만큼의 바이트를 복사하고 set_length를 통해 값의 전체 크기를 보고합니다. 보고된 크기가 버퍼를 초과하면 서버는 결과 버퍼를 늘리고 함수를 다시 호출하므로, 요청된 버퍼보다 큰 STRING 값은 더 이상 잘리지 않습니다.
이 계약은 행 단위로 평가되는 시점에 적용됩니다. 구체화된 STRING 결과 — GROUP BY/DISTINCT 임시 테이블, CREATE TABLE ... SELECT, 또는 UNION 내의 결과 — 는 함수가 .max_result_length(n)을 선언하지 않는 한 여전히 인수 폭에서 잘립니다. .max_result_length(n)은 결과 열의 크기를 지정합니다(문자 단위, VEF_MAX_RESULT_LENGTH인 16 MiB로 제한):
.buffer_size()를 통해 함수의 최대 출력 크기에 기반하여 충분한 버퍼 크기를 요청하세요. 버퍼 크기를 올바르게 지정하면 늘리고 다시 시도하는 왕복 비용을 피할 수 있습니다.함수 구현 전에 C++ API 참조를 검토하여 VDF 계약(널 검사, 결과 유형, 버퍼 크기, 오류 처리)을 완전히 이해하세요.
단계 4: 사용자 정의 유형 만들기
사용자 정의 유형을 통해 새 열 유형(예:COMPLEX, UUID, VECTOR)을 정의할 수 있습니다. 이 유형은 ORDER BY, 인덱스, 집계 함수와 함께 작동합니다. 확장이 단순히 함수만 등록하는 경우 단계 5로 건너뜁니다.
자세한 구현은 C++로 사용자 정의 유형 만들기를 참조하세요. 유형이 매개변수를 받는 경우(예: VECTOR(1536)) 파라미터화된 유형을 참조하세요.
단계 5: 빌드 구성 업데이트
CMakeLists.txt를 편집하여 확장을 VEB 파일로 빌드:
VillageSQLExtensionFramework는 확장 빌드를 위한 CMake 도구 제공VEF_CREATE_VEB()는 라이브러리, 매니페스트, 메타데이터를.veb아카이브로 패키징- 프레임워크는 MySQL/VillageSQL 빌드 플래그 자동 감지
- 라이브러리 타겟 이름은 일반적으로
extension(어떤 이름이든 가능) - VEB 이름은
manifest.json이름과 일치해야 함 - 기본적으로 확장은 안정적 ABI 헤더에 맞춰 빌드됩니다. 불안정한 개발 헤더로 빌드하려면
-DVSQL_USE_DEV_ABI=ON설정
단계 6: 빌드 디렉토리 생성
별도의 빌드 디렉토리 생성:단계 7: CMake 및 Make로 빌드
확장 구성 및 빌드:- 컴파일된 공유 라이브러리(
.so파일) - VEB 패키지(
.veb파일) - 매니페스트와 라이브러리를 포함하는 tar 아카이브
빌드 검증
VEB 파일 내용 확인:단계 8: 설치 및 테스트
옵션 A: VillageSQL 확장 디렉토리에 설치
설치 타겟을 사용하여 VEB를 VillageSQL 설치 디렉토리로 복사:.veb 파일을 VillageSQL_VEB_INSTALL_DIR로 구성된 디렉토리로 복사합니다.
옵션 B: 수동 설치
VEB 파일 수동 복사:확장 테스트
-
VillageSQL에 연결:
-
확장 설치:
-
설치 확인:
-
함수 테스트:
테스트 만들기
확장이 올바르게 작동하는지 검증하기 위해 테스트 파일 추가:-
mysql-test/t/에 테스트 파일 생성: -
예상 결과 생성:
-
테스트 실행:
문제 해결
확장이 로드되지 않음
오류 로그 확인 및 VEB 내용 검증:함수 찾기 실패
설치 및 등록 확인:빌드 오류
예제 확장
기존 VillageSQL 확장에서 배우세요:vsql_complex
복소수 데이터 유형 구현
vsql_extension_template
확장 생성을 위한 최소 템플릿
다음 단계
확장 사용하기
확장 설치 및 관리 방법 배우기
개발 가이드
인수 및 결과 유형, 집계, 시스템 변수, 테스트
확장 아키텍처
라이프사이클, 캐싱, 성능, 보안 모델
소스에서 빌드하기
VillageSQL 소스 코드로 빌드하기

