사전 요구 사항
미리보기 기능을 사용하는 확장은vsql_allow_preview_extensions가 ON일 때만 설치됩니다:
SET GLOBAL이 거부되는 이유를 포함한 자세한 내용은 미리보기 계층 활성화를 참조하세요.
작동하는 Rust 확장 환경도 필요합니다 — Rust로 확장 만들기 안내서가 툴체인, cargo-vsql, 그리고 첫 번째 extension! 블록을 다룹니다.
Rust SDK가 감싸는 기능
나머지 미리보기 기능인
auth, mysql_services, session_var, statement_event, 사용자 정의 인덱스 기능, 그리고 열 저장소 ABI는 현재 C++ 전용입니다. 이 중 하나가 필요하다면 C++ SDK를 사용하세요.
등록 패턴
각 기능을static으로 선언한 다음, extension!의 requires: 섹션에 참조로 나열합니다 — C++ SDK의 .with()에 해당하는 Rust 방식입니다:
static은 필수입니다 — 서버가 확장의 전체 라이프사이클 동안 그 기능을 가리키는 포인터를 보유하기 때문입니다.
상태 변수
status_var 기능은 확장이 소유한 카운터를 SHOW GLOBAL STATUS를 통해 노출합니다. 확장은 저장소를 'static 원자 값으로 소유하고 여기에 씁니다. 서버는 상태 변수가 쿼리될 때마다 포인터를 통해 읽습니다.
각 변수를 StatusVarSpec으로 선언합니다 — Int는 AtomicI64로, Double은 SDK의 AtomicF64로 뒷받침됩니다(Rust 표준 라이브러리에는 원자 f64가 없으므로, SDK가 new, load, store를 갖춘 것을 제공합니다):
INSTALL EXTENSION 이후, 변수는 확장 이름을 접두사로 하여 나타납니다:
시스템 변수
sys_var 기능은 확장이 소유한 MySQL 시스템 변수를 등록합니다. 세 가지 타입이 지원됩니다: Bool, Int(min/max 경계 포함), 그리고 Str입니다. 모든 스펙은 이름, 주석, 기본값, 그리고 선택적 on_change 콜백을 포함합니다.
이름과 문자열 기본값은 &'static CStr 값입니다 — C 문자열 리터럴(c"enabled")로 작성하세요:
funcs: 섹션은 비어 있더라도 requires: 앞에 있어야 합니다.
설치 후, 변수는 확장 이름을 접두사로 하여 지정할 수 있습니다:
변경에 반응하기
on_change는 원시 C 콜백이며, 변수가 설정된 후 서버가 호출합니다. 서버는 전역 시스템 변수 잠금을 보유한 상태에서 이를 호출하므로, 짧게 유지하고 패닉을 일으키지 마세요 — 여기서의 패닉은 FFI 경계를 넘어갑니다. 콜백은 원시 ABI 계층에서 *const vef_sys_var_change_t를 받습니다:
on_change: Some(on_enabled_change)로 스펙에 연결합니다.
확장 코드에서 읽고 쓰기
SysVarCapability는 서버를 통한 프로그래밍 방식 접근을 위해 get()과 set()도 노출합니다(따라서 범위 검증과 지속성이 대신 처리됩니다). set()은 지속성을 선택하는 scope 인자를 받습니다: null은 실행 중인 값만 변경하므로 재시작 시 되돌아갑니다. "PERSIST"는 실행 중인 값을 변경하고 지속되는 구성에도 씁니다. "PERSIST_ONLY"는 실행 중인 값은 건드리지 않고 지속되는 구성에만 쓰므로 다음 재시작 시 적용됩니다. 두 메서드 모두 NUL로 끝나는 C 문자열을 받는 unsafe FFI 메서드이며, 둘 다 반전된 C 규약을 따릅니다: Some(false)는 성공, Some(true)는 서버가 오류를 보고했음, None은 기능을 사용할 수 없음을 의미합니다. get이 성공하면 서버는 malloc으로 할당한 문자열을 쓰며, 이는 C의 free()로 해제해야 합니다. vsql_sys_var 예제가 free extern과 안전성 주석을 포함한 전체 패턴을 보여줍니다.
스레드 워커
thread_worker 기능은 사용자가 제공한 함수를 서버가 관리하는 백그라운드 스레드에서 실행합니다. 서버는 로드 시점에 제어 시스템 변수를 등록하며, 그것이 ON인 동안 작업 함수는 주기적 타이머, 파일 디스크립터 준비, 또는 활성/비활성 전환 시 호출됩니다.
작업 함수는 일반적인 안전한 Rust입니다:
ThreadWorkerCapability::new는 작업 함수, 스레드 이름 접미사, 초기 대기 간격, 그리고 선택적 제어 변수 이름 오버라이드를 받습니다. 오버라이드가 None이면 제어 변수의 이름은 {suffix}_enabled이며 확장의 접두사 아래에 등록됩니다:
웨이크업
WakeupReason은 서버가 호출한 이유를 알려줍니다: Enable, Periodic, PollFd, 또는 Disable입니다. 반환 값이 다음 웨이크업을 조정합니다:
NextWakeup::unchanged()— 현재 대기 간격과 poll fd를 유지합니다.NextWakeup::after(duration)—duration후에 다시 깨어납니다.poll_fd필드를 0보다 큰 파일 디스크립터로 설정하면 그것이 읽기 가능해질 때도 깨어나며,-1로 설정하면 이전에 설정한 값을 지웁니다.
Duration은 “변경 없음”으로 축소됩니다 — 기본 C ABI가 0을 그 용도로 예약하므로, 즉시 웨이크업은 표현할 수 없습니다.
작업 함수가 패닉을 일으키면 SDK가 FFI 경계에서 그 패닉을 잡아 호출이 NextWakeup::unchanged()를 반환한 것으로 처리합니다 — 워커는 계속 실행됩니다.
handle 매개변수를 SqlQueryCapability::open에 전달하면 워커 안에서 SQL을 실행할 수 있습니다.
SQL 쿼리
sql_query 기능은 thread_worker 콜백에서 SQL 세션을 열어, 백그라운드 워커가 자신이 로드된 서버에 대해 문을 실행할 수 있게 합니다. ThreadWorkerCapability와 함께 선언하고, 워커가 받는 ThreadHandle로 세션을 엽니다:
SqlQueryCapability::open(handle)은 기능이 채워지지 않았거나(미리보기가 꺼져 있거나 요청되지 않음), ABI가 너무 오래되었거나, 서버가 세션을 열지 못하면 None을 반환합니다 — 결과를 사용하기 전에 확인하세요.
Session은 문을 실행하는 두 가지 방법을 제공합니다:
execute(sql)은 전체 결과 집합을 버퍼링하고QueryResult를 반환합니다.next_row()가None을 반환할 때까지 반복해서 호출하세요. 각Row는get_int(i),get_str(i),get_real(i), 또는get_bytes(i)로 열을 읽습니다.get_bytes/get_str는 SQLNULL이거나 인덱스가 범위를 벗어나면(get_str는 UTF-8이 아닌 바이트인 경우에도)None을 반환합니다.get_int/get_real은 열을 먼저 텍스트로 파싱하므로, 파싱할 수 없는 텍스트에 대해서도None을 반환합니다.execute자체는 설정 실패(세션 없음 또는 메모리 부족) 시에만None을 반환합니다.for_each(sql, |row: Row<'_>| { ... })는 전체 결과 집합을 버퍼링하는 대신 행을 클로저로 스트리밍합니다. 반환되는QueryResult는 진단 정보만 담고 있으며 — 반복할 버퍼링된 행은 없습니다 — 설정 실패 시에는 마찬가지로None을 반환합니다.
has_error()와 error()(errno, severity, sqlstate, message를 가진 Option<Diag>)를 확인하세요. warnings()는 결과에 첨부된 모든 경고와 노트를 반환합니다.
Session과 QueryResult는 각각 드롭될 때 기반 핸들을 닫습니다 — 직접 호출할 close 메서드는 없습니다.
키링 접근
keyring 기능은 MySQL 키링 구성 요소에 저장된 비밀을 읽고 씁니다 — API 키, 암호화 키, 그리고 테이블에 두어서는 안 되는 모든 것입니다. 키링 구성 요소(예: component_keyring_file)는 키링 구성 요소 설치에 설명된 대로 구성 요소 매니페스트와 그 구성 파일을 통해 서버 시작 시 로드되어야 합니다. INSTALL COMPONENT로는 사용할 수 없습니다. 없으면 모든 읽기와 쓰기가 KeyringError::NoComponent로 실패합니다.
read(data_id, auth_id, buf)는 전달한 버퍼를 채우고 비밀의 길이와 함께 Ok(Some(n))을 반환하거나, data_id 아래에 비밀이 없으면 Ok(None)을 반환합니다 — 이는 오류가 아니라 정상적인 결과입니다. write(data_id, auth_id, data)는 성공 시 Ok(())를 반환합니다. auth_id는 소유 사용자입니다. 특정 사용자와 연결되지 않은 내부 키에는 None을 전달하세요.
둘 다 실패 시 Err(KeyringError)를 반환합니다: CapabilityUnavailable(기능이 연결된 적 없음), NoComponent(서버에 키링 구성 요소 없음), 또는 Other입니다.
키링에는 크기 조회 수단이 없습니다: read에 전달한 버퍼보다 큰 비밀은 Ok(None)으로 돌아오며, 이는 없는 키와 구별되지 않습니다. 저장할 것으로 예상되는 가장 큰 비밀에 맞춰 버퍼 크기를 정하세요.
다음 단계
미리보기 기능(C++)
전체 기능 인덱스, 미리보기 계층, 그리고 C++ 전용 기능: auth,
mysql_services, session_var, statement_event, 사용자 정의 인덱스 기능,
그리고 열 저장소.
Rust API 참조
InValue, VdfReturn, extension!, func!, custom_type! — 모든 필드.