从语法草案到初始实现
1998年3月12日,扬·维克(Jan Wieck)在PostgreSQL开发邮件列表提出PL/pgSQL的第一稿语言说明。他希望让数据库用户通过带有变量、条件判断和循环的语言编写函数与触发程序。这沿用了PostgreSQL自6.3版起提供的可装载过程语言机制,程序由数据库后端调用专门的解释处理器运行。
当时的实现仍很初步:维克已经用flex和bison建立独立的解析器,但处理器只打印生成的指令树,返回一个零值,执行器还待编写。附上的说明明确说,文中描述的完整扩展模块尚不存在。因此,这封邮件记录的是设计讨论及早期原型,而非可投入使用的正式版本。
送入源码库,随6.4版发行
8月13日,维克告诉参与讨论的开发者,他已把初始版本交给布鲁斯·莫姆吉安(Bruce Momjian),准备加入共享源码树。该版除触发程序外尚不能返回完整数据行,也没有他希望增加的CASE条件结构;这些限制被公开列出来,供其他开发者参与改进。8月22日,莫姆吉安回复说,代码已加入contrib目录。
PL/pgSQL随后成为PostgreSQL 6.4版的一项新增功能。关于这一版的发行日期,后来7.1.3版文档列为1998年10月30日;马克·G.富尼耶(Marc G. Fournier)的现存公告则以11月4日为题,宣布6.4版已可从主站下载,并说明镜像站将在随后数小时同步。源代码入库、版本发行记录与公开公告分别留下了不同的时间凭据。
把语言装入具体数据库
6.4版手册将PL/pgSQL列为可装载的过程语言,用来在数据库服务器内部编写函数和触发程序,为结构化查询语言(SQL)添加条件、循环和复杂计算。用户可以沿用数据库已有的类型、函数和运算符,不必为每一项这样的功能单独编写、编译C语言程序。
安装分为共享库、处理器声明和语言登记三个步骤。PL/pgSQL处理器的共享库默认随系统编译安装,但管理员还要在目标数据库声明调用处理器,再用CREATE TRUSTED PROCEDURAL LANGUAGE登记语言。TRUSTED在这里表示普通数据库用户可用它定义函数。若管理员先在template1模板数据库中登记,随后新建的数据库便可继承该语言。
参考:[4]
在后端解析和执行
一个数据库后端第一次调用PL/pgSQL函数时,处理器才解析其源码,生成内部指令树,并用函数的对象标识符辨认它。函数内的查询和表达式也不是一律预先处理:每条语句第一次实际执行时才建立并保存执行计划,没有走到的条件分支可以暂不准备。
变量在DECLARE部分声明,BEGIN与END包围程序语句。函数参数可用$1、$2等位置名称访问,也能另起别名。若变量类型写成某个表字段的%TYPE,处理器会依据字段定义取得类型和长度,使函数较容易适应表结构调整。这里的BEGIN与END只组织语句;6.4版函数和触发程序不能自行开始或提交事务。
参考:[4]
用加一函数和工资记录说明方法
手册先给出add_one例子:它接收一个四字节整数,以RETURN $1 + 1返回加一后的值。更具体的emp_stamp例子则面向一张工资表,表内有雇员姓名、薪资、修改时间和修改用户四个字段。触发器被设定为每行INSERT或UPDATE之前调用。
程序通过NEW读取准备写入的数据,先检查姓名和薪资是否为空,再拒绝负数薪资;这些分支以RAISE EXCEPTION报错并中止事务。通过检查后,它把当时的时间和数据库用户名填入last_date、last_user,最后RETURN NEW,让修改后的行继续写入。由此,检查输入与记录修改者可以放在数据库内部,而不只依赖发起操作的应用程序。
参考:[4]
早期手册留下的边界
这套语言的具体行为已不同于3月草案。草案设想SELECT INTO查得多行时应报错,6.4版手册则规定只把第一行放入目标变量,其余行被舍弃;FOUND变量可用来检查赋值是否成功。程序员必须依据实际发行说明理解这些行为,而非把设计讨论直接当成实现。
6.4版的错误处理也有明显限制。一旦解析、计划或执行阶段发生无法继续的错误,整个事务就会中止;PL/pgSQL所做的是补充调试日志,指出函数和语句位置。手册还提醒,函数源码作为字符串交给CREATE FUNCTION,内部单引号需要加倍或转义。这些安装、调试与书写细节,构成了1998年用户实际接触这门语言的环境。