ClickHouse는 여러 유형의 사용자 정의 함수(UDF)를 지원합니다.
- 실행형 UDFs는 외부 프로그램이나 스크립트(Python, Bash 등)를 시작한 뒤, STDIN / STDOUT을 통해 데이터 블록을 해당 프로그램으로 스트리밍합니다. ClickHouse를 다시 컴파일하지 않고도 기존 코드나 도구를 통합할 때 사용할 수 있습니다. 프로세스 내부 옵션보다 호출당 오버헤드가 크므로, 더 무거운 로직을 처리하거나 다른 런타임이 필요한 경우에 가장 적합합니다.
- SQL UDFs는
CREATE FUNCTION을 사용해 SQL만으로 정의합니다. 쿼리 계획에 인라인되어 확장되므로(프로세스 경계 없음) 가볍고, 표현식 로직을 재사용하거나 복잡한 계산 컬럼을 단순화하는 데 적합합니다. - Experimental WebAssembly UDFs는 서버 프로세스 내 샌드박스에서 WebAssembly로 컴파일된 코드를 실행합니다. 외부 실행형보다 호출당 오버헤드가 낮고 네이티브 확장 기능보다 격리 수준이 높아, WASM을 대상으로 할 수 있는 언어(예: C/C++/Rust)로 작성한 사용자 정의 알고리즘에 적합합니다.
- Experimental driver-based executable UDFs는 연산자가 제공하는 "드라이버"가
CREATE FUNCTION ... ENGINE = DriverName(...) AS '...'에 제공된 코드 스니펫을 함수 생성 시점에 실행형 UDF로 변환하도록 합니다(예를 들어 컴파일을 통해). 이는 실행형 UDFs를 기반으로 하며, 서버 측 드라이버 구성이 필요합니다.
실행형 사용자 정의 함수
ClickHouse는 데이터를 처리하기 위해 외부 실행 프로그램이나 스크립트를 호출할 수 있습니다.
실행형 사용자 정의 함수의 구성은 하나 이상의 XML 파일에 둘 수 있습니다.
구성 경로는 user_defined_executable_functions_config 매개변수로 지정합니다.
함수 구성에는 다음 설정이 포함됩니다:
| 매개변수 | 설명 | 필수 | 기본값 |
|---|---|---|---|
name |
함수 이름 | 예 | - |
command |
실행할 스크립트 이름 또는 execute_direct가 false인 경우 실행할 명령 |
예 | - |
argument |
인수의 type과 선택적 name을 포함하는 인수 설명입니다. 각 인수는 별도의 설정으로 설명합니다. Native 또는 JSONEachRow 같은 사용자 정의 함수 포맷에서 인수 이름이 직렬화의 일부인 경우에는 이름 지정이 필요합니다 |
예 | c + argument_number |
format |
인수를 명령에 전달할 때 사용하는 포맷입니다. 명령의 출력도 동일한 포맷이어야 합니다 | 예 | - |
return_type |
반환 값의 유형 | 예 | - |
return_name |
반환 값의 이름입니다. Native 또는 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에 지정된 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으로 출력해야 합니다. 또한 인수를 반복적으로 처리해야 합니다. 즉, 인수 청크 하나를 처리한 뒤 다음 청크를 기다려야 합니다.
실행형 사용자 정의 함수
예시
인라인 스크립트로 만든 UDF
XML 또는 YAML 구성을 사용해 execute_direct를 0으로 지정하고 test_function_sum을 수동으로 생성합니다.
파일 test_function.xml(기본 경로 설정 기준 /etc/clickhouse-server/test_function.xml).
<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>파일 test_function.yaml(기본 경로 설정 기준 /etc/clickhouse-server/test_function.yaml).
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: trueSELECT test_function_sum(2, 2);┌─test_function_sum(2, 2)─┐
│ 4 │
└─────────────────────────┘Python 스크립트로 만든 UDF
이 예시에서는 STDIN에서 값을 읽어 문자열로 반환하는 UDF를 생성합니다.
XML 또는 YAML 구성으로 test_function을 생성합니다.
파일 test_function.xml(기본 경로 설정 기준: /etc/clickhouse-server/test_function.xml).
<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>파일 test_function.yaml(기본 경로 설정 기준: /etc/clickhouse-server/test_function.yaml).
functions:
type: executable
name: test_function_python
return_type: String
argument:
- type: UInt64
name: value
format: TabSeparated
command: test_function.pyuser_scripts 폴더에 스크립트 파일 test_function.py를 생성합니다(기본 경로 설정 기준: /var/lib/clickhouse/user_scripts/test_function.py).
#!/usr/bin/python3
import sys
if __name__ == '__main__':
for line in sys.stdin:
print("Value " + line, end='')
sys.stdout.flush()SELECT test_function_python(toUInt64(2));┌─test_function_python(2)─┐
│ Value 2 │
└─────────────────────────┘STDIN에서 두 값을 읽어 그 합을 JSON 객체로 반환하기
이름이 지정된 인수와 JSONEachRow 포맷을 사용하여 XML 또는 YAML 구성으로 test_function_sum_json을 생성합니다.
파일 test_function.xml(기본 경로 설정 기준: /etc/clickhouse-server/test_function.xml).
<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>파일 test_function.yaml(기본 경로 설정 기준: /etc/clickhouse-server/test_function.yaml).
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.pyuser_scripts 폴더에 스크립트 파일 test_function_sum_json.py를 생성합니다(기본 경로 설정 기준: /var/lib/clickhouse/user_scripts/test_function_sum_json.py).
#!/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()SELECT test_function_sum_json(2, 2);┌─test_function_sum_json(2, 2)─┐
│ 4 │
└──────────────────────────────┘command 설정에서 매개변수 사용
실행형 사용자 정의 함수는 command 설정에 지정된 상수 매개변수를 받을 수 있습니다(이 기능은 executable 유형의 사용자 정의 함수에서만 작동합니다).
또한 셸 인수 확장 취약점을 방지하려면 execute_direct 옵션도 필요합니다.
파일 test_function_parameter_python.xml (기본 경로 설정 기준: /etc/clickhouse-server/test_function_parameter_python.xml).
<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>파일 test_function_parameter_python.yaml (기본 경로 설정 기준: /etc/clickhouse-server/test_function_parameter_python.yaml).
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}user_scripts 폴더에 스크립트 파일 test_function_parameter_python.py를 생성하십시오(기본 경로 설정 기준: /var/lib/clickhouse/user_scripts/test_function_parameter_python.py).
#!/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()SELECT test_function_parameter_python(1)(2);┌─test_function_parameter_python(1)(2)─┐
│ Parameter 1 value 2 │
└──────────────────────────────────────┘셸 스크립트로 UDF 만들기
이 예시에서는 각 값을 2배로 곱하는 셸 스크립트를 만듭니다.
파일 test_function_shell.xml (/etc/clickhouse-server/test_function_shell.xml, 기본 경로 설정 기준).
<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>파일 test_function_shell.yaml (/etc/clickhouse-server/test_function_shell.yaml, 기본 경로 설정 기준).
functions:
type: executable
name: test_shell
return_type: String
argument:
- type: UInt8
name: value
format: TabSeparated
command: test_shell.shuser_scripts 폴더 안에 스크립트 파일 test_shell.sh를 만듭니다 (/var/lib/clickhouse/user_scripts/test_shell.sh, 기본 경로 설정 기준).
#!/bin/bash
while read read_data;
do printf "$(expr $read_data \* 2)\n";
doneSELECT test_shell(number) FROM numbers(10); ┌─test_shell(number)─┐
1. │ 0 │
2. │ 2 │
3. │ 4 │
4. │ 6 │
5. │ 8 │
6. │ 10 │
7. │ 12 │
8. │ 14 │
9. │ 16 │
10. │ 18 │
└────────────────────┘오류 처리
일부 함수는 데이터가 유효하지 않으면 예외를 발생시킬 수 있습니다. 이 경우 쿼리가 취소되고 클라이언트에 오류 메시지가 반환됩니다. 분산 처리에서는 서버 중 하나에서 예외가 발생하면 다른 서버들도 쿼리를 중단하려고 합니다.
인수 표현식의 평가
거의 모든 프로그래밍 언어에서는 특정 연산자의 경우 일부 인수가 평가되지 않을 수 있습니다.
보통 &&, ||, ?: 같은 연산자가 여기에 해당합니다.
ClickHouse에서는 함수(연산자)의 인수가 항상 평가됩니다.
이는 각 행을 개별적으로 계산하지 않고 컬럼의 전체 파트를 한 번에 평가하기 때문입니다.
분산 쿼리 처리에서 함수 실행
분산 쿼리 처리에서는 가능한 한 많은 쿼리 처리 단계가 원격 서버에서 수행되며, 나머지 단계(중간 결과 병합 및 그 이후의 모든 단계)는 요청자 서버에서 수행됩니다.
즉, 함수가 서로 다른 서버에서 실행될 수 있습니다.
예를 들어, 쿼리 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의 키에 추가할 수 있습니다.
SQL 사용자 정의 함수
람다 표현식에서 사용자 정의 함수를 CREATE FUNCTION SQL 문으로 생성할 수 있습니다. 이러한 함수를 삭제하려면 DROP FUNCTION SQL 문을 사용하십시오.
WebAssembly 사용자 정의 함수
WebAssembly 사용자 정의 함수(WASM UDF)를 사용하면 WebAssembly로 컴파일된 사용자 정의 코드를 ClickHouse 서버 프로세스 내부에서 실행할 수 있습니다.
빠른 시작
ClickHouse 구성에서 experimental WebAssembly 지원을 활성화하세요:
<clickhouse>
<allow_experimental_webassembly_udf>true</allow_experimental_webassembly_udf>
</clickhouse>컴파일된 WASM 모듈을 시스템 테이블에 삽입하세요:
INSERT INTO system.webassembly_modules (name, code)
SELECT 'my_module', base64Decode('AGFzbQEAAAA...');WASM 모듈을 사용해 함수를 만드세요:
CREATE FUNCTION my_function
LANGUAGE WASM
ABI ROW_DIRECT
FROM 'my_module'
ARGUMENTS (x UInt32, y UInt32)
RETURNS UInt32;쿼리에서 이 함수를 사용하세요:
SELECT my_function(10, 20);추가 정보
자세한 내용은 WebAssembly 사용자 정의 함수 문서를 참고하십시오.
드라이버 기반 실행형 사용자 정의 함수
드라이버는 사용자 코드 조각을 실행 가능한 실행형 UDF로 변환하는 운영자 제공 어댑터입니다. 함수를 ENGINE = DriverName(...)으로 생성하면 ClickHouse는 드라이버의 create_command를 실행하면서 함수 시그니처와 코드 본문을 전달합니다. 그러면 드라이버는 본문을 컴파일하거나 다른 방식으로 처리한 뒤 실행형 UDF 구성 정보를 출력하고, ClickHouse는 이를 저장한 후 로드합니다.
이를 통해 관리자는 사용자에게 서버의 설정 파일이나 파일 시스템에 대한 접근 권한을 부여하지 않고도, 임의의 언어(예: 샌드박스된 컨테이너 내부에서 컴파일한 C)로 함수를 정의할 수 있는 안전하고 제한된 방식을 제공할 수 있습니다. 사용 가능한 드라이버는 전적으로 운영자가 제어합니다.
드라이버 활성화
드라이버 기반 실행형 UDF는 기본적으로 비활성화되어 있습니다. 이를 활성화하려면 다음을 수행하십시오.
-
서버 구성에서 experimental gate를 설정합니다.
<clickhouse> <allow_experimental_executable_udf_drivers>true</allow_experimental_executable_udf_drivers> </clickhouse> -
user_defined_executable_function_drivers_config이 하나 이상의 드라이버 설정 파일(glob 지원)을 가리키도록 설정하고, 필요에 따라 생성된 실행형 UDF 구성이 저장되는 디렉터리인dynamic_user_defined_executable_functions_path도 설정합니다.<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 시 갱신되므로, 서버를 재시작하지 않고도 드라이버를 추가, 변경 또는 제거할 수 있습니다.
드라이버 구성
드라이버는 최상위 <driver> 요소를 포함하는 XML(또는 YAML) 파일로 정의됩니다. 지원되는 필드는 다음과 같습니다.
| Field | Description | Required |
|---|---|---|
name |
CREATE FUNCTION ... ENGINE = <name>(...)에 사용되는 드라이버 이름입니다. |
예 |
create_command |
코드 스니펫에서 UDF를 생성하기 위해 호출되는 프로그램의 경로입니다. 상대 경로는 드라이버 설정 파일을 기준으로 해석됩니다. | 예 |
drop_command |
이 드라이버를 기반으로 하는 함수가 삭제될 때 호출되는 프로그램의 경로입니다. | 아니요 |
engine_arguments |
ENGINE = DriverName(...) 내에서 허용되는 인수를 선언합니다. 각 하위 요소는 인수 이름이며, <required>true</required> 하위 요소로 필수 여부를 표시합니다. |
아니요 |
env |
드라이버 명령을 호출할 때 내보내는 환경 변수입니다. | 아니요 |
예시 드라이버 구성:
<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>Driver 호출 규약
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에는 코드 본문이 없음).
함수 생성
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에 기록한 뒤 기존 실행형 UDF 로더가 이를 읽어들입니다. 이후 이 함수는 다른 함수와 동일하게 호출할 수 있습니다.
함수 삭제
DROP FUNCTION [IF EXISTS] name [ON CLUSTER cluster]DROP FUNCTION은 드라이버의 drop_command(있는 경우)를 호출한 다음, 생성된 동적 구성과 함수별 작업 디렉터리를 제거하고, 실행형 UDF 로더를 다시 로드하며, 영구 저장된 쿼리를 삭제합니다.
영속성 및 재시작
원본 쿼리는 사용자 정의 SQL 객체 디렉터리에 ATTACH FUNCTION ... SQL 문으로 저장되므로, 서버를 재시작해도 함수가 유지됩니다. 시작 시에는 dynamic_user_defined_executable_functions_path에 생성된 구성이 드라이버를 다시 실행하지 않고 직접 로드됩니다. 저장된 ATTACH FUNCTION에 해당하는 생성된 구성이 없으면(예: 동적 디렉터리가 손실된 경우) 이를 다시 만들기 위해 드라이버를 다시 실행합니다.
제한 사항
- 이 기능은 실험 단계 기능이며,
allow_experimental_executable_udf_drivers를 활성화해야 사용할 수 있습니다. - 드라이버 기반 함수는 복제된 사용자 정의 함수 저장소(
ON CLUSTER및<user_defined_zookeeper_path>)와 함께 사용할 수 없습니다. 생성된 artifact는 복제되지 않고, 원래 쿼리만 복제되기 때문입니다. - 백업된 드라이버 기반 함수를
RESTORE하면 쿼리는 유지되지만 드라이버는 다시 실행되지 않습니다. 생성된 구성은 이후 재시작 복구 과정에서 구체화됩니다.
예시 C 드라이버
소스 트리에는 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_poolUDF를 생성합니다.GVisorC- 컴파일된 바이너리를 gVisorrunsc런타임에서 실행하는 변형입니다.UnsafeC- 샌드박스 없이 호스트에서 직접 코드를 컴파일하고 실행합니다. 이름에서 알 수 있듯이 격리를 전혀 제공하지 않으며, 신뢰할 수 있는 환경과 테스트 용도로만 사용하도록 설계되었습니다.
이 예시 드라이버는 출발점으로 삼기 위한 것입니다. 신뢰할 수 없는 사용자에게 노출하기 전에 환경에 맞게 샌드박스 구성을 검토하고 강화하십시오.