Guile-pg
Command Reference
Guile-pg
is a Guile module providing a set of procedures to allow
access to the PostgreSQL RDBMS from Scheme programs.
Guile is an interpreter for the Scheme programming language: a dialect of
Lisp. PostgreSQL is a free SQL database management system.
Guile-pg
is intended as but one of the low-level drivers for the
forthcoming Guile database module which will provide a portable interface
to many different SQL database servers. In the mean-time
it will still be a useful module for those who want just a low-level
interface to PostgreSQL.
The Guile-pg
procedures have an almost one-one correspondence
with the PostgreSQL libpq
C library interface so those familiar with
the libpq
library and other similar interfaces like Edmund Mergl's
Pg
Perl module will find it familiar.
Guile-pg
is based on Russ McManus's "Sybase glue" code.
To access a PostgreSQL database from Guile, first load the postgres
database module. This is done using the use-modules
syntax:
(use-modules (database postgres))
The next step is to make a connection to the database using the
pg-connectdb
procedure. Then, having created a valid connection to a
database server, we can use the pg-exec
procedure to execute
queries and the other pg-
procedures to retrieve the results of the
queries.
The following Guile session opens a connection and executes an
SQL statement on the test
database on the default host (either
localhost
or the host specified in the PGHOST
environment
variable.)
guile> (use-modules (database postgres)) guile> (define test (pg-connectdb "dbname=test")) guile> test #<PG-CONN:1:test::5432:> guile> (define result (pg-exec test "SELECT * FROM PEOPLE")) guile> result #<PG-RESULT:1:PGRES_TUPLES_OK:3:5>
The test
object is a PG-CONN
type representing the database
connection. Displaying the PG-CONN
object shows that the serial number
of the connection is 1, that the database name is test
on the default
host (the hostname field is empty) on port number 5432 and that the default
options were passed to the backend. This object is passed to pg-exec
which returns a PG-RESULT
object representing the result of the SQL
statement executed on the server. In this case, displaying the PG-RESULT
object shows us that the serial number of the result is 2, that the return code
from the database was PGRES_TUPLES_OK
and that we have received 3 tuples
with 5 fields.
Having obtained a result object from the database we can find out how many rows and how many columns are in the result. We can also find out the names of the columns:
guile> (pg-ntuples result) 3 guile> (pg-nfields result) 5 guile> (pg-fname result 0) "surname" guile> (pg-fname result 1) "firstname"
To retrieve the data from the result we use the pg-getvalue
procedure.
This takes a result object along with the row and column numbers and returns a
string containing that value. pg-getvalue
always returns a string: it
is up to the caller to convert this to whatever type they require.
guile> (pg-getvalue result 0 0) "Bitdiddle" guile> (pg-getvalue result 0 1) "Ben" guile> (pg-getvalue result 1 0) "Ator" guile> (pg-getvalue result 1 1) "Eva Lu"
Guile-pg
connections are closed when Guile's garbage collector
collects the discarded object. This only happens when the connection itself
and all of the results of pg-exec
are unreachable. So to close the
connection we just rebind the results from that connection and the connection
symbol itself:
guile> (define result '()) guile> (define test '())
Typically though the result and connection variables will be let
bindings so the connection will usually be closed soon after the body of the
let
returns.
This section specifies the procedures that guile-pg
provides to
access databases. To access the module, Guile programs must either be run
under the guile-pg
executable, which is a Guile interpreter statically
linked with the guile-pg
interface and the libpq
library, or
they must be run under the ordinary Guile interpreter guile
and
dynamically load the shared library libpostgres.so
which implements
the module. To do this, use the (use-modules ...)
procedure as follows:
(use-modules (database postgres))
After which the pg-
procedures will be accessable.
name=value
pairs.
If the value contains spaces it must be enclosed in single quotes and any
single quotes appearing in the value must be escaped using backslashes.
Backslashes appearing in the value must similarly be escaped. Note that
if the connect-string
is a Guile string literal then all the backslashes
will themselves require to be escaped a second time.
The name
strings can be any of:
host
host=
sub-string is given then the host is assumed
to be the value of the environment variable PGHOST
or the local
host if PGHOST
is not defined.
port
PGHOST
environment variable is used.
If that too is not defined then the default port 5432 is assumed.
options
PGOPTIONS
. The options string should be a set of command line
switches as would be passed to the backend. See the postgres (1)
man page for more details.
tty
""
) then the environment variable
PGTTY
is checked. If the specified tty
is a file then the file
will be readable only by the user the postmaster runs as (usually
postgres
). Similarly, if the specified tty
is a device then it
must have permissions allowing the postmaster user to write to it.
dbname
dbname=
sub-string is given then the
database name is assumed to be that given by the value of the PGDATABASE
environment variable, or the USER
environment variable if the
PGDATABASE
environment variable is not defined. If the USER
environment variable is not specified either then the value of the
user
option is taken as the database name.
user
PGUSER
environment variable is checked. If that is not given then the
login of the user owning the process is used.
password
pg_hba.conf
file. See the pg_hba.conf (5)
man page for details.
authtype
password
if password authentication is in use,
otherwise it must not be specified.
(define (user-count host) (let* ((conn (pg-connectdb (string-append "host=" host " port=5432 dbname=template1"))) (result (pg-exec conn "SELECT COUNT(*) FROM pg_user"))) (if (and result (eq? (pg-result-status result) PGRES_TUPLES_OK)) (string->number (pg-getvalue result 0 0)) #f)))
pg-connectdb
.
conn must be a valid PG_CONN
object returned by pg-connectdb
.
The following is a set of three procedures which implement a database connection object that logs all the SQL statements it executes.
(define (pg-connectdb-logged options) (let ((conn (pg-connectdb options))) (if conn (begin (pg-set-client-data! conn '()) conn) #f))) (define (pg-exec-logged conn sql) (pg-set-client-data! conn (append (pg-get-client-data conn) (list sql))) (pg-exec conn sql)) (define (pg-conn-log conn) (pg-get-client-data conn))
#t
indicating that the binary part of guile-pg
is loaded.
Thus to test if guile-pg
is loaded, use
(defined? 'pg-guile-pg-loaded)
This function is guaranteed to be present in all future versions of
guile-pg
.
guile-pg
. The string is
always of the form "M.m" giving major and minor versions.
postgres.scm
.
The string is always of the form "M.m" giving major and minor versions.
Unless something is wrong with the installation, this should be the same as
pg-guile-pg-version
.
guile-pg
was configured (this is probably the build time.)
This example defines a pair of procedures pg-trace-on
and
pg-trace-off
which implement a higher-level trace function which
opens the required file and starts/stops the trace.
(define (pg-trace-on conn filename) (let ((port (open-file filename "w"))) (pg-set-client-data! conn port) (pg-trace conn port))) (define (pg-trace-off conn) (let ((port (pg-get-client-data conn))) (if port (begin (close-port port) (pg-untrace conn)) #f)))
PG_RESULT
object containing a pg-result-status
or #f
if an error occurred, in which case the error message can be
obtained using pg-error-message
, passing it the PG_CONN
object on
which the statement was attempted. Note that the error message is available
only until the next call to pg-exec
on this connection.
This example defines a function pg-execute
which wraps pg-exec
so that a misc-error
is thrown instead of returning false. There are
numerous other examples of pg-exec
calls throughout this chapter.
(define (pg-execute conn sql) (let ((result (pg-exec conn sql))) (if result result (error (pg-error-message conn)))))
The entire result set is returned at once from a call to to pg-exec
.
If a SELECT
results in a very large number of tuples then this can be
a problem because it requires a large amount of memory. In these cases it is
better to DECLARE
a cursor over the SELECT
and retrive small
numbers of rows at a time using FETCH
. These commands can only be
issued between BEGIN TRANSACTION/END TRANSACTION
pairs. See the
PostgreSQL declare (l)
and fetch (l)
man pages for more details.
pg-exec
succeeded.
PG_RESULT
object returned by
pg-exec
. One of:
PGRES_TUPLES_OK
pg-nfields
and
pg-ntuples
respectively. The value of a given attribute (field)
of a given tuple can be determined by calling pg-getvalue
.
PGRES_COMMAND_OK
INSERT
, UPDATE
, DELETE
CREATE TABLE
, DROP TABLE
etc.),
which was executed without error. The number of tuples affected by the
command can be determined by a call to pg-cmdtuples
.
PGRES_EMPTY_QUERY
PGRES_COPY_OUT
COPY <table> TO stdout
. The data can be read using
pg-getline
.
PGRES_COPY_IN
COPY <table> FROM stdin
. The rows should be written
using pg-putline
.
PGRES_BAD_RESPONSE
libpq
interface receives an unexpected response
from the backend. It indicates a problem with Postgres.
PGRES_NONFATAL_ERROR
PGRES_FATAL_ERROR
This contrived example defines a procedure to insert records into a given
table, returning the number of tuples inserted (always one) or #f
if an
error occurred.
(define (pg-insert conn table record) (let ((result (pg-exec conn (string-append "INSERT INTO " table " VALUES " record)))) (if (and result (eq? (pg-result-status result) PGRES_COMMAND_OK)) (string->number (pg-cmdtuples result)) #f)))
The procedure could be called as follows
(pg-insert conn "people" "('Warbucks', 'Oliver')")
PG_CONN
object representing the connection from which a
result was returned.
#t
if result contains binary tuple data, #f
otherwise.
CREATE TABLE
, GRANT
,
REVOKE
etc. which don't affect tuples.
INSERT
.
NOTE: This function is deprecated. Use pg-oid-value
instead.
INSERT
command, this function
returns the integer OID of the inserted tuple, otherwise it returns #f
.
-1
otherwise.
This example defines a procedure pg-gettuple
which returns a given
tuple as an alist, keyed on the field name. It's not an especially efficient
procedure because it constructs the list of field-names afresh each time it's
called.
(define (pg-fnames result) (let ((nfields (pg-nfields result))) (define (iter i) (if (= i nfields) '() (cons (pg-fname result i) (iter (+ i 1))))) (iter 0))) (define (pg-getvalues result tuple) (let ((nfields (pg-nfields result))) (define (iter i) (if (= i nfields) '() (cons (pg-getvalue result tuple i) (iter (+ i 1))))) (iter 0))) (define (pg-gettuple result tuple) (map (lambda (n v) (cons (string->symbol n) v)) (pg-fnames result) (pg-getvalues result tuple)))
Field values can be extracted from the tuple using assq-ref
, eg:
(define tup (pg-gettuple result 0)) (assq-ref tup 'firstname)
Using this procedure we can define a version of for-each
which
iterates through the tuples returned from a given SELECT
query:
(define (pg-for-each proc result) (let ((ntuples (pg-ntuples result))) (define (iter i) (cond ((= i ntuples) ntuples) (else (proc (pg-gettuple result i)) (iter (+ i 1))))) (iter 0)))
This implementation of pg-for-each
inherits inefficiency from the
pg-gettuple
procedure.
The pg-getvalue
procedure throws
out-of-range
errors if either the tuple
or field-number
arguments are out of range.
#t
if the attribute is NULL
, #f
otherwise.
pg_type
. A misc-error
is thrown if the field-number
is not valid for the given result
.
Example
This defines a procedure pg-ftype-name
which returns the type
name of a given attribute in a string.
A more efficient implementation would be to define
a type of connection which, when opened, issued the query to retrieve the
pg_type
system table once. An alist for looking up type names could
then be associated with each connection using pg-set-client-data!
.
(define (pg-ftype-name result fnum) (let ((result (pg-exec (pg-get-connection result) (string-append "SELECT typname FROM pg_type WHERE oid = " (number->string (pg-ftype result fnum)))))) (if (and result (eq? (pg-result-status result) PGRES_TUPLES_OK) (> (pg-ntuples result) 0)) (pg-getvalue result 0 0) "")))
COPY <table> TO STDOUT
has
been issued.
Returns a string from the connection. If the returned string consists of only
a backslash followed by a full stop, then the results
from the COPY
command have all been read and pg-endcopy
should
be called to resynchronise the connection before any further calls to
pg-exec
on this connection.
Example
This example defines a procedure pg-copy-to-port
which can be used
to retrieve the results of a COPY <table> TO STDOUT
command.
(define (pg-copy-to-port conn port) (define (iter) (let ((line (pg-getline conn))) (if (string=? line "\\.") (pg-endcopy conn) (begin (write-line line port) (iter))))) (iter))
It is an error to call pg-getline
on a connection without first
executing a COPY <table> TO STDOUT
command on that connection.
It is also an error to call pg-getline
after a terminating line has
been received, without an intervening COPY
command being issued on
that connection.
COPY <table> FROM STDIN
has
been issued. The lines written should include the final newline characters.
The last line should be a backslash, followed by a full-stop. After this,
the pg-endcopy
procedure should be called for this connection before
any further pg-exec
call is made.
The return value is undefined.
This example defines a procedure pg-copy-from-port
which can be used
to supply data to a COPY <table> TO STDIN
command.
(define (pg-copy-from-port conn port) (define (iter) (let ((line (read-line port))) (if (eof-object? line) (begin (pg-putline conn "\\.\n") (pg-endcopy conn)) (begin (pg-putline conn line) (pg-putline conn "\n") (if (string=? line "\\.") (pg-endcopy conn) (iter)))))) (iter))
pg-getline
or
Returns an integer: zero if successful, non-zero otherwise.
All of the operations on large objects must be carried out inside a
BEGIN TRANSACTION/END TRANSACTION
pair. Failure to do this
will result in a loss of synchronisation between the backend and the
libpq
library, resulting in an unusable connection to the
database, and possible corruption of data.
#f
on failure in which case
pg-error-message
from the connection should give some idea of what
happened.
In addition to returning #f
on failure this procedure throws a
misc-error
if the modes
string is invalid.
r
for reading, w
for writing,
a
for append or +
with any of the above indicating both
reading and writing/appending. A
is equivalent to opening the port
for writing and immediately doing a (pg-lo-seek)
to the end.
The return value is either an open large object port
or #f
on failure in which case pg-error-message
from the connection should give some idea of what happened.
Notes
This procedure throws a misc-error
exception if the modes
string is invalid.
#t
if the object was successfully deleted, #f
otherwise,
in which case pg-error-message
applied to conn
should give an
idea of what went wrong.
pg-lo-creat
or pg-lo-open
.
pg-lo-creat
or pg-lo-open
.
pg-lo-creat
or pg-lo-open
.
The return value is either an integer greater than or equal to zero or #f
if an error
occurred. In the latter case pg-error-message
applied to conn
should explain what went wrong.
pg-lo-creat
or pg-lo-open
.
Where is the position to set the pointer. Whence must be one of
SEEK_SET
SEEK_CUR
SEEK_END
The return value is an integer which is the new position relative to the beginning of the object, or a number less than zero if an error occurred.
Notes It is possible to seek beyond the end of file opened only for reading. In which case subsequent reads of the port will return an EOF object.
#f
if an error
occurred.
#f
if an error occurred, in which case pg-error-message
should be
consulted to determine the failure.
#t
on success, #f
otherwise, in which case
pg-error-message
may offer an explanation of the failure.
Jump to:
Jump to: p
This document was generated on 8 July 2000 using texi2html 1.56k.