DECLARE — 定义一个游标
DECLAREname[ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FORquery
DECLARE允许用户创建游标,游标可用于从较大的查询中一次取出少量行。 游标创建后,可使用FETCH从中取出行。
本页面描述的是 SQL 命令层面的游标用法。如果想要在 PL/pgSQL函数中使用游标,规则会有所不同 — 见Section 43.7。
name要创建的游标名称。它必须与该会话中任何其他活动游标的名称不同。
BINARY使游标以二进制格式而不是文本格式返回数据。
INSENSITIVE表示从游标取出的数据不应受到游标创建后对其底层表所做更新的影响。在PostgreSQL中,这是默认行为;因此该关键字没有效果,仅为兼容 SQL 标准而接受它。
SCROLLNO SCROLLSCROLL指定游标可用于以非顺序方式(例如向后)取出行。 根据查询执行计划的复杂程度,指定SCROLL可能会给查询执行带来性能开销。 NO SCROLL指定游标不能以非顺序方式取出行。 默认情况下只在某些情形下允许滚动,这与显式指定 SCROLL并不相同。详见下文 注解。
WITH HOLDWITHOUT HOLDWITH HOLD指定在创建该游标的事务成功提交后,仍可继续使用该游标。 WITHOUT HOLD指定该游标不能在创建它的事务之外使用。 如果既未指定WITHOUT HOLD也未指定WITH HOLD,默认值是WITHOUT HOLD。
query关键字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 38.7),则可能得到意外结果。 当重新取出先前已经取出过的行时,这些函数可能会再次执行,从而导致与第一次不同的结果。 对于涉及易变函数的查询,最好指定NO SCROLL。 如果这不现实,一个变通办法是将游标声明为SCROLL WITH HOLD, 并在读取其中任何行之前提交事务。 这样会强制将游标的整个输出物化到临时存储中,从而使每一行上的易变函数都只执行一次。
如果游标的查询包含FOR UPDATE或FOR SHARE,则返回的行会在首次取出时被锁定,与带有这些选项的普通SELECT命令相同。此外,返回的行将是最新版本;因此,这些选项提供了相当于 SQL 标准所称的“敏感游标”的行为。(将INSENSITIVE与FOR UPDATE或FOR SHARE一起指定会报错。)
通常都建议使用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语句的那些约定。
你可以通过查询pg_cursors 系统视图查看所有可用游标。
SQL 标准规定,游标默认是否对底层数据的并发更新敏感,由实现决定。在PostgreSQL中,游标默认不敏感,可以通过指定FOR UPDATE使其敏感。其他产品的行为可能不同。
SQL 标准只允许在嵌入式SQL和模块中使用游标。 PostgreSQL允许以交互方式使用游标。
二进制游标是PostgreSQL的一种扩展。