用户定义函数 (UDFs) 和用户定义表函数 (UDTFs)¶
BodoSQL 支持在查询和视图中使用 Snowflake UDFs 和 UDTFs。要在 BodoSQL 中使用 UDFs 和 UDTFs,您必须首先使用适当的 create function 命令在您的 Snowflake 账户中注册和定义它们。一旦函数被创建,只要您的用户可以访问 function's metadata,BodoSQL 就可以处理使用该函数的查询。
用法¶
UDF 像其他 SQL 函数一样使用,除了有两种可能的调用约定。
MY_UDF(arg1, arg2, ..., argN)
MY_UDF(name1=>arg1, name2=>arg2, ..., nameN=>argN)
调用函数时,您必须要么按位置传递所有参数,要么按名称传递(不能混合这两种方式)。如果按名称传递参数,则可以按任何顺序传递它们。例如,以下调用是等效的。
调用UDTF时,您必须将函数包装在一个 TABLE() 调用中,之后您可以在可以使用表的任何地方使用该函数。例如:
要在UDTF中引用另一个表的列,您可以使用逗号连接,通常可以与lateral关键字一起使用。例如:
或者
调用约定最佳实践¶
在调用 UDF 或 UDTF 时,我们强烈建议始终使用命名调用约定。这是因为 UDF 支持重载定义,使用不同的名称是确保调用正确函数的最安全方式。有关更多信息,请参见 Snowflake Documentation 的这一部分。即使您当前未使用重载函数,我们也鼓励您采取这种做法,以防将来函数发生重载。
要求¶
BodoSQL 必须能够直接从其定义中执行 UDF。为此,BodoSQL 需要能够获取定义并执行它,产生以下要求:
- 该函数必须用SQL编写。
- 函数体的所有元素必须在 BodoSQL 中受到支持。
- 执行 Bodo 的用户必须有权访问函数主体中引用的任何表或视图。
- 该函数不能使用secure关键字定义。
- 该函数不得使用外部关键字定义。
此外,由于可用元数据的缺口,还有一些其他限制需要注意:
- 此时,我们无法支持默认值,因为默认值未存储在元数据中。仍然可以通过提供默认值来执行这些功能。
- 参数名称中的某些特殊字符,尤其是逗号或空格,可能无法编译,因为它们在Snowflake元数据中未正确转义。
性能¶
BodoSQL支持UDF和UDTF,直接将函数体内联到查询的主体中。这意味着这些函数的用户应该达到与直接在查询中编写函数体相同的性能。
对于复杂的 UDFs 或 UDTFs,简单地执行函数主体可能需要生成相关子查询,这是一种每行在另一个表中都必须执行一次查询的操作。这可能会导致显著的性能下降,因此 BodoSQL 经过一种称为去相关的过程,将查询重写为更高效的连接。如果 BodoSQL 无法重写查询,则会引发错误,指示关联无法完全移除。
重载定义优先级¶
如上所述,Snowflake UDF 支持重载定义。这意味着您可以使用不同的参数签名多次定义相同的函数名称,并且将通过确定“最佳匹配”来选择一个函数,这可能通过隐式转换实现。
BodoSQL 支持此功能,但如果没有精确匹配,则 BodoSQL 无法保证 等效的 Snowflake 行为。Snowflake 说明了哪些 隐式类型转换是合法的, 但它并不提供在多个可能的匹配需要隐式转换的情况下将选择哪个函数的承诺。
当BodoSQL遇到UDF调用时,如果没有精确匹配,我们将查看每个可能的UDF定义的隐式转换优先级,如下表所示。
| 来源类型 | 目标选项 1 | 目标选项 2 | 目标选项 3 | 目标选项 4 | 目标选项 5 | 目标选项 6 | 目标选项 7 | 目标选项 8 | 目标选项 9 | 目标选项 10 |
|---|---|---|---|---|---|---|---|---|---|---|
| 数组 | 变体 | |||||||||
| 布尔值 | 可变字符 | 变体 | ||||||||
| 日期 | 时间戳_LTZ | 时间戳_NTZ | 字符串 | 变体 | ||||||
| 双精度 | 布尔值 | 变体 | 可变字符 | 数字 | ||||||
| 数字 | 双精度 | 布尔值 | 变体 | 变长字符 | ||||||
| 对象 | 变体 | |||||||||
| 时间 | 字符串 | |||||||||
| 时间戳_NTZ | 时间戳_LTZ | 可变字符 | 日期 | 时间 | 变体 | |||||
| 时间戳_LTZ | 时间戳_NTZ | 可变字符 | 日期 | 时间 | 变体 | |||||
| 可变字符 | 布尔值 | 日期 | 双精度 | 本地时间戳 | 无时区时间戳 | 数字 | 时间 | 变体 | ||
| 变体 | 数组 | 布尔值 | 对象 | 可变字符 | 日期 | 时间 | 时区时间戳 | 无时区时间戳 | 双精度浮点数 | 数字 |
在这里,选项编号越低,优先级越高,完全匹配的优先级为0,并被省略。 如果没有完全匹配的函数,则通过计算所需转换的“优先级”来计算最接近的签名,针对每个参数基于上述表格,并选择具有最小距离总和的实现。 如果遇到平局,则根据元数据选择定义最早的函数。虽然在所有情况下这可能不符合Snowflake,但我们发现,在常见情形下(例如,仅通过一个参数不同),这给我们的行为提供了一致性,与Snowflake相符。
然而,随着我们增加对更多类型的支持或扩展我们的UDF基础设施,这个匹配系统将可能发生变化。因此,我们强烈建议为每个参数使用唯一的名称,并仅使用命名调用约定以避免任何潜在的问题。