SQLite中的SQL函数可以是“确定性”或“非确定性”的。
当确定性函数具有相同的输入时,总是给出相同的答案。SQLite中的大多数内置SQL函数都是确定性的。例如,abs(X)函数始终返回相同的答案,只要其输入X相同即可。
即使参数始终相同,非确定性函数也可能在每次调用时给出不同的答案。以下是不确定函数的示例:
在随机()函数显然是不确定的,因为它给出了不同的答案每次调用时。changes() 和last_insert_rowid()的答案取决于先前的SQL语句,因此它们也不是确定性的。该 sqlite3_version()函数主要是恒定的,但是当SQLite的升级,虽然它总是返回任何特定会话相同的答案也可以改变,所以即使,因为它可以改变整个答案会话它仍然被认为不确定性。
SQLite中的某些上下文不允许使用非确定性函数:
在上述情况下,函数返回的值会影响数据库文件中存储的信息。CHECK约束中的函数值确定哪些条目对表有效,并且部分索引的WHERE子句中或表达式的索引中的函数计算存储在索引b树中的值。如果这些函数中的任何一个以后返回一个不同的值,则该数据库可能不再具有良好的格式。因此,为避免数据库损坏,在以上上下文中只能使用确定性函数。
SQLite 的内置日期和时间功能是一种特殊情况。这些功能通常被认为是确定性的。但是,如果这些函数使用字符串“ now”作为日期,或者它们使用localtime修饰符或utc修饰符,则将它们视为不确定的。因为函数输入在运行时之前不一定是已知的,所以如果在仅允许确定性功能的情况下遇到任何非确定性功能,则日期/时间函数将引发异常。
在SQLite 3.20.0(2017-08-01)之前,所有日期/时间函数始终被认为是不确定的。对于日期/时间函数,根据其自变量,有时可以确定性,而在其他时间则不能确定性,这是针对3.20.0版本添加的。
当对SQLite 3.20.0进行增强时,日期/时间函数将被认为是确定性的,它们不依赖于当前时间,则忽略了一种情况:许多日期/时间函数可以完全不带任何参数地被调用。这些无参数的日期/时间函数的行为就像它们只有一个“ 'now' ”参数一样。因此,“ datetime() ”和“ datetime('now') ”都产生当前日期和时间。但是,只有第二种形式被认为是不确定的。这意味着开发人员可以偷偷摸摸地确定“ datetime()形成CHECK约束,索引表达式,生成的列表达式以及类似的地方,这些地方没有确定性函数没有任何意义。这种疏忽在版本3.35.2(2021-03-17)中已得到修复。但是,可能存在遗留数据库由SQLite 3.20.0到3.35.1版本创建的循环,其架构中具有不确定的日期/时间函数。
默认情况下,应用程序定义的SQL函数被认为是不确定的。但是,如果sqlite3_create_function_v2()的第4个参数 与SQLITE_DETERMINISTIC进行或 运算,则SQLite将把该函数视为确定性函数。
请注意,如果使用SQLITE_DETERMINISTIC标记了不确定性函数, 并且该函数最终在部分索引的WHERE子句或 表达式索引中使用,则当该函数开始返回不同的答案时,关联的索引可能会损坏。如果SQL函数几乎是确定性的(也就是说,如果它很少改变,例如sqlite_version()),并且已在损坏的索引中使用它,则可以通过运行REINDEX来修复损坏。
未发布构造有时取决于其输入的确定性和有时不确定性的功能所必需的接口,例如内置的日期/时间函数。通用的应用程序定义的SQL函数必须始终是确定性的或始终是不确定性的。