| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
XEmacs can be linked with PostgreSQL libpq run-time support to provide relational database access from Emacs Lisp code.
| 61.1 Building XEmacs with PostgreSQL support | ||
| 61.2 XEmacs PostgreSQL libpq API | ||
| 61.3 XEmacs PostgreSQL libpq Examples |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
XEmacs PostgreSQL support requires linking to the PostgreSQL libpq library. Describing how to build and install PostgreSQL is beyond the scope of this document. See the PostgreSQL manual for details.
If you have installed XEmacs from one of the binary kits on
(ftp://ftp.xemacs.org/), or are using an XEmacs binary from a CD
ROM, you may have XEmacs PostgreSQL support by default. M-x
describe-installation will tell you if you do.
If you are building XEmacs from source, you need to install PostgreSQL
first. On some systems, PostgreSQL will come pre-installed in /usr. In
this case, it should be autodetected when you run configure. If
PostgreSQL is installed into its default location,
`/usr/local/pgsql', you must specify
--site-prefixes=/usr/local/pgsql when you run configure. If
PostgreSQL is installed into another location, use that instead of
`/usr/local/pgsql' when specifying --site-prefixes.
As of XEmacs 21.2, PostgreSQL versions 6.5.3 and 7.0 are supported. XEmacs Lisp support for V7.0 is somewhat more extensive than support for V6.5. In particular, asynchronous queries are supported.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The XEmacs PostgreSQL API is intended to be a policy-free, low-level binding to libpq. The intent is to provide all the basic functionality and then let high level Lisp code decide its own policies.
This documentation assumes that the reader has knowledge of SQL, but requires no prior knowledge of libpq.
There are many examples in this manual and some setup will be required.
In order to run most of the following examples, the following code needs
to be executed. In addition to the data is in this table, nearly all of
the examples will assume that the free variable P refers to this
database connection. The examples in the original edition of this
manual were run against Postgres 7.0beta1.
(progn
(setq P (pq-connectdb ""))
;; id is the primary key, shikona is a Japanese word that
;; means `the professional name of a Sumo wrestler', and
;; rank is the Sumo rank name.
(pq-exec P (concat "CREATE TABLE xemacs_test"
" (id int, shikona text, rank text);"))
(pq-exec P "COPY xemacs_test FROM stdin;")
(pq-put-line P "1\tMusashimaru\tYokuzuna\n")
(pq-put-line P "2\tDejima\tOozeki\n")
(pq-put-line P "3\tMusoyama\tSekiwake\n")
(pq-put-line P "4\tMiyabiyama\tSekiwake\n")
(pq-put-line P "5\tWakanoyama\tMaegashira\n")
(pq-put-line P "\\.\n")
(pq-end-copy P))
=> nil
|
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Various Unix environment variables are used by libpq to provide defaults
to the many different parameters. In the XEmacs Lisp API, these
environment variables are bound to Lisp variables to provide more
convenient access to Lisp Code. These variables are passed to the
backend database server during the establishment of a database
connection and when the pq-setenv call is made.
PGHOST environment variable. The default
host to connect to.
PGUSER environment variable. The default
database user name.
PGOPTIONS environment variable. Default
additional server options.
PGPORT environment variable. The default
TCP port to connect to.
PGTTY environment variable. The default
debugging TTY.
Compatibility note: Debugging TTYs are turned off in the XEmacs Lisp binding.
PGDATABASE environment variable. The
default database to connect to.
PGREALM environment variable. The default
Kerberos realm.
PGCLIENTENCODING environment variable. The
default client encoding.
Compatibility note: This variable is not present in non-Mule XEmacsen.
This variable is not present in versions of libpq prior to 7.0.
In the current implementation, client encoding is equivalent to the
file-name-coding-system format.
PGAUTHTYPE environment variable. The
default authentication scheme used.
Compatibility note: This variable is unused in versions of libpq after 6.5. It is not implemented at all in the XEmacs Lisp binding.
PGGEQO environment variable. Genetic
optimizer options.
PGCOSTINDEX environment variable. Cost
index options.
PGCOSTHEAP environment variable. Cost heap
options.
PGTZ environment variable. Default
timezone.
PGDATESTYLE environment variable. Default
date style in returned date objects.
Compatibility Note: This variable is not present in InfoDock.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following set of symbols are used to represent the intermediate states involved in the asynchronous interface.
select before polling again.
select before polling again.
pq::db
pq::user
pq::pass
pq::host
pq::port
pq::tty
Compatibility note: Debugging TTYs are not used in the XEmacs Lisp API.
pq::options
pq::status
pg::connection-ok
pg::connection-bad
pq-finish.
pg::connection-started
pg::connection-made
pg::connection-awaiting-response
pg::connection-auth-ok
pg::connection-setenv
pq::error-message
pq::backend-pid
The PGresult object is used by libpq to encapsulate the results
of queries. The printed representation takes on four forms. When the
PGresult object contains tuples from an SQL SELECT it will look
like:
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
=> #<PGresult PGRES_TUPLES_OK[5] - SELECT>
|
The number in brackets indicates how many rows of data are available. When the PGresult object is the result of a command query that doesn't return anything, it will look like:
(pq-exec P "CREATE TABLE a_new_table (i int);")
=> #<PGresult PGRES_COMMAND_OK - CREATE>
|
When either the query is a command-type query that can affect a number of different rows, but doesn't return any of them it will look like:
(progn
(pq-exec P "INSERT INTO a_new_table VALUES (1);")
(pq-exec P "INSERT INTO a_new_table VALUES (2);")
(pq-exec P "INSERT INTO a_new_table VALUES (3);")
(setq R (pq-exec P "DELETE FROM a_new_table;")))
=> #<PGresult PGRES_COMMAND_OK[3] - DELETE 3>
|
Lastly, when the underlying PGresult object has been deallocated
directly by pq-clear the printed representation will look like:
(progn
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
(pq-clear R)
R)
=> #<PGresult DEAD>
|
The following set of functions are accessors to various data in the PGresult object.
pgres::empty-query
pgres::command-ok
pgres::tuples-ok
pgres::copy-out
pgres::copy-in
pgres::bad-response
pgres::nonfatal-error
PQresultStatus is called with a NULL pointer.
pgres::fatal-error
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
=> #<PGresult PGRES_TUPLES_OK[5] - SELECT>
(pq-res-status R)
=> "PGRES_TUPLES_OK"
|
(setq R (pq-exec P "SELECT * FROM xemacs-test;"))
=> <A fatal error is signaled in the echo area>
(pq-result-error-message R)
=> "ERROR: parser: parse error at or near \"-\"
"
|
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
=> #<PGresult PGRES_TUPLES_OK[5] - SELECT>
(pq-ntuples R)
=> 5
|
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
=> #<PGresult PGRES_TUPLES_OK[5] - SELECT>
(pq-nfields R)
=> 3
|
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
=> #<PGresult PGRES_TUPLES_OK[5] - SELECT>
(pq-binary-tuples R)
=> nil
|
(let (i l)
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
(setq i (pq-nfields R))
(while (>= (decf i) 0)
(push (pq-fname R i) l))
l)
=> ("id" "shikona" "rank")
|
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
=> #<PGresult PGRES_TUPLES_OK[5] - SELECT>
(pq-fnumber R "id")
=> 0
(pq-fnumber R "Not a field")
=> -1
|
The return value of this function is the Object ID (Oid) in the database of the type. Further queries need to be made to various system tables in order to convert this value into something useful.
(let (i l)
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
(setq i (pq-nfields R))
(while (>= (decf i) 0)
(push (list (pq-ftype R i) (pq-fsize R i)) l))
l)
=> ((23 23) (25 25) (25 25))
|
Both tuples and fields are numbered from zero.
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
=> #<PGresult PGRES_TUPLES_OK[5] - SELECT>
(pq-get-value R 0 1)
=> "Musashimaru"
(pq-get-value R 1 1)
=> "Dejima"
(pq-get-value R 2 1)
=> "Musoyama"
|
(setq R (pq-exec P "SELECT * FROM xemacs_test;"))
=> #<PGresult PGRES_TUPLES_OK[5] - SELECT>
(pq-get-length R 0 1)
=> 11
(pq-get-length R 1 1)
=> 6
(pq-get-length R 2 1)
=> 8
|
NULL.
result is a PGresult object.
tup-num selects which tuple to fetch from.
field-num selects which field to fetch from.
(setq R (pq-exec P "INSERT INTO xemacs_test
VALUES (6, 'Wakanohana', 'Yokozuna');"))
=> #<PGresult PGRES_COMMAND_OK[1] - INSERT 542086 1>
(pq-cmd-status R)
=> "INSERT 542086 1"
(setq R (pq-exec P "UPDATE xemacs_test SET rank='retired'
WHERE shikona='Wakanohana';"))
=> #<PGresult PGRES_COMMAND_OK[1] - UPDATE 1>
(pq-cmd-status R)
=> "UPDATE 1"
|
Note that the first number returned from an insertion, like in the example, is an object ID number and will almost certainly vary from system to system since object ID numbers in Postgres must be unique across all databases.
(setq R (pq-exec P "INSERT INTO xemacs_test VALUES
(7, 'Takanohana', 'Yokuzuna');"))
=> #<PGresult PGRES_COMMAND_OK[1] - INSERT 38688 1>
(pq-cmd-tuples R)
=> "1"
(setq R (pq-exec P "SELECT * from xemacs_test;"))
=> #<PGresult PGRES_TUPLES_OK[7] - SELECT>
(pq-cmd-tuples R)
=> ""
(setq R (pq-exec P "DELETE FROM xemacs_test
WHERE shikona LIKE '%hana';"))
=> #<PGresult PGRES_COMMAND_OK[2] - DELETE 2>
(pq-cmd-tuples R)
=> "2"
|
In the first example, the numbers you will see on your local system will
almost certainly be different, however the second number from the right
in the unprintable PGresult object and the number returned by
pq-oid-value should match.
(setq R (pq-exec P "INSERT INTO xemacs_test VALUES
(8, 'Terao', 'Maegashira');"))
=> #<PGresult PGRES_COMMAND_OK[1] - INSERT 542089 1>
(pq-oid-value R)
=> 542089
(setq R (pq-exec P "SELECT shikona FROM xemacs_test
WHERE rank='Maegashira';"))
=> #<PGresult PGRES_TUPLES_OK[2] - SELECT>
(pq-oid-value R)
=> 0
|
pq-result-status.
The caller is responsible for making sure the return value gets properly freed.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
(pq-connectdb "dbname=japanese port = 25432")
=> #<PGconn localhost:25432 steve/japanese>
|
Database connection objects which have been disconnected and will generate an immediate error if they are used look like:
#<PGconn BAD> |
pq-reset, or deleted
entirely with pq-finish.
A database connection object that has been deleted looks like:
(let ((P1 (pq-connectdb "")))
(pq-finish P1)
P1)
=> #<PGconn DEAD>
|
Note that database connection objects are the most heavy weight objects in XEmacs Lisp at this writing, usually representing as much as several megabytes of virtual memory on the machine the database server is running on. It is wisest to explicitly delete them when you are finished with them, rather than letting garbage collection do it. An example idiom is:
(let ((P (pq-connectiondb "")))
(unwind-protect
(progn
(...)) ; access database here
(pq-finish P)))
|
The following options are available in the options string:
authtype
PGAUTHTYPE. This is no longer used.
user
PGUSER.
password
dbname
PGDATABASE
host
PGHOST.
hostaddr
port
PGPORT.
tty
PGTTY. This value is suppressed in the
XEmacs Lisp API.
options
PGOPTIONS.
This function reestablishes a database connection using the original connection parameters. This is useful if something has happened to the TCP link and it has become broken.
(setq R (pq-exec P "SELECT * FROM xemacs_test;
DELETE FROM xemacs_test WHERE id=8;"))
=> #<PGresult PGRES_COMMAND_OK[1] - DELETE 1>
|
Environment variable transfer is done as a normal part of database connection.
Compatibility note: This function was present but not documented in versions of libpq prior to 7.0.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Making command by command examples is too complex with the asynchronous interface functions. See the examples section for complete calling sequences.
pq-connectdb for a listing of all the available
flags.
pq-get-result would block waiting for input.
conn A database connection object.
Nil is returned if anything bad happens.
The return value is t if the cancel request was successfully dispatched, nil if not (in which case conn->errorMessage is set). Note: successful dispatch is no guarantee that there will be any effect at the backend. The application must read the operation result as usual.
nil is returned when no more query work remains.
Compatibility note: this function is only available with libpq-7.0.
Compatibility note: this function is only available with libpq-7.0.
Compatibility note: this function is only available with libpq-7.0.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
On success, the object id is returned.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It is possible to not call this routine because the usual XEmacs garbage
collection mechanism will call the underlying libpq routine whenever it
is releasing stale PGconn objects. However, this routine is
useful in unwind-protect clauses to make connections go away
quickly when unrecoverable errors have occurred.
After calling this routine, the printed representation of the XEmacs wrapper object will contain the string "DEAD".
(pq-client-encoding P)
=> 1
|
Compatibility note: This function did not exist prior to libpq-7.0 and does not exist in a non-Mule XEmacs.
(pq-set-client-encoding P "EUC_JP")
=> 0
|
The current idiom for ensuring proper coding system conversion is the following (illustrated for EUC Japanese encoding):
(setq P (pq-connectdb "..."))
(let ((file-name-coding-system 'euc-jp)
(pg-coding-system 'euc-jp))
(pq-set-client-encoding "EUC_JP")
...)
(pq-finish P)
|
PGCLIENTENCODING.
(pq-env-2-encoding)
=> 0
|
Note: The memory allocation systems of libpq and XEmacs are different. The XEmacs representation of a query result object will have both the XEmacs version and the libpq version freed at the next garbage collection when the object is no longer being referenced. Calling this function does not release the XEmacs object, it is still subject to the usual rules for Lisp objects. The printed representation of the XEmacs object will contain the string "DEAD" after this routine is called indicating that it is no longer useful for anything.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This routine is deprecated as of libpq-7.0, and its functionality can be replaced by external Lisp code if needed.
This routine was deprecated in libpq-6.5.
This routine is deprecated as of libpq-7.0 and cannot be sensibly exported to XEmacs Lisp.
This routine was deprecated in libpq-6.5.
This routine was deprecated in libpq-6.5.
*s.
s encoded string
encoding type of encoding
Compatibility note: This function was introduced in libpq-7.0.
debug_port.
conn database connection object.
debug_port C output stream to use.
Compatibility note: This function is deprecated in libpq-7.0, however it is used internally by the XEmacs binding code when linked against versions prior to 7.0.
The following set of very low level large object functions aren't appropriate to be exported to Lisp.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This is an example of one method of establishing an asynchronous connection.
(defun database-poller (P)
(message "%S before poll" (pq-pgconn P 'pq::status))
(pq-connect-poll P)
(message "%S after poll" (pq-pgconn P 'pq::status))
(if (eq (pq-pgconn P 'pq::status) 'pg::connection-ok)
(message "Done!")
(add-timeout .1 'database-poller P)))
=> database-poller
(progn
(setq P (pq-connect-start ""))
(add-timeout .1 'database-poller P))
=> pg::connection-started before poll
=> pg::connection-made after poll
=> pg::connection-made before poll
=> pg::connection-awaiting-response after poll
=> pg::connection-awaiting-response before poll
=> pg::connection-auth-ok after poll
=> pg::connection-auth-ok before poll
=> pg::connection-setenv after poll
=> pg::connection-setenv before poll
=> pg::connection-ok after poll
=> Done!
P
=> #<PGconn localhost:25432 steve/steve>
|
Here is an example of one method of doing an asynchronous reset.
(defun database-poller (P)
(let (PS)
(message "%S before poll" (pq-pgconn P 'pq::status))
(setq PS (pq-reset-poll P))
(message "%S after poll [%S]" (pq-pgconn P 'pq::status) PS)
(if (eq (pq-pgconn P 'pq::status) 'pg::connection-ok)
(message "Done!")
(add-timeout .1 'database-poller P))))
=> database-poller
(progn
(pq-reset-start P)
(add-timeout .1 'database-poller P))
=> pg::connection-started before poll
=> pg::connection-made after poll [pgres::polling-writing]
=> pg::connection-made before poll
=> pg::connection-awaiting-response after poll [pgres::polling-reading]
=> pg::connection-awaiting-response before poll
=> pg::connection-setenv after poll [pgres::polling-reading]
=> pg::connection-setenv before poll
=> pg::connection-ok after poll [pgres::polling-ok]
=> Done!
P
=> #<PGconn localhost:25432 steve/steve>
|
And finally, an asynchronous query.
(defun database-poller (P)
(let (R)
(pq-consume-input P)
(if (pq-is-busy P)
(add-timeout .1 'database-poller P)
(setq R (pq-get-result P))
(if R
(progn
(push R result-list)
(add-timeout .1 'database-poller P))))))
=> database-poller
(when (pq-send-query P "SELECT * FROM xemacs_test;")
(setq result-list nil)
(add-timeout .1 'database-poller P))
=> 885
;; wait a moment
result-list
=> (#<PGresult PGRES_TUPLES_OK - SELECT>)
|
Here is an example showing how multiple SQL statements in a single query can have all their results collected.
;; Using the same |
Here is an example which illustrates collecting all data from a query, including the field names.
(defun pg-util-query-results (results)
"Retrieve results of last SQL query into a list structure."
(let ((i (1- (pq-ntuples R)))
j l1 l2)
(while (>= i 0)
(setq j (1- (pq-nfields R)))
(setq l2 nil)
(while (>= j 0)
(push (pq-get-value R i j) l2)
(decf j))
(push l2 l1)
(decf i))
(setq j (1- (pq-nfields R)))
(setq l2 nil)
(while (>= j 0)
(push (pq-fname R j) l2)
(decf j))
(push l2 l1)
l1))
=> pg-util-query-results
(setq R (pq-exec P "SELECT * FROM xemacs_test ORDER BY field2 DESC;"))
=> #<PGresult PGRES_TUPLES_OK - SELECT>
(pg-util-query-results R)
=> (("f1" "field2") ("a" "97") ("b" "97") ("stuff" "42") ("a string" "12") ("foo" "10") ("string" "2") ("text" "1"))
|
Here is an example of a query that uses a database cursor.
(let (data R)
(setq R (pq-exec P "BEGIN;"))
(setq R (pq-exec P "DECLARE k_cursor CURSOR FOR SELECT * FROM xemacs_test ORDER BY f1 DESC;"))
(setq R (pq-exec P "FETCH k_cursor;"))
(while (eq (pq-ntuples R) 1)
(push (list (pq-get-value R 0 0) (pq-get-value R 0 1)) data)
(setq R (pq-exec P "FETCH k_cursor;")))
(setq R (pq-exec P "END;"))
data)
=> (("a" "97") ("a string" "12") ("b" "97") ("foo" "10") ("string" "2") ("stuff" "42") ("text" "1"))
|
Here's another example of cursors, this time with a Lisp macro to implement a mapping function over a table.
(defmacro map-db (P table condition callout)
`(let (R)
(pq-exec ,P "BEGIN;")
(pq-exec ,P (concat "DECLARE k_cursor CURSOR FOR SELECT * FROM "
,table
" "
,condition
" ORDER BY f1 DESC;"))
(setq R (pq-exec P "FETCH k_cursor;"))
(while (eq (pq-ntuples R) 1)
(,callout (pq-get-value R 0 0) (pq-get-value R 0 1))
(setq R (pq-exec P "FETCH k_cursor;")))
(pq-exec P "END;")))
=> map-db
(defun callback (arg1 arg2)
(message "arg1 = %s, arg2 = %s" arg1 arg2))
=> callback
(map-db P "xemacs_test" "WHERE field2 > 10" callback)
=> arg1 = stuff, arg2 = 42
=> arg1 = b, arg2 = 97
=> arg1 = a string, arg2 = 12
=> arg1 = a, arg2 = 97
=> #<PGresult PGRES_COMMAND_OK - COMMIT>
|
| [ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |