Hi,
Well, I am feverishly trying to meet all the promises I have made to
various people in expectation of the arrival of a new family member
this weekend. So, here's another promise made good - a preview
release of my PostgreSQL library. It works very nicely and I have
even documented it! I include the help file and a uuencoded
gzip'd tar archive of the distribution directory.
If you are not familiar with PostgreSQL it is a very popular and
venerable open source database distributed as part of Red Hat Linux.
This is very much work in progress (or even progresql). Yet for
some applications it is perfectly adequate already. I have
already deployed it successfully in a commercial environment.
But if there is anyone out there who wants to add to what has
been done already - please go right ahead.
(What this does raise is the need for an unified database query
interface, along the lines of Perl's, so that Pop11 programs can
access different databases without the need for any code
rewriting.)
Steve
-----------------------------------------------------------------------
HELP POSTGRESQL Steve Leach, Apr 00
lib postgresql
This library provides a simple but useful interface to the PostgreSQL
driver "libpq". PostgreSQL is a popular open source SQL compliant
database - see <http://www.postgresql.org/> for more information.
If you want Poplog to work with a database, then this is one option
which I can recommend. Another option is to try LIB * ODBC.
This is work in progress but I've decided to release it since I have
found it quite handy even in its current state. If other people would
like to continue this work, that would be fine by me! Contact me at
<mailto:steve@watchfield.com>
CONTENTS - (Use <ENTER> g to access required sections)
1 Getting Started
2 A Simple Example
... Setting Up
... Using Table SCORE from Pop11
3 Database Connection Functions
4 Query Execution Functions
5 Asynchronous Query Processing (unimplemented)
6 Fast Path (unimplemented)
7 Asynchronous Notification (unimplemented)
8 Functions Associated with the COPY Command (unimplemented)
9 libpq Tracing Functions (unimplemented)
10 libpq Control Functions (unimplemented)
11 User Authentication Functions (unimplemented)
12 Limitations
-----------------------------------------------------------------------
1 Getting Started
-----------------------------------------------------------------------
You will need PostgreSQL installed properly first. In particular you
will need the API made available by libpq. In my experience, installing
database software tends to be painful and PostgreSQL is typical in
this respect. Follow the instructions at <http://www.postgresql.org/>
and the best of luck!
Once PostgreSQL is installed, you need to load the library. This
is as simple as
lib postgresql
This library will dynamically link the libpq driver to Poplog and
provides a thin access layer. This layer takes care of closing
connections when they are garbage collected, and so on.
-----------------------------------------------------------------------
2 A Simple Example
-----------------------------------------------------------------------
... Setting Up
---------------
Let's create a table SCORE with a two columns: NAME and RESULT. The
following text is a transcript of a session with "psql", a simple
text-based SQL monitor that comes with PostgreSQL.
[steve@spirit doc]$ psql
Welcome to the POSTGRESQL interactive sql monitor:
Please read the file COPYRIGHT for copyright terms of POSTGRESQL
[PostgreSQL 6.5.2 on i686-pc-linux-gnu, compiled by gcc egcs-2.91.66]
type \? for help on slash commands
type \q to quit
type \g or terminate with semicolon to execute query
You are currently connected to the database: steve
steve=> CREATE TABLE SCORE ( NAME VARCHAR, RESULT INT );
CREATE
Now we populate the table with a few records
steve=> INSERT INTO SCORE VALUES ( 'Steve', 100 );
INSERT 22816 1
steve=> INSERT INTO SCORE VALUES ( 'Bill', 3 );
INSERT 22817 1
steve=> INSERT INTO SCORE VALUES ( 'Nathan', 17 );
INSERT 22818 1
... Using Table SCORE from Pop11
---------------------------------
Now let's connect to this database. The simplest way to do this is
through the function call -pq_connectdb-. (All the function names are
directly based on their libpq equivalents.) The PQconnectdb function
takes a string which supplies all the relevant user name, password and
so on. For our trivial example, all the defaults are fine.
: vars db = pq_connectdb( '' );
: db =>
** <pq_connection <external_ptr>>
Now we want to find out what score 'Steve' has. The appropriate
SQL command is
SELECT RESULT FROM SCORE WHERE NAME='Steve'
Neatly, the pq_connection object can be applied as if it was a
function to return a list of vectors.
: db( 'SELECT RESULT FROM SCORE WHERE NAME=\'Steve\'' ) =>
** [{100}]
Since the above query selects only one column the vector is of
length one. If we had asked for all the records we would have
written :-
: db( 'SELECT * FROM SCORE' ) =>
** [{Steve 100} {Bill 3} {Nathan 17}]
A current limitation of this approach is that all the components
of the vector are strings and not the underlying datatype.
-----------------------------------------------------------------------
3 Database Connection Functions
-----------------------------------------------------------------------
This section lists the database connection functions that have been
implemented. There are quite a lot of functions that are missing
from the list at the moment.
pq_connectdb( connection_string ) -> dbconn
Given a connection string, this procedure attempts to open a
connection. If the attempt fails <false> is returned.
Connections are closed when they are garbage collected or
explicitly by the programmer.
pq_finish( dbconn ) -> ()
Closes a database connection. If it is already closed no action
is taken.
pd_db( dbconn ) -> string
Returns the database name associated with a connection.
-----------------------------------------------------------------------
4 Query Execution Functions
-----------------------------------------------------------------------
This section lists the query execution functions that have been
implemented. There are quite a lot of functions that are missing
from the list at the moment.
pq_exec( dbconn, query ) -> pqresult
This function is the basic method of querying the database.
It takes a database connection and an SQL query, as a string,
and generates a pqresult object.
If the query fails a mishap is raised. If this is not what is
required you will need -pq_try_exec-.
pq_try_exec( dbconn, query ) -> pqresult_or_false
Exactly the same as -pq_exec- except meekly returns <false>
if the query fails.
pq_clear( pqresult ) -> ()
Reclaims the external store used by a pqresult. This is automatically
called on garbage collection of a pqresult. The pqresult is not
usable after this.
pq_fmod( pqresult, index ) -> int
Returns a small integer which encodes the type-specific modification
data ssociated with the given field index. Field indices start at 0.
pq_fname( pqresult, index ) -> name
Returns the field (attribute) name string associated with the
given field index. Field indices start at 0.
pq_fnumber( pqresult, name ) -> index
Returns the field (attribute) index associated with the given field name.
Field indices start at 0.
pq_fsize( pqresult, index ) -> size
Returns the size in bytes of the field associated with the given field
index. Field indices start at 0.
pq_ftype( pqresult, index ) -> type:int
Returns the field type associated with the given field index.
Field indices start at 0.
The type is encoded as a small integer. At present there seems
no way of getting any further structure.
pq_getvalue( pqresult, tuple, index ) -> string
Returns a single field (attribute) value of one tuple of a PGresult.
Tuple and field indices start at 0.
pq_nfields( pqresult ) -> num
Returns the number of fields (attributes) in each tuple of the query
result.
pq_ntuples( pqresult ) -> num
Returns the number of tuples (instances) in the query result.
Tuple indices start at 0.
-----------------------------------------------------------------------
5 Asynchronous Query Processing (unimplemented)
-----------------------------------------------------------------------
-----------------------------------------------------------------------
6 Fast Path (unimplemented)
-----------------------------------------------------------------------
-----------------------------------------------------------------------
7 Asynchronous Notification (unimplemented)
-----------------------------------------------------------------------
-----------------------------------------------------------------------
8 Functions Associated with the COPY Command (unimplemented)
-----------------------------------------------------------------------
-----------------------------------------------------------------------
9 libpq Tracing Functions (unimplemented)
-----------------------------------------------------------------------
-----------------------------------------------------------------------
10 libpq Control Functions (unimplemented)
-----------------------------------------------------------------------
-----------------------------------------------------------------------
11 User Authentication Functions (unimplemented)
-----------------------------------------------------------------------
-----------------------------------------------------------------------
12 Limitations
-----------------------------------------------------------------------
Unfortunately libpq has a fundamental limitation - that the query
buffer is 8192 bytes long, and queries over that length will be
rejected. This is not a particularly oppressive limit but it does
need to be stated.
-----------------------------------------------------------------------
UUencoded, gzip'd, tar archive of lib postgresql.p
-----------------------------------------------------------------------
begin 644 postgresql-dist.tgz
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
@ZE:WNM6M;G6K6]WJ5K>ZU:UN=?LW;_\'Z8<K'`!X````
`
end
|