File: database.tex

package info (click to toggle)
euslisp 9.27%2Bdfsg-7
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 55,344 kB
  • sloc: ansic: 41,162; lisp: 3,339; makefile: 256; sh: 208; asm: 138; python: 53
file content (149 lines) | stat: -rw-r--r-- 6,230 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
\section{PostgreSQL Database}
\markright{\arabic{section}. PostgreSQL Database}

\subsection{PostgreSQL}

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


\begin{description}
\item{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.

\item{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.

\item{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)

\item{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 "\i symbol\_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.
\end{description}

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

\begin{verbatim}
(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"))
\end{verbatim}

\begin{refdesc}

\classdesc{pgsql}{propertied-object}{...}{}{}

\methoddesc{:init}{key host port dbname user password}{
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.
}

\methoddesc{:type-conversion}{flag}{
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.}

\methoddesc{:exec}{sql}{sends the SQL command to the database.
EusLisp waits for the completion of the database processing and
retrieves the results in a synchronous manner.}

\funcdesc{pq:table-fields}{db table}{
returns the list of all fields in the table
managed in the {\it 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.
}

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

\funcdesc{pq:query}{db handler \&rest sql}{
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 {\it sql} arguments by
the {\it format} function.}

\funcdesc{pq:tables}{db}{returns a list of all tables created in db.}

\funcdesc{pq:delimit-list}{xlist delimiter}{
returns a string combining {\it 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.}

\funcdesc{pq:select}{db fields table \&key where limit limit-offset order-by}{
 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'.}

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


\funcdesc{pq:record-count}{db table}{
returns the number of records in the table. db is a pgsql object.}


\end{refdesc}

\newpage