⌘+k ctrl+k
1.4 (LTS)
搜索快捷键 cmd + k | ctrl + k
向量

向量表示列的水平切片。它们包含特定数量的特定类型的值,类似于数组。向量是 DuckDB 中使用的核心数据表示形式。向量通常存储在 数据块 (data chunks) 中。

向量和数据块接口是与 DuckDB 交互最高效的方式,可实现极致性能。然而,这些接口使用起来也比较困难,使用时必须格外小心。

向量格式

向量是特定数据类型的数组。向量的逻辑类型可以使用 duckdb_vector_get_column_type 获取。逻辑类型的类型 ID 可以通过 duckdb_get_type_id 获取。

向量本身没有大小。相反,父级数据块具有大小(可通过 duckdb_data_chunk_get_size 获取)。属于同一个数据块的所有向量具有相同的大小。

原始类型

对于原始类型,底层数组可以使用 duckdb_vector_get_data 方法获取。然后可以使用正确的原生类型访问该数组。下表包含了 duckdb_type 到数组原生类型的映射。

duckdb_type NativeType (原生类型)
DUCKDB_TYPE_BOOLEAN bool
DUCKDB_TYPE_TINYINT int8_t
DUCKDB_TYPE_SMALLINT int16_t
DUCKDB_TYPE_INTEGER int32_t
DUCKDB_TYPE_BIGINT int64_t
DUCKDB_TYPE_UTINYINT uint8_t
DUCKDB_TYPE_USMALLINT uint16_t
DUCKDB_TYPE_UINTEGER uint32_t
DUCKDB_TYPE_UBIGINT uint64_t
DUCKDB_TYPE_FLOAT float
DUCKDB_TYPE_DOUBLE double
DUCKDB_TYPE_TIMESTAMP duckdb_timestamp
DUCKDB_TYPE_DATE duckdb_date
DUCKDB_TYPE_TIME duckdb_time
DUCKDB_TYPE_INTERVAL duckdb_interval
DUCKDB_TYPE_HUGEINT duckdb_hugeint
DUCKDB_TYPE_UHUGEINT duckdb_uhugeint
DUCKDB_TYPE_VARCHAR duckdb_string_t
DUCKDB_TYPE_BLOB duckdb_string_t
DUCKDB_TYPE_TIMESTAMP_S duckdb_timestamp
DUCKDB_TYPE_TIMESTAMP_MS duckdb_timestamp
DUCKDB_TYPE_TIMESTAMP_NS duckdb_timestamp
DUCKDB_TYPE_UUID duckdb_hugeint
DUCKDB_TYPE_TIME_TZ duckdb_time_tz
DUCKDB_TYPE_TIMESTAMP_TZ duckdb_timestamp

NULL

向量中的任何值都可以是 NULL。当值为 NULL 时,主数组在该索引处包含的值是未定义的(并且可能是未初始化的)。有效性掩码 (validity mask) 是由 uint64_t 元素组成的位掩码。向量中每 64 个值,就存在一个 uint64_t 元素(向上取整)。如果值有效,有效性掩码中的位设置为 1;如果值无效(即 NULL),则设置为 0。

位掩码中的位可以直接读取,或者使用较慢的辅助方法 duckdb_validity_row_is_valid 来检查值是否为 NULL

duckdb_vector_get_validity 返回指向有效性掩码的指针。请注意,如果向量中的所有值都有效,此函数可能返回 nullptr,在这种情况下无需检查有效性掩码。

字符串

字符串值存储为 duckdb_string_t。这是一种特殊的结构体,如果字符串较短(即 <= 12 字节),则将字符串内联存储;如果长度超过 12 字节,则存储指向字符串数据的指针。

typedef struct {
	union {
		struct {
			uint32_t length;
			char prefix[4];
			char *ptr;
		} pointer;
		struct {
			uint32_t length;
			char inlined[12];
		} inlined;
	} value;
} duckdb_string_t;

可以直接访问长度,或者使用 duckdb_string_is_inlined 来检查字符串是否已内联。

十进制数 (Decimals)

十进制数在内部存储为整数值。确切的原生类型取决于十进制类型的 width(精度),如下表所示

宽度 (Width) NativeType (原生类型)
<= 4 int16_t
<= 9 int32_t
<= 18 int64_t
<= 38 duckdb_hugeint

duckdb_decimal_internal_type 可用于获取十进制数的内部类型。

十进制数存储为乘以 10^scale 的整数值。十进制数的标度 (scale) 可以使用 duckdb_decimal_scale 获取。例如,类型为 DECIMAL(8, 3) 的十进制值 10.5 在内部存储为 int32_t10500。为了获得正确的十进制值,应将该值除以相应的 10 的幂。

枚举 (Enums)

枚举在内部存储为无符号整数值。确切的原生类型取决于枚举字典的大小,如下表所示

字典大小 NativeType (原生类型)
<= 255 uint8_t
<= 65535 uint16_t
<= 4294967295 uint32_t

duckdb_enum_internal_type 可用于获取枚举的内部类型。

为了获得枚举的实际字符串值,必须使用 duckdb_enum_dictionary_value 函数来获取与给定字典条目对应的枚举值。请注意,整个列的枚举字典是相同的,因此只需构建一次。

结构体 (Structs)

结构体是嵌套类型,包含任意数量的子类型。可以将它们视为 C 语言中的 struct。使用向量访问结构体数据的方法是使用 duckdb_struct_vector_get_child 方法递归访问子向量。

结构体向量本身没有任何数据(即不应在结构体上使用 duckdb_vector_get_data 方法)。但是,结构体向量本身确实有一个有效性掩码。原因是结构体的子元素可以是 NULL,但结构体本身也可以是 NULL

列表 (Lists)

列表是嵌套类型,包含单个子类型,每行重复 x 次。可以将它们视为 C 语言中的变长数组。使用向量访问列表数据的方法是使用 duckdb_list_vector_get_child 方法访问子向量。

必须使用 duckdb_vector_get_data 获取存储为 duckdb_list_entry 的列表的偏移量和长度,然后将其应用于子向量。

typedef struct {
	uint64_t offset;
	uint64_t length;
} duckdb_list_entry;

请注意,列表条目本身以及存储在列表中的任何子项也可以是 NULL。这必须再次使用有效性掩码进行检查。

数组 (Arrays)

数组是嵌套类型,包含单个子类型,每行正好重复 array_size 次。可以将它们视为 C 语言中的定长数组。数组的工作方式与列表完全相同,不同之处在于每个条目的长度和偏移量是固定的。固定数组大小可以通过使用 duckdb_array_type_array_size 获取。条目 n 的数据位于 offset = n * array_size,长度始终为 length = array_size

请注意,与列表一样,数组仍然可以是 NULL,这必须使用有效性掩码进行检查。

示例

以下是关于如何与向量交互的几个完整端到端示例。

示例:读取带有 NULL 值的 int64 向量

duckdb_database db;
duckdb_connection con;
duckdb_open(nullptr, &db);
duckdb_connect(db, &con);

duckdb_result res;
duckdb_query(con, "SELECT CASE WHEN i%2=0 THEN NULL ELSE i END res_col FROM range(10) t(i)", &res);

// iterate until result is exhausted
while (true) {
	duckdb_data_chunk result = duckdb_fetch_chunk(res);
	if (!result) {
		// result is exhausted
		break;
	}
	// get the number of rows from the data chunk
	idx_t row_count = duckdb_data_chunk_get_size(result);
	// get the first column
	duckdb_vector res_col = duckdb_data_chunk_get_vector(result, 0);
	// get the native array and the validity mask of the vector
	int64_t *vector_data = (int64_t *) duckdb_vector_get_data(res_col);
	uint64_t *vector_validity = duckdb_vector_get_validity(res_col);
	// iterate over the rows
	for (idx_t row = 0; row < row_count; row++) {
		if (duckdb_validity_row_is_valid(vector_validity, row)) {
			printf("%lld\n", vector_data[row]);
		} else {
			printf("NULL\n");
		}
	}
	duckdb_destroy_data_chunk(&result);
}
// clean-up
duckdb_destroy_result(&res);
duckdb_disconnect(&con);
duckdb_close(&db);

示例:读取字符串向量

duckdb_database db;
duckdb_connection con;
duckdb_open(nullptr, &db);
duckdb_connect(db, &con);

duckdb_result res;
duckdb_query(con, "SELECT CASE WHEN i%2=0 THEN CONCAT('short_', i) ELSE CONCAT('longstringprefix', i) END FROM range(10) t(i)", &res);

// iterate until result is exhausted
while (true) {
	duckdb_data_chunk result = duckdb_fetch_chunk(res);
	if (!result) {
		// result is exhausted
		break;
	}
	// get the number of rows from the data chunk
	idx_t row_count = duckdb_data_chunk_get_size(result);
	// get the first column
	duckdb_vector res_col = duckdb_data_chunk_get_vector(result, 0);
	// get the native array and the validity mask of the vector
	duckdb_string_t *vector_data = (duckdb_string_t *) duckdb_vector_get_data(res_col);
	uint64_t *vector_validity = duckdb_vector_get_validity(res_col);
	// iterate over the rows
	for (idx_t row = 0; row < row_count; row++) {
		if (duckdb_validity_row_is_valid(vector_validity, row)) {
			duckdb_string_t str = vector_data[row];
			if (duckdb_string_is_inlined(str)) {
				// use inlined string
				printf("%.*s\n", str.value.inlined.length, str.value.inlined.inlined);
			} else {
				// follow string pointer
				printf("%.*s\n", str.value.pointer.length, str.value.pointer.ptr);
			}
		} else {
			printf("NULL\n");
		}
	}
	duckdb_destroy_data_chunk(&result);
}
// clean-up
duckdb_destroy_result(&res);
duckdb_disconnect(&con);
duckdb_close(&db);

示例:读取结构体向量

duckdb_database db;
duckdb_connection con;
duckdb_open(nullptr, &db);
duckdb_connect(db, &con);

duckdb_result res;
duckdb_query(con, "SELECT CASE WHEN i%5=0 THEN NULL ELSE {'col1': i, 'col2': CASE WHEN i%2=0 THEN NULL ELSE 100 + i * 42 END} END FROM range(10) t(i)", &res);

// iterate until result is exhausted
while (true) {
	duckdb_data_chunk result = duckdb_fetch_chunk(res);
	if (!result) {
		// result is exhausted
		break;
	}
	// get the number of rows from the data chunk
	idx_t row_count = duckdb_data_chunk_get_size(result);
	// get the struct column
	duckdb_vector struct_col = duckdb_data_chunk_get_vector(result, 0);
	uint64_t *struct_validity = duckdb_vector_get_validity(struct_col);
	// get the child columns of the struct
	duckdb_vector col1_vector = duckdb_struct_vector_get_child(struct_col, 0);
	int64_t *col1_data = (int64_t *) duckdb_vector_get_data(col1_vector);
	uint64_t *col1_validity = duckdb_vector_get_validity(col1_vector);

	duckdb_vector col2_vector = duckdb_struct_vector_get_child(struct_col, 1);
	int64_t *col2_data = (int64_t *) duckdb_vector_get_data(col2_vector);
	uint64_t *col2_validity = duckdb_vector_get_validity(col2_vector);

	// iterate over the rows
	for (idx_t row = 0; row < row_count; row++) {
		if (!duckdb_validity_row_is_valid(struct_validity, row)) {
			// entire struct is NULL
			printf("NULL\n");
			continue;
		}
		// read col1
		printf("{'col1': ");
		if (!duckdb_validity_row_is_valid(col1_validity, row)) {
			// col1 is NULL
			printf("NULL");
		} else {
			printf("%lld", col1_data[row]);
		}
		printf(", 'col2': ");
		if (!duckdb_validity_row_is_valid(col2_validity, row)) {
			// col2 is NULL
			printf("NULL");
		} else {
			printf("%lld", col2_data[row]);
		}
		printf("}\n");
	}
	duckdb_destroy_data_chunk(&result);
}
// clean-up
duckdb_destroy_result(&res);
duckdb_disconnect(&con);
duckdb_close(&db);

示例:读取列表向量

duckdb_database db;
duckdb_connection con;
duckdb_open(nullptr, &db);
duckdb_connect(db, &con);

duckdb_result res;
duckdb_query(con, "SELECT CASE WHEN i % 5 = 0 THEN NULL WHEN i % 2 = 0 THEN [i, i + 1] ELSE [i * 42, NULL, i * 84] END FROM range(10) t(i)", &res);

// iterate until result is exhausted
while (true) {
	duckdb_data_chunk result = duckdb_fetch_chunk(res);
	if (!result) {
		// result is exhausted
		break;
	}
	// get the number of rows from the data chunk
	idx_t row_count = duckdb_data_chunk_get_size(result);
	// get the list column
	duckdb_vector list_col = duckdb_data_chunk_get_vector(result, 0);
	duckdb_list_entry *list_data = (duckdb_list_entry *) duckdb_vector_get_data(list_col);
	uint64_t *list_validity = duckdb_vector_get_validity(list_col);
	// get the child column of the list
	duckdb_vector list_child = duckdb_list_vector_get_child(list_col);
	int64_t *child_data = (int64_t *) duckdb_vector_get_data(list_child);
	uint64_t *child_validity = duckdb_vector_get_validity(list_child);

	// iterate over the rows
	for (idx_t row = 0; row < row_count; row++) {
		if (!duckdb_validity_row_is_valid(list_validity, row)) {
			// entire list is NULL
			printf("NULL\n");
			continue;
		}
		// read the list offsets for this row
		duckdb_list_entry list = list_data[row];
		printf("[");
		for (idx_t child_idx = list.offset; child_idx < list.offset + list.length; child_idx++) {
			if (child_idx > list.offset) {
				printf(", ");
			}
			if (!duckdb_validity_row_is_valid(child_validity, child_idx)) {
				// col1 is NULL
				printf("NULL");
			} else {
				printf("%lld", child_data[child_idx]);
			}
		}
		printf("]\n");
	}
	duckdb_destroy_data_chunk(&result);
}
// clean-up
duckdb_destroy_result(&res);
duckdb_disconnect(&con);
duckdb_close(&db);

API参考概览

duckdb_vector duckdb_create_vector(duckdb_logical_type type, idx_t capacity);
void duckdb_destroy_vector(duckdb_vector *vector);
duckdb_logical_type duckdb_vector_get_column_type(duckdb_vector vector);
void *duckdb_vector_get_data(duckdb_vector vector);
uint64_t *duckdb_vector_get_validity(duckdb_vector vector);
void duckdb_vector_ensure_validity_writable(duckdb_vector vector);
void duckdb_vector_assign_string_element(duckdb_vector vector, idx_t index, const char *str);
void duckdb_vector_assign_string_element_len(duckdb_vector vector, idx_t index, const char *str, idx_t str_len);
duckdb_vector duckdb_list_vector_get_child(duckdb_vector vector);
idx_t duckdb_list_vector_get_size(duckdb_vector vector);
duckdb_state duckdb_list_vector_set_size(duckdb_vector vector, idx_t size);
duckdb_state duckdb_list_vector_reserve(duckdb_vector vector, idx_t required_capacity);
duckdb_vector duckdb_struct_vector_get_child(duckdb_vector vector, idx_t index);
duckdb_vector duckdb_array_vector_get_child(duckdb_vector vector);
void duckdb_slice_vector(duckdb_vector vector, duckdb_selection_vector sel, idx_t len);
void duckdb_vector_copy_sel(duckdb_vector src, duckdb_vector dst, duckdb_selection_vector sel, idx_t src_count, idx_t src_offset, idx_t dst_offset);
void duckdb_vector_reference_value(duckdb_vector vector, duckdb_value value);
void duckdb_vector_reference_vector(duckdb_vector to_vector, duckdb_vector from_vector);

有效性掩码函数

bool duckdb_validity_row_is_valid(uint64_t *validity, idx_t row);
void duckdb_validity_set_row_validity(uint64_t *validity, idx_t row, bool valid);
void duckdb_validity_set_row_invalid(uint64_t *validity, idx_t row);
void duckdb_validity_set_row_valid(uint64_t *validity, idx_t row);

duckdb_create_vector

创建一个平坦向量 (flat vector)。必须使用 duckdb_destroy_vector 销毁。

语法
duckdb_vector duckdb_create_vector(
  duckdb_logical_type type,
  idx_t capacity
);
参数
  • type: 向量的逻辑类型。
  • capacity: 向量的容量。
返回值

向量。


duckdb_destroy_vector

销毁向量并释放其内存。

语法
void duckdb_destroy_vector(
  duckdb_vector *vector
);
参数
  • vector: 指向向量的指针。


duckdb_vector_get_column_type

检索指定向量的列类型。

结果必须使用 duckdb_destroy_logical_type 销毁。

语法
duckdb_logical_type duckdb_vector_get_column_type(
  duckdb_vector vector
);
参数
  • vector: 获取数据的向量
返回值

向量的类型


duckdb_vector_get_data

检索向量的数据指针。

数据指针可用于从向量读取或写入值。如何读取或写入值取决于向量的类型。

语法
void *duckdb_vector_get_data(
  duckdb_vector vector
);
参数
  • vector: 获取数据的向量
返回值

数据指针


duckdb_vector_get_validity

检索指定向量的有效性掩码指针。

如果所有值都有效,此函数可能返回 NULL!

有效性掩码是一个位集,表示数据块内的空值性。它是一系列 uint64_t 值,其中每个 uint64_t 值包含 64 个元组的有效性。如果值有效(即非 NULL),则位设置为 1;如果值无效(即 NULL),则位设置为 0。

特定值的有效性可以这样获取

idx_t entry_idx = row_idx / 64; idx_t idx_in_entry = row_idx % 64; bool is_valid = validity_mask[entry_idx] & (1 << idx_in_entry);

或者,可以使用(较慢的)duckdb_validity_row_is_valid 函数。

语法
uint64_t *duckdb_vector_get_validity(
  duckdb_vector vector
);
参数
  • vector: 获取数据的向量
返回值

指向有效性掩码的指针,如果不存在有效性掩码,则为 NULL


duckdb_vector_ensure_validity_writable

通过分配内存确保有效性掩码是可写的。

调用此函数后,duckdb_vector_get_validity 将始终返回非 NULL 指针。这允许将 NULL 值写入向量,无论之前是否存在有效性掩码。

语法
void duckdb_vector_ensure_validity_writable(
  duckdb_vector vector
);
参数
  • vector: 要更改的向量


duckdb_vector_assign_string_element

在指定位置分配向量中的字符串元素。

语法
void duckdb_vector_assign_string_element(
  duckdb_vector vector,
  idx_t index,
  const char *str
);
参数
  • vector: 要更改的向量
  • index: 向量中要分配字符串的行位置
  • str: 以空字符结尾的字符串


duckdb_vector_assign_string_element_len

在指定位置分配向量中的字符串元素。您也可以使用此函数分配 BLOB。

语法
void duckdb_vector_assign_string_element_len(
  duckdb_vector vector,
  idx_t index,
  const char *str,
  idx_t str_len
);
参数
  • vector: 要更改的向量
  • index: 向量中要分配字符串的行位置
  • str: 字符串
  • str_len: 字符串长度(以字节为单位)


duckdb_list_vector_get_child

检索列表向量的子向量。

只要父向量有效,生成的向量就有效。

语法
duckdb_vector duckdb_list_vector_get_child(
  duckdb_vector vector
);
参数
  • vector: 向量
返回值

子向量


duckdb_list_vector_get_size

返回列表的子向量的大小。

语法
idx_t duckdb_list_vector_get_size(
  duckdb_vector vector
);
参数
  • vector: 向量
返回值

子列表的大小


duckdb_list_vector_set_size

设置列表向量的底层子向量的总大小。

语法
duckdb_state duckdb_list_vector_set_size(
  duckdb_vector vector,
  idx_t size
);
参数
  • vector: 列表向量。
  • size: 子列表的大小。
返回值

duckdb 状态。如果向量为 nullptr,则返回 DuckDBError。


duckdb_list_vector_reserve

设置列表底层子向量的总容量。

调用此方法后,必须调用 duckdb_vector_get_validityduckdb_vector_get_data 以获取当前数据和有效性指针。

语法
duckdb_state duckdb_list_vector_reserve(
  duckdb_vector vector,
  idx_t required_capacity
);
参数
  • vector: 列表向量。
  • required_capacity: 要预留的总容量。
返回值

duckdb 状态。如果向量为 nullptr,则返回 DuckDBError。


duckdb_struct_vector_get_child

检索结构体向量的子向量。只要父向量有效,生成的向量就有效。

语法
duckdb_vector duckdb_struct_vector_get_child(
  duckdb_vector vector,
  idx_t index
);
参数
  • vector: 向量
  • index:子索引
返回值

子向量


duckdb_array_vector_get_child

检索数组向量的子向量。只要父向量有效,生成的向量就有效。生成的向量大小为父向量大小乘以数组大小。

语法
duckdb_vector duckdb_array_vector_get_child(
  duckdb_vector vector
);
参数
  • vector: 向量
返回值

子向量


duckdb_slice_vector

使用选择向量 (selection vector) 切片向量。选择向量的长度必须小于或等于向量的长度。将向量转换为字典向量 (dictionary vector)。

语法
void duckdb_slice_vector(
  duckdb_vector vector,
  duckdb_selection_vector sel,
  idx_t len
);
参数
  • vector: 要切片的向量。
  • sel: 选择向量。
  • len: 选择向量的长度。


duckdb_vector_copy_sel

使用标识要复制索引的选择向量,将 src 向量复制到 dst。

语法
void duckdb_vector_copy_sel(
  duckdb_vector src,
  duckdb_vector dst,
  duckdb_selection_vector sel,
  idx_t src_count,
  idx_t src_offset,
  idx_t dst_offset
);
参数
  • src: 要从中复制的源向量。
  • dst: 要复制到的目标向量。
  • sel: 选择向量。选择向量的长度不应超过 src 向量的长度。
  • src_count: 从选择向量中要复制的条目数。可以将其视为从索引 0 开始的选择向量的有效长度。
  • src_offset: 选择向量中开始复制的偏移量(重要:实际复制的项目数 = src_count - src_offset)。
  • dst_offset: dst 向量中开始复制的偏移量。


duckdb_vector_reference_value

将值从 value 复制到 vector

语法
void duckdb_vector_reference_value(
  duckdb_vector vector,
  duckdb_value value
);
参数
  • vector: 接收向量。
  • value: 要复制到向量中的值。


duckdb_vector_reference_vector

更改 to_vector 以引用 `from_vector`。之后,向量共享数据的所有权。

语法
void duckdb_vector_reference_vector(
  duckdb_vector to_vector,
  duckdb_vector from_vector
);
参数
  • to_vector: 接收向量。
  • from_vector: 要引用的向量。


duckdb_validity_row_is_valid

返回给定有效性掩码中的行是否有效(即非 NULL)。

语法
bool duckdb_validity_row_is_valid(
  uint64_t *validity,
  idx_t row
);
参数
  • validity: 有效性掩码,通过 duckdb_vector_get_validity 获取。
  • row: 行索引。
返回值

如果行为有效,则为 true,否则为 false。


duckdb_validity_set_row_validity

在有效性掩码中,将特定行设置为有效或无效。

请注意,在调用 duckdb_vector_get_validity 之前,应调用 duckdb_vector_ensure_validity_writable,以确保存在可写入的有效性掩码。

语法
void duckdb_validity_set_row_validity(
  uint64_t *validity,
  idx_t row,
  bool valid
);
参数
  • validity: 有效性掩码,通过 duckdb_vector_get_validity 获取。
  • row: 行索引。
  • valid: 是否将行设置为有效或无效。


duckdb_validity_set_row_invalid

在有效性掩码中,将特定行设置为无效。

等效于 duckdb_validity_set_row_validity,并将 valid 设置为 false。

语法
void duckdb_validity_set_row_invalid(
  uint64_t *validity,
  idx_t row
);
参数
  • validity: 有效性掩码。
  • row: 行索引。


duckdb_validity_set_row_valid

在有效性掩码中,将特定行设置为有效。

等效于 duckdb_validity_set_row_validity,并将 valid 设置为 true。

语法
void duckdb_validity_set_row_valid(
  uint64_t *validity,
  idx_t row
);
参数
  • validity: 有效性掩码。
  • row: 行索引。


© 2025 DuckDB 基金会,阿姆斯特丹,荷兰
行为准则 商标使用指南