PostgreSQL

PostgreSQL is a free implementation of the relational database system, which is available from http://www.postgresql.org. Once PostgreSQL is installed on your computer, EusLisp provides links to the databases via the libpq.so library.

Connecting to the Postgres database Instantiate pq:pgsql with proper arguments. In most cases, you just want to specify the database name and the user name. If you don't know, just trust the defaults, namely (instance pq:pgsql :init) is usually ok to make a connection.

Synchronous data transfer There are the synchronous and asynchronous interface in libpq.so. Synchronous transfer is easier. You send SQL commands by :exec method of the pgsql object, and get the result. (send db :exec "select typname,oid from pg_type order by oid") will give you a list of all data types defined in your database.

Asynchronous database access For asynchronous processing, you have to define a function or method to receive a query result as the first argument. Let's assume the receiver function is 'print'. Then a query should be issued by the :sendQuery method with the receiver function name as the second argument. (send db :sendQuery "select oid from pg_type" 'print)

Type conversion Postgres database stores data in a variety of forms internally, but every data item transferred between the database and the client is always converted to the string format. Thus, integer 1234 is "1234", and a symbol 'SYMBOL is "symbol". But, of course, since we want to access a database to store lisp data, they should be handled as lisp integers and lisp symbols. I found the datatype information is stored in the pg_type table. When we get data from a table, we can also retrieve the oid (object id) attributed to each field. By looking up pg_type table with the oid, we can know the datatype name, such as integer, character, date, etc. However, there is no symbol! We can use the 'name' type instead, but still there is incoherency to use as lisp symbol type, since there is no escapes (vertical bar and backslash) and lower-case to upcase conversion. I mean if we use the 'intern' function to change the 'name' object to symbol, it becomes a symbol with the lower case print-name. Do we call string-upcase before interning? Usually it works, but not always, because escapes are ignored. So I defined input and output function for Postgres in 'symbol_io.c'. There is also a Makefile for it. Make symbol_io.so and copy it to /usr/local/pgsql/lib. Invoke psql, and type "isymbol_io.sql", which will make postgres to load the lisp_symbol_io functions, and and define the symbol type. Call make-type-hashtab function once before any other database retrieval for the faster type look-up. Then, every data transfered from the database is converted properly. Currently, symbol, int, float, char (string), date, time, datetime are coerced to corresponding lisp objects. Other unknown type data are represented by strings.

The following codes put in another file will load this database module, creates the *type-hashtab*, and reads the type list.

(load "pgsql")
(in-package "USER")
(unless (boundp 'db)
   (setq db (instance pq:pgsql :init) ))
(send db :exec "select * from family")
(pq:make-type-hashtab db)
(setq types (send db :exec "select typname,oid from pg\_type order by oid"))




pgsql [class]


  :super   propertied-object 

:slots ...




:init key host port dbname user password [method]
connects to a database designated by host, port and dbname. Host is defaulted to the localhost. The default port number is 5432. Default values to dbname and user are obtained from the USER environment variable.


:type-conversion flag [method]

Basically, every result delivered by a database query consists of a string. If type-conversion is set to NIL, no type conversion is performed, and query result is returned as a list of strings. If type-conversion is set to T, number is coerced to number, and symbol is interned in the current package.


:exec sql [method]

sends the SQL command to the database. EusLisp waits for the completion of the database processing and retrieves the results in a synchronous manner.


pq:table-fields db table [function]

returns the list of all fields in the table managed in the db database. Each list element is again a list, describing the field number starting from one, the symbolic field name, and the field type, such as text, int4, symbol, etc.


pq:table-attributes db table [function]

returns a list that describes attributes of the given table in db. The attributes are, name, owner, read-write grants, number of fields, etc.


pq:query db handler &rest sql [function]

sends an SQL command composed by the sql arguments to db. If handler is specified, the data retrieval is processed in asynchronous manner. The handler function is invoked when the database processing result arrives. The SQL command is composed by combining sql arguments by the format function.


pq:tables db [function]

returns a list of all tables created in db.


pq:delimit-list xlist delimiter [function]

returns a string combining xlist with the constant delimter string. For example, (delimit-list '(a b c) 'or) returns "a or b or c". This function is useful to compose SQL commands.


pq:select db fields table &key where limit limit-offset order-by [function]

sends an SQL command composed by the argument, and retrieves the result in the synchronous manner. The following example gives a list of id, name and email selected from the address_book table where the email ends with ".go.jp". Number of output lists are limited to 10, and the result is sorted by 'id'.


(select db '(id name email) 'address_book
     :where "email like '\*.go.jp'"
     :limit 10
     :order-by 'id)

pq:record-count db table [function]

returns the number of records in the table. db is a pgsql object.


k-okada 2013-05-21