vsql_allow_preview_extensions = ON이 필요합니다 (참조: 미리보기 계층 활성화) — 미리보기 기능을 사용하지 않는 확장 프로그램은 이 설정과 무관하게 일반적으로 설치됩니다.
미리보기 계층 활성화
미리보기 기능을 사용하는 확장 프로그램을 설치하기 전에vsql_allow_preview_extensions = ON을 SET PERSIST로 설정합니다:
SET GLOBAL은 이 변수에 대해 거부됩니다 — 서버는 설정이 재시작 후에도 유지되도록 하기 위해 SET PERSIST를 요구합니다. 미리보기 기능을 사용하는 확장 프로그램은 시작 시 로드되므로, 서버가 시작될 때 이 변수가 ON이어야 합니다.
mysqld를 직접 실행하는 경우(예: 서버를 처음 시작하는 설치 스크립트에서), mysqld-auto.cnf가 아직 존재하지 않아 지속된 값을 저장할 수 없으므로 명령줄 플래그를 전달합니다:
기능 인덱스
등록 패턴
미리보기 기능을 사용하려면 파일 범위에서 값으로 기능 객체를 선언하고,make_extension() 내부의 .with()에 참조로 전달합니다. 서버는 등록 중에 객체의 abi 포인터를 채웁니다:
.with(capability)은 서버에 확장 프로그램이 필요한 기능을 알립니다. vsql_allow_preview_extensions가 OFF 상태에서 확장 프로그램이 설치되면, 서버는 해당 기능 이름을 명시한 오류와 함께 설치를 거부합니다.
Keyring 접근
keyring 기능(vsql::preview::keyring)은 MySQL keyring 구성 요소에 저장된 비밀을 읽고 쓸 수 있게 해줍니다. 확장 프로그램은 API 키, 암호화 키 또는 SQL 테이블에 저장되지 않아야 하는 기타 비밀을 처리하는 데 사용합니다.
기능 이름 VEF_PREVIEW_KEYRING_NAME은 "vsql::preview::keyring"입니다.
읽기와 쓰기 작업이 성공하려면 MySQL 서버에 keyring 구성 요소가 설치되어야 합니다. 없으면 작업은 KeyringCapability::Status::UNAVAILABLE을 반환합니다.
상태 값
KeyringCapability::Status는 read()(내부 ReadResult에서) 및 write()에서 반환되는 범위화된 열거형입니다:
기능 선언
헤더를 포함하고 파일 범위에서 기능 객체를 선언한 후.with()에 전달합니다:
g_keyring 객체는 서버가 로드 시 채웁니다. keyring 구성 요소가 설치되지 않은 경우 read() 및 write() 메서드는 런타임에 Status::UNAVAILABLE을 반환합니다 — 별도의 가용성 검사 대신 각 호출에서 상태를 확인하세요.
읽기 및 쓰기
data_id는 키 식별자입니다. auth_id는 소유 사용자입니다 — 내부 키(특정 사용자와 연결되지 않음)를 읽거나 쓰려면 빈 문자열(또는 read에서 생략, 기본값 {})을 전달합니다.
read는 값으로 ReadResult를 반환합니다. 구조화된 바인딩으로 바인딩합니다:
Status::OK가 아닌 상태에서는 value가 비어 있습니다.
write는 Status를 직접 반환하고 data를 data_id/auth_id 아래에 저장합니다.
완전한 예제
이것은 서버와 함께 제공되는vsql_keyring_reader 테스트 확장 프로그램의 간단한 버전입니다. 이 확장 프로그램은 2개의 VDF를 등록합니다: keyring_read 및 keyring_store.
상태 변수
status_var 기능(vsql::preview::status_var)은 확장 프로그램이 MySQL 상태 변수로 long long 및 double 카운터를 노출할 수 있게 해줍니다. 확장 프로그램은 저장소를 소유하고 쓰며, 서버는 상태 변수가 쿼리될 때마다 포인터를 통해 읽습니다.
vsql::preview_status_var::make_capability()으로 기능을 구축하고, make_int(name, value_ptr) 또는 make_double(name, value_ptr)에서 제공하는 디스크립터 목록을 중괄호로 감싸 전달합니다. 템플릿은 중괄호 목록에서 개수를 추론하므로 명시적 크기는 필요하지 않습니다.
완전한 예제
make_int는 long long *를 요구하며, make_double는 double *를 요구합니다. 이 두 유형만 지원됩니다.
SQL에서 접근
INSTALL EXTENSION my_ext 후, 변수는 확장 프로그램 이름을 접두사로 사용하여 사용 가능합니다:
++를 사용해 동시 증가가 때로 손실될 수 있지만, 이는 SHOW STATUS를 통해 노출된 근사 호출 카운터에 대해 허용됩니다.
시스템 변수
sys_var 기능(vsql::preview::sys_var)은 확장 프로그램 소유 저장소를 백업으로 사용하는 MySQL 시스템 변수를 등록할 수 있게 해줍니다. 세 가지 유형이 지원됩니다: BOOL(bool *), INT(long long *), STR(char **). INT 디스크립터는 min_val 및 max_val 경계를 포함하며, 모든 디스크립터는 기본값과 주석을 포함합니다.
vsql::preview_sys_var::make_capability()으로 기능을 구축하고, 대응하는 팩토리 함수인 make_bool, make_int, make_str을 사용합니다. 기능 객체는 프로그래밍 접근을 위해 get() 및 set()을 노출합니다. 둘 다 성공 시 false를 반환합니다.
값 변경에 반응하려면 디스크립터에 .on_change<&fn>()을 연결합니다. 콜백은 var_name() 및 타입 접근자(as_int(), as_real(), as_str())를 포함하는 sv::SysVarChange를 수신합니다.
기능 객체는 정적 저장 기간을 가져야 합니다. MySQL은 사용자가 변수를 설정할 때 저장소 포인터에 직접 씁니다.
완전한 예제
SQL에서 접근
INSTALL EXTENSION my_ext 후, 변수는 확장 프로그램 이름을 구성 접두사로 사용하여 접근 가능합니다:
확장 코드에서 읽기 및 쓰기
INT 및 BOOL 변수의 경우, 전역 저장소 포인터를 직접 읽습니다 — MySQL은 이들을 원자적으로 업데이트합니다. MySQL을 통해 변수를 업데이트하려면(locking, range validation, persistence가 서버에서 처리되도록), SYS_VARS.set(extension_name, var_name, scope, value)를 호출합니다. set 및 get 둘 다 성공 시 false를 반환합니다.
scope 인수는 다음과 같이 지속성을 제어합니다:
스레드 워커
thread_worker 기능(vsql::preview::thread_worker)은 확장 프로그램이 서버가 제어하는 백그라운드 스레드를 실행할 수 있게 해줍니다. 스레드는 서버가 확장 프로그램 로드 시 등록하는 제어 시스템 변수를 통해 시작 및 중지되며, 서버는 주기적 타이머, 파일 디스크립터 준비, 또는 활성/비활성 이벤트에 반응하여 확장 프로그램의 작업 함수를 호출합니다.
기능 이름 VEF_PREVIEW_THREAD_WORKER_NAME은 "vsql::preview::thread_worker"입니다.
기능 선언
헤더를 포함하고, 파일 범위에서 작업 함수로 인스턴스화된ThreadWorkerCapability을 선언하고, .with()에 전달합니다:
ThreadWorkerCapability<&my_work>)로 제공되므로, 다음 서명을 가진 함수여야 합니다. 첫 번째 생성자 인수는 스레드 이름 접미사이며, 선택적 두 번째 인수는 제어 시스템 변수 이름을 오버라이드합니다.
작업 함수 서명
reason은 서버가 함수를 호출한 이유를 나타냅니다. thread는 이 워커에 대한 서버 소유 핸들입니다(초기 VEF_WAKEUP_ENABLE 호출 시 NULL — 아래 참조). arg는 디스크립터에 등록된 불명확한 포인터이며, 변경 없이 전달됩니다.
웨이크업 라이프사이클
서버는 다음 네 가지 이유 중 하나로 작업 함수를 호출합니다:reason이 VEF_WAKEUP_ENABLE인 경우 thread 매개변수는 NULL입니다. 이 시점에는 스레드 핸들이 아직 존재하지 않기 때문입니다. 다른 세 가지 이유에 대해서는 thread가 NULL이 아닙니다.
웨이크업 반환 값
vef_next_wakeup_t를 반환하여 다음 웨이크업 구성 설정을 업데이트합니다. 각 필드의 0 값은 “현재 설정 유지”를 의미합니다 — 변경하지 않으려면 구조체를 기본값으로 초기화하여 반환(return {};)하세요.
새로운 poll 파일 디스크립터를 설정하려면 해당 값을 반환합니다(0보다 커야 함). 기존 poll 파일 디스크립터를 제거하려면 poll_fd에 -1을 반환합니다.
reason이 VEF_WAKEUP_DISABLE인 경우 반환 값은 무시됩니다.
스레드 이름 및 제어 변수
디스크립터의 두 필드가 이름을 제어합니다:suffix— 스레드 이름 접미사. 서버는 확장 프로그램 이름을 접두사로 추가하여my_ext/monitor과 같은 스레드 이름을 생성합니다.var_name— 선택적. NULL이 아닌 경우 서버는 이 정확한 이름을 제어 시스템 변수로 등록합니다. NULL인 경우 서버는 기본 패턴{suffix}_enabled을 사용합니다.
SET GLOBAL {suffix}_enabled = ON으로 워커를 활성화하고, OFF로 설정하여 중지합니다.
완전한 예제
주기적 워커가 하나 있는 최소 확장 프로그램으로, 각 타이머 틱마다 심장 박동 카운터를 증가시킵니다.vsql_allow_preview_extensions = ON), 서버는 heartbeat_enabled 시스템 변수를 등록합니다. 워커를 활성화하려면:
SQL 쿼리
sql_query 기능(vsql::preview::sql_query)은 확장 프로그램이 백그라운드 스레드에서 SQL 문을 실행할 수 있게 해줍니다. 쿼리는 확장 프로그램이 MySQL 클라이언트 라이브러리에 링크하지 않고 서버를 통해 실행됩니다.
기능 이름 VEF_PREVIEW_SQL_QUERY_NAME은 "vsql::preview::sql_query"입니다.
기능 선언
헤더를 포함하고, 파일 범위에서SqlQueryCapability을 선언한 후 .with()에 전달합니다. 일반적으로 ThreadWorkerCapability과 함께 등록되며, 세션은 워커 콜백에서 열립니다:
g_sql.open(handle)은 Session을 반환합니다. 사용 전에 operator bool로 확인하세요. 유효하지 않은 Session은 기능 vtable이 바인딩되지 않았거나 서버가 세션을 할당하지 못했음을 나타냅니다. Session은 이동 전용이며 소멸 시 자동으로 닫힙니다.
쿼리 실행
Session은 session.sql(sv)를 통해 SqlQuery를 생성합니다. 쿼리는 두 가지 모드로 실행할 수 있습니다:
execute()— 문을 실행하고 전체 결과 세트를Result에 버퍼링합니다.next()를 호출하여 행을 반복합니다.for_each(fn)— 문을 실행하고 행이 생성될 때마다fn을 한 번 호출합니다(버퍼링 없음). 반환된Result는 진단 정보만 포함합니다(행 없음).
Result를 반환합니다. Result가 null이 아닌 경우 문이 성공했다는 의미가 아닙니다 — has_error()를 호출하여 확인하세요.
버퍼링(execute):
column_str()은 next() 호출 또는 Result 소멸 전까지 유효한 string_view를 반환합니다. 더 긴 수명이 필요한 경우 복사하세요. data() == nullptr인 string_view는 SQL NULL을 나타냅니다.
스트리밍(for_each):
Row는 호출 기간 동안만 유효합니다 — 행 간에 참조를 저장하지 마세요. for_each가 반환한 Result는 버퍼링된 행을 보유하지 않습니다. next()는 데이터를 생성하지 않습니다. has_error(), error(), warning_count(), warning(i)에만 사용하세요.
진단
execute() 및 for_each()는 반환된 Result를 통해 진단을 표시합니다. 진단은 하나의 Diag입니다:
Result는 다음과 같이 노출합니다:
error()는 문이 성공했을 때 기본 생성된 Diag(errno_ == 0)을 반환합니다. warning(i)는 i >= warning_count()일 때 기본 생성된 Diag를 반환합니다.
sqlstate 및 message 뷰는 Result가 소멸될 때 무효화되므로, 이들이 Result보다 오래 유지되어야 할 경우 복사하세요.
완전한 예제
각 틱마다 버퍼링 쿼리와 스트리밍 쿼리를 실행하고, 두 쿼리에서 진단을 로깅하는 워커:컬럼 저장
컬럼 저장은 확장 프로그램이 InnoDB에 직접 커스텀 유형의 이진 디스크 레이아웃을 등록할 수 있게 해줍니다. 이는 VARBINARY 페이로드를 통해 유형 바이트를 라우팅하는 대신, 커스텀 유형의 디스크 모양을 VARBINARY이 표현할 수 없는 경우(예: 전용 페이지에 저장되어야 하는 밀집된 부동 소수점 배열)에 사용됩니다. 이는 미리보기 기능(Capability)입니다: 기존 레이아웃에 대한 튜닝 장치가 아닌 새로운 저장 레이아웃을 활성화합니다.기능 선언
두 개의 미리보기 기능이 함께 작동합니다:vsql::preview::storage— InnoDB 저장소 인프라구조(미니 트랜잭션, 세그먼트, 페이지)에 접근합니다. 파일 범위에서StorageCapability을 선언합니다.vsql::preview::column_store— 확장 프로그램의 커스텀 유형 중 하나에 대한 저장 구현을 바인딩합니다.make_column_store<Ctx>(TYPE).…build()를 사용하여 파일 범위에서ColumnStoreCapability을 선언합니다.
make_extension()의 .with()에 전달되어야 합니다:
make_column_store<MyCtx>(MY_TYPE)은 구현을 동일한 확장 프로그램에서 등록된 하나의 커스텀 유형과 연결합니다. 모든 7개의 슬롯은 build() 시점에 필수적입니다. 각 슬롯은 InnoDB가 정상 운영 중에 도달하는 고유한 컬럼 라이프사이클 단계를 나타내기 때문입니다.
일곱 개의 저장 함수
모든 함수는storage::Column::StorageCtx<MyCtx>*를 받습니다. 이 user() 접근자는 확장 프로그램의 컬럼별 상태를 반환하고, arena()는 보조 개체에 대한 서버 관리 할당을 제공합니다. 모든 함수는 성공 시 false를 반환하고, 오류 시 true를 반환하며, error_msg(용량 error_msg_len)에 메시지를 작성하여 SQL 클라이언트에 표시합니다.
mark_delete 및 purge는 InnoDB MVCC가 삭제된 행을 오래된 스냅샷에서 읽을 수 있도록 유지해야 하기 때문에 구분됩니다.
컬럼별 컨텍스트 및 아레나
SDK는create 또는 load를 호출하기 전에 MyCtx를 기본 생성합니다 — ctx->user()는 함수가 실행될 때 이미 채워져 있습니다. MyCtx는 기본 생성 가능해야 하며, SDK는 인수 없이 T()를 호출합니다.
ctx->user()를 직접 사용하여 상태를 초기화하세요. ctx->arena().construct<MyCtx>()를 호출하지 마세요 — 이는 두 번째 사용되지 않는 인스턴스를 할당하고 ctx->user()가 이 인스턴스를 가리키지 않습니다.
load는 동일한 패턴을 따릅니다 — ctx->user()는 미리 채워져 있고, storage_ref는 create에서 ctx->set_ref()로 저장된 패키지된 값을 담고 있습니다:
ctx->arena()는 MyCtx에 직접 포함할 수 없는 크기나 동적 객체를 할당하는 데만 사용하세요. SDK는 drop이 반환된 후 자동으로 아레나를 파괴하고 ~MyCtx()를 호출합니다(성공 여부와 무관).
InnoDB 접근 유틸리티
InnoDB 원시 기능을 위해<villagesql/preview/storage_api.h>를 포함합니다. 모든 페이지 읽기 및 쓰기는 미니 트랜잭션 내에서 발생해야 합니다:
create 시 예약됩니다 — 세그먼트 설정 패턴은 컬럼별 컨텍스트 예제에서 완전히 보여줍니다. DML 작업 중에는 루트 페이지에서 세그먼트 참조를 얻어 새 페이지를 할당합니다:
mtr_ref를 쓰기 호출에 전달합니다:
헤더 또는 트레일러 영역 내부에서 읽기 또는 쓰기 작업을 수행하면 페이지가 손상됩니다 —
InnoDB는 해당 바이트 범위를 자체적인 관리 및 체크섬에 사용합니다.

