duckfn 0.0.18

Write DuckDB extensions in plain Rust: attribute macros that turn ordinary functions into scalar/aggregate/table functions, SQL macros and nested LIST/MAP/ARRAY/STRUCT types.
Documentation
# name: test/sql/functions/table_function.test
# description: duck_table_function 的返回形式、参数(位置/命名/可空/复杂类型)、输出 schema、数据规模与注册控制
# group: [functions]

require duckfn

# LIST / STRUCT 列统一用 CAST(... AS VARCHAR) 后按文本比对

# ============================================================================
# 返回类型:三种形式
# ============================================================================

# -> impl Iterator<Item = RangeRow>:参数解析成功后不会再失败
query II
SELECT * FROM dfn_table_range(3);
----
0	0
1	1
2	4

# 空结果集
query II
SELECT * FROM dfn_table_range(0);
----

query I
SELECT count(*) FROM dfn_table_range(0);
----
0

# 负数由函数自己夹成空
query I
SELECT count(*) FROM dfn_table_range(-5);
----
0

# FROM 语法等价(不需要 SELECT *)
query II
FROM dfn_table_range(2);
----
0	0
1	1

# -> DuckResult<impl Iterator<...>>:入参语义错误在 bind 阶段报错
query II
SELECT * FROM dfn_table_checked(3);
----
0	0
1	1
2	4

statement error
SELECT * FROM dfn_table_checked(-1);
----
dfn_table_checked: n must be >= 0

# -> DuckFullIteratorResult<...>:行级 NULL(Ok(None))让该行所有列为 NULL
query II
SELECT * FROM dfn_table_full(2);
----
0	0
NULL	NULL

# 行级错误(Err)让整条查询失败
statement error
SELECT * FROM dfn_table_full(5);
----
dfn_table_full: bad row 2

# ============================================================================
# 参数:位置 / 命名 / 可空 / 复杂类型
# ============================================================================

# 零参数:DuckArgsImpl 是空结构体
query II
SELECT * FROM dfn_table_zero_args();
----
0	0
1	1
2	4

statement error
SELECT * FROM dfn_table_zero_args(1);
----
No function matches

# 命名参数:step 是位置参数,start/count 从 named_param_from 开始是命名参数
query I
SELECT n FROM dfn_table_countdown(2, start=10, count=3);
----
10
8
6

# 位置参数不能用命名形式传(named_param_from 之前的位置参数没有名字)
statement error
SELECT n FROM dfn_table_countdown(step=2, start=10, count=3);
----
No function matches

# 未知命名参数会被 DuckDB 拦下
statement error
SELECT * FROM dfn_table_countdown(2, start=10, count=3, foo=1);
----
Invalid named parameter "foo"

# 可空命名参数:不传就是 None,函数给默认值
query I
SELECT n FROM dfn_table_opt(start=1);
----
1
2
3

query I
SELECT n FROM dfn_table_opt(start=1, step=10, count=2);
----
1
11

# 显式传 NULL 和不传等价
query I
SELECT n FROM dfn_table_opt(start=1, step=NULL, count=NULL);
----
1
2
3

# 不可空命名参数:不传报错
statement error
SELECT * FROM dfn_table_req();
----
Parameter start cannot be null

# 不可空命名参数:传 NULL 同样报错
statement error
SELECT * FROM dfn_table_req(start=NULL);
----
Parameter start cannot be null

query II
SELECT * FROM dfn_table_req(start=5);
----
5	25

# LIST 参数:Vec<i64>,元素不允许为 NULL
query II
SELECT * FROM dfn_table_from_list([3, 1, 2]);
----
3	9
1	1
2	4

statement error
SELECT * FROM dfn_table_from_list([1, NULL, 3]);
----
Vec<T> value is None

# MAP 参数:IndexMap<String, i64>,保持字面量插入顺序
query TI
SELECT * FROM dfn_table_from_map(MAP {'a': 1, 'b': 2});
----
a	1
b	2

# 参数类型不匹配
statement error
SELECT * FROM dfn_table_range('x');
----
No function matches

statement error
SELECT * FROM dfn_table_from_list(1);
----
No function matches

# ============================================================================
# 输出 schema:多列、可空列、LIST 列、嵌套 STRUCT 列
# ============================================================================

query IT
SELECT id, name FROM dfn_table_typed(3);
----
0	row_0
1	row_1
2	row_2

# Option<f64> 字段是可空列
query IR
SELECT id, score FROM dfn_table_typed(3);
----
0	0.0
1	NULL
2	1.0

# Vec<Option<i64>> 字段是 LIST(BIGINT) 列,空列表是 []
query TT
SELECT id, CAST(tags AS VARCHAR) FROM dfn_table_typed(3);
----
0	[]
1	[0]
2	[0, 1]

# 列名与列类型来自输出结构体
query TT
SELECT column_name, column_type FROM (DESCRIBE SELECT * FROM dfn_table_typed(1));
----
id	BIGINT
name	VARCHAR
score	DOUBLE
tags	BIGINT[]

# 嵌套 DuckStruct 字段是 STRUCT 列
query TT
SELECT name, CAST(from_point AS VARCHAR) FROM dfn_table_nested(2);
----
s0	{'x': 0, 'y': 1}
s1	{'x': 1, 'y': 2}

# STRUCT 列可以直接取子字段
query II
SELECT from_point.x, to_point.y FROM dfn_table_nested(2);
----
0	0
1	3

query T
SELECT column_type FROM (DESCRIBE SELECT * FROM dfn_table_nested(1)) WHERE column_name = 'from_point';
----
STRUCT(x BIGINT, y BIGINT)

# ============================================================================
# 数据规模与在 SQL 中的使用
# ============================================================================

# 正好一个 chunk(vector_size 默认 2048)
query I
SELECT count(*) FROM dfn_table_range(2048);
----
2048

# 跨 chunk:2048 之后的行不能被丢掉或串位
query III
SELECT count(*), min(n), max(n) FROM dfn_table_range(2049);
----
2049	0	2048

query I
SELECT n FROM dfn_table_range(2049) WHERE n >= 2047 ORDER BY n;
----
2047
2048

query III
SELECT count(*), min(n), max(n) FROM dfn_table_range(5000);
----
5000	0	4999

# WHERE / ORDER BY
query I
SELECT n FROM dfn_table_range(5) WHERE n % 2 = 1;
----
1
3

# JOIN
query II
SELECT t.n, x.n FROM dfn_table_range(3) t JOIN dfn_table_range(2) x ON t.n = x.n ORDER BY t.n;
----
0	0
1	1

# CTE + 聚合
query I
SELECT sum(square)::BIGINT FROM (SELECT * FROM dfn_table_range(4)) t;
----
14

# ============================================================================
# 注册控制:auto_register = false 与手动注册
# ============================================================================

# 只声明、不注册:SQL 层看不到这个名字
statement error
SELECT * FROM dfn_table_reg_unregistered(1);
----
Table Function with name dfn_table_reg_unregistered does not exist

# #[duck_custom_register] + table_function_builder() 手动注册后可用
query II
SELECT * FROM dfn_table_reg_manual(2);
----
100	10000
101	10201