DECLARE — 定义一个游标
DECLAREname[ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FORquery
DECLARE 允许用户创建游标,游标可用于从一个较大的查询中一次检索少量行。游标创建之后,可以使用 FETCH 从中取得行。
本页描述在 SQL 命令层面对游标的使用。如果想在 PL/pgSQL 函数中使用游标,规则有所不同 — 参见 Section 41.7。
name要创建的游标的名称。它必须不同于该会话中任何其他活动游标的名称。
BINARY使游标以二进制格式而不是文本格式返回数据。
ASENSITIVEINSENSITIVE 游标敏感性决定了在游标被声明之后,同一事务中对游标底层数据所做的更改在游标中是否可见。INSENSITIVE 表示这些更改不可见,ASENSITIVE 表示行为取决于具体实现。第三种行为是 SENSITIVE,即这类更改在游标中可见,但 PostgreSQL 不提供这种行为。在 PostgreSQL 中,所有游标都是不敏感的;因此这些关键字没有任何效果,只是为了与 SQL 标准兼容而被接受。
将 INSENSITIVE 与 FOR UPDATE 或 FOR SHARE 一起指定是一个错误。
SCROLLNO SCROLLSCROLL 指定可以用非顺序的方式(例如向后)从游标检索行。根据查询执行计划的复杂程度,指定 SCROLL 可能会给查询的执行时间带来性能损失。NO SCROLL 指定不能用非顺序的方式从游标检索行。默认是在某些情况下允许滚动;这与指定 SCROLL 并不相同。详情参见下文 Notes。
WITH HOLDWITHOUT HOLDWITH HOLD 指定在创建该游标的事务成功提交之后,该游标可以继续被使用。WITHOUT HOLD 指定该游标不能在创建它的事务之外使用。如果既未指定 WITHOUT HOLD 也未指定 WITH HOLD,则默认为 WITHOUT HOLD。
query 关键字 ASENSITIVE、BINARY、INSENSITIVE 和 SCROLL 可以以任意顺序出现。
普通游标以文本格式返回数据,与 SELECT 所产生的结果相同。BINARY 选项指定游标应以二进制格式返回数据。这减少了服务器和客户端双方的转换工作,但代价是程序员需要付出更多精力来处理与平台相关的二进制数据格式。举例来说,如果查询从一个整数列返回值 1,使用默认游标时你会得到字符串 1,而使用二进制游标时你会得到一个 4 字节的字段,其中包含该值的内部表示(大端字节序)。
应当谨慎使用二进制游标。许多应用程序(包括 psql)并没有准备好处理二进制游标,它们期望数据以文本格式返回。
当客户端应用程序使用“扩展查询”协议发出 FETCH 命令时,Bind 协议消息会指定是以文本格式还是二进制格式检索数据。这一选择会覆盖游标定义的方式。因此,在使用扩展查询协议时,二进制游标这个概念本身已经过时 — 任何游标都可以按文本或二进制处理。
除非指定了 WITH HOLD,否则此命令创建的游标只能在当前事务中使用。因此,DECLARE 若不带 WITH HOLD,在事务块之外毫无用处:游标只能存活到该语句结束为止。所以,如果在事务块之外使用这样的命令,PostgreSQL 会报告一个错误。可以使用 BEGIN 和 COMMIT(或 ROLLBACK)来定义一个事务块。
如果指定了 WITH HOLD 并且创建游标的事务成功提交,那么该游标可以被同一会话中的后续事务继续访问。(但如果创建事务被中止,游标就会被移除。)用 WITH HOLD 创建的游标在对它发出显式 CLOSE 命令时或会话结束时被关闭。在当前的实现中,被保持的游标所表示的行会被复制到一个临时文件或内存区域中,以便它们对后续事务保持可用。
当查询包含 FOR UPDATE 或 FOR SHARE 时,不能指定 WITH HOLD。
在定义将用于向后取行的游标时,应当指定 SCROLL 选项。这是 SQL 标准的要求。不过,为了与早期版本兼容,如果游标的查询计划足够简单以至于不需要额外的开销,PostgreSQL 会允许在没有 SCROLL 的情况下进行向后取行。但是,建议应用程序开发人员不要依赖从没有用 SCROLL 创建的游标进行向后取行。如果指定了 NO SCROLL,则在任何情况下都不允许向后取行。
当查询包含 FOR UPDATE 或 FOR SHARE 时,同样不允许向后取行;因此在这种情况下不能指定 SCROLL。
如果可滚动游标调用了任何易失函数(参见 Section 36.7),可能会产生意外的结果。当之前取到的行被重新取回时,这些函数可能会被重新执行,也许会导致与第一次不同的结果。对于涉及易失函数的查询,最好指定 NO SCROLL。如果这不切实际,一种变通办法是将游标声明为 SCROLL WITH HOLD,并在从中读取任何行之前提交事务。这会强制把游标的全部输出实体化到临时存储中,从而使易失函数对每一行只执行一次。
如果游标的查询包含 FOR UPDATE 或 FOR SHARE,那么返回的行会在第一次被取到时被锁定,方式与带有这些选项的普通 SELECT 命令相同。此外,返回的行将是最新版本。
一般建议使用 FOR UPDATE,前提是游标打算与 UPDATE ... WHERE CURRENT OF 或 DELETE ... WHERE CURRENT OF 一起使用。使用 FOR UPDATE 可以防止其他会话在行被取到的时间和行被更新的时间之间修改这些行。如果没有 FOR UPDATE,那么当行在游标创建之后被更改过时,后续的 WHERE CURRENT OF 命令将不会产生任何效果。
使用 FOR UPDATE 的另一个原因是,如果没有它,后续的 WHERE CURRENT OF 可能会在游标查询不符合 SQL 标准的“简单可更新”规则时失败(特别是,游标必须只引用一个表,并且不使用分组或 ORDER BY)。不满足简单可更新条件的游标可能工作正常,也可能不工作,这取决于计划选择的细节;因此在最坏的情况下,应用程序可能在测试中工作正常,然后在生产环境中失败。如果指定了 FOR UPDATE,则保证游标是可更新的。
不将 FOR UPDATE 与 WHERE CURRENT OF 一起使用的主要原因,是你需要游标可以滚动,或者需要游标与并发更新相隔离(也就是说,继续显示旧数据)。如果有这样的需求,请密切注意上面列出的注意事项。
SQL 标准只为嵌入式 SQL 中的游标做了规定。PostgreSQL 服务器没有为游标实现 OPEN 语句;游标在声明时即被视为打开。不过,ECPG(即 PostgreSQL 的嵌入式 SQL 预处理器)支持标准的 SQL 游标约定,包括涉及 DECLARE 和 OPEN 语句的那些约定。
打开的游标底层的服务器数据结构被称为一个门户(portal)。门户名称会暴露在客户端协议中:如果客户端知道门户名称,它就可以直接从一个打开的门户取得行。使用 DECLARE 创建游标时,门户名称与游标名称相同。
可以通过查询 pg_cursors 系统视图来查看所有可用的游标。
SQL 标准只允许在嵌入式 SQL 和模块中使用游标。PostgreSQL 允许以交互方式使用游标。
根据 SQL 标准,通过 UPDATE ... WHERE CURRENT OF 和 DELETE ... WHERE CURRENT OF 语句对不敏感游标所做的更改会在同一个游标中可见。PostgreSQL 对待这些语句的方式与对待所有其他数据更改语句的方式相同,即这些更改在不敏感游标中不可见。
二进制游标是一个 PostgreSQL 扩展。