> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 확장 만들기

> 확장 템플릿과 VEF를 사용하여 사용자 정의 VillageSQL 확장을 만드는 방법을 배우세요.

<Warning>
  VEF Protocol 3은 v0.0.4부터 안정적입니다. Protocol 4는 개발 중이며, `-DVSQL_USE_DEV_ABI=ON` 옵션을 사용하여만 개발 ABI 헤더를 통해 사용할 수 있습니다. 이전 Protocol 2로 빌드된 확장은 서버에서 거부되며 재빌드해야 합니다.
</Warning>

## 개요

VillageSQL의 확장 프레임워크를 사용하면 데이터베이스 서버에 사용자 정의 기능을 추가할 수 있습니다. VEF SDK와 확장 템플릿을 사용하여 사용자 정의 확장을 빌드하세요.

이 가이드에서는 확장을 빌드하고 설치하는 끝에서 끝까지의 단계를 다룹니다. VDF 구현을 심층적으로 작성하려면 [개발 가이드](/docs/ko/mysql-8.4/0.0.4/development)를 참조하세요.

<Note>
  Rust를 선호한다면 [Rust로 확장 빌드하기](/docs/ko/mysql-8.4/0.0.4/rust-sdk)를 참조하세요.
</Note>

## VillageSQL 확장이란 무엇인가요?

VillageSQL 확장은 **VEB 파일**(VillageSQL Extension Bundle)로 패키지화되어 있습니다. 이 파일에는 다음이 포함됩니다:

* **매니페스트** - 확장에 대한 메타데이터(이름, 버전, 설명)
* **공유 라이브러리** - 기능을 구현하는 컴파일된 C++ 코드
* **선택적 메타데이터** - 추가 리소스 또는 구성

확장은 **VEF SDK**(VillageSQL Extension Framework)를 사용하여 빌드됩니다. 이 SDK는 다음과 같은 기능을 제공합니다:

* 유형과 함수 정의를 위한 C++ API
* SQL 스크립트 없이 자동 등록
* 유형 안전한 함수 래퍼
* 확장 정의를 위한 빌더 패턴

<Note>
  **VDF vs 기존 UDF:** VEF SDK를 통해 등록된 함수는 VDF(VillageSQL Defined Functions)라고 불립니다. VillageSQL은 `CREATE FUNCTION ... SONAME`을 통해 등록되는 기존 MySQL UDF도 지원하지만, 새로운 확장에는 VEF SDK 방식을 권장합니다.
</Note>

### SQL에서 VDF 호출

VDF는 확장 접두사를 붙이거나 붙이지 않고 호출할 수 있습니다:

```sql theme={null}
-- Unqualified (preferred for cleaner code)
SELECT complex_abs(impedance) FROM signals;

-- Qualified with extension name (explicit)
SELECT vsql_complex.complex_abs(impedance) FROM signals;
```

**함수 해석 순서:**

함수를 접두사 없이 호출할 때 VillageSQL은 다음 순서로 해석합니다:

1. **시스템 함수**(내장 MySQL 함수, 예: `NOW()`, `CONCAT()`)
2. **UDFs**(기존 MySQL 사용자 정의 함수)
3. **VDFs**(확장 함수) - 해당 이름의 함수가 정확히 하나만 존재할 경우에만
4. **저장 함수**(`CREATE FUNCTION`으로 생성된 함수)

**접두사 이름 사용 시기:**

* 여러 확장이 동일한 이름의 함수를 제공할 때 `extension.function_name` 사용
* 모호성이 없을 때 깔끔한 코드를 위해 접두사 없는 이름 사용
* 단일 확장만 해당 함수 이름을 제공할 때는 접두사가 필요하지 않음

확장은 다음을 추가할 수 있습니다:

* **사용자 정의 함수(VDFs)** - 자동 유형 검사 및 검증을 갖춘 SQL 함수
* **사용자 정의 데이터 유형** - ORDER BY 및 인덱스와 함께 작동하는 COMPLEX, UUID, VECTOR와 같은 새 열 유형
* **유형 연산** - 사용자 정의 유형에 대한 인코딩, 디코딩, 비교, 해시 함수

## 사전 요구 사항

시작하기 전에 VillageSQL을 소스에서 빌드해야 합니다. 확장은 서버의 SDK 헤더와 빌드 트리에 연결됩니다. 먼저 [소스에서 빌드하기](/docs/ko/mysql-8.4/0.0.4/source) 가이드를 따르세요.

다음도 필요합니다:

* **Git** - 복제 및 버전 관리
* **CMake** 3.18 이상 - 빌드 시스템
* **C++ 컴파일러** - GCC 8+, Clang 8+, 또는 C++17 지원이 있는 MSVC 2019+
* **기본 C++ 지식** - C++ 및 함수 포인터 이해

<Tip>
  **AI 에이전트로 빌드 중이신가요?** [`vsql-extension-builder`](https://github.com/villagesql/villagesql-skills) 스킬은 클로드 코드, 지미니 등 지원되는 에이전트를 사용하여 전체 워크플로우(스캐폴딩부터 테스트까지)를 자동화합니다. 다음으로 설치하세요:

  ```bash theme={null}
  curl -sSL https://villagesql.com/skills | bash
  ```
</Tip>

## 단계 1: 확장 템플릿 가져오기

확장 템플릿을 두 가지 방법으로 시작할 수 있습니다:

### 옵션 A: VillageSQL 소스에서 템플릿 사용

VillageSQL 소스 코드가 있는 경우 템플릿이 포함되어 있습니다:

```bash theme={null}
cd /path/to/villagesql-source
cp -r villagesql/sdk/template my-extension
cd my-extension
```

### 옵션 B: GitHub에서 포크하기

먼저 VillageSQL 확장 템플릿 리포지토리를 포크하세요:

1. GitHub에서 템플릿 리포지토리 방문:
   ```
   https://github.com/villagesql/vsql-extension-template
   ```

2. **"포크(Fork)"** 버튼 클릭하여 복사본 생성

3. 로컬에 포크 복제:
   ```bash theme={null}
   git clone https://github.com/YOUR_USERNAME/vsql-extension-template.git
   cd vsql-extension-template
   ```

<Tip>
  대신 GitHub에서 "템플릿 사용" 버튼을 사용하여 포크 기록 없이 템플릿 기반으로 새 리포지토리를 생성할 수 있습니다.
</Tip>

## 단계 2: 매니페스트 업데이트

`manifest.json`을 편집하여 확장 메타데이터 정의:

```json theme={null}
{
  "$schema": "https://raw.githubusercontent.com/villagesql/villagesql-docs/main/mysql-8.4/0.0.4/manifest.json.schema.json",
  "name": "my_awesome_extension",
  "version": "1.0.0",
  "description": "My custom VillageSQL extension that does amazing things",
  "author": "Your Name",
  "license": "GPL-2.0"
}
```

`$schema` 필드는 선택 사항이지만, 모든 매니페스트 필드에 대한 IDE 자동 완성과 인라인 검증을 가능하게 합니다.

### manifest.json 스키마

| 필드            | 필수  | 형식                | 설명                                        |
| ------------- | --- | ----------------- | ----------------------------------------- |
| `name`        | ✅ 예 | 알파벳, 숫자, `_`, `-` | 고유 식별자. `INSTALL EXTENSION` 이름과 일치해야 합니다. |
| `version`     | ✅ 예 | MAJOR.MINOR.PATCH | 시맨틱 버전 문자열                                |
| `description` | 아니요 | 문자열               | 기능에 대한 간략한 설명                             |
| `author`      | 아니요 | 문자열               | 저자 이름 또는 조직                               |
| `license`     | 아니요 | 문자열               | 라이선스 식별자(GPL-2.0 권장)                      |

**검증 규칙:**

* `name`: 알파벳으로 시작하고 알파벳 또는 숫자로 끝나야 합니다. 소문자 알파벳, 숫자, 언더스코어, 하이픈을 포함할 수 있습니다. 최대 64자. **언더스코어 사용** — 하이픈은 SQL에서 백틱으로 인용해야 합니다.
* `version`: 시맨틱 버전 규칙 준수(예: 1.0.0, 0.2.1)
* 유효하지 않은 매니페스트는 `INSTALL EXTENSION`을 실패시킵니다.

**예시:**

```sql theme={null}
-- manifest.json has "name": "my_awesome_extension"
INSTALL EXTENSION my_awesome_extension;  -- ✅ Correct: no quoting needed
INSTALL EXTENSION `my-awesome-extension`;  -- ⚠️ Works, but requires backtick quoting
```

SQL, 파일 이름, 리포지토리 이름에 대한 전체 명명 규칙은 [확장 명명 규칙](/docs/ko/mysql-8.4/0.0.4/install#extension-naming-conventions)을 참조하세요.

## 단계 3: VEF SDK로 확장 구현

VEF SDK는 유형 안전한 빌더 패턴을 사용하여 확장을 정의하는 C++ API를 제공합니다:

* 컴파일 타임 검사를 통한 유형 안전한 함수 정의
* 자동 인수 검증 및 유형 변환
* 비교/해시 함수 지원(ORDER BY 및 인덱스 가능)

### VillageSQL 헤더 포함

주 확장 파일(예: `src/extension.cc`)을 만들고 VEF SDK 포함:

```cpp theme={null}
#include <villagesql/vsql.h>

// Your implementation code here
```

`<villagesql/vsql.h>` 헤더는 유형 빌더, 함수 빌더, 확장 빌더를 가져오고 일반적으로 사용되는 기호를 `vsql` 네임스페이스로 재내보냅니다.

### 확장 정의

`VEF_GENERATE_ENTRY_POINTS()` 매크로를 사용하여 확장 정의:

```cpp theme={null}
VEF_GENERATE_ENTRY_POINTS(
  make_extension()
    .func(make_func<&my_reverse_impl>("my_reverse")
      .returns(STRING)
      .param(STRING)
      .build())
    .func(make_func<&count_vowels_impl>("count_vowels")
      .returns(INT)
      .param(STRING)
      .build())
);
```

**함수 빌더 메서드:**

* `make_func<&impl>("name")` - 구현 포인터로 함수 생성
* `.returns(type)` - 반환 유형 설정(STRING, INT, REAL 또는 사용자 정의 유형 이름)
* `.param(type)` - 인수 추가(최대 8개 인수)
* `.buffer_size(size_t)` - STRING/CUSTOM 반환 시 특정 출력 버퍼 크기 요청
* `.deterministic(bool = true)` - 동일한 입력에 항상 동일한 출력을 반환하고 부작용이 없음을 선언. 기본은 비결정적입니다.
* `.prerun<func>()` - 문장별 설정 함수 설정(옵션)
* `.postrun<func>()` - 문장별 정리 함수 설정(옵션)
* `.build()` - 최종 함수 등록

<Note>
  **인수 제한:** 함수는 최대 8개의 인수를 지원합니다(`kMaxParams`로 정의). 더 많은 인수가 필요하면 구조화된 유형 또는 여러 함수를 고려하세요.
</Note>

### 사용자 정의 유형 인수 및 반환 값을 가진 VDF

VDF는 빌더에서 `.param(TYPE_NAME)` 및 `.returns(TYPE_NAME)`을 사용하여 사용자 정의 유형 값을 입력 및 반환할 수 있습니다. 구현은 입력에 `CustomArg`, 출력에 `CustomResult`를 사용합니다 — 유형 연산에 사용되는 동일한 래퍼입니다:

```cpp theme={null}
void complex_conjugate_impl(CustomArg in, CustomResult out) {
    if (in.is_null()) { out.set_null(); return; }
    auto src = in.value();    // Span<const unsigned char> — raw binary
    auto dst = out.buffer();  // Span<unsigned char>
    // ... read src, write result to dst ...
    out.set_length(src.size());
}
```

`.param(COMPLEX)` 및 `.returns(COMPLEX)`로 등록:

```cpp theme={null}
.func(make_func<&complex_conjugate_impl>("complex_conjugate")
          .returns(COMPLEX)
          .param(COMPLEX)
          .build())
```

자세한 `CustomArg`/`CustomResult` API(파라미터화된 유형을 위한 `CustomArgWith<P>` 및 `CustomResultWith<P>`)는 [개발 가이드](/docs/ko/mysql-8.4/0.0.4/development#typed-wrappers-recommended)를 참조하세요.

### 결정적 함수

기본적으로 VDF는 비결정적으로 등록됩니다. 비결정적 함수는 생성된 열, CHECK 제약 조건, 표현식 기본값(`DEFAULT (expr)` 열) 세 가지 SQL 컨텍스트에서 차단됩니다. 비결정적 VDF를 이러한 기능과 함께 사용하면 오류가 반환됩니다. 함수가 동일한 입력에 항상 동일한 출력을 생성하고 부작용이 없으면 빌더 체인에 `.deterministic()`을 추가하여 결정적이라고 선언할 수 있습니다.

최적화기는 이 정보를 사용하여 문장당 한 번만 함수를 평가하고 행 간에 결과를 재사용할 수 있습니다. 비결정적 함수를 잘못 결정적으로 표시하면 서버가 실제로 다른 출력을 생성해야 하는 입력에 대해 동일한 결과를 반환할 수 있습니다. 외부 상태, 난수, 시간에 의존하지 않는 경우에만 `.deterministic()`을 추가하세요.

**빌더 서명:** `.deterministic(bool d = true)` — 인수 없이 사용하면 기본값이 `true`입니다.

**예시:**

```cpp theme={null}
.func(make_func<&complex_add_impl>("complex_add")
          .returns(COMPLEX)
          .param(COMPLEX)
          .param(COMPLEX)
          .deterministic()
          .build())
```

`complex_add`가 결정적이라고 선언되었으므로 생성된 열 정의에서 사용할 수 있습니다:

```sql theme={null}
-- Deterministic VDFs can be used in generated columns
CREATE TABLE t (
    a COMPLEX,
    b COMPLEX,
    result COMPLEX GENERATED ALWAYS AS (complex_add(a, b)) STORED
);
-- STORED vs VIRTUAL follows standard MySQL generated column rules
```

### 사용자 정의 버퍼 크기

변수 길이 데이터를 반환하는 함수의 경우 특정 버퍼 크기 요청:

```cpp theme={null}
make_func<&large_result_impl>("large_result")
  .returns(STRING)
  .param(INT)
  .buffer_size(65536)  // Request 64KB buffer
  .build()
```

쓰기 전에 사용 가능한 버퍼 공간 확인:

```cpp theme={null}
void large_result_impl(StringArg input, StringResult out) {
    if (input.is_null()) { out.set_null(); return; }
    size_t needed = calculate_output_size(input.value());

    auto buf = out.buffer();
    if (needed > buf.size()) {
        out.error("Output exceeds buffer size");
        return;
    }

    // Write output into buf.data()
    out.set_length(actual_output_length);
}
```

<Note>
  `.buffer_size()`를 통해 함수의 최대 출력 크기에 기반하여 충분한 버퍼 크기 요청.
</Note>

<Note>
  함수 구현 전에 [확장 API 참조](/docs/ko/mysql-8.4/0.0.4/extension-api-reference)를 검토하여 VDF 계약(널 검사, 결과 유형, 버퍼 크기, 오류 처리)을 완전히 이해하세요.
</Note>

## 단계 4: 사용자 정의 유형 만들기

사용자 정의 유형을 통해 새 열 유형(예: `COMPLEX`, `UUID`, `VECTOR`)을 정의할 수 있습니다. 이 유형은 `ORDER BY`, 인덱스, 집계 함수와 함께 작동합니다. 확장이 단순히 함수만 등록하는 경우 단계 5로 건너뜁니다.

자세한 구현은 [사용자 정의 유형 만들기](/docs/ko/mysql-8.4/0.0.4/custom-types)를 참조하세요. 유형이 매개변수를 받는 경우(예: `VECTOR(1536)`) [파라미터화된 유형](/docs/ko/mysql-8.4/0.0.4/development#parameterized-types)을 참조하세요.

<h2 id="step-5-update-build-configuration">
  단계 5: 빌드 구성 업데이트
</h2>

`CMakeLists.txt`를 편집하여 확장을 VEB 파일로 빌드:

```cmake theme={null}
cmake_minimum_required(VERSION 3.18)
project(my_extension)

# Find VillageSQL Extension Framework
find_package(VillageSQLExtensionFramework QUIET)

# The framework detects build flags via 4 methods (in order):
# 1. Explicit MYSQL_INCLUDE_FLAGS/MYSQL_CXXFLAGS
# 2. VillageSQL_BUILD_DIR (reads CMakeCache.txt from VillageSQL build)
# 3. VSQL_BASE_DIR (uses mysql_config)
# 4. Default - mysql_config from PATH

# Build shared library with your source files
add_library(extension SHARED
    src/extension.cc
    src/my_functions.cc
)

# Create VEB archive
VEF_CREATE_VEB(
    NAME my_extension
    LIBRARY_TARGET extension
    MANIFEST ${CMAKE_CURRENT_SOURCE_DIR}/manifest.json
)

# Install VEB to VillageSQL extensions directory
install(FILES ${VEB_OUTPUT} DESTINATION ${INSTALL_DIR})
```

**구성 참고 사항:**

* `VillageSQLExtensionFramework`는 확장 빌드를 위한 CMake 도구 제공
* `VEF_CREATE_VEB()`는 라이브러리, 매니페스트, 메타데이터를 `.veb` 아카이브로 패키징
* 프레임워크는 MySQL/VillageSQL 빌드 플래그 자동 감지
* 라이브러리 타겟 이름은 일반적으로 `extension`(어떤 이름이든 가능)
* VEB 이름은 `manifest.json` 이름과 일치해야 함
* 기본적으로 확장은 안정적 ABI 헤더에 맞춰 빌드됩니다. 불안정한 개발 헤더로 빌드하려면 `-DVSQL_USE_DEV_ABI=ON` 설정

***

## 단계 6: 빌드 디렉토리 생성

별도의 빌드 디렉토리 생성:

```bash theme={null}
mkdir build
cd build
```

## 단계 7: CMake 및 Make로 빌드

확장 구성 및 빌드:

```bash theme={null}
# Configure the build
cmake ..

# Or, if building against VillageSQL source:
cmake .. -DVillageSQL_BUILD_DIR=/path/to/villagesql/build

# Or, to build against the unstable dev ABI headers:
cmake .. -DVSQL_USE_DEV_ABI=ON

# Build the extension
make
```

이로 인해 생성되는 파일:

* 컴파일된 공유 라이브러리(`.so` 파일)
* VEB 패키지(`.veb` 파일) - 매니페스트와 라이브러리를 포함하는 tar 아카이브

### 빌드 검증

VEB 파일 내용 확인:

```bash theme={null}
make show_veb
```

다음과 같은 내용이 표시되어야 합니다:

```
manifest.json
lib/myext.so
```

## 단계 8: 설치 및 테스트

### 옵션 A: VillageSQL 확장 디렉토리에 설치

설치 타겟을 사용하여 VEB를 VillageSQL 설치 디렉토리로 복사:

```bash theme={null}
make install
```

이것은 `.veb` 파일을 `VillageSQL_VEB_INSTALL_DIR`로 구성된 디렉토리로 복사합니다.

### 옵션 B: 수동 설치

VEB 파일 수동 복사:

```bash theme={null}
# Find the VEF directory
mysql -u root -p -e "SHOW VARIABLES LIKE 'veb_dir';"

# Copy the VEB file
sudo cp my-awesome-extension.veb /path/to/veb_dir/
```

### 확장 테스트

1. **VillageSQL에 연결**:
   ```bash theme={null}
   mysql -u root -p
   ```

2. **확장 설치**:
   ```sql theme={null}
   INSTALL EXTENSION my_awesome_extension;
   ```

3. **설치 확인**:
   ```sql theme={null}
   SELECT * FROM INFORMATION_SCHEMA.EXTENSIONS;
   ```

4. **함수 테스트**:
   ```sql theme={null}
   SELECT my_reverse('Hello, World!');
   -- Output: !dlroW ,olleH

   SELECT count_vowels('VillageSQL');
   -- Output: 3
   ```

## 테스트 만들기

확장이 올바르게 작동하는지 검증하기 위해 테스트 파일 추가:

1. `mysql-test/t/`에 테스트 파일 생성:
   ```sql theme={null}
   -- mysql-test/t/my_basic.test
   SELECT my_reverse('abc');
   SELECT my_reverse('');
   SELECT my_reverse(NULL);
   ```

2. 예상 결과 생성:
   ```bash theme={null}
   cd /path/to/villagesql/build/mysql-test
   perl mysql-test-run.pl --suite=/path/to/your/extension/mysql-test --record
   ```

3. 테스트 실행:
   ```bash theme={null}
   perl mysql-test-run.pl --suite=/path/to/your/extension/mysql-test
   ```

## 문제 해결

### 확장 불로드

오류 로그 확인 및 VEB 내용 검증:

```bash theme={null}
make show_veb
tail -f /var/log/mysql/error.log
```

### 함수 찾기 실패

설치 및 등록 확인:

```sql theme={null}
SELECT * FROM INFORMATION_SCHEMA.EXTENSIONS;
```

### 빌드 오류

```bash theme={null}
# Verify mysql_config is available
which mysql_config
mysql_config --version

# Check compiler version
gcc --version  # or clang --version

# Verify CMake version (3.18+ required)
cmake --version
```

## 예제 확장

기존 VillageSQL 확장에서 배우세요:

<CardGroup cols={2}>
  <Card title="vsql_complex" icon="wave-square" href="https://github.com/villagesql/villagesql-server/tree/main/villagesql/examples/vsql-complex">
    복소수 데이터 유형 구현
  </Card>

  <Card title="vsql_extension_template" icon="code" href="https://github.com/villagesql/vsql-extension-template">
    확장 생성을 위한 최소 템플릿
  </Card>
</CardGroup>

## 다음 단계

<CardGroup cols={2}>
  <Card title="확장 사용하기" icon="puzzle-piece" href="/docs/ko/mysql-8.4/0.0.4/install">
    확장 설치 및 관리 방법 배우기
  </Card>

  <Card title="개발 가이드" icon="code" href="/docs/ko/mysql-8.4/0.0.4/development">
    유형 래퍼, 집계, 시스템 변수, 테스트
  </Card>

  <Card title="확장 아키텍처" icon="sitemap" href="/docs/ko/mysql-8.4/0.0.4/architecture">
    라이프사이클, 캐싱, 성능, 보안 모델
  </Card>

  <Card title="소스에서 빌드하기" icon="hammer" href="/docs/ko/mysql-8.4/0.0.4/source">
    VillageSQL 소스 코드로 빌드하기
  </Card>
</CardGroup>

## 참고 자료

* [VillageSQL 확장 템플릿](https://github.com/villagesql/vsql-extension-template)
* [MySQL UDF API 문서](https://dev.mysql.com/doc/extending-mysql/8.4/en/adding-loadable-function.html)
* [CMake 문서](https://cmake.org/documentation/)
* [VillageSQL 커뮤니티 Discord](https://discord.gg/KSr6whd3Fr)
