Redrock Postgres 文档
主页 切换暗/亮/自动模式 切换暗/亮/自动模式 切换暗/亮/自动模式 返回首页

PL/Scheme

PL/Scheme 是一个用于 Scheme 编程语言的 PostgreSQL 过程语言处理程序。 PL/Scheme 在后台使用 Chibi Scheme 作为其 Scheme 解释器。 凭借大量内置的 SRFI 和 Chibi Scheme 的完全 R7RS 兼容性,PL/Scheme 可以以 Lisp 风格启动 PostgreSQL 过程。PL/Scheme 默认是没有启用的,但是可以用CREATE EXTENSION plscheme为特定数据库启用它。

函数和参数

要用 PL/Scheme 语言创建一个函数,可使用标准的 CREATE FUNCTION 语法:

CREATE FUNCTION funcname (argument-types) RETURNS return-type
-- 函数相关属性
AS $$
  ; PL/Scheme 函数体
$$ LANGUAGE plscheme;

函数的主体就是普通的 Scheme 代码。事实上,PL/Scheme 的粘合代码会把它包裹在一个 Scheme 子程序中。一个 PL/Scheme 函数会在一种标量上下文中被调用,因此它无法返回列表。如下文所述,可以通过返回引用来返回非标量值(数组、记录和集合)。

在一个 PL/Scheme 过程中,任何从 Scheme 代码返回的值都会被忽略。

PL/Scheme 也支持用 DO 语句调用的匿名代码块:

DO $$
  ; PL/Scheme 代码
$$ LANGUAGE plscheme;

一个匿名代码块没有参数,并且它返回的任何值都会被抛弃。否则其行为就像一个函数。

CREATE FUNCTION命令的语法要求函数体被写作一个字符串常量。通常对字符串常量使用美元符号引用(见 第 4.1.2.4 节)最方便。如果选择使用转义字符串语法E'',必须双写任何在函数体中使用的单引号'和反斜线\(见 第 4.1.2.1 节)。

参数和结果的处理和在任何其他 Scheme 子程序中一样:参数会以 Scheme 变量的形式传递到函数体中,并且函数中计算的最后一个表达式会作为结果值返回。

例如,一个返回两个整数值中较大值的函数可以定义为:

CREATE FUNCTION scheme_max (a integer, b integer) RETURNS integer
AS $$
  (if (> a b) a b)
$$ LANGUAGE plscheme;

数据值

一般来讲,PL/Scheme 的目标是提供在 PostgreSQL 和 Scheme 世界之间的一种“自然的”映射。这包括下面介绍的数据映射规则。

数据类型映射

在调用一个 PL/Scheme 函数时,它的参数会被从 PostgreSQL 的数据类型转换成相应的 Scheme 类型:

  • PostgreSQL 的boolean被转换成 Scheme 的boolean
  • PostgreSQL 的smallintint被转换成 Scheme 的fixnum。PostgreSQL 的bigintoid也被转换成 Scheme 的fixnum
  • PostgreSQL 的realdouble被转换成 Scheme 的flonum
  • PostgreSQL 的numeric被转换成 Scheme 的flonum
  • PostgreSQL 的bytea被转换成 Scheme 的bytevector
  • 包括 PostgreSQL 字符串类型在内的所有其他数据类型会被转换成一个 Scheme 的string
  • 对于非标量数据类型,请见下文。

当一个 PL/Scheme 函数返回时,会按照下列规则把它的返回值转换成该函数声明的 PostgreSQL 返回数据类型:

  • 当 PostgreSQL 返回类型是boolean时,返回值会被根据 Scheme 规则计算真假。
  • 当 PostgreSQL 返回类型是bytea时,返回值会被使用相应的 Scheme 内建机制转换成bytea
  • 对于所有其他 PostgreSQL 返回类型,返回值被使用 Scheme 内建的string转换成一个串,并且结果会被传递给 PostgreSQL 数据类型的输入函数。
  • 对于非标量数据类型,请见下文。

注意所声明的 PostgreSQL 返回类型和实际返回对象的 Scheme 数据类型之间的逻辑失配不会被标志,无论怎样该值都会被转换。

NULL

如果一个 SQL 空值被传递给一个函数,该参数值将作为 Scheme 中的()出现。例如,上面函数和参数中展示的scheme_max的函数定义对于空值输入将会返回错误的回答。我们可以为函数定义增加STRICT让 PostgreSQL 做得更加合理:如果一个空值被传入,该函数将根本不会被调用,而只是自动地返回一个空结果。此外,我们可以在函数体中检查空输入:

CREATE FUNCTION scheme_max (a integer, b integer) RETURNS integer
AS $$
  (if (or (null? a) (null? b))
    '()
    (if (> a b) a b))
$$ LANGUAGE plscheme;

如前所示,要从一个 PL/Scheme 函数返回一个 SQL 空值,可返回值()。不管该函数严格与否都可以这样做。

数组,向量

SQL 数组会被作为一个 Scheme 向量传递到 PL/Scheme 中。要从一个 PL/Scheme 函数中返回出一个 SQL 数组值,可返回一个 Scheme 向量:

CREATE OR REPLACE FUNCTION return_arr() RETURNS int[]
AS $$
  (vector 1 2 '() 3)
$$ LANGUAGE plscheme;

SELECT return_arr();
     return_arr
--------------------
 [0:3]={1,2,NULL,3}
(1 row)

标准模块

我们可以在 PL/Scheme 函数或者匿名代码块中导入 Scheme 提供的标准模块,例如:

DO $$
  (import (scheme small)
          (srfi 1))
$$ LANGUAGE plscheme;

这个导入可以作用于当前会话对 PL/Scheme 函数或者匿名代码块的执行。

Scheme 标准

默认语言是来自 R7RS(scheme base)库,它主要是 R5RS 的超集。

解释器默认区分大小写,跟 R6RS 和 R7RS 一样,但与 R5RS 不同。默认配置包括了完整的数值类型体系:fixnumflonumbignum、精确有理数和复数。此列表包括 R7RS 定义的标准库:

  • (scheme base) - R7RS 基础库
  • (scheme case-lambda) - R7RS case-lambda 库
  • (scheme char) - R7RS 字符库
  • (scheme complex) - R7RS 复数库
  • (scheme cxr) - R7RS CxR 访问器库
  • (scheme eval) - R7RS eval 库
  • (scheme file) - R7RS 文件库
  • (scheme inexact) - R7RS 非精确数值库
  • (scheme lazy) - R7RS 惰性求值库
  • (scheme load) - R7RS 代码加载库
  • (scheme process-context) - R7RS 进程上下文库
  • (scheme read) - R7RS 代码对象读入库
  • (scheme repl) - R7RS 读取/评估/打印循环库
  • (scheme time) - R7RS 时间库
  • (scheme write) - R7RS 代码对象生成库
  • (scheme r5rs) - R5RS 标准库,它是其他库的一个包装
  • (scheme small) - R7RS 标准库,它包含了上面所有的库

SRFI 模块

Chibi Scheme 中提供了许多 SRFI。请注意,SRFI 0、6、23、46 和 62 已内置到默认环境中,因此无需导入它们。此列表包括流行的 SRFI 或标准 Chibi 模块中使用到的 SRFI:

Chibi 模块

额外的非标准模块被放置在(chibi)模块命名空间中。

错误和消息

使用raise函数报告消息以及抛出错误。

(raise level message)

level选项指定了错误的严重性。允许的级别有debugloginfonotice, warning以及exceptionexception会抛出一个错误(通常会中止当前事务)。其他级别仅仅是产生不同优先级的消息。不管一个特定优先级的消息是被报告给客户端、还是写到服务器日志、亦或是二者同时都做,这都由 log_min_messagesclient_min_messages 配置变量控制。详见第 19 章

在这个例子中,我们报告了一个notice级别的简单消息:

(raise "notice" "Notice me.")