JavaScript UDF 限制¶
为了确保 Snowflake 环境中的稳定性,Snowflake 对 JavaScript UDFs 施加了以下限制。这些限制不是在创建 UDF 时实施的,而是在调用 UDF 时的运行时阶段实施的。本主题介绍 JavaScript UDF(用户定义的函数)的一般要求和用法详细信息,以及特定于 JavaScript UDFs 的限制。
本主题内容:
JavaScript 源代码的最大大小¶
Snowflake 限制了 JavaScript UDF 主体中 JavaScript 源代码的最大大小。Snowflake 建议将大小限制为 100 KB。(代码以压缩形式存储,具体限制取决于代码的可压缩性。)
消耗过多内存会导致 UDF 失败¶
如果 JavaScript UDFs 消耗过多内存,则会失败。具体限制可能会发生变化。使用过多的内存将导致返回错误。
需要很长时间才能完成将导致 UDF 被终止并返回错误¶
需要很长时间才能完成的 JavaScript UDFs 将被终止,并会向用户返回错误。此外,进入无限循环的 JavaScript UDFs 将导致错误。
堆栈深度过大将导致错误¶
递归造成的堆栈深度过大将导致错误。
全局状态¶
Snowflake 通常会在 JavaScript 的两次迭代之间保留 UDF 全局状态。但是,您不应坚信先前对全局状态的修改在两次函数调用之间一定可用。此外,您不应假设所有行都将在相同的 JavaScript 环境中执行。
实际上,全局状态与以下两点有关:
复杂/成本高昂的初始化逻辑。默认情况下,将针对处理的每行评估所提供的 UDF 代码。如果该代码包含复杂的逻辑,则效率可能低下。
包含非幂等代码的函数。典型的模式为:
Date.prototype._originalToString = Date.prototype.toString; Date.prototype.toString = function() { /* ... SOME CUSTOM CODE ... */ this._originalToString() }
首次执行此代码时,它会更改
toString
和_originalToString
的状态。这些变更将保留在全局状态中,到了第二次执行此代码时,会以创建递归的方式再次更改值。第二次调用toString
时,代码将无限递归(直到堆栈空间耗尽)。
对于这些情况,推荐的模式是使用 JavaScript 全局变量语义保证仅对相关代码进行一次评估。例如:
var setup = function() { /* SETUP LOGIC */ }; if (typeof(setup_done) === "undefined") { setup(); setup_done = true; // setting global variable to true }
请注意,此机制仅在缓存代码评估的效果时是安全的。不能保证初始化后将为所有行保留全局上下文,并且任何业务逻辑都不应依赖此机制。
JavaScript 库¶
JavaScript UDFs 支持访问标准 JavaScript 库。请注意,这不包括浏览器通常提供的许多对象和方法。没有导入、包含或调用其他库的机制。所有必需的代码都应嵌入到 UDF 中。
此外,内置的 JavaScript eval()
函数已禁用。
返回的变体大小和深度¶
返回的变体对象在大小和嵌套深度上受到限制:
- 大小:
目前限制为几兆字节,但此限制可能会变更。
- 深度:
目前嵌套深度限制为 1000,但此限制可能会变更。
如果任何对象太大或太深,则在调用 UDF 时会返回错误。
实参和返回类型约束有时会被忽略¶
调用 UDF 时,会忽略为实参或返回值声明的某些类型特征。在这些情况下,无论收到的值是否符合声明中指定的约束,都可以将其用作收到的值。
对于用 JavaScript 编写逻辑的 UDFs,以下约束将被忽略:
VARCHAR 类型实参的长度
示例¶
以下示例中的代码声明 arg1
实参和返回值必须为 VARCHAR 类型,并且长度不能超过一个字符。但是,使用值长于一个字符的 arg1
来调用此函数将会成功,就好像未指定该约束一样。
CREATE OR REPLACE FUNCTION tf (arg1 VARCHAR(1))
RETURNS VARCHAR(1)
LANGUAGE JAVASCRIPT AS 'return A.substr(3, 3);';