PL/Scheme
PL/Scheme is a PostgreSQL procedural language handler for Scheme programming language. PL/Scheme uses Chibi Scheme in the background as its Scheme interpreter. With lots of builtin SRFIs and complete R7RS compliancy of Chibi Scheme, PL/Scheme can power up PostgreSQL procedures in a Lisp style. PL/Scheme is not enabled by default, but it can be enabled for a specific database with CREATE EXTENSION plscheme
.
To create a function in the PL/Scheme language, use the standard CREATE FUNCTION syntax:
CREATE FUNCTION funcname (argument-types) RETURNS return-type
-- function attributes can go here
AS $$
; PL/Scheme function body goes here
$$ LANGUAGE plscheme;
The body of the function is ordinary Scheme code. In fact, the PL/Scheme glue code wraps it inside a Scheme subroutine. A PL/Scheme function is called in a scalar context, so it can’t return a list. You can return non-scalar values (arrays, records, and sets) by returning a reference, as discussed below.
In a PL/Scheme procedure, any return value from the Scheme code is ignored.
PL/Scheme also supports anonymous code blocks called with the DO statement:
DO $$
; PL/Scheme code
$$ LANGUAGE plscheme;
An anonymous code block receives no arguments, and whatever value it might return is discarded. Otherwise it behaves just like a function.
The syntax of the CREATE FUNCTION
command requires the function body to be written as a string constant. It is usually most convenient to use dollar quoting (see Section 4.1.2.4) for the string constant. If you choose to use escape string syntax E''
, you must double any single quote marks ('
) and backslashes (\
) used in the body of the function (see Section 4.1.2.1).
Arguments and results are handled as in any other Scheme subroutine: arguments are passed as Scheme variables, and a result value is returned as the last expression evaluated in the function.
For example, a function returning the greater of two integer values could be defined as:
CREATE FUNCTION scheme_max (a integer, b integer) RETURNS integer
AS $$
(if (> a b) a b)
$$ LANGUAGE plscheme;
Generally speaking, the aim of PL/Scheme is to provide a “natural” mapping between the PostgreSQL and the Scheme worlds. This informs the data mapping rules described below.
When a PL/Scheme function is called, its arguments are converted from their PostgreSQL data type to a corresponding Scheme type:
- PostgreSQL
boolean
is converted to Schemeboolean
. - PostgreSQL
smallint
andint
are converted to Schemefixnum
. PostgreSQLbigint
andoid
are converted tofixnum
in Scheme. - PostgreSQL
real
anddouble
are converted to Schemeflonum
. - PostgreSQL
numeric
is converted to Schemeflonum
. - PostgreSQL
bytea
is converted to Schemebytevector
. - All other data types, including the PostgreSQL character string types, are converted to a Scheme
string
. - For nonscalar data types, see below.
When a PL/Scheme function returns, its return value is converted to the function’s declared PostgreSQL return data type as follows:
- When the PostgreSQL return type is
boolean
, the return value will be evaluated for truth according to the Scheme rules. - When the PostgreSQL return type is
bytea
, the return value will be converted to bytes using the respective Scheme built-ins, with the result being converted tobytea
. - For all other PostgreSQL return types, the return value is converted to a string using the Scheme built-in
string
, and the result is passed to the input function of the PostgreSQL data type. - For nonscalar data types, see below.
Note that logical mismatches between the declared PostgreSQL return type and the Scheme data type of the actual return object are not flagged; the value will be converted in any case.
If an SQL null value is passed to a function, the argument value will appear as ()
in Scheme. For example, the function definition of scheme_max
shown in Functions and Arguments will return the wrong answer for null inputs. We could add STRICT
to the function definition to make PostgreSQL do something more reasonable: if a null value is passed, the function will not be called at all, but will just return a null result automatically. Alternatively, we could check for null inputs in the function body:
CREATE FUNCTION scheme_max (a integer, b integer) RETURNS integer
AS $$
(if (or (null? a) (null? b))
'()
(if (> a b) a b))
$$ LANGUAGE plscheme;
As shown above, to return an SQL null value from a PL/Scheme function, return the value ()
. This can be done whether the function is strict or not.
SQL array values are passed into PL/Scheme as a Scheme vector. To return an SQL array value out of a PL/Scheme function, return a Scheme vector:
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)
We can import standard modules provided by Scheme in PL/Scheme functions or anonymous code blocks, for example:
DO $$
(import (scheme small)
(srfi 1))
$$ LANGUAGE plscheme;
This import can affect the execution of PL/Scheme functions or anonymous code blocks in the current session.
The default language is the (scheme base)
library from R7RS, which is mostly a superset of R5RS.
The reader defaults to case-sensitive, like R6RS and R7RS but unlike R5RS. The default configuration includes the full numeric tower: fixnums, flonums, bignums, exact rationals and complex numbers. This list includes standard libraries defined by R7RS:
- (scheme base) - R7RS base library
- (scheme case-lambda) - R7RS case-lambda library
- (scheme char) - R7RS char library
- (scheme complex) - R7RS complex numbers library
- (scheme cxr) - R7RS CxR accessors library
- (scheme eval) - R7RS eval library
- (scheme file) - R7RS file library
- (scheme inexact) - R7RS inexact numbers library
- (scheme lazy) - R7RS lazy evaluation library
- (scheme load) - R7RS load library
- (scheme process-context) - R7RS process-context library
- (scheme read) - R7RS read library
- (scheme repl) - R7RS repl library
- (scheme time) - R7RS time library
- (scheme write) - R7RS write library
- (scheme r5rs) - R5RS standard library, it is a wrapper of other libraries
- (scheme small) - R7RS standard library, it is a wrapper of all above libraries
A number of SRFIs are provided in Chibi Scheme. Note that SRFIs 0, 6, 23, 46 and 62 are built into the default environment so there’s no need to import them. This list includes popular SRFIs or SRFIs used in standard Chibi modules:
- (srfi 0) - cond-expand: feature-based conditional expansion construct
- (srfi 1) - list library
- (srfi 2) - and-let*
- (srfi 6) - basic string ports
- (srfi 8) - receive: binding to multiple values
- (srfi 9) - define-record-type: defining record types
- (srfi 11) - let-values/let*-values: syntax for receiving multiple values
- (srfi 14) - character-set library
- (srfi 16) - case-lambda: syntax for procedures with a variable number of arguments
- (srfi 18) - multi-threading support
- (srfi 23) - error reporting mechanism
- (srfi 26) - cut/cute partial application
- (srfi 27) - sources of random bits
- (srfi 33) - bitwise operators
- (srfi 38) - read/write shared structures
- (srfi 39) - parameter objects
- (srfi 41) - streams
- (srfi 46) - basic syntax-rules extensions
- (srfi 55) - require-extension
- (srfi 62) - s-expression comments
- (srfi 69) - basic hash tables
- (srfi 95) - sorting and merging
- (srfi 98) - environment access
- (srfi 99) - ERR5RS records
- (srfi 101) - purely functional random-access pairs and lists
- (srfi 111) - boxes
- (srfi 113) - sets and bags
- (srfi 115) - Scheme regular expressions
- (srfi 116) - immutable list library
- (srfi 117) - mutable queues
- (srfi 121) - generators
- (srfi 124) - ephemerons
- (srfi 125) - intermediate hash tables
- (srfi 127) - lazy sequences
- (srfi 128) - comparators (reduced)
- (srfi 129) - titlecase procedures
- (srfi 130) - cursor-based string library
- (srfi 132) - sort libraries
- (srfi 133) - vector library
- (srfi 134) - immutable deques
- (srfi 135) - immutable texts
- (srfi 139) - syntax parameters
- (srfi 141) - integer division
- (srfi 142) - bitwise operations
- (srfi 143) - fixnums
- (srfi 144) - flonums
- (srfi 145) - assumptions
- (srfi 147) - custom macro transformers
- (srfi 151) - bitwise operators
- (srfi 154) - first-class dynamic extents
- (srfi 158) - generators and accumulators
- (srfi 160) - homogeneous numeric vector libraries
- (srfi 165) - the environment Monad
- (srfi 166) - monadic formatting
- (srfi 188) - splicing binding constructs for syntactic keywords
Additional non-standard modules are put in the (chibi)
module namespace.
- (chibi app) - Unified option parsing and config
- (chibi ast) - Abstract Syntax Tree and other internal data types
- (chibi base64) - Base64 encoding and decoding
- (chibi bytevector) - Bytevector Utilities
- (chibi config) - General configuration management
- (chibi crypto md5) - MD5 hash
- (chibi crypto rsa) - RSA public key encryption
- (chibi crypto sha2) - SHA-2 hash
- (chibi diff) - LCS Algorithm and diff utilities
- (chibi disasm) - Disassembler for the virtual machine
- (chibi doc) - Chibi documentation utilities
- (chibi edit-distance) - A levenshtein distance implementation
- (chibi equiv) - A version of
equal?
which is guaranteed to terminate - (chibi filesystem) - Interface to the filesystem and file descriptor objects
- (chibi generic) - Generic methods for CLOS-style object oriented programming
- (chibi heap-stats) - Utilities for gathering statistics on the heap
- (chibi io) - Various I/O extensions and custom ports
- (chibi iset base) - Compact integer sets
- (chibi iset constructors) - Compact integer set construction
- (chibi iset iterators) - Iterating over compact integer sets
- (chibi json) - JSON reading and writing
- (chibi loop) - Fast and extensible loop syntax
- (chibi match) - Intuitive and widely supported pattern matching syntax
- (chibi math prime) - Prime number utilities
- (chibi memoize) - Procedure memoization
- (chibi mime) - Parse MIME files into SXML
- (chibi modules) - Introspection for the module system itself
- (chibi net) - Simple networking interface
- (chibi net http-server) - Simple http-server with servlet support
- (chibi net servlet) - HTTP servlets for http-server or CGI
- (chibi parse) - Parser combinators with convenient syntax
- (chibi pathname) - Utilities to decompose and manipulate pathnames
- (chibi process) - Interface to spawn processes and handle signals
- (chibi repl) - A full-featured Read/Eval/Print Loop
- (chibi scribble) - A parser for the scribble syntax used to write this manual
- (chibi string) - Cursor-based string library (predecessor to SRFI 130)
- (chibi stty) - A high-level interface to ioctl
- (chibi sxml) - SXML utilities
- (chibi system) - Access to the host system and current user information
- (chibi temp-file) - Temporary file and directory creation
- (chibi test) - A simple unit testing framework
- (chibi time) - An interface to the current system time
- (chibi trace) - A utility to trace procedure calls
- (chibi type-inference) - An easy-to-use type inference system
- (chibi uri) - Utilities to parse and construct URIs
- (chibi weak) - Data structures with weak references
Use the raise
function to report messages and raise errors.
(raise level message)
The level
option specifies the error severity. Allowed levels are debug
, log
, info
, notice
, warning
, and exception
. exception
raises an error (which normally aborts the current transaction); the other levels only generate messages of different priority levels. Whether messages of a particular priority are reported to the client, written to the server log, or both is controlled by the log_min_messages and client_min_messages configuration variables. See Chapter 19 for more information.
In this example, we report a simple message at the notice
level:
(raise "notice" "Notice me.")