Skip to main content

vldb_controller_ffi/
lib.rs

1// FFI functions inherently operate on raw pointers; this is expected and safe when callers
2// follow the documented protocol. Suppressing the lint avoids 25 false positives.
3#![allow(clippy::not_unsafe_ptr_arg_deref)]
4
5use std::collections::BTreeMap;
6use std::ffi::{CStr, CString, c_char, c_float, c_int, c_uchar, c_ulonglong};
7use std::ptr;
8use std::sync::{Arc, Mutex, OnceLock};
9
10use serde::{Deserialize, Serialize};
11use serde_json::Value as JsonValue;
12use tokio::runtime::Runtime;
13use vldb_controller_client::{
14    ClientRegistration, ControllerClient, ControllerClientConfig, ControllerLanceDbColumnDef,
15    ControllerLanceDbColumnType, ControllerLanceDbCreateTableResult, ControllerLanceDbDeleteResult,
16    ControllerLanceDbDropTableResult, ControllerLanceDbEnableRequest, ControllerLanceDbInputFormat,
17    ControllerLanceDbOutputFormat, ControllerLanceDbSearchResult, ControllerLanceDbUpsertResult,
18    ControllerProcessMode, ControllerSqliteCustomWordEntry,
19    ControllerSqliteDictionaryMutationResult, ControllerSqliteEnableRequest,
20    ControllerSqliteEnsureFtsIndexResult, ControllerSqliteExecuteBatchResult,
21    ControllerSqliteExecuteResult, ControllerSqliteFtsMutationResult,
22    ControllerSqliteListCustomWordsResult, ControllerSqliteQueryResult,
23    ControllerSqliteRebuildFtsIndexResult, ControllerSqliteSearchFtsHit,
24    ControllerSqliteSearchFtsResult, ControllerSqliteTokenizeResult, ControllerSqliteTokenizerMode,
25    ControllerSqliteValue, ControllerStatusSnapshot, SpaceBackendStatus, SpaceKind,
26    SpaceRegistration, SpaceSnapshot,
27};
28
29/// Stable success status returned by all native FFI functions.
30/// 所有原生 FFI 函数返回的稳定成功状态码。
31const FFI_STATUS_OK: c_int = 0;
32
33/// Stable failure status returned by all native FFI functions.
34/// 所有原生 FFI 函数返回的稳定失败状态码。
35const FFI_STATUS_ERR: c_int = 1;
36
37/// Global registry for all live opaque FFI client handles.
38/// 全局存活不透明 FFI 客户端句柄注册表。
39static FFI_CLIENT_HANDLE_REGISTRY: OnceLock<
40    Mutex<BTreeMap<usize, Arc<FfiControllerClientHandleState>>>,
41> = OnceLock::new();
42
43/// Opaque FFI handle that owns one Tokio runtime and one controller client proxy.
44/// 拥有一个 Tokio 运行时和一个控制器客户端代理的不透明 FFI 句柄。
45///
46/// ## Thread Safety Model / 线程安全模型
47///
48/// The pointer value is backed by one private heap allocation and must stay opaque to callers.
49/// 这个指针值由一个私有堆分配支撑,对调用方必须始终保持不透明。
50///
51/// All operations on the same handle are serialized internally through the registry state.
52/// 同一个 handle 上的所有操作都会通过注册表中的状态在内部串行化。
53///
54/// After `free`, the handle is removed from the registry, the shell allocation is dropped,
55/// and later calls fail safely without dereferencing the stale pointer.
56/// 调用 `free` 后句柄会从注册表移除并释放外层壳体分配,后续调用不会解引用陈旧指针且会安全失败。
57pub struct FfiControllerClientHandle {
58    _private: u8,
59}
60
61/// Mutable FFI client resources protected by the outer handle mutex.
62/// 由外层句柄互斥量保护的可变 FFI 客户端资源。
63struct FfiControllerClientHandleInner {
64    runtime: Runtime,
65    client: ControllerClient,
66}
67
68/// Shared registry entry that owns one mutable FFI client resource set.
69/// 持有一组可变 FFI 客户端资源的共享注册表条目。
70struct FfiControllerClientHandleState {
71    inner: Mutex<Option<FfiControllerClientHandleInner>>,
72}
73
74/// Native client configuration used by hosts that prefer structured ABI calls.
75/// 供偏好结构化 ABI 调用的宿主使用的原生客户端配置。
76#[repr(C)]
77pub struct FfiControllerClientConfig {
78    pub endpoint: *const c_char,
79    pub auto_spawn: c_uchar,
80    pub spawn_executable: *const c_char,
81    pub spawn_process_mode: c_int,
82    pub minimum_uptime_secs: c_ulonglong,
83    pub idle_timeout_secs: c_ulonglong,
84    pub default_lease_ttl_secs: c_ulonglong,
85    pub connect_timeout_secs: c_ulonglong,
86    pub startup_timeout_secs: c_ulonglong,
87    pub startup_retry_interval_ms: c_ulonglong,
88    pub lease_renew_interval_secs: c_ulonglong,
89}
90
91/// Native client registration used by hosts that prefer structured ABI calls.
92/// 供偏好结构化 ABI 调用的宿主使用的原生客户端注册结构。
93#[repr(C)]
94pub struct FfiClientRegistration {
95    pub client_name: *const c_char,
96    pub host_kind: *const c_char,
97    pub process_id: u32,
98    pub process_name: *const c_char,
99    pub lease_ttl_secs: c_ulonglong,
100}
101
102/// Native runtime space registration used by structured ABI calls.
103/// 供结构化 ABI 调用使用的原生运行时空间注册结构。
104#[repr(C)]
105pub struct FfiSpaceRegistration {
106    pub space_id: *const c_char,
107    pub space_label: *const c_char,
108    pub space_kind: c_int,
109    pub space_root: *const c_char,
110}
111
112/// Native SQLite enable request used by structured ABI calls.
113/// 供结构化 ABI 调用使用的原生 SQLite 启用请求。
114#[repr(C)]
115pub struct FfiControllerSqliteEnableRequest {
116    pub space_id: *const c_char,
117    pub db_path: *const c_char,
118    pub connection_pool_size: c_ulonglong,
119    pub busy_timeout_ms: c_ulonglong,
120    pub journal_mode: *const c_char,
121    pub synchronous: *const c_char,
122    pub foreign_keys: c_uchar,
123    pub temp_store: *const c_char,
124    pub wal_autocheckpoint_pages: u32,
125    pub cache_size_kib: i64,
126    pub mmap_size_bytes: c_ulonglong,
127    pub enforce_db_file_lock: c_uchar,
128    pub read_only: c_uchar,
129    pub allow_uri_filenames: c_uchar,
130    pub trusted_schema: c_uchar,
131    pub defensive: c_uchar,
132}
133
134/// Native LanceDB enable request used by structured ABI calls.
135/// 供结构化 ABI 调用使用的原生 LanceDB 启用请求。
136#[repr(C)]
137pub struct FfiControllerLanceDbEnableRequest {
138    pub space_id: *const c_char,
139    pub default_db_path: *const c_char,
140    pub db_root: *const c_char,
141    pub read_consistency_interval_ms: c_ulonglong,
142    pub max_upsert_payload: c_ulonglong,
143    pub max_search_limit: c_ulonglong,
144    pub max_concurrent_requests: c_ulonglong,
145}
146
147/// Native backend status snapshot returned by structured ABI calls.
148/// 由结构化 ABI 调用返回的原生后端状态快照。
149#[repr(C)]
150pub struct FfiSpaceBackendStatus {
151    pub enabled: c_uchar,
152    pub mode: *mut c_char,
153    pub target: *mut c_char,
154}
155
156/// Native space snapshot returned by structured ABI calls.
157/// 由结构化 ABI 调用返回的原生空间快照。
158#[repr(C)]
159pub struct FfiSpaceSnapshot {
160    pub space_id: *mut c_char,
161    pub space_label: *mut c_char,
162    pub space_kind: c_int,
163    pub space_root: *mut c_char,
164    pub attached_clients: c_ulonglong,
165    pub sqlite: *mut FfiSpaceBackendStatus,
166    pub lancedb: *mut FfiSpaceBackendStatus,
167}
168
169/// Native array wrapper for space snapshots.
170/// 用于包装空间快照数组的原生结构。
171#[repr(C)]
172pub struct FfiSpaceSnapshotArray {
173    pub items: *mut FfiSpaceSnapshot,
174    pub len: usize,
175}
176
177/// Native controller status snapshot returned by structured ABI calls.
178/// 由结构化 ABI 调用返回的原生控制器状态快照。
179#[repr(C)]
180pub struct FfiControllerStatusSnapshot {
181    pub process_mode: c_int,
182    pub bind_addr: *mut c_char,
183    pub started_at_unix_ms: c_ulonglong,
184    pub last_request_at_unix_ms: c_ulonglong,
185    pub minimum_uptime_secs: c_ulonglong,
186    pub idle_timeout_secs: c_ulonglong,
187    pub default_lease_ttl_secs: c_ulonglong,
188    pub active_clients: c_ulonglong,
189    pub attached_spaces: c_ulonglong,
190    pub inflight_requests: c_ulonglong,
191    pub shutdown_candidate: c_uchar,
192}
193
194/// Native SQLite execution result returned by structured ABI calls.
195/// 由结构化 ABI 调用返回的原生 SQLite 执行结果。
196#[repr(C)]
197pub struct FfiControllerSqliteExecuteResult {
198    pub success: c_uchar,
199    pub message: *mut c_char,
200    pub rows_changed: i64,
201    pub last_insert_rowid: i64,
202}
203
204/// Native SQLite JSON query result returned by structured ABI calls.
205/// 由结构化 ABI 调用返回的原生 SQLite JSON 查询结果。
206#[repr(C)]
207pub struct FfiControllerSqliteQueryResult {
208    pub json_data: *mut c_char,
209    pub row_count: c_ulonglong,
210}
211
212/// Native byte-buffer item returned by structured ABI calls.
213/// 由结构化 ABI 调用返回的原生字节缓冲项。
214#[repr(C)]
215pub struct FfiByteBuffer {
216    pub data: *mut u8,
217    pub len: usize,
218}
219
220/// Native byte-buffer array returned by structured ABI calls.
221/// 由结构化 ABI 调用返回的原生字节缓冲数组。
222#[repr(C)]
223pub struct FfiByteBufferArray {
224    pub items: *mut FfiByteBuffer,
225    pub len: usize,
226}
227
228/// Native string array used by structured ABI calls.
229/// 供结构化 ABI 调用使用的原生字符串数组。
230#[repr(C)]
231pub struct FfiStringArray {
232    pub items: *const *const c_char,
233    pub len: usize,
234}
235
236/// Native SQLite value used by structured ABI calls.
237/// 供结构化 ABI 调用使用的原生 SQLite 值。
238#[repr(C)]
239pub struct FfiSqliteValue {
240    pub kind: c_int,
241    pub int64_value: i64,
242    pub float64_value: f64,
243    pub string_value: *const c_char,
244    pub bytes_value: *const u8,
245    pub bytes_len: usize,
246    pub bool_value: c_uchar,
247}
248
249/// Native SQLite batch item used by structured ABI calls.
250/// 供结构化 ABI 调用使用的原生 SQLite 批量参数项。
251#[repr(C)]
252pub struct FfiSqliteBatchItem {
253    pub params: *const FfiSqliteValue,
254    pub params_len: usize,
255}
256
257/// Native SQLite batch execution result returned by structured ABI calls.
258/// 由结构化 ABI 调用返回的原生 SQLite 批量执行结果。
259#[repr(C)]
260pub struct FfiControllerSqliteExecuteBatchResult {
261    pub success: c_uchar,
262    pub message: *mut c_char,
263    pub rows_changed: i64,
264    pub last_insert_rowid: i64,
265    pub statements_executed: i64,
266}
267
268/// Native SQLite streaming query result returned by structured ABI calls.
269/// 由结构化 ABI 调用返回的原生 SQLite 流式查询结果。
270#[repr(C)]
271pub struct FfiControllerSqliteQueryStreamResult {
272    pub chunks: *mut FfiByteBufferArray,
273    pub row_count: c_ulonglong,
274    pub chunk_count: c_ulonglong,
275    pub total_bytes: c_ulonglong,
276}
277
278/// Native SQLite tokenize result returned by structured ABI calls.
279/// 由结构化 ABI 调用返回的原生 SQLite 分词结果。
280#[repr(C)]
281pub struct FfiControllerSqliteTokenizeResult {
282    pub tokenizer_mode: *mut c_char,
283    pub normalized_text: *mut c_char,
284    pub tokens_json: *mut c_char,
285    pub fts_query: *mut c_char,
286}
287
288/// Native SQLite custom-word entry returned by structured ABI calls.
289/// 由结构化 ABI 调用返回的原生 SQLite 自定义词条目。
290#[repr(C)]
291pub struct FfiControllerSqliteCustomWordEntry {
292    pub word: *mut c_char,
293    pub weight: c_ulonglong,
294}
295
296/// Native SQLite custom-word array returned by structured ABI calls.
297/// 由结构化 ABI 调用返回的原生 SQLite 自定义词数组。
298#[repr(C)]
299pub struct FfiControllerSqliteCustomWordArray {
300    pub items: *mut FfiControllerSqliteCustomWordEntry,
301    pub len: usize,
302}
303
304/// Native SQLite dictionary mutation result returned by structured ABI calls.
305/// 由结构化 ABI 调用返回的原生 SQLite 词典变更结果。
306#[repr(C)]
307pub struct FfiControllerSqliteDictionaryMutationResult {
308    pub success: c_uchar,
309    pub message: *mut c_char,
310    pub affected_rows: c_ulonglong,
311}
312
313/// Native SQLite custom-word listing result returned by structured ABI calls.
314/// 由结构化 ABI 调用返回的原生 SQLite 自定义词列表结果。
315#[repr(C)]
316pub struct FfiControllerSqliteListCustomWordsResult {
317    pub success: c_uchar,
318    pub message: *mut c_char,
319    pub words: *mut FfiControllerSqliteCustomWordArray,
320}
321
322/// Native SQLite ensure-FTS result returned by structured ABI calls.
323/// 由结构化 ABI 调用返回的原生 SQLite FTS 确认结果。
324#[repr(C)]
325pub struct FfiControllerSqliteEnsureFtsIndexResult {
326    pub success: c_uchar,
327    pub message: *mut c_char,
328    pub index_name: *mut c_char,
329    pub tokenizer_mode: *mut c_char,
330}
331
332/// Native SQLite rebuild-FTS result returned by structured ABI calls.
333/// 由结构化 ABI 调用返回的原生 SQLite FTS 重建结果。
334#[repr(C)]
335pub struct FfiControllerSqliteRebuildFtsIndexResult {
336    pub success: c_uchar,
337    pub message: *mut c_char,
338    pub index_name: *mut c_char,
339    pub tokenizer_mode: *mut c_char,
340    pub reindexed_rows: c_ulonglong,
341}
342
343/// Native SQLite FTS document mutation result returned by structured ABI calls.
344/// 由结构化 ABI 调用返回的原生 SQLite FTS 文档变更结果。
345#[repr(C)]
346pub struct FfiControllerSqliteFtsMutationResult {
347    pub success: c_uchar,
348    pub message: *mut c_char,
349    pub affected_rows: c_ulonglong,
350    pub index_name: *mut c_char,
351}
352
353/// Native SQLite FTS search hit returned by structured ABI calls.
354/// 由结构化 ABI 调用返回的原生 SQLite FTS 检索命中。
355#[repr(C)]
356pub struct FfiControllerSqliteSearchFtsHit {
357    pub id: *mut c_char,
358    pub file_path: *mut c_char,
359    pub title: *mut c_char,
360    pub title_highlight: *mut c_char,
361    pub content_snippet: *mut c_char,
362    pub score: f64,
363    pub rank: c_ulonglong,
364    pub raw_score: f64,
365}
366
367/// Native SQLite FTS hit array returned by structured ABI calls.
368/// 由结构化 ABI 调用返回的原生 SQLite FTS 命中数组。
369#[repr(C)]
370pub struct FfiControllerSqliteSearchFtsHitArray {
371    pub items: *mut FfiControllerSqliteSearchFtsHit,
372    pub len: usize,
373}
374
375/// Native SQLite FTS search result returned by structured ABI calls.
376/// 由结构化 ABI 调用返回的原生 SQLite FTS 检索结果。
377#[repr(C)]
378pub struct FfiControllerSqliteSearchFtsResult {
379    pub success: c_uchar,
380    pub message: *mut c_char,
381    pub index_name: *mut c_char,
382    pub tokenizer_mode: *mut c_char,
383    pub normalized_query: *mut c_char,
384    pub fts_query: *mut c_char,
385    pub source: *mut c_char,
386    pub query_mode: *mut c_char,
387    pub total: c_ulonglong,
388    pub hits: *mut FfiControllerSqliteSearchFtsHitArray,
389}
390
391/// Native LanceDB create-table result returned by structured ABI calls.
392/// 由结构化 ABI 调用返回的原生 LanceDB 建表结果。
393#[repr(C)]
394pub struct FfiControllerLanceDbCreateTableResult {
395    pub message: *mut c_char,
396}
397
398/// Native LanceDB upsert result returned by structured ABI calls.
399/// 由结构化 ABI 调用返回的原生 LanceDB 写入结果。
400#[repr(C)]
401pub struct FfiControllerLanceDbUpsertResult {
402    pub message: *mut c_char,
403    pub version: c_ulonglong,
404    pub input_rows: c_ulonglong,
405    pub inserted_rows: c_ulonglong,
406    pub updated_rows: c_ulonglong,
407    pub deleted_rows: c_ulonglong,
408}
409
410/// Native LanceDB search result returned by structured ABI calls.
411/// 由结构化 ABI 调用返回的原生 LanceDB 检索结果。
412#[repr(C)]
413pub struct FfiControllerLanceDbSearchResult {
414    pub message: *mut c_char,
415    pub format: *mut c_char,
416    pub rows: c_ulonglong,
417    pub data: *mut u8,
418    pub data_len: usize,
419}
420
421/// Native LanceDB delete result returned by structured ABI calls.
422/// 由结构化 ABI 调用返回的原生 LanceDB 删除结果。
423#[repr(C)]
424pub struct FfiControllerLanceDbDeleteResult {
425    pub message: *mut c_char,
426    pub version: c_ulonglong,
427    pub deleted_rows: c_ulonglong,
428}
429
430/// Native LanceDB drop-table result returned by structured ABI calls.
431/// 由结构化 ABI 调用返回的原生 LanceDB 删表结果。
432#[repr(C)]
433pub struct FfiControllerLanceDbDropTableResult {
434    pub message: *mut c_char,
435}
436
437/// Native LanceDB column definition used by structured ABI calls.
438/// 供结构化 ABI 调用使用的原生 LanceDB 列定义。
439#[repr(C)]
440pub struct FfiControllerLanceDbColumnDef {
441    pub name: *const c_char,
442    pub column_type: c_int,
443    pub vector_dim: u32,
444    pub nullable: c_uchar,
445}
446
447/// JSON request used by `client_create_json`.
448/// `client_create_json` 使用的 JSON 请求结构。
449#[derive(Deserialize)]
450struct CreateClientJsonRequest {
451    config: ControllerClientConfig,
452    registration: ClientRegistration,
453}
454
455/// JSON request used by `connect_json`.
456/// `connect_json` 使用的 JSON 请求结构。
457#[derive(Default, Deserialize)]
458struct EmptyJsonRequest {}
459
460/// JSON request used by `attach_space_json`.
461/// `attach_space_json` 使用的 JSON 请求结构。
462#[derive(Deserialize)]
463struct AttachSpaceJsonRequest {
464    registration: SpaceRegistration,
465}
466
467/// JSON request used by `detach_space_json`.
468/// `detach_space_json` 使用的 JSON 请求结构。
469#[derive(Deserialize)]
470struct DetachSpaceJsonRequest {
471    space_id: String,
472}
473
474/// JSON request used by `enable_sqlite_json`.
475/// `enable_sqlite_json` 使用的 JSON 请求结构。
476#[derive(Deserialize)]
477struct EnableSqliteJsonRequest {
478    request: ControllerSqliteEnableRequest,
479}
480
481/// JSON request used by `disable_backend_json`.
482/// `disable_backend_json` 使用的 JSON 请求结构。
483#[derive(Deserialize)]
484struct DisableBackendJsonRequest {
485    space_id: String,
486}
487
488/// JSON request used by `execute_sqlite_script_json`.
489/// `execute_sqlite_script_json` 使用的 JSON 请求结构。
490#[derive(Deserialize)]
491struct ExecuteSqliteScriptJsonRequest {
492    space_id: String,
493    sql: String,
494    #[serde(default)]
495    params: Vec<JsonValue>,
496}
497
498/// JSON request used by `query_sqlite_json_json`.
499/// `query_sqlite_json_json` 使用的 JSON 请求结构。
500#[derive(Deserialize)]
501struct QuerySqliteJsonJsonRequest {
502    space_id: String,
503    sql: String,
504    #[serde(default)]
505    params: Vec<JsonValue>,
506}
507
508/// JSON request used by `execute_sqlite_batch_json`.
509/// `execute_sqlite_batch_json` 使用的 JSON 请求结构。
510#[derive(Deserialize)]
511struct ExecuteSqliteBatchJsonRequest {
512    space_id: String,
513    sql: String,
514    #[serde(default)]
515    batch_params: Vec<Vec<JsonValue>>,
516}
517
518/// JSON request used by `query_sqlite_stream_json`.
519/// `query_sqlite_stream_json` 使用的 JSON 请求结构。
520#[derive(Deserialize)]
521struct QuerySqliteStreamJsonRequest {
522    space_id: String,
523    sql: String,
524    #[serde(default)]
525    params: Vec<JsonValue>,
526    target_chunk_size: Option<u64>,
527}
528
529/// JSON request used by `tokenize_sqlite_text_json`.
530/// `tokenize_sqlite_text_json` 使用的 JSON 请求结构。
531#[derive(Deserialize)]
532struct TokenizeSqliteTextJsonRequest {
533    space_id: String,
534    tokenizer_mode: String,
535    text: String,
536    search_mode: bool,
537}
538
539/// JSON request used by `list_sqlite_custom_words_json`.
540/// `list_sqlite_custom_words_json` 使用的 JSON 请求结构。
541#[derive(Deserialize)]
542struct ListSqliteCustomWordsJsonRequest {
543    space_id: String,
544}
545
546/// JSON request used by `upsert_sqlite_custom_word_json`.
547/// `upsert_sqlite_custom_word_json` 使用的 JSON 请求结构。
548#[derive(Deserialize)]
549struct UpsertSqliteCustomWordJsonRequest {
550    space_id: String,
551    word: String,
552    weight: u32,
553}
554
555/// JSON request used by `remove_sqlite_custom_word_json`.
556/// `remove_sqlite_custom_word_json` 使用的 JSON 请求结构。
557#[derive(Deserialize)]
558struct RemoveSqliteCustomWordJsonRequest {
559    space_id: String,
560    word: String,
561}
562
563/// JSON request used by `ensure_sqlite_fts_index_json`.
564/// `ensure_sqlite_fts_index_json` 使用的 JSON 请求结构。
565#[derive(Deserialize)]
566struct EnsureSqliteFtsIndexJsonRequest {
567    space_id: String,
568    index_name: String,
569    tokenizer_mode: String,
570}
571
572/// JSON request used by `rebuild_sqlite_fts_index_json`.
573/// `rebuild_sqlite_fts_index_json` 使用的 JSON 请求结构。
574#[derive(Deserialize)]
575struct RebuildSqliteFtsIndexJsonRequest {
576    space_id: String,
577    index_name: String,
578    tokenizer_mode: String,
579}
580
581/// JSON request used by `upsert_sqlite_fts_document_json`.
582/// `upsert_sqlite_fts_document_json` 使用的 JSON 请求结构。
583#[derive(Deserialize)]
584struct UpsertSqliteFtsDocumentJsonRequest {
585    space_id: String,
586    index_name: String,
587    tokenizer_mode: String,
588    id: String,
589    file_path: String,
590    title: String,
591    content: String,
592}
593
594/// JSON request used by `delete_sqlite_fts_document_json`.
595/// `delete_sqlite_fts_document_json` 使用的 JSON 请求结构。
596#[derive(Deserialize)]
597struct DeleteSqliteFtsDocumentJsonRequest {
598    space_id: String,
599    index_name: String,
600    id: String,
601}
602
603/// JSON request used by `search_sqlite_fts_json`.
604/// `search_sqlite_fts_json` 使用的 JSON 请求结构。
605#[derive(Deserialize)]
606struct SearchSqliteFtsJsonRequest {
607    space_id: String,
608    index_name: String,
609    tokenizer_mode: String,
610    query: String,
611    limit: u32,
612    offset: u32,
613}
614
615/// JSON request used by `enable_lancedb_json`.
616/// `enable_lancedb_json` 使用的 JSON 请求结构。
617#[derive(Deserialize)]
618struct EnableLanceDbJsonRequest {
619    request: ControllerLanceDbEnableRequest,
620}
621
622/// JSON request used by `create_lancedb_table_json`.
623/// `create_lancedb_table_json` 使用的 JSON 请求结构。
624#[derive(Deserialize)]
625struct CreateLanceDbTableJsonRequest {
626    space_id: String,
627    table_name: String,
628    columns: Vec<CreateLanceDbTableJsonColumn>,
629    #[serde(default)]
630    overwrite_if_exists: bool,
631}
632
633/// JSON create-table column used by FFI JSON mode.
634/// FFI JSON 模式使用的建表列定义。
635#[derive(Deserialize, Serialize)]
636struct CreateLanceDbTableJsonColumn {
637    name: String,
638    column_type: String,
639    #[serde(default)]
640    vector_dim: u32,
641    #[serde(default = "default_nullable")]
642    nullable: bool,
643}
644
645/// JSON request used by `upsert_lancedb_json`.
646/// `upsert_lancedb_json` 使用的 JSON 请求结构。
647#[derive(Deserialize)]
648struct UpsertLanceDbJsonRequest {
649    space_id: String,
650    table_name: String,
651    input_format: String,
652    #[serde(default)]
653    key_columns: Vec<String>,
654    data_base64: String,
655}
656
657/// JSON request used by `search_lancedb_json`.
658/// `search_lancedb_json` 使用的 JSON 请求结构。
659#[derive(Deserialize)]
660struct SearchLanceDbJsonRequest {
661    space_id: String,
662    table_name: String,
663    vector: Vec<f32>,
664    #[serde(default = "default_search_limit")]
665    limit: u32,
666    #[serde(default)]
667    filter: String,
668    #[serde(default)]
669    vector_column: String,
670    #[serde(default)]
671    output_format: String,
672}
673
674/// JSON request used by `delete_lancedb_json`.
675/// `delete_lancedb_json` 使用的 JSON 请求结构。
676#[derive(Deserialize)]
677struct DeleteLanceDbJsonRequest {
678    space_id: String,
679    table_name: String,
680    condition: String,
681}
682
683/// JSON bytes wrapper used by SQLite JSON-mode parameters.
684/// SQLite JSON 模式参数使用的 JSON 字节包装结构。
685#[derive(Deserialize)]
686struct JsonSqliteBytesValue {
687    #[serde(default)]
688    r#type: String,
689    #[serde(default)]
690    __type: String,
691    base64: String,
692}
693
694/// Compatibility JSON create-table payload used internally by the Rust SDK wrapper.
695/// 供 Rust SDK 兼容包装层内部使用的 JSON 建表负载。
696#[derive(Serialize)]
697struct CreateLanceDbTableJsonCompatRequest {
698    table_name: String,
699    columns: Vec<CreateLanceDbTableJsonColumn>,
700    overwrite_if_exists: bool,
701}
702
703impl From<CreateLanceDbTableJsonRequest> for CreateLanceDbTableJsonCompatRequest {
704    fn from(value: CreateLanceDbTableJsonRequest) -> Self {
705        Self {
706            table_name: value.table_name,
707            columns: value.columns,
708            overwrite_if_exists: value.overwrite_if_exists,
709        }
710    }
711}
712
713/// Compatibility JSON upsert payload used internally by the Rust SDK wrapper.
714/// 供 Rust SDK 兼容包装层内部使用的 JSON 写入负载。
715#[derive(Serialize)]
716struct UpsertLanceDbJsonCompatRequest {
717    table_name: String,
718    input_format: String,
719    key_columns: Vec<String>,
720}
721
722impl From<&UpsertLanceDbJsonRequest> for UpsertLanceDbJsonCompatRequest {
723    fn from(value: &UpsertLanceDbJsonRequest) -> Self {
724        Self {
725            table_name: value.table_name.clone(),
726            input_format: value.input_format.clone(),
727            key_columns: value.key_columns.clone(),
728        }
729    }
730}
731
732/// Compatibility JSON search payload used internally by the Rust SDK wrapper.
733/// 供 Rust SDK 兼容包装层内部使用的 JSON 检索负载。
734#[derive(Serialize)]
735struct SearchLanceDbJsonCompatRequest {
736    table_name: String,
737    vector: Vec<f32>,
738    limit: u32,
739    filter: String,
740    vector_column: String,
741    output_format: String,
742}
743
744impl From<&SearchLanceDbJsonRequest> for SearchLanceDbJsonCompatRequest {
745    fn from(value: &SearchLanceDbJsonRequest) -> Self {
746        Self {
747            table_name: value.table_name.clone(),
748            vector: value.vector.clone(),
749            limit: value.limit,
750            filter: value.filter.clone(),
751            vector_column: value.vector_column.clone(),
752            output_format: value.output_format.clone(),
753        }
754    }
755}
756
757/// Compatibility JSON delete payload used internally by the Rust SDK wrapper.
758/// 供 Rust SDK 兼容包装层内部使用的 JSON 删除负载。
759#[derive(Serialize)]
760struct DeleteLanceDbJsonCompatRequest {
761    table_name: String,
762    condition: String,
763}
764
765impl From<&DeleteLanceDbJsonRequest> for DeleteLanceDbJsonCompatRequest {
766    fn from(value: &DeleteLanceDbJsonRequest) -> Self {
767        Self {
768            table_name: value.table_name.clone(),
769            condition: value.condition.clone(),
770        }
771    }
772}
773
774/// JSON request used by `drop_lancedb_table_json`.
775/// `drop_lancedb_table_json` 使用的 JSON 请求结构。
776#[derive(Deserialize)]
777struct DropLanceDbTableJsonRequest {
778    space_id: String,
779    table_name: String,
780}
781
782/// JSON response used by empty-result operations.
783/// 用于空结果操作的 JSON 响应结构。
784#[derive(Serialize)]
785struct SuccessJsonResponse {
786    ok: bool,
787}
788
789/// JSON-friendly SQLite query-stream response that encodes chunks as base64 text.
790/// 将分块编码成 base64 文本的 JSON 友好 SQLite 流式查询响应。
791#[derive(Serialize)]
792struct QuerySqliteStreamJsonResponse {
793    chunks_base64: Vec<String>,
794    row_count: u64,
795    chunk_count: u64,
796    total_bytes: u64,
797}
798
799/// Internal SQLite stream compatibility result used by the current FFI layer.
800/// 当前 FFI 层使用的内部 SQLite 流式兼容结果。
801struct ControllerSqliteQueryStreamCompatResult {
802    chunks: Vec<Vec<u8>>,
803    row_count: u64,
804    chunk_count: u64,
805    total_bytes: u64,
806}
807
808/// Return the FFI package version.
809/// 返回 FFI 包版本号。
810#[unsafe(no_mangle)]
811pub extern "C" fn vldb_controller_ffi_version() -> *mut c_char {
812    string_into_raw(env!("CARGO_PKG_VERSION").to_string())
813}
814
815/// Free one string allocated by the FFI layer.
816/// 释放一条由 FFI 层分配的字符串。
817#[unsafe(no_mangle)]
818pub extern "C" fn vldb_controller_ffi_string_free(value: *mut c_char) {
819    if !value.is_null() {
820        unsafe {
821            drop(CString::from_raw(value));
822        }
823    }
824}
825
826/// Free one byte buffer allocated by the FFI layer.
827/// 释放一段由 FFI 层分配的字节缓冲区。
828#[unsafe(no_mangle)]
829pub extern "C" fn vldb_controller_ffi_bytes_free(data: *mut u8, len: usize) {
830    if !data.is_null() {
831        unsafe {
832            drop(Vec::from_raw_parts(data, len, len));
833        }
834    }
835}
836
837/// Create one controller client handle from native input structures.
838/// 从原生输入结构创建一个控制器客户端句柄。
839#[unsafe(no_mangle)]
840pub extern "C" fn vldb_controller_ffi_client_create(
841    config: *const FfiControllerClientConfig,
842    registration: *const FfiClientRegistration,
843    client_out: *mut *mut FfiControllerClientHandle,
844    error_out: *mut *mut c_char,
845) -> c_int {
846    if client_out.is_null() {
847        return ffi_error_status(error_out, "client_out pointer must not be null");
848    }
849
850    clear_out_ptr(client_out);
851    match native_client_create(config, registration) {
852        Ok(handle) => {
853            write_out_ptr(client_out, handle);
854            ffi_ok_status(error_out)
855        }
856        Err(error) => ffi_error_status(error_out, error),
857    }
858}
859
860/// Create one controller client handle from JSON input payloads.
861/// 从 JSON 输入载荷创建一个控制器客户端句柄。
862#[unsafe(no_mangle)]
863pub extern "C" fn vldb_controller_ffi_client_create_json(
864    request_json: *const c_char,
865    client_out: *mut *mut FfiControllerClientHandle,
866    response_out: *mut *mut c_char,
867    error_out: *mut *mut c_char,
868) -> c_int {
869    if client_out.is_null() {
870        return ffi_error_status(error_out, "client_out pointer must not be null");
871    }
872
873    clear_out_ptr(client_out);
874    clear_out_ptr(response_out);
875    let result = (|| -> Result<(*mut FfiControllerClientHandle, String), String> {
876        let request: CreateClientJsonRequest = parse_json_input(request_json)?;
877        let handle = build_client_handle(request.config, request.registration)?;
878        let response = serde_json::to_string(&SuccessJsonResponse { ok: true })
879            .map_err(|error| format!("failed to serialize create_client_json response: {error}"))?;
880        Ok((handle, response))
881    })();
882
883    match result {
884        Ok((handle, response)) => {
885            write_out_ptr(client_out, handle);
886            write_string_out(response_out, response);
887            ffi_ok_status(error_out)
888        }
889        Err(error) => ffi_error_status(error_out, error),
890    }
891}
892
893/// Free one controller client handle created by the FFI layer.
894/// 释放一个由 FFI 层创建的控制器客户端句柄。
895#[unsafe(no_mangle)]
896pub extern "C" fn vldb_controller_ffi_client_free(client: *mut FfiControllerClientHandle) {
897    let Ok(handle_id) = ffi_client_handle_id_from_ptr(client) else {
898        return;
899    };
900    let state = {
901        let mut registry = match ffi_client_handle_registry().lock() {
902            Ok(registry) => registry,
903            Err(poisoned) => poisoned.into_inner(),
904        };
905        registry.remove(&handle_id)
906    };
907    if let Some(state) = state {
908        let mut guard = match state.inner.lock() {
909            Ok(guard) => guard,
910            Err(poisoned) => poisoned.into_inner(),
911        };
912        if let Some(inner) = guard.take() {
913            let _ = inner.runtime.block_on(inner.client.shutdown());
914        }
915        unsafe {
916            drop(Box::from_raw(client));
917        }
918    }
919}
920
921/// Connect one controller client and start lease maintenance.
922/// 连接一个控制器客户端并启动租约维护。
923#[unsafe(no_mangle)]
924pub extern "C" fn vldb_controller_ffi_client_connect(
925    client: *mut FfiControllerClientHandle,
926    error_out: *mut *mut c_char,
927) -> c_int {
928    let result = with_client_handle(client, |handle| {
929        handle
930            .runtime
931            .block_on(handle.client.connect())
932            .map_err(error_to_string)
933    });
934    match result {
935        Ok(()) => ffi_ok_status(error_out),
936        Err(error) => ffi_error_status(error_out, error),
937    }
938}
939
940/// Connect one controller client using JSON mode.
941/// 使用 JSON 模式连接一个控制器客户端。
942#[unsafe(no_mangle)]
943pub extern "C" fn vldb_controller_ffi_client_connect_json(
944    client: *mut FfiControllerClientHandle,
945    request_json: *const c_char,
946    response_out: *mut *mut c_char,
947    error_out: *mut *mut c_char,
948) -> c_int {
949    clear_out_ptr(response_out);
950    let result = (|| -> Result<String, String> {
951        let _: EmptyJsonRequest = parse_json_input(request_json)?;
952        with_client_handle(client, |handle| {
953            handle
954                .runtime
955                .block_on(handle.client.connect())
956                .map_err(error_to_string)?;
957            serde_json::to_string(&SuccessJsonResponse { ok: true })
958                .map_err(|error| format!("failed to serialize connect_json response: {error}"))
959        })
960    })();
961    match result {
962        Ok(response) => {
963            write_string_out(response_out, response);
964            ffi_ok_status(error_out)
965        }
966        Err(error) => ffi_error_status(error_out, error),
967    }
968}
969
970/// Shutdown one controller client and unregister its lease explicitly.
971/// 关闭一个控制器客户端并显式注销其租约。
972#[unsafe(no_mangle)]
973pub extern "C" fn vldb_controller_ffi_client_shutdown(
974    client: *mut FfiControllerClientHandle,
975    error_out: *mut *mut c_char,
976) -> c_int {
977    let result = with_client_handle(client, |handle| {
978        handle
979            .runtime
980            .block_on(handle.client.shutdown())
981            .map_err(error_to_string)
982    });
983    match result {
984        Ok(()) => ffi_ok_status(error_out),
985        Err(error) => ffi_error_status(error_out, error),
986    }
987}
988
989/// Shutdown one controller client using JSON mode.
990/// 使用 JSON 模式关闭一个控制器客户端。
991#[unsafe(no_mangle)]
992pub extern "C" fn vldb_controller_ffi_client_shutdown_json(
993    client: *mut FfiControllerClientHandle,
994    request_json: *const c_char,
995    response_out: *mut *mut c_char,
996    error_out: *mut *mut c_char,
997) -> c_int {
998    clear_out_ptr(response_out);
999    let result = (|| -> Result<String, String> {
1000        let _: EmptyJsonRequest = parse_json_input(request_json)?;
1001        with_client_handle(client, |handle| {
1002            handle
1003                .runtime
1004                .block_on(handle.client.shutdown())
1005                .map_err(error_to_string)?;
1006            serde_json::to_string(&SuccessJsonResponse { ok: true })
1007                .map_err(|error| format!("failed to serialize shutdown_json response: {error}"))
1008        })
1009    })();
1010    match result {
1011        Ok(response) => {
1012            write_string_out(response_out, response);
1013            ffi_ok_status(error_out)
1014        }
1015        Err(error) => ffi_error_status(error_out, error),
1016    }
1017}
1018
1019/// Return one native controller status snapshot.
1020/// 返回一份原生控制器状态快照。
1021#[unsafe(no_mangle)]
1022pub extern "C" fn vldb_controller_ffi_client_get_status(
1023    client: *mut FfiControllerClientHandle,
1024    status_out: *mut *mut FfiControllerStatusSnapshot,
1025    error_out: *mut *mut c_char,
1026) -> c_int {
1027    clear_out_ptr(status_out);
1028    let result = with_client_handle(client, |handle| {
1029        handle
1030            .runtime
1031            .block_on(handle.client.get_status())
1032            .map_err(error_to_string)
1033    });
1034    match result {
1035        Ok(snapshot) => {
1036            write_boxed_out_ptr(status_out, map_status_snapshot(snapshot));
1037            ffi_ok_status(error_out)
1038        }
1039        Err(error) => ffi_error_status(error_out, error),
1040    }
1041}
1042
1043/// Return one JSON controller status snapshot.
1044/// 返回一份 JSON 控制器状态快照。
1045#[unsafe(no_mangle)]
1046pub extern "C" fn vldb_controller_ffi_client_get_status_json(
1047    client: *mut FfiControllerClientHandle,
1048    response_out: *mut *mut c_char,
1049    error_out: *mut *mut c_char,
1050) -> c_int {
1051    clear_out_ptr(response_out);
1052    let result = with_client_handle(client, |handle| {
1053        let snapshot = handle
1054            .runtime
1055            .block_on(handle.client.get_status())
1056            .map_err(error_to_string)?;
1057        serde_json::to_string(&snapshot)
1058            .map_err(|error| format!("failed to serialize get_status_json response: {error}"))
1059    });
1060    match result {
1061        Ok(response) => {
1062            write_string_out(response_out, response);
1063            ffi_ok_status(error_out)
1064        }
1065        Err(error) => ffi_error_status(error_out, error),
1066    }
1067}
1068
1069/// Free one native controller status snapshot.
1070/// 释放一份原生控制器状态快照。
1071#[unsafe(no_mangle)]
1072pub extern "C" fn vldb_controller_ffi_controller_status_free(
1073    status: *mut FfiControllerStatusSnapshot,
1074) {
1075    if !status.is_null() {
1076        unsafe {
1077            let status = Box::from_raw(status);
1078            vldb_controller_ffi_string_free(status.bind_addr);
1079        }
1080    }
1081}
1082
1083/// Attach one runtime space using native structured input.
1084/// 使用原生结构化输入附着一个运行时空间。
1085#[unsafe(no_mangle)]
1086pub extern "C" fn vldb_controller_ffi_client_attach_space(
1087    client: *mut FfiControllerClientHandle,
1088    registration: *const FfiSpaceRegistration,
1089    space_out: *mut *mut FfiSpaceSnapshot,
1090    error_out: *mut *mut c_char,
1091) -> c_int {
1092    clear_out_ptr(space_out);
1093    let result = (|| -> Result<SpaceSnapshot, String> {
1094        let registration = ffi_space_registration_to_rust(registration)?;
1095        with_client_handle(client, |handle| {
1096            handle
1097                .runtime
1098                .block_on(handle.client.attach_space(registration))
1099                .map_err(error_to_string)
1100        })
1101    })();
1102    match result {
1103        Ok(snapshot) => {
1104            write_boxed_out_ptr(space_out, map_space_snapshot(snapshot));
1105            ffi_ok_status(error_out)
1106        }
1107        Err(error) => ffi_error_status(error_out, error),
1108    }
1109}
1110
1111/// Attach one runtime space using JSON input and JSON output.
1112/// 使用 JSON 输入与 JSON 输出附着一个运行时空间。
1113#[unsafe(no_mangle)]
1114pub extern "C" fn vldb_controller_ffi_client_attach_space_json(
1115    client: *mut FfiControllerClientHandle,
1116    request_json: *const c_char,
1117    response_out: *mut *mut c_char,
1118    error_out: *mut *mut c_char,
1119) -> c_int {
1120    clear_out_ptr(response_out);
1121    let result = (|| -> Result<String, String> {
1122        let request: AttachSpaceJsonRequest = parse_json_input(request_json)?;
1123        let snapshot = with_client_handle(client, |handle| {
1124            handle
1125                .runtime
1126                .block_on(handle.client.attach_space(request.registration))
1127                .map_err(error_to_string)
1128        })?;
1129        serde_json::to_string(&snapshot)
1130            .map_err(|error| format!("failed to serialize attach_space_json response: {error}"))
1131    })();
1132    match result {
1133        Ok(response) => {
1134            write_string_out(response_out, response);
1135            ffi_ok_status(error_out)
1136        }
1137        Err(error) => ffi_error_status(error_out, error),
1138    }
1139}
1140
1141/// Detach one runtime space using native structured input.
1142/// 使用原生结构化输入解除一个运行时空间附着。
1143#[unsafe(no_mangle)]
1144pub extern "C" fn vldb_controller_ffi_client_detach_space(
1145    client: *mut FfiControllerClientHandle,
1146    space_id: *const c_char,
1147    detached_out: *mut c_uchar,
1148    error_out: *mut *mut c_char,
1149) -> c_int {
1150    clear_out_u8(detached_out);
1151    let result = (|| -> Result<bool, String> {
1152        let space_id = required_c_string(space_id, "space_id")?;
1153        with_client_handle(client, |handle| {
1154            handle
1155                .runtime
1156                .block_on(handle.client.detach_space(space_id))
1157                .map_err(error_to_string)
1158        })
1159    })();
1160    match result {
1161        Ok(detached) => {
1162            write_out_u8(detached_out, if detached { 1 } else { 0 });
1163            ffi_ok_status(error_out)
1164        }
1165        Err(error) => ffi_error_status(error_out, error),
1166    }
1167}
1168
1169/// Detach one runtime space using JSON input and JSON output.
1170/// 使用 JSON 输入与 JSON 输出解除一个运行时空间附着。
1171#[unsafe(no_mangle)]
1172pub extern "C" fn vldb_controller_ffi_client_detach_space_json(
1173    client: *mut FfiControllerClientHandle,
1174    request_json: *const c_char,
1175    response_out: *mut *mut c_char,
1176    error_out: *mut *mut c_char,
1177) -> c_int {
1178    clear_out_ptr(response_out);
1179    let result = (|| -> Result<String, String> {
1180        let request: DetachSpaceJsonRequest = parse_json_input(request_json)?;
1181        let detached = with_client_handle(client, |handle| {
1182            handle
1183                .runtime
1184                .block_on(handle.client.detach_space(request.space_id))
1185                .map_err(error_to_string)
1186        })?;
1187        serde_json::to_string(&detached)
1188            .map_err(|error| format!("failed to serialize detach_space_json response: {error}"))
1189    })();
1190    match result {
1191        Ok(response) => {
1192            write_string_out(response_out, response);
1193            ffi_ok_status(error_out)
1194        }
1195        Err(error) => ffi_error_status(error_out, error),
1196    }
1197}
1198
1199/// Return all known spaces using a native array payload.
1200/// 使用原生数组载荷返回全部已知空间。
1201#[unsafe(no_mangle)]
1202pub extern "C" fn vldb_controller_ffi_client_list_spaces(
1203    client: *mut FfiControllerClientHandle,
1204    spaces_out: *mut *mut FfiSpaceSnapshotArray,
1205    error_out: *mut *mut c_char,
1206) -> c_int {
1207    clear_out_ptr(spaces_out);
1208    let result = with_client_handle(client, |handle| {
1209        handle
1210            .runtime
1211            .block_on(handle.client.list_spaces())
1212            .map_err(error_to_string)
1213    });
1214    match result {
1215        Ok(spaces) => {
1216            let mapped = map_space_snapshot_array(spaces);
1217            write_boxed_out_ptr(spaces_out, mapped);
1218            ffi_ok_status(error_out)
1219        }
1220        Err(error) => ffi_error_status(error_out, error),
1221    }
1222}
1223
1224/// Return all known spaces using JSON mode.
1225/// 使用 JSON 模式返回全部已知空间。
1226#[unsafe(no_mangle)]
1227pub extern "C" fn vldb_controller_ffi_client_list_spaces_json(
1228    client: *mut FfiControllerClientHandle,
1229    response_out: *mut *mut c_char,
1230    error_out: *mut *mut c_char,
1231) -> c_int {
1232    clear_out_ptr(response_out);
1233    let result = with_client_handle(client, |handle| {
1234        let spaces = handle
1235            .runtime
1236            .block_on(handle.client.list_spaces())
1237            .map_err(error_to_string)?;
1238        serde_json::to_string(&spaces)
1239            .map_err(|error| format!("failed to serialize list_spaces_json response: {error}"))
1240    });
1241    match result {
1242        Ok(response) => {
1243            write_string_out(response_out, response);
1244            ffi_ok_status(error_out)
1245        }
1246        Err(error) => ffi_error_status(error_out, error),
1247    }
1248}
1249
1250/// Free one native space snapshot array.
1251/// 释放一份原生空间快照数组。
1252#[unsafe(no_mangle)]
1253pub extern "C" fn vldb_controller_ffi_space_snapshot_array_free(
1254    spaces: *mut FfiSpaceSnapshotArray,
1255) {
1256    if spaces.is_null() {
1257        return;
1258    }
1259    unsafe {
1260        let spaces = Box::from_raw(spaces);
1261        if !spaces.items.is_null() {
1262            let items = Vec::from_raw_parts(spaces.items, spaces.len, spaces.len);
1263            for item in items {
1264                free_space_snapshot_fields(item);
1265            }
1266        }
1267    }
1268}
1269
1270/// Free one native space snapshot returned by single-object APIs.
1271/// 释放由单对象接口返回的一份原生空间快照。
1272#[unsafe(no_mangle)]
1273pub extern "C" fn vldb_controller_ffi_space_snapshot_free(space: *mut FfiSpaceSnapshot) {
1274    if space.is_null() {
1275        return;
1276    }
1277    unsafe {
1278        let space = Box::from_raw(space);
1279        free_space_snapshot_fields(*space);
1280    }
1281}
1282
1283/// Enable one SQLite backend using native structured input.
1284/// 使用原生结构化输入启用一个 SQLite 后端。
1285#[unsafe(no_mangle)]
1286pub extern "C" fn vldb_controller_ffi_client_enable_sqlite(
1287    client: *mut FfiControllerClientHandle,
1288    request: *const FfiControllerSqliteEnableRequest,
1289    error_out: *mut *mut c_char,
1290) -> c_int {
1291    let result = (|| -> Result<(), String> {
1292        let request = ffi_sqlite_enable_request_to_rust(request)?;
1293        with_client_handle(client, |handle| {
1294            handle
1295                .runtime
1296                .block_on(handle.client.enable_sqlite(request))
1297                .map_err(error_to_string)
1298        })
1299    })();
1300    match result {
1301        Ok(()) => ffi_ok_status(error_out),
1302        Err(error) => ffi_error_status(error_out, error),
1303    }
1304}
1305
1306/// Enable one SQLite backend using JSON mode.
1307/// 使用 JSON 模式启用一个 SQLite 后端。
1308#[unsafe(no_mangle)]
1309pub extern "C" fn vldb_controller_ffi_client_enable_sqlite_json(
1310    client: *mut FfiControllerClientHandle,
1311    request_json: *const c_char,
1312    response_out: *mut *mut c_char,
1313    error_out: *mut *mut c_char,
1314) -> c_int {
1315    clear_out_ptr(response_out);
1316    let result = (|| -> Result<String, String> {
1317        let request: EnableSqliteJsonRequest = parse_json_input(request_json)?;
1318        with_client_handle(client, |handle| {
1319            handle
1320                .runtime
1321                .block_on(handle.client.enable_sqlite(request.request))
1322                .map_err(error_to_string)
1323        })?;
1324        serde_json::to_string(&SuccessJsonResponse { ok: true })
1325            .map_err(|error| format!("failed to serialize enable_sqlite_json response: {error}"))
1326    })();
1327    match result {
1328        Ok(response) => {
1329            write_string_out(response_out, response);
1330            ffi_ok_status(error_out)
1331        }
1332        Err(error) => ffi_error_status(error_out, error),
1333    }
1334}
1335
1336/// Disable one SQLite backend using native structured input.
1337/// 使用原生结构化输入关闭一个 SQLite 后端。
1338#[unsafe(no_mangle)]
1339pub extern "C" fn vldb_controller_ffi_client_disable_sqlite(
1340    client: *mut FfiControllerClientHandle,
1341    space_id: *const c_char,
1342    disabled_out: *mut c_uchar,
1343    error_out: *mut *mut c_char,
1344) -> c_int {
1345    clear_out_u8(disabled_out);
1346    let result = (|| -> Result<bool, String> {
1347        let space_id = required_c_string(space_id, "space_id")?;
1348        let binding_id = space_id.clone();
1349        with_client_handle(client, |handle| {
1350            handle
1351                .runtime
1352                .block_on(handle.client.disable_sqlite(space_id, binding_id))
1353                .map_err(error_to_string)
1354        })
1355    })();
1356    match result {
1357        Ok(disabled) => {
1358            write_out_u8(disabled_out, if disabled { 1 } else { 0 });
1359            ffi_ok_status(error_out)
1360        }
1361        Err(error) => ffi_error_status(error_out, error),
1362    }
1363}
1364
1365/// Disable one SQLite backend using JSON mode.
1366/// 使用 JSON 模式关闭一个 SQLite 后端。
1367#[unsafe(no_mangle)]
1368pub extern "C" fn vldb_controller_ffi_client_disable_sqlite_json(
1369    client: *mut FfiControllerClientHandle,
1370    request_json: *const c_char,
1371    response_out: *mut *mut c_char,
1372    error_out: *mut *mut c_char,
1373) -> c_int {
1374    clear_out_ptr(response_out);
1375    let result = (|| -> Result<String, String> {
1376        let request: DisableBackendJsonRequest = parse_json_input(request_json)?;
1377        let binding_id = request.space_id.clone();
1378        let disabled = with_client_handle(client, |handle| {
1379            handle
1380                .runtime
1381                .block_on(handle.client.disable_sqlite(request.space_id, binding_id))
1382                .map_err(error_to_string)
1383        })?;
1384        serde_json::to_string(&disabled)
1385            .map_err(|error| format!("failed to serialize disable_sqlite_json response: {error}"))
1386    })();
1387    match result {
1388        Ok(response) => {
1389            write_string_out(response_out, response);
1390            ffi_ok_status(error_out)
1391        }
1392        Err(error) => ffi_error_status(error_out, error),
1393    }
1394}
1395
1396/// Execute one SQLite script using native arguments.
1397/// 使用原生参数执行一条 SQLite 脚本。
1398#[unsafe(no_mangle)]
1399pub extern "C" fn vldb_controller_ffi_client_execute_sqlite_script(
1400    client: *mut FfiControllerClientHandle,
1401    space_id: *const c_char,
1402    sql: *const c_char,
1403    params: *const FfiSqliteValue,
1404    params_len: usize,
1405    result_out: *mut *mut FfiControllerSqliteExecuteResult,
1406    error_out: *mut *mut c_char,
1407) -> c_int {
1408    clear_out_ptr(result_out);
1409    let result = (|| -> Result<ControllerSqliteExecuteResult, String> {
1410        let space_id = required_c_string(space_id, "space_id")?;
1411        let binding_id = space_id.clone();
1412        let sql = required_c_string(sql, "sql")?;
1413        let params = read_sqlite_values(params, params_len, "params")?;
1414        with_client_handle(client, |handle| {
1415            handle
1416                .runtime
1417                .block_on(
1418                    handle
1419                        .client
1420                        .execute_sqlite_script_typed(space_id, binding_id, sql, params),
1421                )
1422                .map_err(error_to_string)
1423        })
1424    })();
1425    match result {
1426        Ok(result) => {
1427            write_boxed_out_ptr(result_out, map_sqlite_execute_result(result));
1428            ffi_ok_status(error_out)
1429        }
1430        Err(error) => ffi_error_status(error_out, error),
1431    }
1432}
1433
1434/// Execute one SQLite script using JSON mode.
1435/// 使用 JSON 模式执行一条 SQLite 脚本。
1436#[unsafe(no_mangle)]
1437pub extern "C" fn vldb_controller_ffi_client_execute_sqlite_script_json(
1438    client: *mut FfiControllerClientHandle,
1439    request_json: *const c_char,
1440    response_out: *mut *mut c_char,
1441    error_out: *mut *mut c_char,
1442) -> c_int {
1443    clear_out_ptr(response_out);
1444    let result = (|| -> Result<String, String> {
1445        let request: ExecuteSqliteScriptJsonRequest = parse_json_input(request_json)?;
1446        let binding_id = request.space_id.clone();
1447        let result = with_client_handle(client, |handle| {
1448            let params_json = serde_json::to_string(&request.params).map_err(|error| {
1449                format!("failed to serialize execute_sqlite_script_json params: {error}")
1450            })?;
1451            handle
1452                .runtime
1453                .block_on(handle.client.execute_sqlite_script(
1454                    request.space_id,
1455                    binding_id,
1456                    request.sql,
1457                    params_json,
1458                ))
1459                .map_err(error_to_string)
1460        })?;
1461        serde_json::to_string(&result).map_err(|error| {
1462            format!("failed to serialize execute_sqlite_script_json response: {error}")
1463        })
1464    })();
1465    match result {
1466        Ok(response) => {
1467            write_string_out(response_out, response);
1468            ffi_ok_status(error_out)
1469        }
1470        Err(error) => ffi_error_status(error_out, error),
1471    }
1472}
1473
1474/// Free one native SQLite execution result.
1475/// 释放一份原生 SQLite 执行结果。
1476#[unsafe(no_mangle)]
1477pub extern "C" fn vldb_controller_ffi_sqlite_execute_result_free(
1478    result: *mut FfiControllerSqliteExecuteResult,
1479) {
1480    if !result.is_null() {
1481        unsafe {
1482            let result = Box::from_raw(result);
1483            vldb_controller_ffi_string_free(result.message);
1484        }
1485    }
1486}
1487
1488/// Execute one SQLite JSON query using native arguments.
1489/// 使用原生参数执行一条 SQLite JSON 查询。
1490#[unsafe(no_mangle)]
1491pub extern "C" fn vldb_controller_ffi_client_query_sqlite_json(
1492    client: *mut FfiControllerClientHandle,
1493    space_id: *const c_char,
1494    sql: *const c_char,
1495    params: *const FfiSqliteValue,
1496    params_len: usize,
1497    result_out: *mut *mut FfiControllerSqliteQueryResult,
1498    error_out: *mut *mut c_char,
1499) -> c_int {
1500    clear_out_ptr(result_out);
1501    let result = (|| -> Result<ControllerSqliteQueryResult, String> {
1502        let space_id = required_c_string(space_id, "space_id")?;
1503        let binding_id = space_id.clone();
1504        let sql = required_c_string(sql, "sql")?;
1505        let params = read_sqlite_values(params, params_len, "params")?;
1506        with_client_handle(client, |handle| {
1507            handle
1508                .runtime
1509                .block_on(
1510                    handle
1511                        .client
1512                        .query_sqlite_json_typed(space_id, binding_id, sql, params),
1513                )
1514                .map_err(error_to_string)
1515        })
1516    })();
1517    match result {
1518        Ok(result) => {
1519            write_boxed_out_ptr(result_out, map_sqlite_query_result(result));
1520            ffi_ok_status(error_out)
1521        }
1522        Err(error) => ffi_error_status(error_out, error),
1523    }
1524}
1525
1526/// Execute one SQLite JSON query using JSON mode.
1527/// 使用 JSON 模式执行一条 SQLite JSON 查询。
1528#[unsafe(no_mangle)]
1529pub extern "C" fn vldb_controller_ffi_client_query_sqlite_json_json(
1530    client: *mut FfiControllerClientHandle,
1531    request_json: *const c_char,
1532    response_out: *mut *mut c_char,
1533    error_out: *mut *mut c_char,
1534) -> c_int {
1535    clear_out_ptr(response_out);
1536    let result = (|| -> Result<String, String> {
1537        let request: QuerySqliteJsonJsonRequest = parse_json_input(request_json)?;
1538        let binding_id = request.space_id.clone();
1539        let result = with_client_handle(client, |handle| {
1540            let params_json = serde_json::to_string(&request.params).map_err(|error| {
1541                format!("failed to serialize query_sqlite_json_json params: {error}")
1542            })?;
1543            handle
1544                .runtime
1545                .block_on(handle.client.query_sqlite_json(
1546                    request.space_id,
1547                    binding_id,
1548                    request.sql,
1549                    params_json,
1550                ))
1551                .map_err(error_to_string)
1552        })?;
1553        serde_json::to_string(&result).map_err(|error| {
1554            format!("failed to serialize query_sqlite_json_json response: {error}")
1555        })
1556    })();
1557    match result {
1558        Ok(response) => {
1559            write_string_out(response_out, response);
1560            ffi_ok_status(error_out)
1561        }
1562        Err(error) => ffi_error_status(error_out, error),
1563    }
1564}
1565
1566/// Free one native SQLite JSON query result.
1567/// 释放一份原生 SQLite JSON 查询结果。
1568#[unsafe(no_mangle)]
1569pub extern "C" fn vldb_controller_ffi_sqlite_query_result_free(
1570    result: *mut FfiControllerSqliteQueryResult,
1571) {
1572    if !result.is_null() {
1573        unsafe {
1574            let result = Box::from_raw(result);
1575            vldb_controller_ffi_string_free(result.json_data);
1576        }
1577    }
1578}
1579
1580/// Execute one SQLite batch using native arguments.
1581/// 使用原生参数执行一组 SQLite 批量语句。
1582#[unsafe(no_mangle)]
1583pub extern "C" fn vldb_controller_ffi_client_execute_sqlite_batch(
1584    client: *mut FfiControllerClientHandle,
1585    space_id: *const c_char,
1586    sql: *const c_char,
1587    items: *const FfiSqliteBatchItem,
1588    items_len: usize,
1589    result_out: *mut *mut FfiControllerSqliteExecuteBatchResult,
1590    error_out: *mut *mut c_char,
1591) -> c_int {
1592    clear_out_ptr(result_out);
1593    let result = (|| -> Result<ControllerSqliteExecuteBatchResult, String> {
1594        let space_id = required_c_string(space_id, "space_id")?;
1595        let binding_id = space_id.clone();
1596        let sql = required_c_string(sql, "sql")?;
1597        let items = read_sqlite_batch_items(items, items_len, "items")?;
1598        with_client_handle(client, |handle| {
1599            handle
1600                .runtime
1601                .block_on(
1602                    handle
1603                        .client
1604                        .execute_sqlite_batch_typed(space_id, binding_id, sql, items),
1605                )
1606                .map_err(error_to_string)
1607        })
1608    })();
1609    match result {
1610        Ok(result) => {
1611            write_boxed_out_ptr(result_out, map_sqlite_execute_batch_result(result));
1612            ffi_ok_status(error_out)
1613        }
1614        Err(error) => ffi_error_status(error_out, error),
1615    }
1616}
1617
1618/// Execute one SQLite batch using JSON mode.
1619/// 使用 JSON 模式执行一组 SQLite 批量语句。
1620#[unsafe(no_mangle)]
1621pub extern "C" fn vldb_controller_ffi_client_execute_sqlite_batch_json(
1622    client: *mut FfiControllerClientHandle,
1623    request_json: *const c_char,
1624    response_out: *mut *mut c_char,
1625    error_out: *mut *mut c_char,
1626) -> c_int {
1627    clear_out_ptr(response_out);
1628    let result = (|| -> Result<String, String> {
1629        let request: ExecuteSqliteBatchJsonRequest = parse_json_input(request_json)?;
1630        let binding_id = request.space_id.clone();
1631        let result = with_client_handle(client, |handle| {
1632            let batch_params_json = request
1633                .batch_params
1634                .iter()
1635                .map(|item| {
1636                    serde_json::to_string(item).map_err(|error| {
1637                        format!(
1638                            "failed to serialize execute_sqlite_batch_json batch_params item: {error}"
1639                        )
1640                    })
1641                })
1642                .collect::<Result<Vec<_>, _>>()?;
1643            handle
1644                .runtime
1645                .block_on(handle.client.execute_sqlite_batch(
1646                    request.space_id,
1647                    binding_id,
1648                    request.sql,
1649                    batch_params_json,
1650                ))
1651                .map_err(error_to_string)
1652        })?;
1653        serde_json::to_string(&result).map_err(|error| {
1654            format!("failed to serialize execute_sqlite_batch_json response: {error}")
1655        })
1656    })();
1657    match result {
1658        Ok(response) => {
1659            write_string_out(response_out, response);
1660            ffi_ok_status(error_out)
1661        }
1662        Err(error) => ffi_error_status(error_out, error),
1663    }
1664}
1665
1666/// Free one native SQLite batch execution result.
1667/// 释放一份原生 SQLite 批量执行结果。
1668#[unsafe(no_mangle)]
1669pub extern "C" fn vldb_controller_ffi_sqlite_execute_batch_result_free(
1670    result: *mut FfiControllerSqliteExecuteBatchResult,
1671) {
1672    if !result.is_null() {
1673        unsafe {
1674            let result = Box::from_raw(result);
1675            vldb_controller_ffi_string_free(result.message);
1676        }
1677    }
1678}
1679
1680/// Execute one SQLite streaming query using native arguments.
1681/// 使用原生参数执行一条 SQLite 流式查询。
1682#[unsafe(no_mangle)]
1683pub extern "C" fn vldb_controller_ffi_client_query_sqlite_stream(
1684    client: *mut FfiControllerClientHandle,
1685    space_id: *const c_char,
1686    sql: *const c_char,
1687    params: *const FfiSqliteValue,
1688    params_len: usize,
1689    target_chunk_size: c_ulonglong,
1690    result_out: *mut *mut FfiControllerSqliteQueryStreamResult,
1691    error_out: *mut *mut c_char,
1692) -> c_int {
1693    clear_out_ptr(result_out);
1694    let result = (|| -> Result<ControllerSqliteQueryStreamCompatResult, String> {
1695        let space_id = required_c_string(space_id, "space_id")?;
1696        let binding_id = space_id.clone();
1697        let sql = required_c_string(sql, "sql")?;
1698        let params = read_sqlite_values(params, params_len, "params")?;
1699        let chunk_size = if target_chunk_size == 0 {
1700            None
1701        } else {
1702            Some(target_chunk_size)
1703        };
1704        with_client_handle(client, |handle| {
1705            collect_sqlite_query_stream_result(
1706                &handle.runtime,
1707                &handle.client,
1708                space_id,
1709                binding_id,
1710                sql,
1711                params,
1712                chunk_size,
1713            )
1714        })
1715    })();
1716    match result {
1717        Ok(result) => {
1718            write_boxed_out_ptr(result_out, map_sqlite_query_stream_result(result));
1719            ffi_ok_status(error_out)
1720        }
1721        Err(error) => ffi_error_status(error_out, error),
1722    }
1723}
1724
1725/// Execute one SQLite streaming query using JSON mode.
1726/// 使用 JSON 模式执行一条 SQLite 流式查询。
1727#[unsafe(no_mangle)]
1728pub extern "C" fn vldb_controller_ffi_client_query_sqlite_stream_json(
1729    client: *mut FfiControllerClientHandle,
1730    request_json: *const c_char,
1731    response_out: *mut *mut c_char,
1732    error_out: *mut *mut c_char,
1733) -> c_int {
1734    clear_out_ptr(response_out);
1735    let result = (|| -> Result<String, String> {
1736        let request: QuerySqliteStreamJsonRequest = parse_json_input(request_json)?;
1737        let binding_id = request.space_id.clone();
1738        let result = with_client_handle(client, |handle| {
1739            let params = request
1740                .params
1741                .iter()
1742                .cloned()
1743                .map(json_to_sqlite_value)
1744                .collect::<Result<Vec<_>, _>>()?;
1745            collect_sqlite_query_stream_result(
1746                &handle.runtime,
1747                &handle.client,
1748                request.space_id,
1749                binding_id,
1750                request.sql,
1751                params,
1752                request.target_chunk_size,
1753            )
1754        })?;
1755        serde_json::to_string(&QuerySqliteStreamJsonResponse {
1756            chunks_base64: result
1757                .chunks
1758                .iter()
1759                .map(|chunk| encode_base64(chunk))
1760                .collect(),
1761            row_count: result.row_count,
1762            chunk_count: result.chunk_count,
1763            total_bytes: result.total_bytes,
1764        })
1765        .map_err(|error| format!("failed to serialize query_sqlite_stream_json response: {error}"))
1766    })();
1767    match result {
1768        Ok(response) => {
1769            write_string_out(response_out, response);
1770            ffi_ok_status(error_out)
1771        }
1772        Err(error) => ffi_error_status(error_out, error),
1773    }
1774}
1775
1776/// Free one native SQLite streaming query result.
1777/// 释放一份原生 SQLite 流式查询结果。
1778#[unsafe(no_mangle)]
1779pub extern "C" fn vldb_controller_ffi_sqlite_query_stream_result_free(
1780    result: *mut FfiControllerSqliteQueryStreamResult,
1781) {
1782    if !result.is_null() {
1783        unsafe {
1784            let result = Box::from_raw(result);
1785            vldb_controller_ffi_byte_buffer_array_free(result.chunks);
1786        }
1787    }
1788}
1789
1790/// Free one native byte-buffer array.
1791/// 释放一份原生字节缓冲数组。
1792#[unsafe(no_mangle)]
1793pub extern "C" fn vldb_controller_ffi_byte_buffer_array_free(value: *mut FfiByteBufferArray) {
1794    if value.is_null() {
1795        return;
1796    }
1797    unsafe {
1798        let value = Box::from_raw(value);
1799        if !value.items.is_null() {
1800            let items = Vec::from_raw_parts(value.items, value.len, value.len);
1801            for item in items {
1802                vldb_controller_ffi_bytes_free(item.data, item.len);
1803            }
1804        }
1805    }
1806}
1807
1808/// Tokenize SQLite text using native arguments.
1809/// 使用原生参数执行 SQLite 文本分词。
1810#[unsafe(no_mangle)]
1811pub extern "C" fn vldb_controller_ffi_client_tokenize_sqlite_text(
1812    client: *mut FfiControllerClientHandle,
1813    space_id: *const c_char,
1814    tokenizer_mode: *const c_char,
1815    text: *const c_char,
1816    search_mode: c_uchar,
1817    result_out: *mut *mut FfiControllerSqliteTokenizeResult,
1818    error_out: *mut *mut c_char,
1819) -> c_int {
1820    clear_out_ptr(result_out);
1821    let result = (|| -> Result<ControllerSqliteTokenizeResult, String> {
1822        let space_id = required_c_string(space_id, "space_id")?;
1823        let binding_id = space_id.clone();
1824        let tokenizer_mode = parse_sqlite_tokenizer_mode_text(tokenizer_mode)?;
1825        let text = required_c_string_preserve(text, "text")?;
1826        with_client_handle(client, |handle| {
1827            handle
1828                .runtime
1829                .block_on(handle.client.tokenize_sqlite_text(
1830                    space_id,
1831                    binding_id,
1832                    tokenizer_mode,
1833                    text,
1834                    search_mode != 0,
1835                ))
1836                .map_err(error_to_string)
1837        })
1838    })();
1839    match result {
1840        Ok(result) => {
1841            write_boxed_out_ptr(result_out, map_sqlite_tokenize_result(result));
1842            ffi_ok_status(error_out)
1843        }
1844        Err(error) => ffi_error_status(error_out, error),
1845    }
1846}
1847
1848/// Tokenize SQLite text using JSON mode.
1849/// 使用 JSON 模式执行 SQLite 文本分词。
1850#[unsafe(no_mangle)]
1851pub extern "C" fn vldb_controller_ffi_client_tokenize_sqlite_text_json(
1852    client: *mut FfiControllerClientHandle,
1853    request_json: *const c_char,
1854    response_out: *mut *mut c_char,
1855    error_out: *mut *mut c_char,
1856) -> c_int {
1857    clear_out_ptr(response_out);
1858    let result = (|| -> Result<String, String> {
1859        let request: TokenizeSqliteTextJsonRequest = parse_json_input(request_json)?;
1860        let binding_id = request.space_id.clone();
1861        let tokenizer_mode = parse_sqlite_tokenizer_mode_name(&request.tokenizer_mode)?;
1862        let result = with_client_handle(client, |handle| {
1863            handle
1864                .runtime
1865                .block_on(handle.client.tokenize_sqlite_text(
1866                    request.space_id,
1867                    binding_id,
1868                    tokenizer_mode,
1869                    request.text,
1870                    request.search_mode,
1871                ))
1872                .map_err(error_to_string)
1873        })?;
1874        serde_json::to_string(&result).map_err(|error| {
1875            format!("failed to serialize tokenize_sqlite_text_json response: {error}")
1876        })
1877    })();
1878    match result {
1879        Ok(response) => {
1880            write_string_out(response_out, response);
1881            ffi_ok_status(error_out)
1882        }
1883        Err(error) => ffi_error_status(error_out, error),
1884    }
1885}
1886
1887/// Free one native SQLite tokenize result.
1888/// 释放一份原生 SQLite 分词结果。
1889#[unsafe(no_mangle)]
1890pub extern "C" fn vldb_controller_ffi_sqlite_tokenize_result_free(
1891    result: *mut FfiControllerSqliteTokenizeResult,
1892) {
1893    if !result.is_null() {
1894        unsafe {
1895            let result = Box::from_raw(result);
1896            vldb_controller_ffi_string_free(result.tokenizer_mode);
1897            vldb_controller_ffi_string_free(result.normalized_text);
1898            vldb_controller_ffi_string_free(result.tokens_json);
1899            vldb_controller_ffi_string_free(result.fts_query);
1900        }
1901    }
1902}
1903
1904/// List SQLite custom words using native arguments.
1905/// 使用原生参数列出 SQLite 自定义词。
1906#[unsafe(no_mangle)]
1907pub extern "C" fn vldb_controller_ffi_client_list_sqlite_custom_words(
1908    client: *mut FfiControllerClientHandle,
1909    space_id: *const c_char,
1910    result_out: *mut *mut FfiControllerSqliteListCustomWordsResult,
1911    error_out: *mut *mut c_char,
1912) -> c_int {
1913    clear_out_ptr(result_out);
1914    let result = (|| -> Result<ControllerSqliteListCustomWordsResult, String> {
1915        let space_id = required_c_string(space_id, "space_id")?;
1916        let binding_id = space_id.clone();
1917        with_client_handle(client, |handle| {
1918            handle
1919                .runtime
1920                .block_on(handle.client.list_sqlite_custom_words(space_id, binding_id))
1921                .map_err(error_to_string)
1922        })
1923    })();
1924    match result {
1925        Ok(result) => {
1926            write_boxed_out_ptr(result_out, map_sqlite_list_custom_words_result(result));
1927            ffi_ok_status(error_out)
1928        }
1929        Err(error) => ffi_error_status(error_out, error),
1930    }
1931}
1932
1933/// List SQLite custom words using JSON mode.
1934/// 使用 JSON 模式列出 SQLite 自定义词。
1935#[unsafe(no_mangle)]
1936pub extern "C" fn vldb_controller_ffi_client_list_sqlite_custom_words_json(
1937    client: *mut FfiControllerClientHandle,
1938    request_json: *const c_char,
1939    response_out: *mut *mut c_char,
1940    error_out: *mut *mut c_char,
1941) -> c_int {
1942    clear_out_ptr(response_out);
1943    let result = (|| -> Result<String, String> {
1944        let request: ListSqliteCustomWordsJsonRequest = parse_json_input(request_json)?;
1945        let binding_id = request.space_id.clone();
1946        let result = with_client_handle(client, |handle| {
1947            handle
1948                .runtime
1949                .block_on(
1950                    handle
1951                        .client
1952                        .list_sqlite_custom_words(request.space_id, binding_id),
1953                )
1954                .map_err(error_to_string)
1955        })?;
1956        serde_json::to_string(&result).map_err(|error| {
1957            format!("failed to serialize list_sqlite_custom_words_json response: {error}")
1958        })
1959    })();
1960    match result {
1961        Ok(response) => {
1962            write_string_out(response_out, response);
1963            ffi_ok_status(error_out)
1964        }
1965        Err(error) => ffi_error_status(error_out, error),
1966    }
1967}
1968
1969/// Free one native SQLite custom-word array.
1970/// 释放一份原生 SQLite 自定义词数组。
1971#[unsafe(no_mangle)]
1972pub extern "C" fn vldb_controller_ffi_sqlite_custom_word_array_free(
1973    value: *mut FfiControllerSqliteCustomWordArray,
1974) {
1975    if value.is_null() {
1976        return;
1977    }
1978    unsafe {
1979        let value = Box::from_raw(value);
1980        if !value.items.is_null() {
1981            let items = Vec::from_raw_parts(value.items, value.len, value.len);
1982            for item in items {
1983                vldb_controller_ffi_string_free(item.word);
1984            }
1985        }
1986    }
1987}
1988
1989/// Free one native SQLite custom-word listing result.
1990/// 释放一份原生 SQLite 自定义词列表结果。
1991#[unsafe(no_mangle)]
1992pub extern "C" fn vldb_controller_ffi_sqlite_list_custom_words_result_free(
1993    result: *mut FfiControllerSqliteListCustomWordsResult,
1994) {
1995    if !result.is_null() {
1996        unsafe {
1997            let result = Box::from_raw(result);
1998            vldb_controller_ffi_string_free(result.message);
1999            vldb_controller_ffi_sqlite_custom_word_array_free(result.words);
2000        }
2001    }
2002}
2003
2004/// Upsert one SQLite custom word using native arguments.
2005/// 使用原生参数写入一条 SQLite 自定义词。
2006#[unsafe(no_mangle)]
2007pub extern "C" fn vldb_controller_ffi_client_upsert_sqlite_custom_word(
2008    client: *mut FfiControllerClientHandle,
2009    space_id: *const c_char,
2010    word: *const c_char,
2011    weight: u32,
2012    result_out: *mut *mut FfiControllerSqliteDictionaryMutationResult,
2013    error_out: *mut *mut c_char,
2014) -> c_int {
2015    clear_out_ptr(result_out);
2016    let result = (|| -> Result<ControllerSqliteDictionaryMutationResult, String> {
2017        let space_id = required_c_string(space_id, "space_id")?;
2018        let binding_id = space_id.clone();
2019        let word = required_c_string(word, "word")?;
2020        with_client_handle(client, |handle| {
2021            handle
2022                .runtime
2023                .block_on(
2024                    handle
2025                        .client
2026                        .upsert_sqlite_custom_word(space_id, binding_id, word, weight),
2027                )
2028                .map_err(error_to_string)
2029        })
2030    })();
2031    match result {
2032        Ok(result) => {
2033            write_boxed_out_ptr(result_out, map_sqlite_dictionary_mutation_result(result));
2034            ffi_ok_status(error_out)
2035        }
2036        Err(error) => ffi_error_status(error_out, error),
2037    }
2038}
2039
2040/// Upsert one SQLite custom word using JSON mode.
2041/// 使用 JSON 模式写入一条 SQLite 自定义词。
2042#[unsafe(no_mangle)]
2043pub extern "C" fn vldb_controller_ffi_client_upsert_sqlite_custom_word_json(
2044    client: *mut FfiControllerClientHandle,
2045    request_json: *const c_char,
2046    response_out: *mut *mut c_char,
2047    error_out: *mut *mut c_char,
2048) -> c_int {
2049    clear_out_ptr(response_out);
2050    let result = (|| -> Result<String, String> {
2051        let request: UpsertSqliteCustomWordJsonRequest = parse_json_input(request_json)?;
2052        let binding_id = request.space_id.clone();
2053        let result = with_client_handle(client, |handle| {
2054            handle
2055                .runtime
2056                .block_on(handle.client.upsert_sqlite_custom_word(
2057                    request.space_id,
2058                    binding_id,
2059                    request.word,
2060                    request.weight,
2061                ))
2062                .map_err(error_to_string)
2063        })?;
2064        serde_json::to_string(&result).map_err(|error| {
2065            format!("failed to serialize upsert_sqlite_custom_word_json response: {error}")
2066        })
2067    })();
2068    match result {
2069        Ok(response) => {
2070            write_string_out(response_out, response);
2071            ffi_ok_status(error_out)
2072        }
2073        Err(error) => ffi_error_status(error_out, error),
2074    }
2075}
2076
2077/// Remove one SQLite custom word using native arguments.
2078/// 使用原生参数删除一条 SQLite 自定义词。
2079#[unsafe(no_mangle)]
2080pub extern "C" fn vldb_controller_ffi_client_remove_sqlite_custom_word(
2081    client: *mut FfiControllerClientHandle,
2082    space_id: *const c_char,
2083    word: *const c_char,
2084    result_out: *mut *mut FfiControllerSqliteDictionaryMutationResult,
2085    error_out: *mut *mut c_char,
2086) -> c_int {
2087    clear_out_ptr(result_out);
2088    let result = (|| -> Result<ControllerSqliteDictionaryMutationResult, String> {
2089        let space_id = required_c_string(space_id, "space_id")?;
2090        let binding_id = space_id.clone();
2091        let word = required_c_string(word, "word")?;
2092        with_client_handle(client, |handle| {
2093            handle
2094                .runtime
2095                .block_on(
2096                    handle
2097                        .client
2098                        .remove_sqlite_custom_word(space_id, binding_id, word),
2099                )
2100                .map_err(error_to_string)
2101        })
2102    })();
2103    match result {
2104        Ok(result) => {
2105            write_boxed_out_ptr(result_out, map_sqlite_dictionary_mutation_result(result));
2106            ffi_ok_status(error_out)
2107        }
2108        Err(error) => ffi_error_status(error_out, error),
2109    }
2110}
2111
2112/// Remove one SQLite custom word using JSON mode.
2113/// 使用 JSON 模式删除一条 SQLite 自定义词。
2114#[unsafe(no_mangle)]
2115pub extern "C" fn vldb_controller_ffi_client_remove_sqlite_custom_word_json(
2116    client: *mut FfiControllerClientHandle,
2117    request_json: *const c_char,
2118    response_out: *mut *mut c_char,
2119    error_out: *mut *mut c_char,
2120) -> c_int {
2121    clear_out_ptr(response_out);
2122    let result = (|| -> Result<String, String> {
2123        let request: RemoveSqliteCustomWordJsonRequest = parse_json_input(request_json)?;
2124        let binding_id = request.space_id.clone();
2125        let result = with_client_handle(client, |handle| {
2126            handle
2127                .runtime
2128                .block_on(handle.client.remove_sqlite_custom_word(
2129                    request.space_id,
2130                    binding_id,
2131                    request.word,
2132                ))
2133                .map_err(error_to_string)
2134        })?;
2135        serde_json::to_string(&result).map_err(|error| {
2136            format!("failed to serialize remove_sqlite_custom_word_json response: {error}")
2137        })
2138    })();
2139    match result {
2140        Ok(response) => {
2141            write_string_out(response_out, response);
2142            ffi_ok_status(error_out)
2143        }
2144        Err(error) => ffi_error_status(error_out, error),
2145    }
2146}
2147
2148/// Free one native SQLite dictionary mutation result.
2149/// 释放一份原生 SQLite 词典变更结果。
2150#[unsafe(no_mangle)]
2151pub extern "C" fn vldb_controller_ffi_sqlite_dictionary_mutation_result_free(
2152    result: *mut FfiControllerSqliteDictionaryMutationResult,
2153) {
2154    if !result.is_null() {
2155        unsafe {
2156            let result = Box::from_raw(result);
2157            vldb_controller_ffi_string_free(result.message);
2158        }
2159    }
2160}
2161
2162/// Ensure one SQLite FTS index using native arguments.
2163/// 使用原生参数确认一条 SQLite FTS 索引。
2164#[unsafe(no_mangle)]
2165pub extern "C" fn vldb_controller_ffi_client_ensure_sqlite_fts_index(
2166    client: *mut FfiControllerClientHandle,
2167    space_id: *const c_char,
2168    index_name: *const c_char,
2169    tokenizer_mode: *const c_char,
2170    result_out: *mut *mut FfiControllerSqliteEnsureFtsIndexResult,
2171    error_out: *mut *mut c_char,
2172) -> c_int {
2173    clear_out_ptr(result_out);
2174    let result = (|| -> Result<ControllerSqliteEnsureFtsIndexResult, String> {
2175        let space_id = required_c_string(space_id, "space_id")?;
2176        let binding_id = space_id.clone();
2177        let index_name = required_c_string(index_name, "index_name")?;
2178        let tokenizer_mode = parse_sqlite_tokenizer_mode_text(tokenizer_mode)?;
2179        with_client_handle(client, |handle| {
2180            handle
2181                .runtime
2182                .block_on(handle.client.ensure_sqlite_fts_index(
2183                    space_id,
2184                    binding_id,
2185                    index_name,
2186                    tokenizer_mode,
2187                ))
2188                .map_err(error_to_string)
2189        })
2190    })();
2191    match result {
2192        Ok(result) => {
2193            write_boxed_out_ptr(result_out, map_sqlite_ensure_fts_index_result(result));
2194            ffi_ok_status(error_out)
2195        }
2196        Err(error) => ffi_error_status(error_out, error),
2197    }
2198}
2199
2200/// Ensure one SQLite FTS index using JSON mode.
2201/// 使用 JSON 模式确认一条 SQLite FTS 索引。
2202#[unsafe(no_mangle)]
2203pub extern "C" fn vldb_controller_ffi_client_ensure_sqlite_fts_index_json(
2204    client: *mut FfiControllerClientHandle,
2205    request_json: *const c_char,
2206    response_out: *mut *mut c_char,
2207    error_out: *mut *mut c_char,
2208) -> c_int {
2209    clear_out_ptr(response_out);
2210    let result = (|| -> Result<String, String> {
2211        let request: EnsureSqliteFtsIndexJsonRequest = parse_json_input(request_json)?;
2212        let binding_id = request.space_id.clone();
2213        let tokenizer_mode = parse_sqlite_tokenizer_mode_name(&request.tokenizer_mode)?;
2214        let result = with_client_handle(client, |handle| {
2215            handle
2216                .runtime
2217                .block_on(handle.client.ensure_sqlite_fts_index(
2218                    request.space_id,
2219                    binding_id,
2220                    request.index_name,
2221                    tokenizer_mode,
2222                ))
2223                .map_err(error_to_string)
2224        })?;
2225        serde_json::to_string(&result).map_err(|error| {
2226            format!("failed to serialize ensure_sqlite_fts_index_json response: {error}")
2227        })
2228    })();
2229    match result {
2230        Ok(response) => {
2231            write_string_out(response_out, response);
2232            ffi_ok_status(error_out)
2233        }
2234        Err(error) => ffi_error_status(error_out, error),
2235    }
2236}
2237
2238/// Free one native SQLite ensure-FTS result.
2239/// 释放一份原生 SQLite FTS 确认结果。
2240#[unsafe(no_mangle)]
2241pub extern "C" fn vldb_controller_ffi_sqlite_ensure_fts_index_result_free(
2242    result: *mut FfiControllerSqliteEnsureFtsIndexResult,
2243) {
2244    if !result.is_null() {
2245        unsafe {
2246            let result = Box::from_raw(result);
2247            vldb_controller_ffi_string_free(result.message);
2248            vldb_controller_ffi_string_free(result.index_name);
2249            vldb_controller_ffi_string_free(result.tokenizer_mode);
2250        }
2251    }
2252}
2253
2254/// Rebuild one SQLite FTS index using native arguments.
2255/// 使用原生参数重建一条 SQLite FTS 索引。
2256#[unsafe(no_mangle)]
2257pub extern "C" fn vldb_controller_ffi_client_rebuild_sqlite_fts_index(
2258    client: *mut FfiControllerClientHandle,
2259    space_id: *const c_char,
2260    index_name: *const c_char,
2261    tokenizer_mode: *const c_char,
2262    result_out: *mut *mut FfiControllerSqliteRebuildFtsIndexResult,
2263    error_out: *mut *mut c_char,
2264) -> c_int {
2265    clear_out_ptr(result_out);
2266    let result = (|| -> Result<ControllerSqliteRebuildFtsIndexResult, String> {
2267        let space_id = required_c_string(space_id, "space_id")?;
2268        let binding_id = space_id.clone();
2269        let index_name = required_c_string(index_name, "index_name")?;
2270        let tokenizer_mode = parse_sqlite_tokenizer_mode_text(tokenizer_mode)?;
2271        with_client_handle(client, |handle| {
2272            handle
2273                .runtime
2274                .block_on(handle.client.rebuild_sqlite_fts_index(
2275                    space_id,
2276                    binding_id,
2277                    index_name,
2278                    tokenizer_mode,
2279                ))
2280                .map_err(error_to_string)
2281        })
2282    })();
2283    match result {
2284        Ok(result) => {
2285            write_boxed_out_ptr(result_out, map_sqlite_rebuild_fts_index_result(result));
2286            ffi_ok_status(error_out)
2287        }
2288        Err(error) => ffi_error_status(error_out, error),
2289    }
2290}
2291
2292/// Rebuild one SQLite FTS index using JSON mode.
2293/// 使用 JSON 模式重建一条 SQLite FTS 索引。
2294#[unsafe(no_mangle)]
2295pub extern "C" fn vldb_controller_ffi_client_rebuild_sqlite_fts_index_json(
2296    client: *mut FfiControllerClientHandle,
2297    request_json: *const c_char,
2298    response_out: *mut *mut c_char,
2299    error_out: *mut *mut c_char,
2300) -> c_int {
2301    clear_out_ptr(response_out);
2302    let result = (|| -> Result<String, String> {
2303        let request: RebuildSqliteFtsIndexJsonRequest = parse_json_input(request_json)?;
2304        let binding_id = request.space_id.clone();
2305        let tokenizer_mode = parse_sqlite_tokenizer_mode_name(&request.tokenizer_mode)?;
2306        let result = with_client_handle(client, |handle| {
2307            handle
2308                .runtime
2309                .block_on(handle.client.rebuild_sqlite_fts_index(
2310                    request.space_id,
2311                    binding_id,
2312                    request.index_name,
2313                    tokenizer_mode,
2314                ))
2315                .map_err(error_to_string)
2316        })?;
2317        serde_json::to_string(&result).map_err(|error| {
2318            format!("failed to serialize rebuild_sqlite_fts_index_json response: {error}")
2319        })
2320    })();
2321    match result {
2322        Ok(response) => {
2323            write_string_out(response_out, response);
2324            ffi_ok_status(error_out)
2325        }
2326        Err(error) => ffi_error_status(error_out, error),
2327    }
2328}
2329
2330/// Free one native SQLite rebuild-FTS result.
2331/// 释放一份原生 SQLite FTS 重建结果。
2332#[unsafe(no_mangle)]
2333pub extern "C" fn vldb_controller_ffi_sqlite_rebuild_fts_index_result_free(
2334    result: *mut FfiControllerSqliteRebuildFtsIndexResult,
2335) {
2336    if !result.is_null() {
2337        unsafe {
2338            let result = Box::from_raw(result);
2339            vldb_controller_ffi_string_free(result.message);
2340            vldb_controller_ffi_string_free(result.index_name);
2341            vldb_controller_ffi_string_free(result.tokenizer_mode);
2342        }
2343    }
2344}
2345
2346/// Upsert one SQLite FTS document using native arguments.
2347/// 使用原生参数写入一条 SQLite FTS 文档。
2348#[unsafe(no_mangle)]
2349#[allow(clippy::too_many_arguments)]
2350pub extern "C" fn vldb_controller_ffi_client_upsert_sqlite_fts_document(
2351    client: *mut FfiControllerClientHandle,
2352    space_id: *const c_char,
2353    index_name: *const c_char,
2354    tokenizer_mode: *const c_char,
2355    id: *const c_char,
2356    file_path: *const c_char,
2357    title: *const c_char,
2358    content: *const c_char,
2359    result_out: *mut *mut FfiControllerSqliteFtsMutationResult,
2360    error_out: *mut *mut c_char,
2361) -> c_int {
2362    clear_out_ptr(result_out);
2363    let result = (|| -> Result<ControllerSqliteFtsMutationResult, String> {
2364        let space_id = required_c_string(space_id, "space_id")?;
2365        let binding_id = space_id.clone();
2366        let index_name = required_c_string(index_name, "index_name")?;
2367        let tokenizer_mode = parse_sqlite_tokenizer_mode_text(tokenizer_mode)?;
2368        let id = required_c_string(id, "id")?;
2369        let file_path = required_c_string_preserve(file_path, "file_path")?;
2370        let title = required_c_string_preserve(title, "title")?;
2371        let content = required_c_string_preserve(content, "content")?;
2372        with_client_handle(client, |handle| {
2373            handle
2374                .runtime
2375                .block_on(handle.client.upsert_sqlite_fts_document(
2376                    space_id,
2377                    binding_id,
2378                    index_name,
2379                    tokenizer_mode,
2380                    id,
2381                    file_path,
2382                    title,
2383                    content,
2384                ))
2385                .map_err(error_to_string)
2386        })
2387    })();
2388    match result {
2389        Ok(result) => {
2390            write_boxed_out_ptr(result_out, map_sqlite_fts_mutation_result(result));
2391            ffi_ok_status(error_out)
2392        }
2393        Err(error) => ffi_error_status(error_out, error),
2394    }
2395}
2396
2397/// Upsert one SQLite FTS document using JSON mode.
2398/// 使用 JSON 模式写入一条 SQLite FTS 文档。
2399#[unsafe(no_mangle)]
2400pub extern "C" fn vldb_controller_ffi_client_upsert_sqlite_fts_document_json(
2401    client: *mut FfiControllerClientHandle,
2402    request_json: *const c_char,
2403    response_out: *mut *mut c_char,
2404    error_out: *mut *mut c_char,
2405) -> c_int {
2406    clear_out_ptr(response_out);
2407    let result = (|| -> Result<String, String> {
2408        let request: UpsertSqliteFtsDocumentJsonRequest = parse_json_input(request_json)?;
2409        let binding_id = request.space_id.clone();
2410        let tokenizer_mode = parse_sqlite_tokenizer_mode_name(&request.tokenizer_mode)?;
2411        let result = with_client_handle(client, |handle| {
2412            handle
2413                .runtime
2414                .block_on(handle.client.upsert_sqlite_fts_document(
2415                    request.space_id,
2416                    binding_id,
2417                    request.index_name,
2418                    tokenizer_mode,
2419                    request.id,
2420                    request.file_path,
2421                    request.title,
2422                    request.content,
2423                ))
2424                .map_err(error_to_string)
2425        })?;
2426        serde_json::to_string(&result).map_err(|error| {
2427            format!("failed to serialize upsert_sqlite_fts_document_json response: {error}")
2428        })
2429    })();
2430    match result {
2431        Ok(response) => {
2432            write_string_out(response_out, response);
2433            ffi_ok_status(error_out)
2434        }
2435        Err(error) => ffi_error_status(error_out, error),
2436    }
2437}
2438
2439/// Delete one SQLite FTS document using native arguments.
2440/// 使用原生参数删除一条 SQLite FTS 文档。
2441#[unsafe(no_mangle)]
2442pub extern "C" fn vldb_controller_ffi_client_delete_sqlite_fts_document(
2443    client: *mut FfiControllerClientHandle,
2444    space_id: *const c_char,
2445    index_name: *const c_char,
2446    id: *const c_char,
2447    result_out: *mut *mut FfiControllerSqliteFtsMutationResult,
2448    error_out: *mut *mut c_char,
2449) -> c_int {
2450    clear_out_ptr(result_out);
2451    let result = (|| -> Result<ControllerSqliteFtsMutationResult, String> {
2452        let space_id = required_c_string(space_id, "space_id")?;
2453        let binding_id = space_id.clone();
2454        let index_name = required_c_string(index_name, "index_name")?;
2455        let id = required_c_string(id, "id")?;
2456        with_client_handle(client, |handle| {
2457            handle
2458                .runtime
2459                .block_on(
2460                    handle
2461                        .client
2462                        .delete_sqlite_fts_document(space_id, binding_id, index_name, id),
2463                )
2464                .map_err(error_to_string)
2465        })
2466    })();
2467    match result {
2468        Ok(result) => {
2469            write_boxed_out_ptr(result_out, map_sqlite_fts_mutation_result(result));
2470            ffi_ok_status(error_out)
2471        }
2472        Err(error) => ffi_error_status(error_out, error),
2473    }
2474}
2475
2476/// Delete one SQLite FTS document using JSON mode.
2477/// 使用 JSON 模式删除一条 SQLite FTS 文档。
2478#[unsafe(no_mangle)]
2479pub extern "C" fn vldb_controller_ffi_client_delete_sqlite_fts_document_json(
2480    client: *mut FfiControllerClientHandle,
2481    request_json: *const c_char,
2482    response_out: *mut *mut c_char,
2483    error_out: *mut *mut c_char,
2484) -> c_int {
2485    clear_out_ptr(response_out);
2486    let result = (|| -> Result<String, String> {
2487        let request: DeleteSqliteFtsDocumentJsonRequest = parse_json_input(request_json)?;
2488        let binding_id = request.space_id.clone();
2489        let result = with_client_handle(client, |handle| {
2490            handle
2491                .runtime
2492                .block_on(handle.client.delete_sqlite_fts_document(
2493                    request.space_id,
2494                    binding_id,
2495                    request.index_name,
2496                    request.id,
2497                ))
2498                .map_err(error_to_string)
2499        })?;
2500        serde_json::to_string(&result).map_err(|error| {
2501            format!("failed to serialize delete_sqlite_fts_document_json response: {error}")
2502        })
2503    })();
2504    match result {
2505        Ok(response) => {
2506            write_string_out(response_out, response);
2507            ffi_ok_status(error_out)
2508        }
2509        Err(error) => ffi_error_status(error_out, error),
2510    }
2511}
2512
2513/// Free one native SQLite FTS document mutation result.
2514/// 释放一份原生 SQLite FTS 文档变更结果。
2515#[unsafe(no_mangle)]
2516pub extern "C" fn vldb_controller_ffi_sqlite_fts_mutation_result_free(
2517    result: *mut FfiControllerSqliteFtsMutationResult,
2518) {
2519    if !result.is_null() {
2520        unsafe {
2521            let result = Box::from_raw(result);
2522            vldb_controller_ffi_string_free(result.message);
2523            vldb_controller_ffi_string_free(result.index_name);
2524        }
2525    }
2526}
2527
2528/// Search one SQLite FTS index using native arguments.
2529/// 使用原生参数检索一条 SQLite FTS 索引。
2530#[unsafe(no_mangle)]
2531pub extern "C" fn vldb_controller_ffi_client_search_sqlite_fts(
2532    client: *mut FfiControllerClientHandle,
2533    space_id: *const c_char,
2534    index_name: *const c_char,
2535    tokenizer_mode: *const c_char,
2536    query: *const c_char,
2537    limit: u32,
2538    offset: u32,
2539    result_out: *mut *mut FfiControllerSqliteSearchFtsResult,
2540    error_out: *mut *mut c_char,
2541) -> c_int {
2542    clear_out_ptr(result_out);
2543    let result = (|| -> Result<ControllerSqliteSearchFtsResult, String> {
2544        let space_id = required_c_string(space_id, "space_id")?;
2545        let binding_id = space_id.clone();
2546        let index_name = required_c_string(index_name, "index_name")?;
2547        let tokenizer_mode = parse_sqlite_tokenizer_mode_text(tokenizer_mode)?;
2548        let query = required_c_string(query, "query")?;
2549        with_client_handle(client, |handle| {
2550            handle
2551                .runtime
2552                .block_on(handle.client.search_sqlite_fts(
2553                    space_id,
2554                    binding_id,
2555                    index_name,
2556                    tokenizer_mode,
2557                    query,
2558                    limit,
2559                    offset,
2560                ))
2561                .map_err(error_to_string)
2562        })
2563    })();
2564    match result {
2565        Ok(result) => {
2566            write_boxed_out_ptr(result_out, map_sqlite_search_fts_result(result));
2567            ffi_ok_status(error_out)
2568        }
2569        Err(error) => ffi_error_status(error_out, error),
2570    }
2571}
2572
2573/// Search one SQLite FTS index using JSON mode.
2574/// 使用 JSON 模式检索一条 SQLite FTS 索引。
2575#[unsafe(no_mangle)]
2576pub extern "C" fn vldb_controller_ffi_client_search_sqlite_fts_json(
2577    client: *mut FfiControllerClientHandle,
2578    request_json: *const c_char,
2579    response_out: *mut *mut c_char,
2580    error_out: *mut *mut c_char,
2581) -> c_int {
2582    clear_out_ptr(response_out);
2583    let result = (|| -> Result<String, String> {
2584        let request: SearchSqliteFtsJsonRequest = parse_json_input(request_json)?;
2585        let binding_id = request.space_id.clone();
2586        let tokenizer_mode = parse_sqlite_tokenizer_mode_name(&request.tokenizer_mode)?;
2587        let result = with_client_handle(client, |handle| {
2588            handle
2589                .runtime
2590                .block_on(handle.client.search_sqlite_fts(
2591                    request.space_id,
2592                    binding_id,
2593                    request.index_name,
2594                    tokenizer_mode,
2595                    request.query,
2596                    request.limit,
2597                    request.offset,
2598                ))
2599                .map_err(error_to_string)
2600        })?;
2601        serde_json::to_string(&result).map_err(|error| {
2602            format!("failed to serialize search_sqlite_fts_json response: {error}")
2603        })
2604    })();
2605    match result {
2606        Ok(response) => {
2607            write_string_out(response_out, response);
2608            ffi_ok_status(error_out)
2609        }
2610        Err(error) => ffi_error_status(error_out, error),
2611    }
2612}
2613
2614/// Free one native SQLite FTS hit array.
2615/// 释放一份原生 SQLite FTS 命中数组。
2616#[unsafe(no_mangle)]
2617pub extern "C" fn vldb_controller_ffi_sqlite_search_fts_hit_array_free(
2618    value: *mut FfiControllerSqliteSearchFtsHitArray,
2619) {
2620    if value.is_null() {
2621        return;
2622    }
2623    unsafe {
2624        let value = Box::from_raw(value);
2625        if !value.items.is_null() {
2626            let items = Vec::from_raw_parts(value.items, value.len, value.len);
2627            for item in items {
2628                vldb_controller_ffi_string_free(item.id);
2629                vldb_controller_ffi_string_free(item.file_path);
2630                vldb_controller_ffi_string_free(item.title);
2631                vldb_controller_ffi_string_free(item.title_highlight);
2632                vldb_controller_ffi_string_free(item.content_snippet);
2633            }
2634        }
2635    }
2636}
2637
2638/// Free one native SQLite FTS search result.
2639/// 释放一份原生 SQLite FTS 检索结果。
2640#[unsafe(no_mangle)]
2641pub extern "C" fn vldb_controller_ffi_sqlite_search_fts_result_free(
2642    result: *mut FfiControllerSqliteSearchFtsResult,
2643) {
2644    if !result.is_null() {
2645        unsafe {
2646            let result = Box::from_raw(result);
2647            vldb_controller_ffi_string_free(result.message);
2648            vldb_controller_ffi_string_free(result.index_name);
2649            vldb_controller_ffi_string_free(result.tokenizer_mode);
2650            vldb_controller_ffi_string_free(result.normalized_query);
2651            vldb_controller_ffi_string_free(result.fts_query);
2652            vldb_controller_ffi_string_free(result.source);
2653            vldb_controller_ffi_string_free(result.query_mode);
2654            vldb_controller_ffi_sqlite_search_fts_hit_array_free(result.hits);
2655        }
2656    }
2657}
2658
2659/// Enable one LanceDB backend using native structured input.
2660/// 使用原生结构化输入启用一个 LanceDB 后端。
2661#[unsafe(no_mangle)]
2662pub extern "C" fn vldb_controller_ffi_client_enable_lancedb(
2663    client: *mut FfiControllerClientHandle,
2664    request: *const FfiControllerLanceDbEnableRequest,
2665    error_out: *mut *mut c_char,
2666) -> c_int {
2667    let result = (|| -> Result<(), String> {
2668        let request = ffi_lancedb_enable_request_to_rust(request)?;
2669        with_client_handle(client, |handle| {
2670            handle
2671                .runtime
2672                .block_on(handle.client.enable_lancedb(request))
2673                .map_err(error_to_string)
2674        })
2675    })();
2676    match result {
2677        Ok(()) => ffi_ok_status(error_out),
2678        Err(error) => ffi_error_status(error_out, error),
2679    }
2680}
2681
2682/// Enable one LanceDB backend using JSON mode.
2683/// 使用 JSON 模式启用一个 LanceDB 后端。
2684#[unsafe(no_mangle)]
2685pub extern "C" fn vldb_controller_ffi_client_enable_lancedb_json(
2686    client: *mut FfiControllerClientHandle,
2687    request_json: *const c_char,
2688    response_out: *mut *mut c_char,
2689    error_out: *mut *mut c_char,
2690) -> c_int {
2691    clear_out_ptr(response_out);
2692    let result = (|| -> Result<String, String> {
2693        let request: EnableLanceDbJsonRequest = parse_json_input(request_json)?;
2694        with_client_handle(client, |handle| {
2695            handle
2696                .runtime
2697                .block_on(handle.client.enable_lancedb(request.request))
2698                .map_err(error_to_string)
2699        })?;
2700        serde_json::to_string(&SuccessJsonResponse { ok: true })
2701            .map_err(|error| format!("failed to serialize enable_lancedb_json response: {error}"))
2702    })();
2703    match result {
2704        Ok(response) => {
2705            write_string_out(response_out, response);
2706            ffi_ok_status(error_out)
2707        }
2708        Err(error) => ffi_error_status(error_out, error),
2709    }
2710}
2711
2712/// Disable one LanceDB backend using native structured input.
2713/// 使用原生结构化输入关闭一个 LanceDB 后端。
2714#[unsafe(no_mangle)]
2715pub extern "C" fn vldb_controller_ffi_client_disable_lancedb(
2716    client: *mut FfiControllerClientHandle,
2717    space_id: *const c_char,
2718    disabled_out: *mut c_uchar,
2719    error_out: *mut *mut c_char,
2720) -> c_int {
2721    clear_out_u8(disabled_out);
2722    let result = (|| -> Result<bool, String> {
2723        let space_id = required_c_string(space_id, "space_id")?;
2724        let binding_id = space_id.clone();
2725        with_client_handle(client, |handle| {
2726            handle
2727                .runtime
2728                .block_on(handle.client.disable_lancedb(space_id, binding_id))
2729                .map_err(error_to_string)
2730        })
2731    })();
2732    match result {
2733        Ok(disabled) => {
2734            write_out_u8(disabled_out, if disabled { 1 } else { 0 });
2735            ffi_ok_status(error_out)
2736        }
2737        Err(error) => ffi_error_status(error_out, error),
2738    }
2739}
2740
2741/// Disable one LanceDB backend using JSON mode.
2742/// 使用 JSON 模式关闭一个 LanceDB 后端。
2743#[unsafe(no_mangle)]
2744pub extern "C" fn vldb_controller_ffi_client_disable_lancedb_json(
2745    client: *mut FfiControllerClientHandle,
2746    request_json: *const c_char,
2747    response_out: *mut *mut c_char,
2748    error_out: *mut *mut c_char,
2749) -> c_int {
2750    clear_out_ptr(response_out);
2751    let result = (|| -> Result<String, String> {
2752        let request: DisableBackendJsonRequest = parse_json_input(request_json)?;
2753        let binding_id = request.space_id.clone();
2754        let disabled = with_client_handle(client, |handle| {
2755            handle
2756                .runtime
2757                .block_on(handle.client.disable_lancedb(request.space_id, binding_id))
2758                .map_err(error_to_string)
2759        })?;
2760        serde_json::to_string(&disabled)
2761            .map_err(|error| format!("failed to serialize disable_lancedb_json response: {error}"))
2762    })();
2763    match result {
2764        Ok(response) => {
2765            write_string_out(response_out, response);
2766            ffi_ok_status(error_out)
2767        }
2768        Err(error) => ffi_error_status(error_out, error),
2769    }
2770}
2771
2772/// Create one LanceDB table using native input.
2773/// 使用原生输入创建一张 LanceDB 表。
2774#[unsafe(no_mangle)]
2775pub extern "C" fn vldb_controller_ffi_client_create_lancedb_table(
2776    client: *mut FfiControllerClientHandle,
2777    space_id: *const c_char,
2778    table_name: *const c_char,
2779    columns: *const FfiControllerLanceDbColumnDef,
2780    columns_len: usize,
2781    overwrite_if_exists: c_uchar,
2782    result_out: *mut *mut FfiControllerLanceDbCreateTableResult,
2783    error_out: *mut *mut c_char,
2784) -> c_int {
2785    clear_out_ptr(result_out);
2786    let result = (|| -> Result<ControllerLanceDbCreateTableResult, String> {
2787        let space_id = required_c_string(space_id, "space_id")?;
2788        let binding_id = space_id.clone();
2789        let table_name = required_c_string(table_name, "table_name")?;
2790        let columns = read_lancedb_columns(columns, columns_len, "columns")?;
2791        with_client_handle(client, |handle| {
2792            handle
2793                .runtime
2794                .block_on(handle.client.create_lancedb_table_typed(
2795                    space_id,
2796                    binding_id,
2797                    table_name,
2798                    columns,
2799                    overwrite_if_exists != 0,
2800                ))
2801                .map_err(error_to_string)
2802        })
2803    })();
2804    match result {
2805        Ok(result) => {
2806            write_boxed_out_ptr(result_out, map_lancedb_create_table_result(result));
2807            ffi_ok_status(error_out)
2808        }
2809        Err(error) => ffi_error_status(error_out, error),
2810    }
2811}
2812
2813/// Create one LanceDB table using JSON mode.
2814/// 使用 JSON 模式创建一张 LanceDB 表。
2815#[unsafe(no_mangle)]
2816pub extern "C" fn vldb_controller_ffi_client_create_lancedb_table_json(
2817    client: *mut FfiControllerClientHandle,
2818    request_json: *const c_char,
2819    response_out: *mut *mut c_char,
2820    error_out: *mut *mut c_char,
2821) -> c_int {
2822    clear_out_ptr(response_out);
2823    let result = (|| -> Result<String, String> {
2824        let request: CreateLanceDbTableJsonRequest = parse_json_input(request_json)?;
2825        let space_id = request.space_id.clone();
2826        let binding_id = request.space_id.clone();
2827        let result = with_client_handle(client, |handle| {
2828            let inner_request_json =
2829                serde_json::to_string(&CreateLanceDbTableJsonCompatRequest::from(request))
2830                    .map_err(|error| {
2831                        format!("failed to serialize create_lancedb_table_json request: {error}")
2832                    })?;
2833            handle
2834                .runtime
2835                .block_on(handle.client.create_lancedb_table(
2836                    space_id,
2837                    binding_id,
2838                    inner_request_json,
2839                ))
2840                .map_err(error_to_string)
2841        })?;
2842        serde_json::to_string(&result).map_err(|error| {
2843            format!("failed to serialize create_lancedb_table_json response: {error}")
2844        })
2845    })();
2846    match result {
2847        Ok(response) => {
2848            write_string_out(response_out, response);
2849            ffi_ok_status(error_out)
2850        }
2851        Err(error) => ffi_error_status(error_out, error),
2852    }
2853}
2854
2855/// Free one native LanceDB create-table result.
2856/// 释放一份原生 LanceDB 建表结果。
2857#[unsafe(no_mangle)]
2858pub extern "C" fn vldb_controller_ffi_lancedb_create_table_result_free(
2859    result: *mut FfiControllerLanceDbCreateTableResult,
2860) {
2861    if !result.is_null() {
2862        unsafe {
2863            let result = Box::from_raw(result);
2864            vldb_controller_ffi_string_free(result.message);
2865        }
2866    }
2867}
2868
2869/// Upsert LanceDB rows using native input.
2870/// 使用原生输入写入 LanceDB 行数据。
2871#[unsafe(no_mangle)]
2872pub extern "C" fn vldb_controller_ffi_client_upsert_lancedb(
2873    client: *mut FfiControllerClientHandle,
2874    space_id: *const c_char,
2875    table_name: *const c_char,
2876    input_format: c_int,
2877    data: *const u8,
2878    data_len: usize,
2879    key_columns: *const *const c_char,
2880    key_columns_len: usize,
2881    result_out: *mut *mut FfiControllerLanceDbUpsertResult,
2882    error_out: *mut *mut c_char,
2883) -> c_int {
2884    clear_out_ptr(result_out);
2885    let result = (|| -> Result<ControllerLanceDbUpsertResult, String> {
2886        let space_id = required_c_string(space_id, "space_id")?;
2887        let binding_id = space_id.clone();
2888        let table_name = required_c_string(table_name, "table_name")?;
2889        let input_format = map_lancedb_input_format_native(input_format)?;
2890        let data = required_bytes(data, data_len, "data")?.to_vec();
2891        let key_columns = optional_string_array(key_columns, key_columns_len, "key_columns")?;
2892        with_client_handle(client, |handle| {
2893            handle
2894                .runtime
2895                .block_on(handle.client.upsert_lancedb_typed(
2896                    space_id,
2897                    binding_id,
2898                    table_name,
2899                    input_format,
2900                    data,
2901                    key_columns,
2902                ))
2903                .map_err(error_to_string)
2904        })
2905    })();
2906    match result {
2907        Ok(result) => {
2908            write_boxed_out_ptr(result_out, map_lancedb_upsert_result(result));
2909            ffi_ok_status(error_out)
2910        }
2911        Err(error) => ffi_error_status(error_out, error),
2912    }
2913}
2914
2915/// Upsert LanceDB rows using JSON mode.
2916/// 使用 JSON 模式写入 LanceDB 行数据。
2917#[unsafe(no_mangle)]
2918pub extern "C" fn vldb_controller_ffi_client_upsert_lancedb_json(
2919    client: *mut FfiControllerClientHandle,
2920    request_json: *const c_char,
2921    response_out: *mut *mut c_char,
2922    error_out: *mut *mut c_char,
2923) -> c_int {
2924    clear_out_ptr(response_out);
2925    let result = (|| -> Result<String, String> {
2926        let request: UpsertLanceDbJsonRequest = parse_json_input(request_json)?;
2927        let binding_id = request.space_id.clone();
2928        let data = decode_base64(&request.data_base64)?;
2929        let result = with_client_handle(client, |handle| {
2930            let inner_request_json = serde_json::to_string(&UpsertLanceDbJsonCompatRequest::from(
2931                &request,
2932            ))
2933            .map_err(|error| format!("failed to serialize upsert_lancedb_json request: {error}"))?;
2934            handle
2935                .runtime
2936                .block_on(handle.client.upsert_lancedb(
2937                    request.space_id,
2938                    binding_id,
2939                    inner_request_json,
2940                    data,
2941                ))
2942                .map_err(error_to_string)
2943        })?;
2944        serde_json::to_string(&result)
2945            .map_err(|error| format!("failed to serialize upsert_lancedb_json response: {error}"))
2946    })();
2947    match result {
2948        Ok(response) => {
2949            write_string_out(response_out, response);
2950            ffi_ok_status(error_out)
2951        }
2952        Err(error) => ffi_error_status(error_out, error),
2953    }
2954}
2955
2956/// Free one native LanceDB upsert result.
2957/// 释放一份原生 LanceDB 写入结果。
2958#[unsafe(no_mangle)]
2959pub extern "C" fn vldb_controller_ffi_lancedb_upsert_result_free(
2960    result: *mut FfiControllerLanceDbUpsertResult,
2961) {
2962    if !result.is_null() {
2963        unsafe {
2964            let result = Box::from_raw(result);
2965            vldb_controller_ffi_string_free(result.message);
2966        }
2967    }
2968}
2969
2970/// Search LanceDB rows using native input.
2971/// 使用原生输入检索 LanceDB 行数据。
2972#[unsafe(no_mangle)]
2973pub extern "C" fn vldb_controller_ffi_client_search_lancedb(
2974    client: *mut FfiControllerClientHandle,
2975    space_id: *const c_char,
2976    table_name: *const c_char,
2977    vector: *const c_float,
2978    vector_len: usize,
2979    limit: u32,
2980    filter: *const c_char,
2981    vector_column: *const c_char,
2982    output_format: c_int,
2983    result_out: *mut *mut FfiControllerLanceDbSearchResult,
2984    error_out: *mut *mut c_char,
2985) -> c_int {
2986    clear_out_ptr(result_out);
2987    let result = (|| -> Result<ControllerLanceDbSearchResult, String> {
2988        let space_id = required_c_string(space_id, "space_id")?;
2989        let binding_id = space_id.clone();
2990        let table_name = required_c_string(table_name, "table_name")?;
2991        let vector = required_f32_slice(vector, vector_len, "vector")?.to_vec();
2992        let filter = optional_c_string(filter)?.unwrap_or_default();
2993        let vector_column = optional_c_string(vector_column)?.unwrap_or_default();
2994        let output_format = map_lancedb_output_format_native(output_format)?;
2995        with_client_handle(client, |handle| {
2996            handle
2997                .runtime
2998                .block_on(handle.client.search_lancedb_typed(
2999                    space_id,
3000                    binding_id,
3001                    table_name,
3002                    vector,
3003                    limit,
3004                    filter,
3005                    vector_column,
3006                    output_format,
3007                ))
3008                .map_err(error_to_string)
3009        })
3010    })();
3011    match result {
3012        Ok(result) => {
3013            write_boxed_out_ptr(result_out, map_lancedb_search_result(result));
3014            ffi_ok_status(error_out)
3015        }
3016        Err(error) => ffi_error_status(error_out, error),
3017    }
3018}
3019
3020/// Search LanceDB rows using JSON mode.
3021/// 使用 JSON 模式检索 LanceDB 行数据。
3022#[unsafe(no_mangle)]
3023pub extern "C" fn vldb_controller_ffi_client_search_lancedb_json(
3024    client: *mut FfiControllerClientHandle,
3025    request_json: *const c_char,
3026    response_out: *mut *mut c_char,
3027    error_out: *mut *mut c_char,
3028) -> c_int {
3029    clear_out_ptr(response_out);
3030    let result = (|| -> Result<String, String> {
3031        let request: SearchLanceDbJsonRequest = parse_json_input(request_json)?;
3032        let binding_id = request.space_id.clone();
3033        let result = with_client_handle(client, |handle| {
3034            let inner_request_json = serde_json::to_string(&SearchLanceDbJsonCompatRequest::from(
3035                &request,
3036            ))
3037            .map_err(|error| format!("failed to serialize search_lancedb_json request: {error}"))?;
3038            handle
3039                .runtime
3040                .block_on(handle.client.search_lancedb(
3041                    request.space_id,
3042                    binding_id,
3043                    inner_request_json,
3044                ))
3045                .map_err(error_to_string)
3046        })?;
3047        serde_json::to_string(&SearchLanceDbJsonResponse::from(result))
3048            .map_err(|error| format!("failed to serialize search_lancedb_json response: {error}"))
3049    })();
3050    match result {
3051        Ok(response) => {
3052            write_string_out(response_out, response);
3053            ffi_ok_status(error_out)
3054        }
3055        Err(error) => ffi_error_status(error_out, error),
3056    }
3057}
3058
3059/// Free one native LanceDB search result.
3060/// 释放一份原生 LanceDB 检索结果。
3061#[unsafe(no_mangle)]
3062pub extern "C" fn vldb_controller_ffi_lancedb_search_result_free(
3063    result: *mut FfiControllerLanceDbSearchResult,
3064) {
3065    if !result.is_null() {
3066        unsafe {
3067            let result = Box::from_raw(result);
3068            vldb_controller_ffi_string_free(result.message);
3069            vldb_controller_ffi_string_free(result.format);
3070            vldb_controller_ffi_bytes_free(result.data, result.data_len);
3071        }
3072    }
3073}
3074
3075/// Delete LanceDB rows using native input.
3076/// 使用原生输入删除 LanceDB 行数据。
3077#[unsafe(no_mangle)]
3078pub extern "C" fn vldb_controller_ffi_client_delete_lancedb(
3079    client: *mut FfiControllerClientHandle,
3080    space_id: *const c_char,
3081    table_name: *const c_char,
3082    condition: *const c_char,
3083    result_out: *mut *mut FfiControllerLanceDbDeleteResult,
3084    error_out: *mut *mut c_char,
3085) -> c_int {
3086    clear_out_ptr(result_out);
3087    let result = (|| -> Result<ControllerLanceDbDeleteResult, String> {
3088        let space_id = required_c_string(space_id, "space_id")?;
3089        let binding_id = space_id.clone();
3090        let table_name = required_c_string(table_name, "table_name")?;
3091        let condition = required_c_string(condition, "condition")?;
3092        with_client_handle(client, |handle| {
3093            handle
3094                .runtime
3095                .block_on(
3096                    handle
3097                        .client
3098                        .delete_lancedb_typed(space_id, binding_id, table_name, condition),
3099                )
3100                .map_err(error_to_string)
3101        })
3102    })();
3103    match result {
3104        Ok(result) => {
3105            write_boxed_out_ptr(result_out, map_lancedb_delete_result(result));
3106            ffi_ok_status(error_out)
3107        }
3108        Err(error) => ffi_error_status(error_out, error),
3109    }
3110}
3111
3112/// Delete LanceDB rows using JSON mode.
3113/// 使用 JSON 模式删除 LanceDB 行数据。
3114#[unsafe(no_mangle)]
3115pub extern "C" fn vldb_controller_ffi_client_delete_lancedb_json(
3116    client: *mut FfiControllerClientHandle,
3117    request_json: *const c_char,
3118    response_out: *mut *mut c_char,
3119    error_out: *mut *mut c_char,
3120) -> c_int {
3121    clear_out_ptr(response_out);
3122    let result = (|| -> Result<String, String> {
3123        let request: DeleteLanceDbJsonRequest = parse_json_input(request_json)?;
3124        let binding_id = request.space_id.clone();
3125        let result = with_client_handle(client, |handle| {
3126            let inner_request_json = serde_json::to_string(&DeleteLanceDbJsonCompatRequest::from(
3127                &request,
3128            ))
3129            .map_err(|error| format!("failed to serialize delete_lancedb_json request: {error}"))?;
3130            handle
3131                .runtime
3132                .block_on(handle.client.delete_lancedb(
3133                    request.space_id,
3134                    binding_id,
3135                    inner_request_json,
3136                ))
3137                .map_err(error_to_string)
3138        })?;
3139        serde_json::to_string(&result)
3140            .map_err(|error| format!("failed to serialize delete_lancedb_json response: {error}"))
3141    })();
3142    match result {
3143        Ok(response) => {
3144            write_string_out(response_out, response);
3145            ffi_ok_status(error_out)
3146        }
3147        Err(error) => ffi_error_status(error_out, error),
3148    }
3149}
3150
3151/// Free one native LanceDB delete result.
3152/// 释放一份原生 LanceDB 删除结果。
3153#[unsafe(no_mangle)]
3154pub extern "C" fn vldb_controller_ffi_lancedb_delete_result_free(
3155    result: *mut FfiControllerLanceDbDeleteResult,
3156) {
3157    if !result.is_null() {
3158        unsafe {
3159            let result = Box::from_raw(result);
3160            vldb_controller_ffi_string_free(result.message);
3161        }
3162    }
3163}
3164
3165/// Drop one LanceDB table using native input.
3166/// 使用原生输入删除一张 LanceDB 表。
3167#[unsafe(no_mangle)]
3168pub extern "C" fn vldb_controller_ffi_client_drop_lancedb_table(
3169    client: *mut FfiControllerClientHandle,
3170    space_id: *const c_char,
3171    table_name: *const c_char,
3172    result_out: *mut *mut FfiControllerLanceDbDropTableResult,
3173    error_out: *mut *mut c_char,
3174) -> c_int {
3175    clear_out_ptr(result_out);
3176    let result = (|| -> Result<ControllerLanceDbDropTableResult, String> {
3177        let space_id = required_c_string(space_id, "space_id")?;
3178        let binding_id = space_id.clone();
3179        let table_name = required_c_string(table_name, "table_name")?;
3180        with_client_handle(client, |handle| {
3181            handle
3182                .runtime
3183                .block_on(
3184                    handle
3185                        .client
3186                        .drop_lancedb_table(space_id, binding_id, table_name),
3187                )
3188                .map_err(error_to_string)
3189        })
3190    })();
3191    match result {
3192        Ok(result) => {
3193            write_boxed_out_ptr(result_out, map_lancedb_drop_table_result(result));
3194            ffi_ok_status(error_out)
3195        }
3196        Err(error) => ffi_error_status(error_out, error),
3197    }
3198}
3199
3200/// Drop one LanceDB table using JSON mode.
3201/// 使用 JSON 模式删除一张 LanceDB 表。
3202#[unsafe(no_mangle)]
3203pub extern "C" fn vldb_controller_ffi_client_drop_lancedb_table_json(
3204    client: *mut FfiControllerClientHandle,
3205    request_json: *const c_char,
3206    response_out: *mut *mut c_char,
3207    error_out: *mut *mut c_char,
3208) -> c_int {
3209    clear_out_ptr(response_out);
3210    let result = (|| -> Result<String, String> {
3211        let request: DropLanceDbTableJsonRequest = parse_json_input(request_json)?;
3212        let binding_id = request.space_id.clone();
3213        let result = with_client_handle(client, |handle| {
3214            handle
3215                .runtime
3216                .block_on(handle.client.drop_lancedb_table(
3217                    request.space_id,
3218                    binding_id,
3219                    request.table_name,
3220                ))
3221                .map_err(error_to_string)
3222        })?;
3223        serde_json::to_string(&result).map_err(|error| {
3224            format!("failed to serialize drop_lancedb_table_json response: {error}")
3225        })
3226    })();
3227    match result {
3228        Ok(response) => {
3229            write_string_out(response_out, response);
3230            ffi_ok_status(error_out)
3231        }
3232        Err(error) => ffi_error_status(error_out, error),
3233    }
3234}
3235
3236/// Free one native LanceDB drop-table result.
3237/// 释放一份原生 LanceDB 删表结果。
3238#[unsafe(no_mangle)]
3239pub extern "C" fn vldb_controller_ffi_lancedb_drop_table_result_free(
3240    result: *mut FfiControllerLanceDbDropTableResult,
3241) {
3242    if !result.is_null() {
3243        unsafe {
3244            let result = Box::from_raw(result);
3245            vldb_controller_ffi_string_free(result.message);
3246        }
3247    }
3248}
3249
3250/// JSON-friendly LanceDB search response that encodes binary payloads as base64 text.
3251/// 将二进制载荷编码成 base64 文本的 JSON 友好 LanceDB 检索响应。
3252#[derive(Serialize)]
3253struct SearchLanceDbJsonResponse {
3254    message: String,
3255    format: String,
3256    rows: u64,
3257    data_base64: String,
3258}
3259
3260impl From<ControllerLanceDbSearchResult> for SearchLanceDbJsonResponse {
3261    /// Convert one native search result into a JSON-safe response.
3262    /// 将一份原生检索结果转换成 JSON 安全响应。
3263    fn from(value: ControllerLanceDbSearchResult) -> Self {
3264        Self {
3265            message: value.message,
3266            format: value.format,
3267            rows: value.rows,
3268            data_base64: encode_base64(&value.data),
3269        }
3270    }
3271}
3272
3273/// Build one client handle from already parsed Rust values.
3274/// 从已解析的 Rust 值构造一个客户端句柄。
3275fn build_client_handle(
3276    config: ControllerClientConfig,
3277    registration: ClientRegistration,
3278) -> Result<*mut FfiControllerClientHandle, String> {
3279    let runtime =
3280        Runtime::new().map_err(|error| format!("failed to create tokio runtime: {error}"))?;
3281    let client = ControllerClient::new(config, registration);
3282    register_client_handle(FfiControllerClientHandleInner { runtime, client })
3283}
3284
3285/// Build one client handle from native input structures.
3286/// 从原生输入结构构造一个客户端句柄。
3287fn native_client_create(
3288    config: *const FfiControllerClientConfig,
3289    registration: *const FfiClientRegistration,
3290) -> Result<*mut FfiControllerClientHandle, String> {
3291    let config = ffi_client_config_to_rust(config)?;
3292    let registration = ffi_client_registration_to_rust(registration)?;
3293    build_client_handle(config, registration)
3294}
3295
3296/// Return the global registry that owns all live opaque FFI client handles.
3297/// 返回持有全部存活不透明 FFI 客户端句柄的全局注册表。
3298fn ffi_client_handle_registry()
3299-> &'static Mutex<BTreeMap<usize, Arc<FfiControllerClientHandleState>>> {
3300    FFI_CLIENT_HANDLE_REGISTRY.get_or_init(|| Mutex::new(BTreeMap::new()))
3301}
3302
3303/// Convert one opaque pointer value into the internal handle identifier.
3304/// 将一个不透明指针值转换成内部句柄标识符。
3305fn ffi_client_handle_id_from_ptr(client: *mut FfiControllerClientHandle) -> Result<usize, String> {
3306    if client.is_null() {
3307        return Err("client handle pointer must not be null".to_string());
3308    }
3309    Ok(client as usize)
3310}
3311
3312/// Register one live client-handle state and return the exported opaque pointer.
3313/// 注册一个存活客户端句柄状态并返回导出的不透明指针。
3314fn register_client_handle(
3315    inner: FfiControllerClientHandleInner,
3316) -> Result<*mut FfiControllerClientHandle, String> {
3317    let state = Arc::new(FfiControllerClientHandleState {
3318        inner: Mutex::new(Some(inner)),
3319    });
3320    let mut registry = ffi_client_handle_registry()
3321        .lock()
3322        .map_err(|poisoned| format!("ffi client handle registry lock poisoned: {poisoned}"))?;
3323    let handle_ptr = Box::into_raw(Box::new(FfiControllerClientHandle { _private: 0 }));
3324    let handle_id = handle_ptr as usize;
3325    registry.insert(handle_id, state);
3326    Ok(handle_ptr)
3327}
3328
3329/// Convert one native client configuration into the Rust SDK type.
3330/// 将一份原生客户端配置转换成 Rust SDK 类型。
3331fn ffi_client_config_to_rust(
3332    config: *const FfiControllerClientConfig,
3333) -> Result<ControllerClientConfig, String> {
3334    if config.is_null() {
3335        return Err("config pointer must not be null".to_string());
3336    }
3337    let config = unsafe { &*config };
3338    let defaults = ControllerClientConfig::default();
3339    Ok(ControllerClientConfig {
3340        endpoint: optional_c_string(config.endpoint)?.unwrap_or(defaults.endpoint),
3341        auto_spawn: config.auto_spawn != 0,
3342        spawn_executable: optional_c_string(config.spawn_executable)?,
3343        spawn_process_mode: map_process_mode_native(config.spawn_process_mode)?,
3344        minimum_uptime_secs: default_u64(config.minimum_uptime_secs, defaults.minimum_uptime_secs),
3345        idle_timeout_secs: default_u64(config.idle_timeout_secs, defaults.idle_timeout_secs),
3346        default_lease_ttl_secs: default_u64(
3347            config.default_lease_ttl_secs,
3348            defaults.default_lease_ttl_secs,
3349        ),
3350        connect_timeout_secs: default_u64(
3351            config.connect_timeout_secs,
3352            defaults.connect_timeout_secs,
3353        ),
3354        startup_timeout_secs: default_u64(
3355            config.startup_timeout_secs,
3356            defaults.startup_timeout_secs,
3357        ),
3358        startup_retry_interval_ms: default_u64(
3359            config.startup_retry_interval_ms,
3360            defaults.startup_retry_interval_ms,
3361        ),
3362        lease_renew_interval_secs: default_u64(
3363            config.lease_renew_interval_secs,
3364            defaults.lease_renew_interval_secs,
3365        ),
3366    })
3367}
3368
3369/// Convert one native client registration into the Rust SDK type.
3370/// 将一份原生客户端注册转换成 Rust SDK 类型。
3371fn ffi_client_registration_to_rust(
3372    registration: *const FfiClientRegistration,
3373) -> Result<ClientRegistration, String> {
3374    if registration.is_null() {
3375        return Err("registration pointer must not be null".to_string());
3376    }
3377    let registration = unsafe { &*registration };
3378    Ok(ClientRegistration {
3379        client_name: required_c_string(registration.client_name, "client_name")?,
3380        host_kind: required_c_string(registration.host_kind, "host_kind")?,
3381        process_id: registration.process_id,
3382        process_name: required_c_string(registration.process_name, "process_name")?,
3383        lease_ttl_secs: optional_nonzero_u64(registration.lease_ttl_secs),
3384    })
3385}
3386
3387/// Convert one native space registration into the Rust SDK type.
3388/// 将一份原生空间注册转换成 Rust SDK 类型。
3389fn ffi_space_registration_to_rust(
3390    registration: *const FfiSpaceRegistration,
3391) -> Result<SpaceRegistration, String> {
3392    if registration.is_null() {
3393        return Err("registration pointer must not be null".to_string());
3394    }
3395    let registration = unsafe { &*registration };
3396    Ok(SpaceRegistration {
3397        space_id: required_c_string(registration.space_id, "space_id")?,
3398        space_label: required_c_string(registration.space_label, "space_label")?,
3399        space_kind: map_space_kind_native(registration.space_kind)?,
3400        space_root: required_c_string(registration.space_root, "space_root")?,
3401    })
3402}
3403
3404/// Convert one native SQLite enable request into the Rust SDK type.
3405/// 将一份原生 SQLite 启用请求转换成 Rust SDK 类型。
3406fn ffi_sqlite_enable_request_to_rust(
3407    request: *const FfiControllerSqliteEnableRequest,
3408) -> Result<ControllerSqliteEnableRequest, String> {
3409    if request.is_null() {
3410        return Err("sqlite enable request pointer must not be null".to_string());
3411    }
3412    let request = unsafe { &*request };
3413    let defaults = ControllerSqliteEnableRequest::default();
3414    let space_id = required_c_string(request.space_id, "space_id")?;
3415    Ok(ControllerSqliteEnableRequest {
3416        space_id: space_id.clone(),
3417        binding_id: space_id,
3418        db_path: required_c_string(request.db_path, "db_path")?,
3419        connection_pool_size: default_u64(
3420            request.connection_pool_size,
3421            defaults.connection_pool_size as u64,
3422        ) as usize,
3423        busy_timeout_ms: default_u64(request.busy_timeout_ms, defaults.busy_timeout_ms),
3424        journal_mode: optional_c_string(request.journal_mode)?.unwrap_or(defaults.journal_mode),
3425        synchronous: optional_c_string(request.synchronous)?.unwrap_or(defaults.synchronous),
3426        foreign_keys: request.foreign_keys != 0,
3427        temp_store: optional_c_string(request.temp_store)?.unwrap_or(defaults.temp_store),
3428        wal_autocheckpoint_pages: if request.wal_autocheckpoint_pages == 0 {
3429            defaults.wal_autocheckpoint_pages
3430        } else {
3431            request.wal_autocheckpoint_pages
3432        },
3433        cache_size_kib: if request.cache_size_kib == 0 {
3434            defaults.cache_size_kib
3435        } else {
3436            request.cache_size_kib
3437        },
3438        mmap_size_bytes: default_u64(request.mmap_size_bytes, defaults.mmap_size_bytes),
3439        enforce_db_file_lock: request.enforce_db_file_lock != 0,
3440        read_only: request.read_only != 0,
3441        allow_uri_filenames: request.allow_uri_filenames != 0,
3442        trusted_schema: request.trusted_schema != 0,
3443        defensive: request.defensive != 0,
3444    })
3445}
3446
3447/// Convert one native LanceDB enable request into the Rust SDK type.
3448/// 将一份原生 LanceDB 启用请求转换成 Rust SDK 类型。
3449fn ffi_lancedb_enable_request_to_rust(
3450    request: *const FfiControllerLanceDbEnableRequest,
3451) -> Result<ControllerLanceDbEnableRequest, String> {
3452    if request.is_null() {
3453        return Err("lancedb enable request pointer must not be null".to_string());
3454    }
3455    let request = unsafe { &*request };
3456    let defaults = ControllerLanceDbEnableRequest::default();
3457    let space_id = required_c_string(request.space_id, "space_id")?;
3458    Ok(ControllerLanceDbEnableRequest {
3459        space_id: space_id.clone(),
3460        binding_id: space_id,
3461        default_db_path: required_c_string(request.default_db_path, "default_db_path")?,
3462        db_root: optional_c_string(request.db_root)?,
3463        read_consistency_interval_ms: optional_nonzero_u64(request.read_consistency_interval_ms),
3464        max_upsert_payload: default_u64(
3465            request.max_upsert_payload,
3466            defaults.max_upsert_payload as u64,
3467        ) as usize,
3468        max_search_limit: default_u64(request.max_search_limit, defaults.max_search_limit as u64)
3469            as usize,
3470        max_concurrent_requests: default_u64(
3471            request.max_concurrent_requests,
3472            defaults.max_concurrent_requests as u64,
3473        ) as usize,
3474    })
3475}
3476
3477/// Convert one Rust status snapshot into the native FFI shape.
3478/// 将一份 Rust 状态快照转换成原生 FFI 结构。
3479fn map_status_snapshot(snapshot: ControllerStatusSnapshot) -> FfiControllerStatusSnapshot {
3480    FfiControllerStatusSnapshot {
3481        process_mode: map_process_mode_to_native(snapshot.process_mode),
3482        bind_addr: string_into_raw(snapshot.bind_addr),
3483        started_at_unix_ms: snapshot.started_at_unix_ms,
3484        last_request_at_unix_ms: snapshot.last_request_at_unix_ms,
3485        minimum_uptime_secs: snapshot.minimum_uptime_secs,
3486        idle_timeout_secs: snapshot.idle_timeout_secs,
3487        default_lease_ttl_secs: snapshot.default_lease_ttl_secs,
3488        active_clients: snapshot.active_clients as c_ulonglong,
3489        attached_spaces: snapshot.attached_spaces as c_ulonglong,
3490        inflight_requests: snapshot.inflight_requests as c_ulonglong,
3491        shutdown_candidate: if snapshot.shutdown_candidate { 1 } else { 0 },
3492    }
3493}
3494
3495/// Convert one Rust space snapshot into the native FFI shape.
3496/// 将一份 Rust 空间快照转换成原生 FFI 结构。
3497fn map_space_snapshot(snapshot: SpaceSnapshot) -> FfiSpaceSnapshot {
3498    FfiSpaceSnapshot {
3499        space_id: string_into_raw(snapshot.space_id),
3500        space_label: string_into_raw(snapshot.space_label),
3501        space_kind: map_space_kind_to_native(snapshot.space_kind),
3502        space_root: string_into_raw(snapshot.space_root),
3503        attached_clients: snapshot.attached_clients as c_ulonglong,
3504        sqlite: map_backend_status_option(snapshot.sqlite),
3505        lancedb: map_backend_status_option(snapshot.lancedb),
3506    }
3507}
3508
3509/// Convert one Rust space snapshot vector into the native FFI array wrapper.
3510/// 将一组 Rust 空间快照转换成原生 FFI 数组包装结构。
3511fn map_space_snapshot_array(spaces: Vec<SpaceSnapshot>) -> FfiSpaceSnapshotArray {
3512    let mut mapped: Vec<FfiSpaceSnapshot> = spaces.into_iter().map(map_space_snapshot).collect();
3513    let items = mapped.as_mut_ptr();
3514    let len = mapped.len();
3515    std::mem::forget(mapped);
3516    FfiSpaceSnapshotArray { items, len }
3517}
3518
3519/// Convert one optional backend status into one optional native heap allocation.
3520/// 将一条可选后端状态转换成可选原生堆分配。
3521fn map_backend_status_option(status: Option<SpaceBackendStatus>) -> *mut FfiSpaceBackendStatus {
3522    status
3523        .map(|status| {
3524            Box::into_raw(Box::new(FfiSpaceBackendStatus {
3525                enabled: if status.enabled { 1 } else { 0 },
3526                mode: string_into_raw(status.mode),
3527                target: string_into_raw(status.target),
3528            }))
3529        })
3530        .unwrap_or(ptr::null_mut())
3531}
3532
3533/// Convert one Rust SQLite execute result into the native FFI shape.
3534/// 将一份 Rust SQLite 执行结果转换成原生 FFI 结构。
3535fn map_sqlite_execute_result(
3536    result: ControllerSqliteExecuteResult,
3537) -> FfiControllerSqliteExecuteResult {
3538    FfiControllerSqliteExecuteResult {
3539        success: if result.success { 1 } else { 0 },
3540        message: string_into_raw(result.message),
3541        rows_changed: result.rows_changed,
3542        last_insert_rowid: result.last_insert_rowid,
3543    }
3544}
3545
3546/// Convert one Rust SQLite query result into the native FFI shape.
3547/// 将一份 Rust SQLite 查询结果转换成原生 FFI 结构。
3548fn map_sqlite_query_result(result: ControllerSqliteQueryResult) -> FfiControllerSqliteQueryResult {
3549    FfiControllerSqliteQueryResult {
3550        json_data: string_into_raw(result.json_data),
3551        row_count: result.row_count,
3552    }
3553}
3554
3555/// Convert one Rust SQLite batch execution result into the native FFI shape.
3556/// 将一份 Rust SQLite 批量执行结果转换成原生 FFI 结构。
3557fn map_sqlite_execute_batch_result(
3558    result: ControllerSqliteExecuteBatchResult,
3559) -> FfiControllerSqliteExecuteBatchResult {
3560    FfiControllerSqliteExecuteBatchResult {
3561        success: if result.success { 1 } else { 0 },
3562        message: string_into_raw(result.message),
3563        rows_changed: result.rows_changed,
3564        last_insert_rowid: result.last_insert_rowid,
3565        statements_executed: result.statements_executed,
3566    }
3567}
3568
3569/// Convert one Rust SQLite streaming query result into the native FFI shape.
3570/// 将一份 Rust SQLite 流式查询结果转换成原生 FFI 结构。
3571fn map_sqlite_query_stream_result(
3572    result: ControllerSqliteQueryStreamCompatResult,
3573) -> FfiControllerSqliteQueryStreamResult {
3574    let chunks = map_byte_buffer_array(result.chunks);
3575    FfiControllerSqliteQueryStreamResult {
3576        chunks: Box::into_raw(Box::new(chunks)),
3577        row_count: result.row_count,
3578        chunk_count: result.chunk_count,
3579        total_bytes: result.total_bytes,
3580    }
3581}
3582
3583/// Collect one controller-managed SQLite stream into the current FFI compatibility result shape.
3584/// 将一条由控制器管理的 SQLite 流收集成当前 FFI 兼容结果形态。
3585fn collect_sqlite_query_stream_result(
3586    runtime: &Runtime,
3587    client: &ControllerClient,
3588    space_id: String,
3589    binding_id: String,
3590    sql: String,
3591    params: Vec<ControllerSqliteValue>,
3592    chunk_size: Option<u64>,
3593) -> Result<ControllerSqliteQueryStreamCompatResult, String> {
3594    let stream = runtime
3595        .block_on(
3596            client.open_sqlite_query_stream_typed(space_id, binding_id, sql, params, chunk_size),
3597        )
3598        .map_err(error_to_string)?;
3599    let stream_id = stream.stream_id;
3600
3601    let collected = (|| -> Result<ControllerSqliteQueryStreamCompatResult, String> {
3602        let metrics = runtime
3603            .block_on(client.wait_sqlite_query_stream_metrics(stream_id))
3604            .map_err(error_to_string)?;
3605        let mut chunks = Vec::with_capacity(metrics.chunk_count as usize);
3606        for index in 0..metrics.chunk_count {
3607            let chunk = runtime
3608                .block_on(client.read_sqlite_query_stream_chunk(stream_id, index))
3609                .map_err(error_to_string)?;
3610            chunks.push(chunk);
3611        }
3612        Ok(ControllerSqliteQueryStreamCompatResult {
3613            chunks,
3614            row_count: metrics.row_count,
3615            chunk_count: metrics.chunk_count,
3616            total_bytes: metrics.total_bytes,
3617        })
3618    })();
3619
3620    let _ = runtime.block_on(client.close_sqlite_query_stream(stream_id));
3621    collected
3622}
3623
3624/// Convert one Rust SQLite tokenize result into the native FFI shape.
3625/// 将一份 Rust SQLite 分词结果转换成原生 FFI 结构。
3626fn map_sqlite_tokenize_result(
3627    result: ControllerSqliteTokenizeResult,
3628) -> FfiControllerSqliteTokenizeResult {
3629    FfiControllerSqliteTokenizeResult {
3630        tokenizer_mode: string_into_raw(result.tokenizer_mode),
3631        normalized_text: string_into_raw(result.normalized_text),
3632        tokens_json: string_into_raw(
3633            serde_json::to_string(&result.tokens).expect("token list serialization must not fail"),
3634        ),
3635        fts_query: string_into_raw(result.fts_query),
3636    }
3637}
3638
3639/// Convert one Rust SQLite list-custom-words result into the native FFI shape.
3640/// 将一份 Rust SQLite 自定义词列表结果转换成原生 FFI 结构。
3641fn map_sqlite_list_custom_words_result(
3642    result: ControllerSqliteListCustomWordsResult,
3643) -> FfiControllerSqliteListCustomWordsResult {
3644    FfiControllerSqliteListCustomWordsResult {
3645        success: if result.success { 1 } else { 0 },
3646        message: string_into_raw(result.message),
3647        words: Box::into_raw(Box::new(map_custom_word_array(result.words))),
3648    }
3649}
3650
3651/// Convert one Rust SQLite dictionary mutation result into the native FFI shape.
3652/// 将一份 Rust SQLite 词典变更结果转换成原生 FFI 结构。
3653fn map_sqlite_dictionary_mutation_result(
3654    result: ControllerSqliteDictionaryMutationResult,
3655) -> FfiControllerSqliteDictionaryMutationResult {
3656    FfiControllerSqliteDictionaryMutationResult {
3657        success: if result.success { 1 } else { 0 },
3658        message: string_into_raw(result.message),
3659        affected_rows: result.affected_rows,
3660    }
3661}
3662
3663/// Convert one Rust SQLite ensure-FTS result into the native FFI shape.
3664/// 将一份 Rust SQLite FTS 确认结果转换成原生 FFI 结构。
3665fn map_sqlite_ensure_fts_index_result(
3666    result: ControllerSqliteEnsureFtsIndexResult,
3667) -> FfiControllerSqliteEnsureFtsIndexResult {
3668    FfiControllerSqliteEnsureFtsIndexResult {
3669        success: if result.success { 1 } else { 0 },
3670        message: string_into_raw(result.message),
3671        index_name: string_into_raw(result.index_name),
3672        tokenizer_mode: string_into_raw(result.tokenizer_mode),
3673    }
3674}
3675
3676/// Convert one Rust SQLite rebuild-FTS result into the native FFI shape.
3677/// 将一份 Rust SQLite FTS 重建结果转换成原生 FFI 结构。
3678fn map_sqlite_rebuild_fts_index_result(
3679    result: ControllerSqliteRebuildFtsIndexResult,
3680) -> FfiControllerSqliteRebuildFtsIndexResult {
3681    FfiControllerSqliteRebuildFtsIndexResult {
3682        success: if result.success { 1 } else { 0 },
3683        message: string_into_raw(result.message),
3684        index_name: string_into_raw(result.index_name),
3685        tokenizer_mode: string_into_raw(result.tokenizer_mode),
3686        reindexed_rows: result.reindexed_rows,
3687    }
3688}
3689
3690/// Convert one Rust SQLite FTS mutation result into the native FFI shape.
3691/// 将一份 Rust SQLite FTS 文档变更结果转换成原生 FFI 结构。
3692fn map_sqlite_fts_mutation_result(
3693    result: ControllerSqliteFtsMutationResult,
3694) -> FfiControllerSqliteFtsMutationResult {
3695    FfiControllerSqliteFtsMutationResult {
3696        success: if result.success { 1 } else { 0 },
3697        message: string_into_raw(result.message),
3698        affected_rows: result.affected_rows,
3699        index_name: string_into_raw(result.index_name),
3700    }
3701}
3702
3703/// Convert one Rust SQLite FTS search result into the native FFI shape.
3704/// 将一份 Rust SQLite FTS 检索结果转换成原生 FFI 结构。
3705fn map_sqlite_search_fts_result(
3706    result: ControllerSqliteSearchFtsResult,
3707) -> FfiControllerSqliteSearchFtsResult {
3708    FfiControllerSqliteSearchFtsResult {
3709        success: if result.success { 1 } else { 0 },
3710        message: string_into_raw(result.message),
3711        index_name: string_into_raw(result.index_name),
3712        tokenizer_mode: string_into_raw(result.tokenizer_mode),
3713        normalized_query: string_into_raw(result.normalized_query),
3714        fts_query: string_into_raw(result.fts_query),
3715        source: string_into_raw(result.source),
3716        query_mode: string_into_raw(result.query_mode),
3717        total: result.total,
3718        hits: Box::into_raw(Box::new(map_search_fts_hit_array(result.hits))),
3719    }
3720}
3721
3722/// Convert one Rust LanceDB create-table result into the native FFI shape.
3723/// 将一份 Rust LanceDB 建表结果转换成原生 FFI 结构。
3724fn map_lancedb_create_table_result(
3725    result: ControllerLanceDbCreateTableResult,
3726) -> FfiControllerLanceDbCreateTableResult {
3727    FfiControllerLanceDbCreateTableResult {
3728        message: string_into_raw(result.message),
3729    }
3730}
3731
3732/// Convert one Rust LanceDB upsert result into the native FFI shape.
3733/// 将一份 Rust LanceDB 写入结果转换成原生 FFI 结构。
3734fn map_lancedb_upsert_result(
3735    result: ControllerLanceDbUpsertResult,
3736) -> FfiControllerLanceDbUpsertResult {
3737    FfiControllerLanceDbUpsertResult {
3738        message: string_into_raw(result.message),
3739        version: result.version,
3740        input_rows: result.input_rows,
3741        inserted_rows: result.inserted_rows,
3742        updated_rows: result.updated_rows,
3743        deleted_rows: result.deleted_rows,
3744    }
3745}
3746
3747/// Convert one Rust LanceDB search result into the native FFI shape.
3748/// 将一份 Rust LanceDB 检索结果转换成原生 FFI 结构。
3749fn map_lancedb_search_result(
3750    result: ControllerLanceDbSearchResult,
3751) -> FfiControllerLanceDbSearchResult {
3752    let (data, data_len) = bytes_into_raw(result.data);
3753    FfiControllerLanceDbSearchResult {
3754        message: string_into_raw(result.message),
3755        format: string_into_raw(result.format),
3756        rows: result.rows,
3757        data,
3758        data_len,
3759    }
3760}
3761
3762/// Convert one Rust LanceDB delete result into the native FFI shape.
3763/// 将一份 Rust LanceDB 删除结果转换成原生 FFI 结构。
3764fn map_lancedb_delete_result(
3765    result: ControllerLanceDbDeleteResult,
3766) -> FfiControllerLanceDbDeleteResult {
3767    FfiControllerLanceDbDeleteResult {
3768        message: string_into_raw(result.message),
3769        version: result.version,
3770        deleted_rows: result.deleted_rows,
3771    }
3772}
3773
3774/// Convert one Rust LanceDB drop-table result into the native FFI shape.
3775/// 将一份 Rust LanceDB 删表结果转换成原生 FFI 结构。
3776fn map_lancedb_drop_table_result(
3777    result: ControllerLanceDbDropTableResult,
3778) -> FfiControllerLanceDbDropTableResult {
3779    FfiControllerLanceDbDropTableResult {
3780        message: string_into_raw(result.message),
3781    }
3782}
3783
3784/// Convert one byte-chunk vector into the native FFI array shape.
3785/// 将一组字节分块转换成原生 FFI 数组结构。
3786fn map_byte_buffer_array(chunks: Vec<Vec<u8>>) -> FfiByteBufferArray {
3787    let mut items: Vec<FfiByteBuffer> = chunks
3788        .into_iter()
3789        .map(|chunk| {
3790            let (data, len) = bytes_into_raw(chunk);
3791            FfiByteBuffer { data, len }
3792        })
3793        .collect();
3794    let ptr = items.as_mut_ptr();
3795    let len = items.len();
3796    std::mem::forget(items);
3797    FfiByteBufferArray { items: ptr, len }
3798}
3799
3800/// Convert one custom-word vector into the native FFI array shape.
3801/// 将一组自定义词向量转换成原生 FFI 数组结构。
3802fn map_custom_word_array(
3803    words: Vec<ControllerSqliteCustomWordEntry>,
3804) -> FfiControllerSqliteCustomWordArray {
3805    let mut items: Vec<FfiControllerSqliteCustomWordEntry> = words
3806        .into_iter()
3807        .map(|entry| FfiControllerSqliteCustomWordEntry {
3808            word: string_into_raw(entry.word),
3809            weight: entry.weight as c_ulonglong,
3810        })
3811        .collect();
3812    let ptr = items.as_mut_ptr();
3813    let len = items.len();
3814    std::mem::forget(items);
3815    FfiControllerSqliteCustomWordArray { items: ptr, len }
3816}
3817
3818/// Convert one FTS hit vector into the native FFI array shape.
3819/// 将一组 FTS 命中向量转换成原生 FFI 数组结构。
3820fn map_search_fts_hit_array(
3821    hits: Vec<ControllerSqliteSearchFtsHit>,
3822) -> FfiControllerSqliteSearchFtsHitArray {
3823    let mut items: Vec<FfiControllerSqliteSearchFtsHit> = hits
3824        .into_iter()
3825        .map(|hit| FfiControllerSqliteSearchFtsHit {
3826            id: string_into_raw(hit.id),
3827            file_path: string_into_raw(hit.file_path),
3828            title: string_into_raw(hit.title),
3829            title_highlight: string_into_raw(hit.title_highlight),
3830            content_snippet: string_into_raw(hit.content_snippet),
3831            score: hit.score,
3832            rank: hit.rank,
3833            raw_score: hit.raw_score,
3834        })
3835        .collect();
3836    let ptr = items.as_mut_ptr();
3837    let len = items.len();
3838    std::mem::forget(items);
3839    FfiControllerSqliteSearchFtsHitArray { items: ptr, len }
3840}
3841
3842/// Read one required UTF-8 string from an FFI pointer.
3843/// 从 FFI 指针读取一条必填 UTF-8 字符串。
3844fn required_c_string(value: *const c_char, field_name: &str) -> Result<String, String> {
3845    if value.is_null() {
3846        return Err(format!("{field_name} pointer must not be null"));
3847    }
3848    let value = unsafe { CStr::from_ptr(value) };
3849    let text = value
3850        .to_str()
3851        .map_err(|error| format!("{field_name} must be valid UTF-8: {error}"))?
3852        .trim()
3853        .to_string();
3854    if text.is_empty() {
3855        return Err(format!("{field_name} must not be empty"));
3856    }
3857    Ok(text)
3858}
3859
3860/// Read one required UTF-8 string from an FFI pointer without trimming or empty rejection.
3861/// 从 FFI 指针读取一条必填 UTF-8 字符串,但不裁剪空白且允许空串。
3862fn required_c_string_preserve(value: *const c_char, field_name: &str) -> Result<String, String> {
3863    if value.is_null() {
3864        return Err(format!("{field_name} pointer must not be null"));
3865    }
3866    let value = unsafe { CStr::from_ptr(value) };
3867    value
3868        .to_str()
3869        .map(|text| text.to_string())
3870        .map_err(|error| format!("{field_name} must be valid UTF-8: {error}"))
3871}
3872
3873/// Read one required UTF-8 string array from FFI pointers.
3874/// 从 FFI 指针读取一组必填 UTF-8 字符串。
3875fn required_string_array(
3876    items: *const *const c_char,
3877    len: usize,
3878    field_name: &str,
3879) -> Result<Vec<String>, String> {
3880    if items.is_null() {
3881        return Err(format!("{field_name} pointer must not be null"));
3882    }
3883    let slice = unsafe { std::slice::from_raw_parts(items, len) };
3884    slice
3885        .iter()
3886        .enumerate()
3887        .map(|(index, item)| required_c_string(*item, &format!("{field_name}[{index}]")))
3888        .collect()
3889}
3890
3891/// Read one optional UTF-8 string from an FFI pointer.
3892/// 从 FFI 指针读取一条可选 UTF-8 字符串。
3893fn optional_c_string(value: *const c_char) -> Result<Option<String>, String> {
3894    if value.is_null() {
3895        return Ok(None);
3896    }
3897    let value = unsafe { CStr::from_ptr(value) };
3898    let text = value
3899        .to_str()
3900        .map_err(|error| format!("optional string must be valid UTF-8: {error}"))?
3901        .trim()
3902        .to_string();
3903    if text.is_empty() {
3904        Ok(None)
3905    } else {
3906        Ok(Some(text))
3907    }
3908}
3909
3910/// Parse one native tokenizer-mode string into the shared enum.
3911/// 将一条原生分词模式字符串解析成共享枚举。
3912fn parse_sqlite_tokenizer_mode_text(
3913    value: *const c_char,
3914) -> Result<ControllerSqliteTokenizerMode, String> {
3915    let value = required_c_string(value, "tokenizer_mode")?;
3916    parse_sqlite_tokenizer_mode_name(&value)
3917}
3918
3919/// Parse one tokenizer-mode name into the shared enum.
3920/// 将一条分词模式名称解析成共享枚举。
3921fn parse_sqlite_tokenizer_mode_name(value: &str) -> Result<ControllerSqliteTokenizerMode, String> {
3922    match value.trim().to_ascii_lowercase().as_str() {
3923        "" | "none" => Ok(ControllerSqliteTokenizerMode::None),
3924        "jieba" => Ok(ControllerSqliteTokenizerMode::Jieba),
3925        other => Err(format!("unsupported tokenizer_mode: {other}")),
3926    }
3927}
3928
3929/// Convert one JSON scalar or bytes wrapper into the shared SQLite typed value.
3930/// 将一条 JSON 标量或 bytes 包装对象转换成共享 SQLite 类型化值。
3931fn json_to_sqlite_value(value: JsonValue) -> Result<ControllerSqliteValue, String> {
3932    match value {
3933        JsonValue::Null => Ok(ControllerSqliteValue::Null),
3934        JsonValue::Bool(value) => Ok(ControllerSqliteValue::Bool(value)),
3935        JsonValue::Number(value) => {
3936            if let Some(value) = value.as_i64() {
3937                Ok(ControllerSqliteValue::Int64(value))
3938            } else if let Some(value) = value.as_u64() {
3939                Ok(ControllerSqliteValue::Int64(i64::try_from(value).map_err(
3940                    |_| "params contains an unsigned integer larger than i64".to_string(),
3941                )?))
3942            } else if let Some(value) = value.as_f64() {
3943                Ok(ControllerSqliteValue::Float64(value))
3944            } else {
3945                Err("params contains an unsupported numeric value".to_string())
3946            }
3947        }
3948        JsonValue::String(value) => Ok(ControllerSqliteValue::String(value)),
3949        JsonValue::Object(value) => {
3950            let wrapper = serde_json::from_value::<JsonSqliteBytesValue>(JsonValue::Object(value))
3951                .map_err(|_| {
3952                    "params object values must use {\"type\":\"bytes_base64\",\"base64\":\"...\"} or {\"__type\":\"bytes_base64\",\"base64\":\"...\"}".to_string()
3953                })?;
3954            let wrapper_type = if !wrapper.r#type.trim().is_empty() {
3955                wrapper.r#type.trim()
3956            } else {
3957                wrapper.__type.trim()
3958            };
3959            if wrapper_type != "bytes_base64" {
3960                return Err(
3961                    "params object values only support the bytes_base64 wrapper type".to_string(),
3962                );
3963            }
3964            Ok(ControllerSqliteValue::Bytes(decode_base64(
3965                &wrapper.base64,
3966            )?))
3967        }
3968        JsonValue::Array(_) => {
3969            Err("params only supports scalar JSON values or bytes wrapper objects".to_string())
3970        }
3971    }
3972}
3973
3974/// Read one required byte slice from raw pointer and length.
3975/// 从原始指针与长度读取一段必填字节切片。
3976fn required_bytes<'a>(data: *const u8, len: usize, field_name: &str) -> Result<&'a [u8], String> {
3977    if data.is_null() {
3978        return Err(format!("{field_name} pointer must not be null"));
3979    }
3980    if len == 0 {
3981        return Err(format!("{field_name} length must be greater than zero"));
3982    }
3983    Ok(unsafe { std::slice::from_raw_parts(data, len) })
3984}
3985
3986/// Read one byte slice from raw pointer and length while allowing an empty blob.
3987/// 从原始指针与长度读取一段字节切片,并允许空 blob。
3988fn optional_bytes<'a>(data: *const u8, len: usize, field_name: &str) -> Result<&'a [u8], String> {
3989    if len == 0 {
3990        return Ok(&[]);
3991    }
3992    if data.is_null() {
3993        return Err(format!(
3994            "{field_name} pointer must not be null when len > 0"
3995        ));
3996    }
3997    Ok(unsafe { std::slice::from_raw_parts(data, len) })
3998}
3999
4000/// Read one optional UTF-8 string array from FFI pointers.
4001/// 从 FFI 指针读取一组可选 UTF-8 字符串。
4002fn optional_string_array(
4003    items: *const *const c_char,
4004    len: usize,
4005    field_name: &str,
4006) -> Result<Vec<String>, String> {
4007    if len == 0 {
4008        return Ok(Vec::new());
4009    }
4010    required_string_array(items, len, field_name)
4011}
4012
4013/// Read one required float32 slice from raw pointer and length.
4014/// 从原始指针与长度读取一段必填 float32 切片。
4015fn required_f32_slice<'a>(
4016    data: *const c_float,
4017    len: usize,
4018    field_name: &str,
4019) -> Result<&'a [c_float], String> {
4020    if data.is_null() {
4021        return Err(format!("{field_name} pointer must not be null"));
4022    }
4023    if len == 0 {
4024        return Err(format!("{field_name} length must be greater than zero"));
4025    }
4026    Ok(unsafe { std::slice::from_raw_parts(data, len) })
4027}
4028
4029/// Read one native SQLite value array into shared typed values.
4030/// 将一组原生 SQLite 值数组读取成共享类型化值。
4031fn read_sqlite_values(
4032    values: *const FfiSqliteValue,
4033    len: usize,
4034    field_name: &str,
4035) -> Result<Vec<ControllerSqliteValue>, String> {
4036    if len == 0 {
4037        return Ok(Vec::new());
4038    }
4039    if values.is_null() {
4040        return Err(format!("{field_name} pointer must not be null"));
4041    }
4042    let slice = unsafe { std::slice::from_raw_parts(values, len) };
4043    slice
4044        .iter()
4045        .enumerate()
4046        .map(|(index, value)| map_sqlite_value_native(value, &format!("{field_name}[{index}]")))
4047        .collect()
4048}
4049
4050/// Read one native SQLite batch item array into shared typed values.
4051/// 将一组原生 SQLite 批量参数项读取成共享类型化值。
4052fn read_sqlite_batch_items(
4053    items: *const FfiSqliteBatchItem,
4054    len: usize,
4055    field_name: &str,
4056) -> Result<Vec<Vec<ControllerSqliteValue>>, String> {
4057    if len == 0 {
4058        return Ok(Vec::new());
4059    }
4060    if items.is_null() {
4061        return Err(format!("{field_name} pointer must not be null"));
4062    }
4063    let slice = unsafe { std::slice::from_raw_parts(items, len) };
4064    slice
4065        .iter()
4066        .enumerate()
4067        .map(|(index, item)| {
4068            read_sqlite_values(
4069                item.params,
4070                item.params_len,
4071                &format!("{field_name}[{index}].params"),
4072            )
4073        })
4074        .collect()
4075}
4076
4077/// Read one native LanceDB column-definition array into shared typed values.
4078/// 将一组原生 LanceDB 列定义数组读取成共享类型化值。
4079fn read_lancedb_columns(
4080    columns: *const FfiControllerLanceDbColumnDef,
4081    len: usize,
4082    field_name: &str,
4083) -> Result<Vec<ControllerLanceDbColumnDef>, String> {
4084    if columns.is_null() {
4085        return Err(format!("{field_name} pointer must not be null"));
4086    }
4087    if len == 0 {
4088        return Err(format!("{field_name} length must be greater than zero"));
4089    }
4090    let slice = unsafe { std::slice::from_raw_parts(columns, len) };
4091    slice
4092        .iter()
4093        .enumerate()
4094        .map(|(index, column)| {
4095            Ok(ControllerLanceDbColumnDef {
4096                name: required_c_string(column.name, &format!("{field_name}[{index}].name"))?,
4097                column_type: map_lancedb_column_type_native(column.column_type)?,
4098                vector_dim: column.vector_dim,
4099                nullable: column.nullable != 0,
4100            })
4101        })
4102        .collect()
4103}
4104
4105/// Convert one native SQLite value into the shared typed value.
4106/// 将一条原生 SQLite 值转换成共享类型化值。
4107fn map_sqlite_value_native(
4108    value: &FfiSqliteValue,
4109    field_name: &str,
4110) -> Result<ControllerSqliteValue, String> {
4111    match value.kind {
4112        0 => Ok(ControllerSqliteValue::Int64(value.int64_value)),
4113        1 => Ok(ControllerSqliteValue::Float64(value.float64_value)),
4114        2 => Ok(ControllerSqliteValue::String(required_c_string_preserve(
4115            value.string_value,
4116            &format!("{field_name}.string_value"),
4117        )?)),
4118        3 => Ok(ControllerSqliteValue::Bytes(
4119            optional_bytes(
4120                value.bytes_value,
4121                value.bytes_len,
4122                &format!("{field_name}.bytes_value"),
4123            )?
4124            .to_vec(),
4125        )),
4126        4 => Ok(ControllerSqliteValue::Bool(value.bool_value != 0)),
4127        5 => Ok(ControllerSqliteValue::Null),
4128        other => Err(format!("unsupported sqlite value kind `{other}`")),
4129    }
4130}
4131
4132/// Return the default nullable flag for JSON LanceDB column definitions.
4133/// 返回 JSON LanceDB 列定义使用的默认可空标记。
4134fn default_nullable() -> bool {
4135    true
4136}
4137
4138/// Return the default search limit for JSON LanceDB search requests.
4139/// 返回 JSON LanceDB 检索请求使用的默认 limit。
4140fn default_search_limit() -> u32 {
4141    10
4142}
4143
4144/// Parse one JSON input pointer into the requested Rust type.
4145/// 将一个 JSON 输入指针解析成请求的 Rust 类型。
4146fn parse_json_input<T>(json: *const c_char) -> Result<T, String>
4147where
4148    T: for<'de> Deserialize<'de>,
4149{
4150    let json = required_c_string(json, "json")?;
4151    serde_json::from_str(&json).map_err(|error| format!("failed to parse json input: {error}"))
4152}
4153
4154/// Encode one Rust string into a heap-owned C string pointer.
4155/// 将一条 Rust 字符串编码成堆拥有的 C 字符串指针。
4156fn string_into_raw(value: String) -> *mut c_char {
4157    let sanitized = if value.contains('\0') {
4158        value.replace('\0', "\u{FFFD}")
4159    } else {
4160        value
4161    };
4162    CString::new(sanitized)
4163        .expect("sanitized string must not contain interior null bytes")
4164        .into_raw()
4165}
4166
4167/// Encode one byte vector into one heap-owned raw pointer and length.
4168/// 将一段字节向量编码成堆拥有的原始指针与长度。
4169fn bytes_into_raw(mut value: Vec<u8>) -> (*mut u8, usize) {
4170    let ptr = value.as_mut_ptr();
4171    let len = value.len();
4172    std::mem::forget(value);
4173    (ptr, len)
4174}
4175
4176/// Run one closure with a mutable controller handle reference.
4177/// 使用一个可变控制器句柄引用执行闭包。
4178fn with_client_handle<T>(
4179    client: *mut FfiControllerClientHandle,
4180    func: impl FnOnce(&mut FfiControllerClientHandleInner) -> Result<T, String>,
4181) -> Result<T, String> {
4182    let handle_id = ffi_client_handle_id_from_ptr(client)?;
4183    let state = {
4184        let registry = ffi_client_handle_registry()
4185            .lock()
4186            .map_err(|poisoned| format!("ffi client handle registry lock poisoned: {poisoned}"))?;
4187        registry
4188            .get(&handle_id)
4189            .cloned()
4190            .ok_or_else(|| "client handle is invalid or has been freed".to_string())?
4191    };
4192    let mut guard = match state.inner.lock() {
4193        Ok(guard) => guard,
4194        Err(poisoned) => poisoned.into_inner(),
4195    };
4196    let inner = guard
4197        .as_mut()
4198        .ok_or_else(|| "client handle is invalid or has been freed".to_string())?;
4199    func(inner)
4200}
4201
4202/// Convert one process mode integer into the Rust enum.
4203/// 将一个进程模式整数转换成 Rust 枚举。
4204fn map_process_mode_native(raw: c_int) -> Result<ControllerProcessMode, String> {
4205    match raw {
4206        0 => Ok(ControllerProcessMode::Service),
4207        1 => Ok(ControllerProcessMode::Managed),
4208        _ => Err(format!("unsupported process mode value `{raw}`")),
4209    }
4210}
4211
4212/// Convert one Rust process mode into the stable native integer.
4213/// 将一个 Rust 进程模式转换成稳定原生整数。
4214fn map_process_mode_to_native(mode: ControllerProcessMode) -> c_int {
4215    match mode {
4216        ControllerProcessMode::Service => 0,
4217        ControllerProcessMode::Managed => 1,
4218    }
4219}
4220
4221/// Convert one space kind integer into the Rust enum.
4222/// 将一个空间类型整数转换成 Rust 枚举。
4223fn map_space_kind_native(raw: c_int) -> Result<SpaceKind, String> {
4224    match raw {
4225        0 => Ok(SpaceKind::Root),
4226        1 => Ok(SpaceKind::User),
4227        2 => Ok(SpaceKind::Project),
4228        _ => Err(format!("unsupported space kind value `{raw}`")),
4229    }
4230}
4231
4232/// Convert one Rust space kind into the stable native integer.
4233/// 将一个 Rust 空间类型转换成稳定原生整数。
4234fn map_space_kind_to_native(kind: SpaceKind) -> c_int {
4235    match kind {
4236        SpaceKind::Root => 0,
4237        SpaceKind::User => 1,
4238        SpaceKind::Project => 2,
4239    }
4240}
4241
4242/// Convert one native LanceDB column-type integer into the shared enum.
4243/// 将一个原生 LanceDB 列类型整数转换成共享枚举。
4244fn map_lancedb_column_type_native(raw: c_int) -> Result<ControllerLanceDbColumnType, String> {
4245    match raw {
4246        0 => Ok(ControllerLanceDbColumnType::Unspecified),
4247        1 => Ok(ControllerLanceDbColumnType::String),
4248        2 => Ok(ControllerLanceDbColumnType::Int64),
4249        3 => Ok(ControllerLanceDbColumnType::Float64),
4250        4 => Ok(ControllerLanceDbColumnType::Bool),
4251        5 => Ok(ControllerLanceDbColumnType::VectorFloat32),
4252        6 => Ok(ControllerLanceDbColumnType::Float32),
4253        7 => Ok(ControllerLanceDbColumnType::Uint64),
4254        8 => Ok(ControllerLanceDbColumnType::Int32),
4255        9 => Ok(ControllerLanceDbColumnType::Uint32),
4256        other => Err(format!("unsupported lancedb column type `{other}`")),
4257    }
4258}
4259
4260/// Convert one native LanceDB input-format integer into the shared enum.
4261/// 将一个原生 LanceDB 输入格式整数转换成共享枚举。
4262fn map_lancedb_input_format_native(raw: c_int) -> Result<ControllerLanceDbInputFormat, String> {
4263    match raw {
4264        0 => Ok(ControllerLanceDbInputFormat::Unspecified),
4265        1 => Ok(ControllerLanceDbInputFormat::JsonRows),
4266        2 => Ok(ControllerLanceDbInputFormat::ArrowIpc),
4267        other => Err(format!("unsupported lancedb input format `{other}`")),
4268    }
4269}
4270
4271/// Convert one native LanceDB output-format integer into the shared enum.
4272/// 将一个原生 LanceDB 输出格式整数转换成共享枚举。
4273fn map_lancedb_output_format_native(raw: c_int) -> Result<ControllerLanceDbOutputFormat, String> {
4274    match raw {
4275        0 => Ok(ControllerLanceDbOutputFormat::Unspecified),
4276        1 => Ok(ControllerLanceDbOutputFormat::ArrowIpc),
4277        2 => Ok(ControllerLanceDbOutputFormat::JsonRows),
4278        other => Err(format!("unsupported lancedb output format `{other}`")),
4279    }
4280}
4281
4282/// Return the fallback when the provided value is zero.
4283/// 当提供值为零时返回回退值。
4284fn default_u64(value: c_ulonglong, fallback: u64) -> u64 {
4285    if value == 0 { fallback } else { value }
4286}
4287
4288/// Convert zero into `None`.
4289/// 将零值转换成 `None`。
4290fn optional_nonzero_u64(value: c_ulonglong) -> Option<u64> {
4291    if value == 0 { None } else { Some(value) }
4292}
4293
4294/// Write a native pointer output slot.
4295/// 写入一个原生指针输出槽位。
4296fn write_out_ptr<T>(slot: *mut *mut T, value: *mut T) {
4297    if !slot.is_null() {
4298        unsafe {
4299            *slot = value;
4300        }
4301    }
4302}
4303
4304/// Write one boxed native value only when the output slot is available.
4305/// 仅在输出槽可用时写入一个装箱后的原生值。
4306fn write_boxed_out_ptr<T>(slot: *mut *mut T, value: T) {
4307    if !slot.is_null() {
4308        unsafe {
4309            *slot = Box::into_raw(Box::new(value));
4310        }
4311    }
4312}
4313
4314/// Clear a native pointer output slot.
4315/// 清空一个原生指针输出槽位。
4316fn clear_out_ptr<T>(slot: *mut *mut T) {
4317    if !slot.is_null() {
4318        unsafe {
4319            *slot = ptr::null_mut();
4320        }
4321    }
4322}
4323
4324/// Write one byte flag output slot.
4325/// 写入一个字节标志输出槽位。
4326fn write_out_u8(slot: *mut c_uchar, value: c_uchar) {
4327    if !slot.is_null() {
4328        unsafe {
4329            *slot = value;
4330        }
4331    }
4332}
4333
4334/// Clear one byte flag output slot.
4335/// 清空一个字节标志输出槽位。
4336fn clear_out_u8(slot: *mut c_uchar) {
4337    if !slot.is_null() {
4338        unsafe {
4339            *slot = 0;
4340        }
4341    }
4342}
4343
4344/// Clear the error output slot.
4345/// 清空错误输出槽位。
4346fn clear_error_out(error_out: *mut *mut c_char) {
4347    clear_out_ptr(error_out);
4348}
4349
4350/// Write one heap-owned response string only when the output slot is available.
4351/// 仅在输出槽可用时写入一条堆拥有的响应字符串。
4352fn write_string_out(slot: *mut *mut c_char, value: String) {
4353    if !slot.is_null() {
4354        unsafe {
4355            *slot = string_into_raw(value);
4356        }
4357    }
4358}
4359
4360/// Return one success status and clear any stale error output.
4361/// 返回成功状态并清空任何陈旧错误输出。
4362fn ffi_ok_status(error_out: *mut *mut c_char) -> c_int {
4363    clear_error_out(error_out);
4364    FFI_STATUS_OK
4365}
4366
4367/// Return one error status and write the error string when possible.
4368/// 返回错误状态并在可能时写入错误字符串。
4369fn ffi_error_status(error_out: *mut *mut c_char, message: impl Into<String>) -> c_int {
4370    clear_error_out(error_out);
4371    if !error_out.is_null() {
4372        unsafe {
4373            *error_out = string_into_raw(message.into());
4374        }
4375    }
4376    FFI_STATUS_ERR
4377}
4378
4379/// Convert one displayable error into a stable string.
4380/// 将一个可显示错误转换成稳定字符串。
4381fn error_to_string(error: impl std::fmt::Display) -> String {
4382    error.to_string()
4383}
4384
4385/// Free one space snapshot and all nested heap allocations.
4386/// 释放一份空间快照及其全部嵌套堆分配。
4387fn free_space_snapshot_fields(snapshot: FfiSpaceSnapshot) {
4388    vldb_controller_ffi_string_free(snapshot.space_id);
4389    vldb_controller_ffi_string_free(snapshot.space_label);
4390    vldb_controller_ffi_string_free(snapshot.space_root);
4391    free_backend_status_ptr(snapshot.sqlite);
4392    free_backend_status_ptr(snapshot.lancedb);
4393}
4394
4395/// Free one optional backend status allocation.
4396/// 释放一条可选后端状态分配。
4397fn free_backend_status_ptr(status: *mut FfiSpaceBackendStatus) {
4398    if !status.is_null() {
4399        unsafe {
4400            let status = Box::from_raw(status);
4401            vldb_controller_ffi_string_free(status.mode);
4402            vldb_controller_ffi_string_free(status.target);
4403        }
4404    }
4405}
4406
4407/// Encode bytes as base64 without introducing extra dependencies.
4408/// 在不引入额外依赖的前提下将字节编码成 base64。
4409fn encode_base64(data: &[u8]) -> String {
4410    const TABLE: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4411    let mut output = String::with_capacity(data.len().div_ceil(3) * 4);
4412    for chunk in data.chunks(3) {
4413        let a = chunk[0];
4414        let b = *chunk.get(1).unwrap_or(&0);
4415        let c = *chunk.get(2).unwrap_or(&0);
4416        output.push(TABLE[(a >> 2) as usize] as char);
4417        output.push(TABLE[(((a & 0x03) << 4) | (b >> 4)) as usize] as char);
4418        if chunk.len() > 1 {
4419            output.push(TABLE[(((b & 0x0f) << 2) | (c >> 6)) as usize] as char);
4420        } else {
4421            output.push('=');
4422        }
4423        if chunk.len() > 2 {
4424            output.push(TABLE[(c & 0x3f) as usize] as char);
4425        } else {
4426            output.push('=');
4427        }
4428    }
4429    output
4430}
4431
4432/// Decode base64 text without introducing extra dependencies.
4433/// 在不引入额外依赖的前提下解码 base64 文本。
4434fn decode_base64(input: &str) -> Result<Vec<u8>, String> {
4435    let bytes = input.as_bytes();
4436    if !bytes.len().is_multiple_of(4) {
4437        return Err("base64 input length must be a multiple of 4".to_string());
4438    }
4439    let mut output = Vec::with_capacity(bytes.len() / 4 * 3);
4440    for chunk in bytes.chunks(4) {
4441        let a = decode_base64_char(chunk[0])?;
4442        let b = decode_base64_char(chunk[1])?;
4443        let c = if chunk[2] == b'=' {
4444            64
4445        } else {
4446            decode_base64_char(chunk[2])?
4447        };
4448        let d = if chunk[3] == b'=' {
4449            64
4450        } else {
4451            decode_base64_char(chunk[3])?
4452        };
4453
4454        output.push((a << 2) | (b >> 4));
4455        if c != 64 {
4456            output.push(((b & 0x0f) << 4) | (c >> 2));
4457        }
4458        if d != 64 {
4459            output.push(((c & 0x03) << 6) | d);
4460        }
4461    }
4462    Ok(output)
4463}
4464
4465/// Decode one base64 character into its 6-bit value.
4466/// 将一个 base64 字符解码成 6 位值。
4467fn decode_base64_char(value: u8) -> Result<u8, String> {
4468    match value {
4469        b'A'..=b'Z' => Ok(value - b'A'),
4470        b'a'..=b'z' => Ok(value - b'a' + 26),
4471        b'0'..=b'9' => Ok(value - b'0' + 52),
4472        b'+' => Ok(62),
4473        b'/' => Ok(63),
4474        _ => Err(format!("invalid base64 character `{}`", value as char)),
4475    }
4476}
4477
4478#[cfg(test)]
4479mod tests {
4480    use super::{
4481        CreateLanceDbTableJsonRequest, DeleteLanceDbJsonRequest, ExecuteSqliteBatchJsonRequest,
4482        ExecuteSqliteScriptJsonRequest, FFI_STATUS_ERR, FFI_STATUS_OK, FfiClientRegistration,
4483        FfiControllerClientConfig, FfiControllerClientHandle, FfiSqliteValue,
4484        QuerySqliteJsonJsonRequest, QuerySqliteStreamJsonRequest, SearchLanceDbJsonRequest,
4485        UpsertLanceDbJsonRequest, build_client_handle, map_sqlite_value_native,
4486        required_c_string_preserve, vldb_controller_ffi_client_create,
4487        vldb_controller_ffi_client_free, with_client_handle,
4488    };
4489    use serde_json::json;
4490    use std::ffi::CString;
4491    use vldb_controller_client::{
4492        ClientRegistration, ControllerClientConfig, ControllerSqliteValue,
4493    };
4494
4495    #[test]
4496    fn sqlite_native_string_preserves_whitespace_and_allows_empty() {
4497        let spaced = CString::new("  a  ").expect("cstring should build");
4498        let empty = CString::new("").expect("cstring should build");
4499        let spaced_value = FfiSqliteValue {
4500            kind: 2,
4501            int64_value: 0,
4502            float64_value: 0.0,
4503            string_value: spaced.as_ptr(),
4504            bytes_value: std::ptr::null(),
4505            bytes_len: 0,
4506            bool_value: 0,
4507        };
4508        let empty_value = FfiSqliteValue {
4509            kind: 2,
4510            int64_value: 0,
4511            float64_value: 0.0,
4512            string_value: empty.as_ptr(),
4513            bytes_value: std::ptr::null(),
4514            bytes_len: 0,
4515            bool_value: 0,
4516        };
4517
4518        assert_eq!(
4519            map_sqlite_value_native(&spaced_value, "value").expect("string should parse"),
4520            ControllerSqliteValue::String("  a  ".to_string())
4521        );
4522        assert_eq!(
4523            map_sqlite_value_native(&empty_value, "value").expect("empty string should parse"),
4524            ControllerSqliteValue::String(String::new())
4525        );
4526        assert_eq!(
4527            required_c_string_preserve(empty.as_ptr(), "value").expect("empty string should read"),
4528            String::new()
4529        );
4530    }
4531
4532    #[test]
4533    fn sqlite_native_bytes_allow_empty_blob() {
4534        let value = FfiSqliteValue {
4535            kind: 3,
4536            int64_value: 0,
4537            float64_value: 0.0,
4538            string_value: std::ptr::null(),
4539            bytes_value: std::ptr::null(),
4540            bytes_len: 0,
4541            bool_value: 0,
4542        };
4543
4544        assert_eq!(
4545            map_sqlite_value_native(&value, "value").expect("empty blob should parse"),
4546            ControllerSqliteValue::Bytes(Vec::new())
4547        );
4548    }
4549
4550    #[test]
4551    fn preserve_string_reader_keeps_whitespace_for_text_payloads() {
4552        let spaced = CString::new("  keep  ").expect("cstring should build");
4553        assert_eq!(
4554            required_c_string_preserve(spaced.as_ptr(), "text").expect("text should read"),
4555            "  keep  ".to_string()
4556        );
4557    }
4558
4559    #[test]
4560    fn preserve_string_reader_allows_empty_text_payloads() {
4561        let empty = CString::new("").expect("cstring should build");
4562        assert_eq!(
4563            required_c_string_preserve(empty.as_ptr(), "content")
4564                .expect("empty content should read"),
4565            String::new()
4566        );
4567    }
4568
4569    #[test]
4570    fn sqlite_json_requests_accept_nested_params_without_inner_json_strings() {
4571        let execute: ExecuteSqliteScriptJsonRequest = serde_json::from_value(json!({
4572            "space_id": "ROOT",
4573            "sql": "SELECT ?",
4574            "params": [1, {"type": "bytes_base64", "base64": "AQID"}]
4575        }))
4576        .expect("execute request should parse");
4577        assert_eq!(execute.params.len(), 2);
4578
4579        let query: QuerySqliteJsonJsonRequest = serde_json::from_value(json!({
4580            "space_id": "ROOT",
4581            "sql": "SELECT ?",
4582            "params": ["  keep  "]
4583        }))
4584        .expect("query request should parse");
4585        assert_eq!(query.params.len(), 1);
4586
4587        let batch: ExecuteSqliteBatchJsonRequest = serde_json::from_value(json!({
4588            "space_id": "ROOT",
4589            "sql": "INSERT INTO demo VALUES (?)",
4590            "batch_params": [[1], [2], [{"__type": "bytes_base64", "base64": "AQ=="}]]
4591        }))
4592        .expect("batch request should parse");
4593        assert_eq!(batch.batch_params.len(), 3);
4594
4595        let stream: QuerySqliteStreamJsonRequest = serde_json::from_value(json!({
4596            "space_id": "ROOT",
4597            "sql": "SELECT ?",
4598            "params": [],
4599            "target_chunk_size": 1024
4600        }))
4601        .expect("stream request should parse");
4602        assert_eq!(stream.target_chunk_size, Some(1024));
4603    }
4604
4605    #[test]
4606    fn lancedb_json_requests_accept_nested_objects_without_request_json() {
4607        let create: CreateLanceDbTableJsonRequest = serde_json::from_value(json!({
4608            "space_id": "ROOT",
4609            "table_name": "memory",
4610            "columns": [
4611                {"name": "id", "column_type": "string", "nullable": false},
4612                {"name": "vector", "column_type": "vector", "vector_dim": 3, "nullable": false}
4613            ],
4614            "overwrite_if_exists": true
4615        }))
4616        .expect("create request should parse");
4617        assert_eq!(create.columns.len(), 2);
4618
4619        let upsert: UpsertLanceDbJsonRequest = serde_json::from_value(json!({
4620            "space_id": "ROOT",
4621            "table_name": "memory",
4622            "input_format": "json_rows",
4623            "key_columns": ["id"],
4624            "data_base64": "W10="
4625        }))
4626        .expect("upsert request should parse");
4627        assert_eq!(upsert.key_columns, vec!["id".to_string()]);
4628
4629        let search: SearchLanceDbJsonRequest = serde_json::from_value(json!({
4630            "space_id": "ROOT",
4631            "table_name": "memory",
4632            "vector": [0.1, 0.2, 0.3],
4633            "limit": 5,
4634            "filter": "kind = 'note'",
4635            "vector_column": "vector",
4636            "output_format": "json_rows"
4637        }))
4638        .expect("search request should parse");
4639        assert_eq!(search.vector.len(), 3);
4640
4641        let delete: DeleteLanceDbJsonRequest = serde_json::from_value(json!({
4642            "space_id": "ROOT",
4643            "table_name": "memory",
4644            "condition": "id = 'a'"
4645        }))
4646        .expect("delete request should parse");
4647        assert_eq!(delete.condition, "id = 'a'");
4648    }
4649
4650    #[test]
4651    fn freed_handle_rejects_follow_up_calls_safely() {
4652        let handle_ptr = build_client_handle(
4653            ControllerClientConfig::default(),
4654            ClientRegistration {
4655                client_name: "ffi-test-client".to_string(),
4656                host_kind: "test".to_string(),
4657                process_id: 7,
4658                process_name: "ffi-test".to_string(),
4659                lease_ttl_secs: Some(60),
4660            },
4661        )
4662        .expect("handle should build");
4663
4664        with_client_handle(handle_ptr, |_handle| Ok(())).expect("live handle should work");
4665        vldb_controller_ffi_client_free(handle_ptr);
4666
4667        let error = with_client_handle(handle_ptr, |_handle| Ok(()))
4668            .expect_err("freed handle should reject later calls");
4669        assert!(
4670            error.contains("freed"),
4671            "error should mention freed state, got: {error}"
4672        );
4673
4674        vldb_controller_ffi_client_free(handle_ptr);
4675    }
4676
4677    #[test]
4678    fn native_create_keeps_error_out_optional_and_clears_reused_slots() {
4679        let client_name = CString::new("ffi-create-client").expect("client_name should build");
4680        let host_kind = CString::new("test").expect("host_kind should build");
4681        let process_name = CString::new("ffi-create").expect("process_name should build");
4682        let config = FfiControllerClientConfig {
4683            endpoint: std::ptr::null(),
4684            auto_spawn: 0,
4685            spawn_executable: std::ptr::null(),
4686            spawn_process_mode: 0,
4687            minimum_uptime_secs: 0,
4688            idle_timeout_secs: 0,
4689            default_lease_ttl_secs: 0,
4690            connect_timeout_secs: 0,
4691            startup_timeout_secs: 0,
4692            startup_retry_interval_ms: 0,
4693            lease_renew_interval_secs: 0,
4694        };
4695        let registration = FfiClientRegistration {
4696            client_name: client_name.as_ptr(),
4697            host_kind: host_kind.as_ptr(),
4698            process_id: 9,
4699            process_name: process_name.as_ptr(),
4700            lease_ttl_secs: 0,
4701        };
4702
4703        let mut handle_ptr = std::ptr::null_mut::<FfiControllerClientHandle>();
4704        let create_status = vldb_controller_ffi_client_create(
4705            &config,
4706            &registration,
4707            &mut handle_ptr,
4708            std::ptr::null_mut(),
4709        );
4710        assert_eq!(create_status, FFI_STATUS_OK);
4711        assert!(
4712            !handle_ptr.is_null(),
4713            "create should still succeed without error_out"
4714        );
4715        vldb_controller_ffi_client_free(handle_ptr);
4716
4717        let mut stale_handle_ptr = std::ptr::dangling_mut::<FfiControllerClientHandle>();
4718        let failure_status = vldb_controller_ffi_client_create(
4719            std::ptr::null(),
4720            &registration,
4721            &mut stale_handle_ptr,
4722            std::ptr::null_mut(),
4723        );
4724        assert_eq!(failure_status, FFI_STATUS_ERR);
4725        assert!(
4726            stale_handle_ptr.is_null(),
4727            "client_out should be cleared before returning an error"
4728        );
4729    }
4730
4731    #[test]
4732    fn forged_handle_pointer_is_rejected_even_when_other_handles_are_live() {
4733        let handle_ptr = build_client_handle(
4734            ControllerClientConfig::default(),
4735            ClientRegistration {
4736                client_name: "ffi-forge-client".to_string(),
4737                host_kind: "test".to_string(),
4738                process_id: 11,
4739                process_name: "ffi-forge".to_string(),
4740                lease_ttl_secs: Some(60),
4741            },
4742        )
4743        .expect("handle should build");
4744
4745        let forged_handle_ptr = std::ptr::dangling_mut::<FfiControllerClientHandle>();
4746        assert_ne!(
4747            handle_ptr, forged_handle_ptr,
4748            "forged handle pointer must differ from the live registered handle"
4749        );
4750
4751        let error = with_client_handle(forged_handle_ptr, |_handle| Ok(()))
4752            .expect_err("forged handle pointer should be rejected");
4753        assert!(
4754            error.contains("invalid") || error.contains("freed"),
4755            "error should mention invalid or freed handle state, got: {error}"
4756        );
4757
4758        with_client_handle(handle_ptr, |_handle| Ok(())).expect("live handle should still work");
4759        vldb_controller_ffi_client_free(handle_ptr);
4760    }
4761}