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

> 사용자 정의 함수(UDFs) 문서

# 사용자 정의 함수(UDFs)

export const ExperimentalBadge = () => {
  return <div className="experimentalBadge">
            <div className="experimentalIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.25" d="M5.5 2H10.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M9.50015 2V6.19625L13.4283 12.7425C13.4738 12.8183 13.4985 12.9049 13.4996 12.9934C13.5008 13.0818 13.4785 13.169 13.435 13.246C13.3914 13.323 13.3283 13.3871 13.2519 13.4317C13.1755 13.4764 13.0886 13.4999 13.0002 13.5H3.00015C2.91164 13.5 2.8247 13.4766 2.74822 13.432C2.67174 13.3874 2.60847 13.3233 2.56487 13.2463C2.52126 13.1693 2.49889 13.082 2.50004 12.9935C2.50119 12.905 2.52582 12.8184 2.5714 12.7425L6.50015 6.19625V2" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M4.47656 9.56754C5.30344 9.41254 6.47656 9.47942 7.99969 10.25C10.0153 11.2707 11.4216 11.0569 12.2184 10.7282" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            실험 기능입니다. <u><a href="/docs/docs/beta-and-experimental-features#experimental-features">자세히 알아보세요.</a></u>
        </div>;
};

export const CloudNotSupportedBadge = () => {
  return <div className="cloudNotSupportedBadge">
            <div className="cloudNotSupportedIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.5" d="M6.33366 12.6666L12.3739 12.6667C13.6593 12.6667 14.7073 11.6187 14.7073 10.3334C14.7073 9.04804 13.6593 8.00003 12.3739 8.00003C12.3739 8.00003 12.3337 7.66659 12.0003 7.33325M10.667 5.33322C8.00033 2.33325 4.45395 4.78537 4.14195 6.68203C2.55728 6.7627 1.29395 8.06203 1.29395 9.6667C1.29395 11.3234 2.66699 12.6666 4.00033 12.6666" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.5" d="M2.66699 14L12.0003 4.66663" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>

        </div>
            ClickHouse Cloud에서 지원되지 않음
        </div>;
};

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <Icon />
                <span>베타</span>
            </a>;
  }
  return <div className="betaBadge">
            <Icon />
            <span>
                베타 기능. 
                <u>
                    <a href="/docs/docs/beta-and-experimental-features#beta-features">
                        자세히 보기.
                    </a>
                </u>
            </span>
        </div>;
};

ClickHouse는 여러 유형의 사용자 정의 함수(UDF)를 지원합니다.

* [실행형 UDFs](#executable-user-defined-functions)는 외부 프로그램이나 스크립트(Python, Bash 등)를 시작한 뒤, STDIN / STDOUT을 통해 데이터 블록을 해당 프로그램으로 스트리밍합니다. ClickHouse를 다시 컴파일하지 않고도 기존 코드나 도구를 통합할 때 사용할 수 있습니다. 프로세스 내부 옵션보다 호출당 오버헤드가 크므로, 더 무거운 로직을 처리하거나 다른 런타임이 필요한 경우에 가장 적합합니다.
* [SQL UDFs](#sql-user-defined-functions)는 `CREATE FUNCTION`을 사용해 SQL만으로 정의합니다. 쿼리 계획에 인라인되어 확장되므로(프로세스 경계 없음) 가볍고, 표현식 로직을 재사용하거나 복잡한 계산 컬럼을 단순화하는 데 적합합니다.
* [Experimental WebAssembly UDFs](#webassembly-user-defined-functions)는 서버 프로세스 내 샌드박스에서 WebAssembly로 컴파일된 코드를 실행합니다. 외부 실행형보다 호출당 오버헤드가 낮고 네이티브 확장 기능보다 격리 수준이 높아, WASM을 대상으로 할 수 있는 언어(예: C/C++/Rust)로 작성한 사용자 정의 알고리즘에 적합합니다.
* [Experimental driver-based executable UDFs](#driver-based-executable-user-defined-functions)는 연산자가 제공하는 "드라이버"가 `CREATE FUNCTION ... ENGINE = DriverName(...) AS '...'`에 제공된 코드 스니펫을 함수 생성 시점에 실행형 UDF로 변환하도록 합니다(예를 들어 컴파일을 통해). 이는 실행형 UDFs를 기반으로 하며, 서버 측 드라이버 구성이 필요합니다.

<div id="executable-user-defined-functions">
  ## 실행형 사용자 정의 함수
</div>

<BetaBadge />

<Note>
  ClickHouse Cloud에서 실행형 UDF는 퍼블릭 베타로 제공되며 Cloud Console UI를 통해 생성됩니다. Cloud 전용 절차는 [User-defined functions in Cloud](/docs/ko/products/cloud/features/sql-console-features/user-defined-functions)를 참조하십시오.
</Note>

ClickHouse는 데이터를 처리하기 위해 외부 실행 프로그램이나 스크립트를 호출할 수 있습니다.

실행형 사용자 정의 함수의 구성은 하나 이상의 XML 파일에 둘 수 있습니다.
구성 경로는 [`user_defined_executable_functions_config`](/docs/ko/reference/settings/server-settings/settings#user_defined_executable_functions_config) 매개변수로 지정합니다.

함수 구성에는 다음 설정이 포함됩니다:

| 매개변수                          | 설명                                                                                                                                                                                                                                                                                   | 필수    | 기본값                    |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- | ---------------------- |
| `name`                        | 함수 이름                                                                                                                                                                                                                                                                                | 예     | -                      |
| `command`                     | 실행할 스크립트 이름 또는 `execute_direct`가 false인 경우 실행할 명령                                                                                                                                                                                                                                    | 예     | -                      |
| `argument`                    | 인수의 `type`과 선택적 `name`을 포함하는 인수 설명입니다. 각 인수는 별도의 설정으로 설명합니다. [Native](/docs/ko/reference/formats/Native) 또는 [JSONEachRow](/docs/ko/reference/formats/JSON/JSONEachRow) 같은 사용자 정의 함수 포맷에서 인수 이름이 직렬화의 일부인 경우에는 이름 지정이 필요합니다                                                                     | 예     | `c` + argument\_number |
| `format`                      | 인수를 명령에 전달할 때 사용하는 [포맷](/docs/ko/reference/formats/index)입니다. 명령의 출력도 동일한 포맷이어야 합니다                                                                                                                                                                                                       | 예     | -                      |
| `return_type`                 | 반환 값의 유형                                                                                                                                                                                                                                                                             | 예     | -                      |
| `return_name`                 | 반환 값의 이름입니다. [Native](/docs/ko/reference/formats/Native) 또는 [JSONEachRow](/docs/ko/reference/formats/JSON/JSONEachRow) 같은 사용자 정의 함수 포맷에서 반환 이름이 직렬화의 일부인 경우에는 반환 이름 지정이 필요합니다                                                                                                                  | 선택 사항 | `result`               |
| `type`                        | 실행형 유형입니다. `type`이 `executable`로 설정되면 단일 명령이 시작됩니다. `executable_pool`로 설정되면 명령 풀(pool)이 생성됩니다                                                                                                                                                                                        | 예     | -                      |
| `max_command_execution_time`  | 데이터 블록을 처리하는 최대 실행 시간(초)입니다. 이 설정은 `executable_pool` 명령에만 적용됩니다                                                                                                                                                                                                                      | 선택 사항 | `10`                   |
| `command_termination_timeout` | 파이프가 닫힌 뒤 명령이 종료되어야 하는 시간(초)입니다. 이 시간이 지나면 명령을 실행 중인 프로세스에 `SIGTERM`이 전송됩니다                                                                                                                                                                                                          | 선택 사항 | `10`                   |
| `command_read_timeout`        | 명령의 stdout에서 데이터를 읽을 때의 timeout(밀리초)입니다                                                                                                                                                                                                                                              | 선택 사항 | `10000`                |
| `command_write_timeout`       | 명령의 stdin에 데이터를 쓸 때의 timeout(밀리초)입니다                                                                                                                                                                                                                                                 | 선택 사항 | `10000`                |
| `pool_size`                   | 명령 풀의 크기입니다                                                                                                                                                                                                                                                                          | 선택 사항 | `16`                   |
| `send_chunk_header`           | 프로세스에 데이터 청크를 보내기 전에 행 수를 먼저 전송할지 여부를 제어합니다                                                                                                                                                                                                                                          | 선택 사항 | `false`                |
| `execute_direct`              | `execute_direct` = `1`이면 `command`는 [user\_scripts\_path](/docs/ko/reference/settings/server-settings/settings#user_scripts_path)에 지정된 user\_scripts 폴더에서 검색됩니다. 추가 스크립트 인수는 공백으로 구분해 지정할 수 있습니다. 예시: `script_name arg1 arg2`. `execute_direct` = `0`이면 `command`는 `bin/sh -c`의 인수로 전달됩니다 | 선택 사항 | `1`                    |
| `lifetime`                    | 함수의 다시 로드 간격(초)입니다. `0`으로 설정하면 함수는 다시 로드되지 않습니다                                                                                                                                                                                                                                      | 선택 사항 | `0`                    |
| `deterministic`               | 함수가 결정적인지 여부입니다(같은 입력에 대해 항상 같은 결과를 반환)                                                                                                                                                                                                                                              | 선택 사항 | `false`                |
| `stderr_reaction`             | 명령의 stderr 출력을 처리하는 방식입니다. 값: `none`(무시), `log`(모든 stderr를 즉시 기록), `log_first`(종료 후 처음 4 KiB를 기록), `log_last`(종료 후 마지막 4 KiB를 기록), `throw`(stderr 출력이 있으면 즉시 예외 발생). `log_first` 또는 `log_last`를 0이 아닌 종료 코드와 함께 사용하는 경우 stderr 내용이 예외 메시지에 포함됩니다                                     | 선택 사항 | `log_last`             |
| `check_exit_code`             | true이면 ClickHouse가 명령의 종료 코드를 확인합니다. 종료 코드가 0이 아니면 예외가 발생합니다                                                                                                                                                                                                                         | 선택 사항 | `true`                 |

명령은 `STDIN`에서 인수를 읽고 결과를 `STDOUT`으로 출력해야 합니다. 또한 인수를 반복적으로 처리해야 합니다. 즉, 인수 청크 하나를 처리한 뒤 다음 청크를 기다려야 합니다.

<div id="executable-user-defined-functions">
  ## 실행형 사용자 정의 함수
</div>

<div id="examples">
  ## 예시
</div>

<div id="udf-inline">
  ### 인라인 스크립트로 만든 UDF
</div>

XML 또는 YAML 구성을 사용해 `execute_direct`를 `0`으로 지정하고 `test_function_sum`을 수동으로 생성합니다.

<Tabs>
  <Tab title="XML">
    파일 `test_function.xml`(기본 경로 설정 기준 `/etc/clickhouse-server/test_function.xml`).

    ```xml title="/etc/clickhouse-server/test_function.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <name>test_function_sum</name>
            <return_type>UInt64</return_type>
            <argument>
                <type>UInt64</type>
                <name>lhs</name>
            </argument>
            <argument>
                <type>UInt64</type>
                <name>rhs</name>
            </argument>
            <format>TabSeparated</format>
            <command>cd /; clickhouse-local --input-format TabSeparated --output-format TabSeparated --structure 'x UInt64, y UInt64' --query "SELECT x + y FROM table"</command>
            <execute_direct>0</execute_direct>
            <deterministic>true</deterministic>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    파일 `test_function.yaml`(기본 경로 설정 기준 `/etc/clickhouse-server/test_function.yaml`).

    ```yml title="/etc/clickhouse-server/test_function.yaml" theme={null}
    functions:
      type: executable
      name: test_function_sum
      return_type: UInt64
      argument:
        - type: UInt64
          name: lhs
        - type: UInt64
          name: rhs
      format: TabSeparated
      command: 'cd /; clickhouse-local --input-format TabSeparated --output-format TabSeparated --structure ''x UInt64, y UInt64'' --query "SELECT x + y FROM table"'
      execute_direct: 0
      deterministic: true
    ```
  </Tab>
</Tabs>

<br />

```sql title="Query" theme={null}
SELECT test_function_sum(2, 2);
```

```text title="Result" theme={null}
┌─test_function_sum(2, 2)─┐
│                       4 │
└─────────────────────────┘
```

<div id="udf-python">
  ### Python 스크립트로 만든 UDF
</div>

이 예시에서는 `STDIN`에서 값을 읽어 문자열로 반환하는 UDF를 생성합니다.

XML 또는 YAML 구성으로 `test_function`을 생성합니다.

<Tabs>
  <Tab title="XML">
    파일 `test_function.xml`(기본 경로 설정 기준: `/etc/clickhouse-server/test_function.xml`).

    ```xml title="/etc/clickhouse-server/test_function.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <name>test_function_python</name>
            <return_type>String</return_type>
            <argument>
                <type>UInt64</type>
                <name>value</name>
            </argument>
            <format>TabSeparated</format>
            <command>test_function.py</command>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    파일 `test_function.yaml`(기본 경로 설정 기준: `/etc/clickhouse-server/test_function.yaml`).

    ```yml title="/etc/clickhouse-server/test_function.yaml" theme={null}
    functions:
      type: executable
      name: test_function_python
      return_type: String
      argument:
        - type: UInt64
          name: value
      format: TabSeparated
      command: test_function.py
    ```
  </Tab>
</Tabs>

<br />

`user_scripts` 폴더에 스크립트 파일 `test_function.py`를 생성합니다(기본 경로 설정 기준: `/var/lib/clickhouse/user_scripts/test_function.py`).

```python theme={null}
#!/usr/bin/python3

import sys

if __name__ == '__main__':
    for line in sys.stdin:
        print("Value " + line, end='')
        sys.stdout.flush()
```

```sql title="Query" theme={null}
SELECT test_function_python(toUInt64(2));
```

```text title="Result" theme={null}
┌─test_function_python(2)─┐
│ Value 2                 │
└─────────────────────────┘
```

<div id="udf-stdin">
  ### `STDIN`에서 두 값을 읽어 그 합을 JSON 객체로 반환하기
</div>

이름이 지정된 인수와 [JSONEachRow](/docs/ko/reference/formats/JSON/JSONEachRow) 포맷을 사용하여 XML 또는 YAML 구성으로 `test_function_sum_json`을 생성합니다.

<Tabs>
  <Tab title="XML">
    파일 `test_function.xml`(기본 경로 설정 기준: `/etc/clickhouse-server/test_function.xml`).

    ```xml title="/etc/clickhouse-server/test_function.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <name>test_function_sum_json</name>
            <return_type>UInt64</return_type>
            <return_name>result_name</return_name>
            <argument>
                <type>UInt64</type>
                <name>argument_1</name>
            </argument>
            <argument>
                <type>UInt64</type>
                <name>argument_2</name>
            </argument>
            <format>JSONEachRow</format>
            <command>test_function_sum_json.py</command>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    파일 `test_function.yaml`(기본 경로 설정 기준: `/etc/clickhouse-server/test_function.yaml`).

    ```yml title="/etc/clickhouse-server/test_function.yaml" theme={null}
    functions:
      type: executable
      name: test_function_sum_json
      return_type: UInt64
      return_name: result_name
      argument:
        - type: UInt64
          name: argument_1
        - type: UInt64
          name: argument_2
      format: JSONEachRow
      command: test_function_sum_json.py
    ```
  </Tab>
</Tabs>

<br />

`user_scripts` 폴더에 스크립트 파일 `test_function_sum_json.py`를 생성합니다(기본 경로 설정 기준: `/var/lib/clickhouse/user_scripts/test_function_sum_json.py`).

```python theme={null}
#!/usr/bin/python3

import sys
import json

if __name__ == '__main__':
    for line in sys.stdin:
        value = json.loads(line)
        first_arg = int(value['argument_1'])
        second_arg = int(value['argument_2'])
        result = {'result_name': first_arg + second_arg}
        print(json.dumps(result), end='\n')
        sys.stdout.flush()
```

```sql title="Query" theme={null}
SELECT test_function_sum_json(2, 2);
```

```text title="Result" theme={null}
┌─test_function_sum_json(2, 2)─┐
│                            4 │
└──────────────────────────────┘
```

<div id="udf-parameters-in-command">
  ### `command` 설정에서 매개변수 사용
</div>

실행형 사용자 정의 함수는 `command` 설정에 지정된 상수 매개변수를 받을 수 있습니다(이 기능은 `executable` 유형의 사용자 정의 함수에서만 작동합니다).
또한 셸 인수 확장 취약점을 방지하려면 `execute_direct` 옵션도 필요합니다.

<Tabs>
  <Tab title="XML">
    파일 `test_function_parameter_python.xml` (기본 경로 설정 기준: `/etc/clickhouse-server/test_function_parameter_python.xml`).

    ```xml title="/etc/clickhouse-server/test_function_parameter_python.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <execute_direct>true</execute_direct>
            <name>test_function_parameter_python</name>
            <return_type>String</return_type>
            <argument>
                <type>UInt64</type>
            </argument>
            <format>TabSeparated</format>
            <command>test_function_parameter_python.py {test_parameter:UInt64}</command>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    파일 `test_function_parameter_python.yaml` (기본 경로 설정 기준: `/etc/clickhouse-server/test_function_parameter_python.yaml`).

    ```yml title="/etc/clickhouse-server/test_function_parameter_python.yaml" theme={null}
    functions:
      type: executable
      execute_direct: true
      name: test_function_parameter_python
      return_type: String
      argument:
        - type: UInt64
      format: TabSeparated
      command: test_function_parameter_python.py {test_parameter:UInt64}
    ```
  </Tab>
</Tabs>

<br />

`user_scripts` 폴더에 스크립트 파일 `test_function_parameter_python.py`를 생성하십시오(기본 경로 설정 기준: `/var/lib/clickhouse/user_scripts/test_function_parameter_python.py`).

```python theme={null}
#!/usr/bin/python3

import sys

if __name__ == "__main__":
    for line in sys.stdin:
        print("Parameter " + str(sys.argv[1]) + " value " + str(line), end="")
        sys.stdout.flush()
```

```sql title="Query" theme={null}
SELECT test_function_parameter_python(1)(2);
```

```text title="Result" theme={null}
┌─test_function_parameter_python(1)(2)─┐
│ Parameter 1 value 2                  │
└──────────────────────────────────────┘
```

<div id="udf-shell-script">
  ### 셸 스크립트로 UDF 만들기
</div>

이 예시에서는 각 값을 2배로 곱하는 셸 스크립트를 만듭니다.

<Tabs>
  <Tab title="XML">
    파일 `test_function_shell.xml` (`/etc/clickhouse-server/test_function_shell.xml`, 기본 경로 설정 기준).

    ```xml title="/etc/clickhouse-server/test_function_shell.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <name>test_shell</name>
            <return_type>String</return_type>
            <argument>
                <type>UInt8</type>
                <name>value</name>
            </argument>
            <format>TabSeparated</format>
            <command>test_shell.sh</command>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    파일 `test_function_shell.yaml` (`/etc/clickhouse-server/test_function_shell.yaml`, 기본 경로 설정 기준).

    ```yml title="/etc/clickhouse-server/test_function_shell.yaml" theme={null}
    functions:
      type: executable
      name: test_shell
      return_type: String
      argument:
        - type: UInt8
          name: value
      format: TabSeparated
      command: test_shell.sh
    ```
  </Tab>
</Tabs>

<br />

`user_scripts` 폴더 안에 스크립트 파일 `test_shell.sh`를 만듭니다 (`/var/lib/clickhouse/user_scripts/test_shell.sh`, 기본 경로 설정 기준).

```bash title="/var/lib/clickhouse/user_scripts/test_shell.sh" theme={null}
#!/bin/bash

while read read_data;
    do printf "$(expr $read_data \* 2)\n";
done
```

```sql title="Query" theme={null}
SELECT test_shell(number) FROM numbers(10);
```

```text title="Result" theme={null}
    ┌─test_shell(number)─┐
 1. │ 0                  │
 2. │ 2                  │
 3. │ 4                  │
 4. │ 6                  │
 5. │ 8                  │
 6. │ 10                 │
 7. │ 12                 │
 8. │ 14                 │
 9. │ 16                 │
10. │ 18                 │
    └────────────────────┘
```

<div id="error-handling">
  ## 오류 처리
</div>

일부 함수는 데이터가 유효하지 않으면 예외를 발생시킬 수 있습니다.
이 경우 쿼리가 취소되고 클라이언트에 오류 메시지가 반환됩니다.
분산 처리에서는 서버 중 하나에서 예외가 발생하면 다른 서버들도 쿼리를 중단하려고 합니다.

<div id="evaluation-of-argument-expressions">
  ## 인수 표현식의 평가
</div>

거의 모든 프로그래밍 언어에서는 특정 연산자의 경우 일부 인수가 평가되지 않을 수 있습니다.
보통 `&&`, `||`, `?:` 같은 연산자가 여기에 해당합니다.
ClickHouse에서는 함수(연산자)의 인수가 항상 평가됩니다.
이는 각 행을 개별적으로 계산하지 않고 컬럼의 전체 파트를 한 번에 평가하기 때문입니다.

<div id="performing-functions-for-distributed-query-processing">
  ## 분산 쿼리 처리에서 함수 실행
</div>

분산 쿼리 처리에서는 가능한 한 많은 쿼리 처리 단계가 원격 서버에서 수행되며, 나머지 단계(중간 결과 병합 및 그 이후의 모든 단계)는 요청자 서버에서 수행됩니다.

즉, 함수가 서로 다른 서버에서 실행될 수 있습니다.
예를 들어, 쿼리 `SELECT f(sum(g(x))) FROM distributed_table GROUP BY h(y),` 에서

* `distributed_table`에 세그먼트가 2개 이상 있으면 함수 'g'와 'h'는 원격 서버에서 수행되고, 함수 'f'는 요청자 서버에서 수행됩니다.
* `distributed_table`에 세그먼트가 1개만 있으면 'f', 'g', 'h' 함수가 모두 이 세그먼트가 있는 서버에서 수행됩니다.

함수의 결과는 일반적으로 어느 서버에서 수행되는지와 무관합니다. 하지만 경우에 따라서는 이것이 중요할 수 있습니다.
예를 들어, 딕셔너리를 사용하는 함수는 해당 함수가 실행되는 서버에 있는 딕셔너리를 사용합니다.
또 다른 예로 `hostName` 함수가 있습니다. 이 함수는 `SELECT` 쿼리에서 서버별로 `GROUP BY`를 수행할 수 있도록, 자신이 실행 중인 서버의 이름을 반환합니다.

쿼리의 함수가 요청자 서버에서 수행되지만 이를 원격 서버에서 수행해야 한다면, 해당 함수를 'any' 집계 함수로 감싸거나 `GROUP BY`의 키에 추가할 수 있습니다.

<div id="sql-user-defined-functions">
  ## SQL 사용자 정의 함수
</div>

람다 표현식에서 사용자 정의 함수를 [CREATE FUNCTION](/docs/ko/reference/statements/create/function) SQL 문으로 생성할 수 있습니다. 이러한 함수를 삭제하려면 [DROP FUNCTION](/docs/ko/reference/statements/drop#drop-function) SQL 문을 사용하십시오.

<div id="webassembly-user-defined-functions">
  ## WebAssembly 사용자 정의 함수
</div>

<CloudNotSupportedBadge />

<ExperimentalBadge />

WebAssembly 사용자 정의 함수(WASM UDF)를 사용하면 WebAssembly로 컴파일된 사용자 정의 코드를 ClickHouse 서버 프로세스 내부에서 실행할 수 있습니다.

<div id="quick-start">
  ### 빠른 시작
</div>

ClickHouse 구성에서 experimental WebAssembly 지원을 활성화하세요:

```xml theme={null}
<clickhouse>
    <allow_experimental_webassembly_udf>true</allow_experimental_webassembly_udf>
</clickhouse>
```

컴파일된 WASM 모듈을 시스템 테이블에 삽입하세요:

```sql theme={null}
INSERT INTO system.webassembly_modules (name, code)
SELECT 'my_module', base64Decode('AGFzbQEAAAA...');
```

WASM 모듈을 사용해 함수를 만드세요:

```sql theme={null}
CREATE FUNCTION my_function
LANGUAGE WASM
ABI ROW_DIRECT
FROM 'my_module'
ARGUMENTS (x UInt32, y UInt32)
RETURNS UInt32;
```

쿼리에서 이 함수를 사용하세요:

```sql theme={null}
SELECT my_function(10, 20);
```

<div id="more-information">
  ### 추가 정보
</div>

자세한 내용은 [WebAssembly 사용자 정의 함수](/docs/ko/reference/functions/regular-functions/wasm_udf) 문서를 참고하십시오.

<div id="driver-based-executable-user-defined-functions">
  ## 드라이버 기반 실행형 사용자 정의 함수
</div>

<CloudNotSupportedBadge />

<ExperimentalBadge />

<Note>
  이 기능은 실험적 기능이며, 향후 릴리스에서 하위 호환되지 않는 방식으로 변경될 수 있습니다. [`allow_experimental_executable_udf_drivers`](/docs/ko/reference/settings/server-settings/settings#allow_experimental_executable_udf_drivers) 서버 설정으로 활성화하십시오.
</Note>

*드라이버*는 사용자 코드 조각을 실행 가능한 [실행형 UDF](#executable-user-defined-functions)로 변환하는 운영자 제공 어댑터입니다. 함수를 `ENGINE = DriverName(...)`으로 생성하면 ClickHouse는 드라이버의 `create_command`를 실행하면서 함수 시그니처와 코드 본문을 전달합니다. 그러면 드라이버는 본문을 컴파일하거나 다른 방식으로 처리한 뒤 실행형 UDF 구성 정보를 출력하고, ClickHouse는 이를 저장한 후 로드합니다.

이를 통해 관리자는 사용자에게 서버의 설정 파일이나 파일 시스템에 대한 접근 권한을 부여하지 않고도, 임의의 언어(예: 샌드박스된 컨테이너 내부에서 컴파일한 C)로 함수를 정의할 수 있는 안전하고 제한된 방식을 제공할 수 있습니다. 사용 가능한 드라이버는 전적으로 운영자가 제어합니다.

<div id="enabling-drivers">
  ### 드라이버 활성화
</div>

드라이버 기반 실행형 UDF는 기본적으로 비활성화되어 있습니다. 이를 활성화하려면 다음을 수행하십시오.

1. 서버 구성에서 experimental gate를 설정합니다.

   ```xml theme={null}
   <clickhouse>
       <allow_experimental_executable_udf_drivers>true</allow_experimental_executable_udf_drivers>
   </clickhouse>
   ```

2. `user_defined_executable_function_drivers_config`이 하나 이상의 드라이버 설정 파일(glob 지원)을 가리키도록 설정하고, 필요에 따라 생성된 실행형 UDF 구성이 저장되는 디렉터리인 [`dynamic_user_defined_executable_functions_path`](/docs/ko/reference/settings/server-settings/settings#dynamic_user_defined_executable_functions_path)도 설정합니다.

   ```xml theme={null}
   <clickhouse>
       <user_defined_executable_function_drivers_config>user_defined_executable_function_drivers_config.d/*_driver.xml</user_defined_executable_function_drivers_config>
       <dynamic_user_defined_executable_functions_path>/var/lib/clickhouse/dynamic_user_defined_executable_functions/</dynamic_user_defined_executable_functions_path>
   </clickhouse>
   ```

드라이버 레지스트리는 서버 시작 시 로드되고 `SYSTEM RELOAD CONFIG` 시 갱신되므로, 서버를 재시작하지 않고도 드라이버를 추가, 변경 또는 제거할 수 있습니다.

<div id="driver-configuration">
  ### 드라이버 구성
</div>

드라이버는 최상위 `<driver>` 요소를 포함하는 XML(또는 YAML) 파일로 정의됩니다. 지원되는 필드는 다음과 같습니다.

| Field              | Description                                                                                                       | Required |
| ------------------ | ----------------------------------------------------------------------------------------------------------------- | -------- |
| `name`             | `CREATE FUNCTION ... ENGINE = <name>(...)`에 사용되는 드라이버 이름입니다.                                                      | 예        |
| `create_command`   | 코드 스니펫에서 UDF를 생성하기 위해 호출되는 프로그램의 경로입니다. 상대 경로는 드라이버 설정 파일을 기준으로 해석됩니다.                                            | 예        |
| `drop_command`     | 이 드라이버를 기반으로 하는 함수가 삭제될 때 호출되는 프로그램의 경로입니다.                                                                       | 아니요      |
| `engine_arguments` | `ENGINE = DriverName(...)` 내에서 허용되는 인수를 선언합니다. 각 하위 요소는 인수 이름이며, `<required>true</required>` 하위 요소로 필수 여부를 표시합니다. | 아니요      |
| `env`              | 드라이버 명령을 호출할 때 내보내는 환경 변수입니다.                                                                                     | 아니요      |

예시 드라이버 구성:

```xml theme={null}
<clickhouse>
    <driver>
        <name>DockerC</name>
        <create_command>../user_defined_executable_function_drivers/docker_c_create.sh</create_command>
        <drop_command>../user_defined_executable_function_drivers/docker_c_drop.sh</drop_command>
        <engine_arguments>
            <opt_level><required>false</required></opt_level>
        </engine_arguments>
        <env>
            <CLICKHOUSE_C_DRIVER_MEMORY>256m</CLICKHOUSE_C_DRIVER_MEMORY>
            <CLICKHOUSE_C_DRIVER_CPUS>1.0</CLICKHOUSE_C_DRIVER_CPUS>
        </env>
    </driver>
</clickhouse>
```

<div id="driver-invocation-contract">
  #### Driver 호출 규약
</div>

`CREATE FUNCTION`이 실행되면, 구성된 `env` 변수가 설정된 상태에서 `create_command`가 다음 인수와 함께 호출됩니다.

* `--name <function_name>`
* `--return <return_type>` (`RETURNS` 절이 있는 경우)
* `--args <signature>` (`ARGUMENTS` 절이 있는 경우). 여기서 시그니처는 선언된 인수 목록이며, 예를 들면 `x UInt8, y DateTime`입니다.
* `ENGINE = DriverName(key = value)`에 제공된 선언된 각 엔진 인수마다 `--<key> <value>`

사용자 코드 본문(`AS` 뒤의 텍스트)은 명령의 표준 입력으로 전달됩니다. 명령은 실행형 UDF의 구성을 표준 출력에 출력해야 합니다. 포맷은 자동으로 감지됩니다. 출력이 `<`로 시작하면 XML로 처리되고, 그렇지 않으면 YAML로 처리됩니다. 생성된 구성에 정의된 함수 이름은 생성 중인 이름과 일치해야 합니다. `create_command`가 0이 아닌 종료 상태로 끝나면 종료 코드와 드라이버의 표준 오류를 포함한 예외와 함께 구문이 실패합니다.

`drop_command`가 있으면 함수가 삭제될 때도 동일한 방식으로 호출됩니다(stdin에는 코드 본문이 없음).

<div id="creating-a-function-with-a-driver">
  ### 함수 생성
</div>

```sql theme={null}
CREATE [OR REPLACE] FUNCTION [IF NOT EXISTS] name [ON CLUSTER cluster]
    ARGUMENTS (a UInt8, b String) RETURNS UInt64
    ENGINE = DriverName(key1 = 'value1', key2 = 42)
    AS '...code body...'
```

ClickHouse는 드라이버의 `create_command`를 실행하고, 생성된 구성을 [`dynamic_user_defined_executable_functions_path`](/docs/ko/reference/settings/server-settings/settings#dynamic_user_defined_executable_functions_path)에 기록한 뒤 기존 실행형 UDF 로더가 이를 읽어들입니다. 이후 이 함수는 다른 함수와 동일하게 호출할 수 있습니다.

<div id="dropping-a-function-with-a-driver">
  ### 함수 삭제
</div>

```sql theme={null}
DROP FUNCTION [IF EXISTS] name [ON CLUSTER cluster]
```

`DROP FUNCTION`은 드라이버의 `drop_command`(있는 경우)를 호출한 다음, 생성된 동적 구성과 함수별 작업 디렉터리를 제거하고, 실행형 UDF 로더를 다시 로드하며, 영구 저장된 쿼리를 삭제합니다.

<div id="driver-persistence-and-restart">
  ### 영속성 및 재시작
</div>

원본 쿼리는 사용자 정의 SQL 객체 디렉터리에 `ATTACH FUNCTION ...` 구문으로 저장되므로, 서버를 재시작해도 함수가 유지됩니다. 시작 시에는 [`dynamic_user_defined_executable_functions_path`](/docs/ko/reference/settings/server-settings/settings#dynamic_user_defined_executable_functions_path)에 생성된 구성이 드라이버를 다시 실행하지 않고 직접 로드됩니다. 저장된 `ATTACH FUNCTION`에 해당하는 생성된 구성이 없으면(예: 동적 디렉터리가 손실된 경우) 이를 다시 만들기 위해 드라이버를 다시 실행합니다.

<div id="driver-limitations">
  ### 제한 사항
</div>

* 이 기능은 실험 단계 기능이며, `allow_experimental_executable_udf_drivers`를 활성화해야 사용할 수 있습니다.
* 드라이버 기반 함수는 복제된 사용자 정의 함수 저장소(`ON CLUSTER` 및 `<user_defined_zookeeper_path>`)와 함께 사용할 수 없습니다. 생성된 artifact는 복제되지 않고, 원래 쿼리만 복제되기 때문입니다.
* 백업된 드라이버 기반 함수를 `RESTORE`하면 쿼리는 유지되지만 드라이버는 다시 실행되지 않습니다. 생성된 구성은 이후 재시작 복구 과정에서 구체화됩니다.

<div id="example-c-drivers">
  ### 예시 C 드라이버
</div>

소스 트리에는 C 함수 본문을 컴파일하고 실행하는 개념 증명용 드라이버가 `programs/server/user_defined_executable_function_drivers_config.d/` 아래에 제공됩니다. 이들은 예시이며 **패키지로는 설치되지 않습니다**:

* `DockerC` - 격리된 Docker 컨테이너 내부에서 코드를 컴파일하고 실행하며 (`--network=none --read-only --cap-drop=ALL --security-opt=no-new-privileges`와 메모리/CPU/PID 제한 사용), `executable_pool` UDF를 생성합니다.
* `GVisorC` - 컴파일된 바이너리를 [gVisor](https://gvisor.dev/) `runsc` 런타임에서 실행하는 변형입니다.
* `UnsafeC` - 샌드박스 없이 호스트에서 직접 코드를 컴파일하고 실행합니다. 이름에서 알 수 있듯이 격리를 전혀 제공하지 않으며, 신뢰할 수 있는 환경과 테스트 용도로만 사용하도록 설계되었습니다.

이 예시 드라이버는 출발점으로 삼기 위한 것입니다. 신뢰할 수 없는 사용자에게 노출하기 전에 환경에 맞게 샌드박스 구성을 검토하고 강화하십시오.

<div id="related-content">
  ## 관련 콘텐츠
</div>

* [ClickHouse Cloud의 사용자 정의 함수](https://clickhouse.com/blog/user-defined-functions-clickhouse-udfs)
