Chapter 19. PL/pgSQL - SQL 过程语言

Table of Contents
19.1. 概述
19.1.1. 使用PL/pgSQL的优点
19.1.2. PL/pgSQL做开发
19.2. PL/pgSQL的结构
19.3. 声明
19.3.1. 函数参数的别名
19.3.2. 行类型
19.3.3. 记录
19.3.4. 属性
19.3.5. RENAME
19.4. 表达式
19.5. 基本语句
19.5.1. 赋值
19.5.2. SELECT INTO
19.5.3. 执行一个没有结果的表达式或者查询
19.5.4. 执行动态查询
19.5.5. 获取结果状态
19.6. 控制结构
19.6.1. 从函数返回
19.6.2. 条件
19.6.3. 简单循环
19.6.4. 遍历查询结果
19.7. 游标
19.7.1. 声明游标变量
19.7.2. 打开游标
19.7.3. 使用游标
19.8. 错误和消息
19.9. 触发器过程
19.10. 例子
19.11. 从 Oracle 的 PL/SQL 向 PL/pgSQL移植
19.11.1. 主要的区别
19.11.2. 移植函数
19.11.3. 过程
19.11.4.
19.11.5. 其它要注意的东西
19.11.6. 附录

PL/pgSQLPostgreSQL 数据库系统的一个可装载的过程语言.

这个包最初是 Jan Wieck 写的. 这份文档的一部分是 Roberto Mello () 写的.

19.1. 概述

PL/pgSQL的设计目标是创建一种可装载的过程语言,可以

PL/pgSQL 函数第一次(在任何一个后端进程内部)被调用时, PL/pgSQL 的调用句柄分析函数源文本生成二进制指令树. 该指令树完全转换了 PL/pgSQL 语句结构, 但是在函数内实用到的独立的 SQL 表达式和 SQL 查询并未立即转换.

在每个函数中用到的表达式和 SQL 查询首次使用的时候, PL/pgSQL 解释器创建一个准备好的执行规划 (使用 SPI 管理器的 SPI_prepareSPI_saveplan 函数).随后对该表达式或者 查询的访问都将使用已准备好的规划.因此,一个在条件代码中有许多语句, 可能需要执行规划的函数,只需要准备和保存那些真正在数据库联接期间 真正使用到的规划.这样可疑节约大量分析动作.不过有个缺点是在特定 表达式或者查询中的错误可能要到函数中的那部分执行到的时候才能发现.

一旦 PL/pgSQL 在一个函数里为一个查询制作了查询规划, 那么它将在该次数据库联接的生命期内复用该规划.这么做在性能上通常 会更好一些,但是如果你动态地修改你的数据库大纲,那么就可能有问题. 比如∶

CREATE FUNCTION populate() RETURNS INTEGER AS '
DECLARE
    -- Declarations
BEGIN
    PERFORM my_function();
END;
' LANGUAGE 'plpgsql';

如果你执行上面的函数,那么它将在为PERFORM语句生成的查询规划中中引用 my_function() 的 OID.然后,如果你 删除然后重新创建 my_function(), 那么 populate() 就会再也找不到 my_function().这时候你只能重新 创建 populate(),或者至少是重新 开始一个新的数据库会话,好让该函数能重新编译一次.

因为Pl/pgSQL用这种方法保存执行规划, 所以那些在PL/pgSQL里直接 出现的查询必须在每次执行的时候引用相同的表和字段;也就是说, 你不能拿一个参数用做查询中的表或者字段的名称.要绕开这个限制, 你可以用PL/pgSQLEXECUTE语句动态地构造查询 --- 代价是每次 执行的时候都构造一个新的查询计划.

注意: PL/pgSQLEXECUTE语句和 PostgreSQL 后端支持的EXECUTE语句没有关系。 后端的EXECUTE语句不能在 PL/pgSQL 函数中使用(而且也没必要)。

除了用于用户定义类型的输入/输出转换和计算函数以外, 任何可以在 C 语言函数里定义的东西都可以在 PL/pgSQL里使用. 我们可以创建复杂的条件计算函数, 并随后将之用于定义操作符或者用于函数索引中.

19.1.1. 使用PL/pgSQL的优点

19.1.1.1. 更好的性能

SQLPostgreSQL (和大多数其它关系型数据库) 用做查询语言的语言.它是可以移植的,并且容易学习使用. 但是所有 SQL 语句都必须由数据库服务器 独立地执行.

这就意味着你的客户端应用必须把每条查询发送到数据库服务器, 等待它处理这个查询,接收结果,做一些运算,然后给服务器发送另外 一条查询.所有这些东西都会产生进程间通讯,并且如果你的 客户端在另外一台机器上甚至还会导致网络开销.

如果使用了PL/pgSQL,那么你可以把一块运算和一系列查询 在数据库服务器里面组成一个块, 这样就拥有了过程语言的力量并且简化 SQL 的使用,因而 节约了大量的时间,因为你用不着付出客户端/服务器通讯的过热. 这样可能产生明显的性能提升.

19.1.1.2. SQL 支持

PL/pgSQLSQL 灵活简单的基础上 为它增加了过程语言的能力.在PL/pgSQL里,你可以使用 所有数据类型,字段,操作符和 SQL 的函数.

19.1.1.3. 可移植性

因为PL/pgSQL函数在PostgreSQL内部运行, 这些函数将可以运行在任何PostgreSQL能够运行的机器上. 因此你可以复用代码并且减少开发费用.

19.1.2. 用PL/pgSQL做开发

PL/pgSQL做开发是相当直接的,尤其是如果你已经用过 其它的数据库过程语言的情况下,比如 Oracle 的PL/SQL之类. 用PL/pgSQL做开发的两个好方法是∶

  • 使用一个文本编辑器并且用 psql 重载该文件

  • 使用PostgreSQL的 GUI 工具∶pgaccess

PL/pgSQL 做开发的一个好方法是简单地使用你喜欢的文本编辑器 创建你的函数,然后在另外一个控制台里,用 psql (PostgreSQL 的交互监控器)装载这些函数.如果你用这种方法, 那么用 CREATE OR REPLACE FUNCTION 写函数是个 好主意.这样,你就可以重载文件以更新函数定义.比如∶

CREATE OR REPLACE FUNCTION testfunc(INTEGER) RETURN INTEGER AS '
    ....
END;
' LANGUAGE'plpgsql';

在运行 psql 的时候,你可以用下面命令 装载或者重载这样的函数定义文件

    \i filename.sql

然后马上发出 SQL 命令测试该函数.

另外一个开发PL/pgSQL程序的好方法是用 PostgreSQL 的 GUI 工具∶pgaccess. 它会为你做一些很有用的事情,比如逃逸单引号, 令重建和调试函数更简单等.