Commit c8cfb0ce authored by Thomas G. Lockhart's avatar Thomas G. Lockhart

SGML source for new documentation.

parent 878531f1
# Postgres documentation makefile
# Thomas Lockhart
PGDOCS= ..
SRCDIR= ../../src
HPATH=$(PGDOCS)/doc
PPATH=$(PGDOCS)/doc
#HSTYLE=/usr/lib/sgml/stylesheets/jade/docbook/html
#PSTYLE=/usr/lib/sgml/stylesheets/jade/docbook/print
HSTYLE=/home/tgl/SGML/db107.d/docbook/html
PSTYLE=/home/tgl/SGML/db107.d/docbook/print
HDSL=$(HSTYLE)/docbook.dsl
PDSL=$(PSTYLE)/docbook.dsl
#DBOPTS=-V %no-split-output% -V %no-make-index%
TAR= tar
TAREXCLUDE= --exclude=Makefile --exclude='*.sgml'
# Pick up Makefile.custom from the source area
# This is the only resource from the code source area and is optional
ifneq ($(wildcard $(SRCDIR)/Makefile.custom), )
include $(SRCDIR)/Makefile.custom
endif
TARGETS= postgres tutorial user admin programmer
HTARGETS=#make this a mapping from targets
PTARGETS=#make this a mapping from targets
.PRECIOUS: postgres.html postgres.tex postgres.dvi
.PHONY: sources clean
install::
$(MAKE) all
(mv -rf *.gz ..)
all:: $(SGO) $(SGP)
sources::
($(TAR) zcf sources.tar.gz --exclude='*.htm*' --exclude='*.gz' .)
user.tar.gz:
$(MAKE) -C sgml clean
$(MAKE) -C sgml user.html
($(TAR) zcf $@ $(TAREXCLUDE) -C sgml .)
tutorial.tar.gz:
$(MAKE) -C sgml clean
$(MAKE) -C sgml tutorial.html
($(TAR) zcf $@ $(TAREXCLUDE) -C sgml . -C .. -C graphics clientserver.gif)
clean::
(rm -rf *.html *.htm)
distclean::
$(MAKE) -C sgml clean
# Generic production rules
# Compressed file
%.gz: %
(gzip -f $<)
# TAR file for HTML package
%.tar: %.html # %.ps
(tar cf $@ $*.html index.html *.htm *.gif) # $*.ps
(rm -rf index.html *.htm)
# (mkdir $*)
# (rm -rf $*/*)
# (mv *.htm $*/)
# (cd $*/; ln -sf book01.htm index.html)
# (tar cf $@ $*)
# HTML
# Include some softlinks to the generic default file names
%.html: %.sgml $(HDSL)
(rm -rf *.htm)
jade $(DBOPTS) -D sgml -d $(HDSL) -t sgml $<
(ln -sf book01.htm index.html)
(ln -sf book01.htm $*.html)
# (mkdir $(HPATH)/$*) # be sure there is somewhere to put them
# (rm -rf $(HPATH)/$*/*) # remove existing files since some names may be obsolete
# (mv *.htm $(HPATH)/$*/) # and copy 'em over
# (cd $(HPATH)/$*/; ln -sf book01.htm index.html)
# RTF to allow minor editing for hardcopy
# This is used for v6.3 docs
%.rtf: %.sgml $(PDSL)
jade $(DBOPTS) -d $(PDSL) -t rtf $<
# TeX and DVI
%.tex: %.sgml $(PDSL)
jade $(DBOPTS) -d $(PDSL) -t tex $<
%.dvi: %.tex
jadetex $<
jadetex $<
# Postscript from TeX
%.ps: %.dvi
dvips -o $@ $<
# Graphics
%.gif:
cp -p graphics/%.gif .
<!-- admin.sgml
-
- Postgres administrator's guide.
- Derived from postgres.sgml.
- thomas 1998-02-27
-
- -->
<!doctype book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
<!entity intro SYSTEM "intro.sgml">
<!entity install SYSTEM "install.sgml">
<!entity ports SYSTEM "ports.sgml">
<!entity recovery SYSTEM "recovery.sgml">
<!entity regress SYSTEM "regress.sgml">
<!entity release SYSTEM "release.sgml">
<!entity start-ag SYSTEM "start-ag.sgml">
<!entity biblio SYSTEM "biblio.sgml">
]>
<!-- entity manpages SYSTEM "man/manpages.sgml" subdoc -->
<Book>
<!-- Title information -->
<Title>PostgreSQL Administrator's Guide</Title>
<BookInfo>
<ReleaseInfo>Covering v6.3 for general release</ReleaseInfo>
<BookBiblio>
<AuthorGroup>
<CorpAuthor>The PostgreSQL Development Team</CorpAuthor>
</AuthorGroup>
<!-- editor in authorgroup is not supported
<AuthorGroup>
-->
<Editor>
<FirstName>Thomas</FirstName>
<SurName>Lockhart</SurName>
<Affiliation>
<OrgName>Caltech/JPL</OrgName>
</Affiliation>
</Editor>
<!--
</AuthorGroup>
-->
<!--
<AuthorInitials>TGL</AuthorInitials>
-->
<Date>(last updated 1998-02-23)</Date>
</BookBiblio>
<LegalNotice>
<Para>
<ProductName>PostgreSQL</ProductName> is copyright (C) 1998 by the Postgres Global Development Group.
</Para>
</LegalNotice>
</BookInfo>
<!--
<TOC> </TOC>
<LOT> </LOT>
-->
<!--
<Dedication>
<Para>
Your name here...
</Para>
</Dedication>
-->
<Preface>
<Title>Summary</Title>
<Para>
<ProductName>Postgres</ProductName>,
developed originally in the UC Berkeley Computer Science Department,
pioneered many of the object-relational concepts
now becoming available in some commercial databases.
It provides SQL92/SQL3 language support,
transaction integrity, and type extensibility.
<ProductName>PostgreSQL</ProductName> is a public-domain, open source descendant
of this original Berkeley code.
</Para>
</Preface>
&intro;
&ports;
&install;
&start-ag;
&recovery;
&regress;
&release;
&biblio;
<INDEX> </INDEX>
</Book>
<Chapter>
<Title>Advanced <ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> Features</Title>
<Para>
Having covered the basics of using <ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> to
access your data, we will now discuss those features of
<ProductName>Postgres</ProductName> that distinguish it from conventional data
managers. These features include inheritance, time
travel and non-atomic data values (array- and
set-valued attributes).
Examples in this section can also be found in
<FileName>advance.sql</FileName> in the tutorial directory.
(Refer to <XRef LinkEnd="QUERY"> for how to use it.)
</Para>
<Sect1>
<Title>Inheritance</Title>
<Para>
Let's create two classes. The capitals class contains
state capitals which are also cities. Naturally, the
capitals class should inherit from cities.
<ProgramListing>
CREATE TABLE cities (
name text,
population float,
altitude int -- (in ft)
);
CREATE TABLE capitals (
state char2
) INHERITS (cities);
</ProgramListing>
In this case, an instance of capitals <FirstTerm>inherits</FirstTerm> all
attributes (name, population, and altitude) from its
parent, cities. The type of the attribute name is
<Type>text</Type>, a native <ProductName>Postgres</ProductName> type for variable length
ASCII strings. The type of the attribute population is
<Type>float</Type>, a native <ProductName>Postgres</ProductName> type for double precision
floating point numbers. State capitals have an extra
attribute, state, that shows their state. In <ProductName>Postgres</ProductName>,
a class can inherit from zero or more other classes,
and a query can reference either all instances of a
class or all instances of a class plus all of its
descendants.
<Note>
<Para>
The inheritance hierarchy is a directed acyclic graph.
</Para>
</Note>
For example, the following query finds
all the cities that are situated at an attitude of 500ft or higher:
<ProgramListing>
SELECT name, altitude
FROM cities
WHERE altitude &gt; 500;
+----------+----------+
|name | altitude |
+----------+----------+
|Las Vegas | 2174 |
+----------+----------+
|Mariposa | 1953 |
+----------+----------+
</ProgramListing>
<Para>
On the other hand, to find the names of all cities,
including state capitals, that are located at an altitude
over 500ft, the query is:
<ProgramListing>
SELECT c.name, c.altitude
FROM cities* c
WHERE c.altitude > 500;
</ProgramListing>
which returns:
<ProgramListing>
+----------+----------+
|name | altitude |
+----------+----------+
|Las Vegas | 2174 |
+----------+----------+
|Mariposa | 1953 |
+----------+----------+
|Madison | 845 |
+----------+----------+
</ProgramListing>
Here the <Quote>*</Quote> after cities indicates that the query should
be run over cities and all classes below cities in the
inheritance hierarchy. Many of the commands that we
have already discussed (<Command>select</Command>, <Command>update</Command> and <Command>delete</Command>)
support this <Quote>*</Quote> notation, as do others, like <Command>alter</Command>.
</Para>
</Sect1>
<Sect1>
<Title>Non-Atomic Values</Title>
<Para>
One of the tenets of the relational model is that the
attributes of a relation are atomic. <ProductName>Postgres</ProductName> does not
have this restriction; attributes can themselves contain
sub-values that can be accessed from the query
language. For example, you can create attributes that
are arrays of base types.
<Sect2>
<Title>Arrays</Title>
<Para>
<ProductName>Postgres</ProductName> allows attributes of an instance to be defined
as fixed-length or variable-length multi-dimensional
arrays. Arrays of any base type or user-defined type
can be created. To illustrate their use, we first create a
class with arrays of base types.
<ProgramListing>
CREATE TABLE SAL_EMP (
name text,
pay_by_quarter int4[],
schedule char16[][]
);
</ProgramListing>
</Para>
<Para>
The above query will create a class named SAL_EMP with
a <FirstTerm>text</FirstTerm> string (name), a one-dimensional array of <FirstTerm>int4</FirstTerm>
(pay_by_quarter), which represents the employee's
salary by quarter and a two-dimensional array of <FirstTerm>char16</FirstTerm>
(schedule), which represents the employee's weekly
schedule. Now we do some <FirstTerm>INSERTS</FirstTerm>s; note that when
appending to an array, we enclose the values within
braces and separate them by commas. If you know <FirstTerm>C</FirstTerm>,
this is not unlike the syntax for initializing structures.
<ProgramListing>
INSERT INTO SAL_EMP
VALUES ('Bill',
'{10000, 10000, 10000, 10000}',
'{{"meeting", "lunch"}, {}}');
INSERT INTO SAL_EMP
VALUES ('Carol',
'{20000, 25000, 25000, 25000}',
'{{"talk", "consult"}, {"meeting"}}');
</ProgramListing>
By default, <ProductName>Postgres</ProductName> uses the "one-based" numbering
convention for arrays -- that is, an array of n elements starts with array[1] and ends with array[n].
Now, we can run some queries on SAL_EMP. First, we
show how to access a single element of an array at a
time. This query retrieves the names of the employees
whose pay changed in the second quarter:
<ProgramListing>
SELECT name
FROM SAL_EMP
WHERE SAL_EMP.pay_by_quarter[1] &lt;&gt;
SAL_EMP.pay_by_quarter[2];
+------+
|name |
+------+
|Carol |
+------+
</ProgramListing>
</Para>
<Para>
This query retrieves the third quarter pay of all
employees:
<ProgramListing>
SELECT SAL_EMP.pay_by_quarter[3] FROM SAL_EMP;
+---------------+
|pay_by_quarter |
+---------------+
|10000 |
+---------------+
|25000 |
+---------------+
</ProgramListing>
</Para>
<Para>
We can also access arbitrary slices of an array, or
subarrays. This query retrieves the first item on
Bill's schedule for the first two days of the week.
<ProgramListing>
SELECT SAL_EMP.schedule[1:2][1:1]
FROM SAL_EMP
WHERE SAL_EMP.name = 'Bill';
+-------------------+
|schedule |
+-------------------+
|{{"meeting"},{""}} |
+-------------------+
</ProgramListing>
</Para>
</Sect1>
<Sect1>
<Title>Time Travel</Title>
<Para>
As of <ProductName>Postgres</ProductName> v6.2, <Emphasis>time travel is no longer supported</Emphasis>. There are
several reasons for this: performance impact, storage size, and a pg_time file which grows
toward infinite size in a short period of time.
</Para>
<Para>
New features such as triggers allow one to mimic the behavior of time travel when desired, without
incurring the overhead when it is not needed (for most users, this is most of the time).
See examples in the <FileName>contrib</FileName> directory for more information.
</Para>
<Note>
<Title>Time travel is deprecated</Title>
<Para>
The remaining text in this section is retained only until it can be rewritten in the context
of new techniques to accomplish the same purpose. Volunteers? - thomas 1998-01-12
</Para>
</Note>
<Para>
<ProductName>Postgres</ProductName> supports the notion of time travel. This feature
allows a user to run historical queries. For
example, to find the current population of Mariposa
city, one would query:
<ProgramListing>
SELECT * FROM cities WHERE name = 'Mariposa';
+---------+------------+----------+
|name | population | altitude |
+---------+------------+----------+
|Mariposa | 1320 | 1953 |
+---------+------------+----------+
</ProgramListing>
<ProductName>Postgres</ProductName> will automatically find the version of Mariposa's
record valid at the current time.
One can also give a time range. For example to see the
past and present populations of Mariposa, one would
query:
<ProgramListing>
SELECT name, population
FROM cities['epoch', 'now']
WHERE name = 'Mariposa';
</ProgramListing>
where "epoch" indicates the beginning of the system
clock.
<Note>
<Para>
On UNIX systems, this is always midnight, January 1, 1970 GMT.
</Para>
</Note>
</Para>
If you have executed all of the examples so
far, then the above query returns:
<ProgramListing>
+---------+------------+
|name | population |
+---------+------------+
|Mariposa | 1200 |
+---------+------------+
|Mariposa | 1320 |
+---------+------------+
</ProgramListing>
<Para>
The default beginning of a time range is the earliest
time representable by the system and the default end is
the current time; thus, the above time range can be
abbreviated as ``[,].''
</Para>
<Sect1>
<Title>More Advanced Features</Title>
<Para>
<ProductName>Postgres</ProductName> has many features not touched upon in this
tutorial introduction, which has been oriented toward newer users of <Acronym>SQL</Acronym>.
These are discussed in more detail in both the User's and Programmer's Guides.
</Chapter>
<Chapter>
<TITLE>Architecture</TITLE>
<Sect1>
<Title><ProductName>Postgres</ProductName> Architectural Concepts</Title>
<Para>
Before we continue, you should understand the basic
<ProductName>Postgres</ProductName> system architecture. Understanding how the
parts of <ProductName>Postgres</ProductName> interact will make the next chapter
somewhat clearer.
In database jargon, <ProductName>Postgres</ProductName> uses a simple "process
per-user" client/server model. A <ProductName>Postgres</ProductName> session
consists of the following cooperating UNIX processes (programs):
<ItemizedList>
<ListItem>
<Para>
A supervisory daemon process (<Application>postmaster</Application>),
</Para>
</ListItem>
<ListItem>
<Para>
the user's frontend application (e.g., the <Application>psql</Application> program), and
</Para>
</ListItem>
<ListItem>
<Para>
the one or more backend database servers (the <Application>postgres</Application> process itself).
</Para>
</ListItem>
</ItemizedList>
<Para>
A single <Application>postmaster</Application> manages a given collection of
databases on a single host. Such a collection of
databases is called an installation or site. Frontend
applications that wish to access a given database
within an installation make calls to the library.
The library sends user requests over the network to the
<Application>postmaster</Application> (<XRef LinkEnd="ARCHDEV-CONNECTIONS" EndTerm="ARCHDEV-CONNECTIONS">(a)), which in turn starts a new
backend server process (<XRef LinkEnd="ARCHDEV-CONNECTIONS" EndTerm="ARCHDEV-CONNECTIONS">(b))
<Figure id="ARCHDEV-CONNECTIONS">
<Title>How a connection is established</Title>
<Graphic Align="center" FileRef="connections.gif" Format="GIF"></Graphic>
</Figure>
and connects the
frontend process to the new server (<XRef LinkEnd="ARCHDEV-CONNECTIONS" EndTerm="ARCHDEV-CONNECTIONS">(c)). From
that point on, the frontend process and the backend
server communicate without intervention by the
<Application>postmaster</Application>. Hence, the <Application>postmaster</Application> is always running, waiting
for requests, whereas frontend and backend processes
come and go. The <FileName>libpq</FileName> library allows a single
frontend to make multiple connections to backend processes.
However, the frontend application is still a
single-threaded process. Multithreaded frontend/backend
connections are not currently supported in <FileName>libpq</FileName>.
One implication of this architecture is that the
<Application>postmaster</Application> and the backend always run on the same
machine (the database server), while the frontend
application may run anywhere. You should keep this
in mind,
because the files that can be accessed on a client
machine may not be accessible (or may only be accessed
using a different filename) on the database server
machine.
You should also be aware that the <Application>postmaster</Application> and
postgres servers run with the user-id of the <ProductName>Postgres</ProductName>
"superuser." Note that the <ProductName>Postgres</ProductName> superuser does not
have to be a special user (e.g., a user named
"postgres"). Furthermore, the <ProductName>Postgres</ProductName> superuser
should
definitely not be the UNIX superuser, "root"! In any
case, all files relating to a database should belong to
this <ProductName>Postgres</ProductName> superuser.
</Para>
</Chapter>
<Chapter>
<TITLE>Architecture</TITLE>
<Sect1>
<Title><ProductName>Postgres</ProductName> Architectural Concepts</Title>
<Para>
Before we continue, you should understand the basic
<ProductName>Postgres</ProductName> system architecture. Understanding how the
parts of <ProductName>Postgres</ProductName> interact will make the next chapter
somewhat clearer.
In database jargon, <ProductName>Postgres</ProductName> uses a simple "process
per-user" client/server model. A <ProductName>Postgres</ProductName> session
consists of the following cooperating UNIX processes (programs):
<ItemizedList>
<ListItem>
<Para>
A supervisory daemon process (<Application>postmaster</Application>),
</Para>
</ListItem>
<ListItem>
<Para>
the user's frontend application (e.g., the <Application>psql</Application> program), and
</Para>
</ListItem>
<ListItem>
<Para>
the one or more backend database servers (the <Application>postgres</Application> process itself).
</Para>
</ListItem>
</ItemizedList>
<Para>
A single <Application>postmaster</Application> manages a given collection of
databases on a single host. Such a collection of
databases is called an installation or site. Frontend
applications that wish to access a given database
within an installation make calls to the library.
The library sends user requests over the network to the
<Application>postmaster</Application>
(<XRef LinkEnd="PGARCH-CONNECTIONS" EndTerm="PGARCH-CONNECTIONS">(a)),
which in turn starts a new backend server process
(<XRef LinkEnd="PGARCH-CONNECTIONS" EndTerm="PGARCH-CONNECTIONS">(b))
<Figure Id="PGARCH-CONNECTIONS">
<Title>How a connection is established</Title>
<Graphic Align="center" FileRef="connections.gif" Format="GIF"></Graphic>
</Figure>
and connects the frontend process to the new server
(<XRef LinkEnd="PGARCH-CONNECTIONS" EndTerm="PGARCH-CONNECTIONS">(c)).
From that point on, the frontend process and the backend
server communicate without intervention by the
<Application>postmaster</Application>. Hence, the <Application>postmaster</Application> is always running, waiting
for requests, whereas frontend and backend processes
come and go. The <FileName>libpq</FileName> library allows a single
frontend to make multiple connections to backend processes.
However, the frontend application is still a
single-threaded process. Multithreaded frontend/backend
connections are not currently supported in <FileName>libpq</FileName>.
One implication of this architecture is that the
<Application>postmaster</Application> and the backend always run on the same
machine (the database server), while the frontend
application may run anywhere. You should keep this
in mind,
because the files that can be accessed on a client
machine may not be accessible (or may only be accessed
using a different filename) on the database server
machine.
You should also be aware that the <Application>postmaster</Application> and
postgres servers run with the user-id of the <ProductName>Postgres</ProductName>
"superuser."
Note that the <ProductName>Postgres</ProductName> superuser does not
have to be a special user (e.g., a user named
"postgres"), although many systems are installed that way.
Furthermore, the <ProductName>Postgres</ProductName> superuser should
definitely not be the UNIX superuser, "root"! In any
case, all files relating to a database should belong to
this <ProductName>Postgres</ProductName> superuser.
</Para>
</Chapter>
<Chapter>
<TITLE>Architecture</TITLE>
<Sect1>
<Title><ProductName>Postgres</ProductName> Architectural Concepts</Title>
<Para>
Before we begin, you should understand the basic
<ProductName>Postgres</ProductName> system architecture. Understanding how the
parts of <ProductName>Postgres</ProductName> interact will make the next chapter
somewhat clearer.
In database jargon, <ProductName>Postgres</ProductName> uses a simple "process
per-user" client/server model. A <ProductName>Postgres</ProductName> session
consists of the following cooperating UNIX processes (programs):
<ItemizedList>
<ListItem>
<Para>
A supervisory daemon process (<Application>postmaster</Application>),
</Para>
</ListItem>
<ListItem>
<Para>
the user's frontend application (e.g., the <Application>psql</Application> program), and
</Para>
</ListItem>
<ListItem>
<Para>
the one or more backend database servers (the <Application>postgres</Application> process itself).
</Para>
</ListItem>
</ItemizedList>
<Para>
A single <Application>postmaster</Application> manages a given collection of
databases on a single host. Such a collection of
databases is called an installation or site. Frontend
applications that wish to access a given database
within an installation make calls to the library.
The library sends user requests over the network to the
<Application>postmaster</Application> (<XRef LinkEnd="ARCH-CLIENTSERVER" EndTerm="ARCH-CLIENTSERVER">),
which in turn starts a new backend server process
<Figure Id="ARCH-CLIENTSERVER">
<Title>How a connection is established</Title>
<Graphic Align="center" FileRef="clientserver.gif" Format="GIF"></Graphic>
</Figure>
and connects the
frontend process to the new server. From
that point on, the frontend process and the backend
server communicate without intervention by the
<Application>postmaster</Application>. Hence, the <Application>postmaster</Application> is always running, waiting
for requests, whereas frontend and backend processes
come and go.
<Para>
The <FileName>libpq</FileName> library allows a single
frontend to make multiple connections to backend processes.
However, the frontend application is still a
single-threaded process. Multithreaded frontend/backend
connections are not currently supported in <FileName>libpq</FileName>.
One implication of this architecture is that the
<Application>postmaster</Application> and the backend always run on the same
machine (the database server), while the frontend
application may run anywhere. You should keep this
in mind,
because the files that can be accessed on a client
machine may not be accessible (or may only be accessed
using a different filename) on the database server
machine.
<Para>
You should also be aware that the <Application>postmaster</Application> and
postgres servers run with the user-id of the <ProductName>Postgres</ProductName>
"superuser." Note that the <ProductName>Postgres</ProductName> superuser does not
have to be a special user (e.g., a user named
"postgres"). Furthermore, the <ProductName>Postgres</ProductName> superuser
should
definitely not be the UNIX superuser ("root")! In any
case, all files relating to a database should belong to
this <ProductName>Postgres</ProductName> superuser.
</Para>
</Chapter>
<Chapter>
<Title>Arrays</Title>
<Para>
<Note>
<Para>
This must become a chapter on array behavior. Volunteers? - thomas 1998-01-12
</Para>
</Note>
</Para>
<Para>
<ProductName>Postgres</ProductName> allows attributes of an instance to be defined
as fixed-length or variable-length multi-dimensional
arrays. Arrays of any base type or user-defined type
can be created. To illustrate their use, we first create a
class with arrays of base types.
<ProgramListing>
CREATE TABLE SAL_EMP (
name text,
pay_by_quarter int4[],
schedule char16[][]
);
</ProgramListing>
</Para>
<Para>
The above query will create a class named SAL_EMP with
a <FirstTerm>text</FirstTerm> string (name), a one-dimensional array of <FirstTerm>int4</FirstTerm>
(pay_by_quarter), which represents the employee's
salary by quarter and a two-dimensional array of <FirstTerm>char16</FirstTerm>
(schedule), which represents the employee's weekly
schedule. Now we do some <FirstTerm>INSERTS</FirstTerm>s; note that when
appending to an array, we enclose the values within
braces and separate them by commas. If you know <FirstTerm>C</FirstTerm>,
this is not unlike the syntax for initializing structures.
<ProgramListing>
INSERT INTO SAL_EMP
VALUES ('Bill',
'{10000, 10000, 10000, 10000}',
'{{"meeting", "lunch"}, {}}');
INSERT INTO SAL_EMP
VALUES ('Carol',
'{20000, 25000, 25000, 25000}',
'{{"talk", "consult"}, {"meeting"}}');
</ProgramListing>
By default, <ProductName>Postgres</ProductName> uses the "one-based" numbering
convention for arrays -- that is, an array of n elements starts with array[1] and ends with array[n].
Now, we can run some queries on SAL_EMP. First, we
show how to access a single element of an array at a
time. This query retrieves the names of the employees
whose pay changed in the second quarter:
<ProgramListing>
SELECT name
FROM SAL_EMP
WHERE SAL_EMP.pay_by_quarter[1] &lt;&gt;
SAL_EMP.pay_by_quarter[2];
+------+
|name |
+------+
|Carol |
+------+
</ProgramListing>
</Para>
<Para>
This query retrieves the third quarter pay of all
employees:
<ProgramListing>
SELECT SAL_EMP.pay_by_quarter[3] FROM SAL_EMP;
+---------------+
|pay_by_quarter |
+---------------+
|10000 |
+---------------+
|25000 |
+---------------+
</ProgramListing>
</Para>
<Para>
We can also access arbitrary slices of an array, or
subarrays. This query retrieves the first item on
Bill's schedule for the first two days of the week.
<ProgramListing>
SELECT SAL_EMP.schedule[1:2][1:1]
FROM SAL_EMP
WHERE SAL_EMP.name = 'Bill';
+-------------------+
|schedule |
+-------------------+
|{{"meeting"},{""}} |
+-------------------+
</ProgramListing>
</Para>
</Chapter>
<BIBLIOGRAPHY>
<Title><Acronym>SQL</Acronym> References</Title>
<Para>
Selected references and readings for <Acronym>SQL</Acronym> and <ProductName>Postgres</ProductName>.
</Para>
<BIBLIODIV>
<TITLE><Acronym>SQL</Acronym> Reference Books</TITLE>
<PARA>Reference texts for <Acronym>SQL</Acronym> features.</PARA>
<BIBLIOENTRY ID="BOWMAN93">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="BOWMAN93">
-->
<TITLE>The Practical <Acronym>SQL</Acronym> Handbook</TITLE>
<SUBTITLE>Using Structured Query Language</SUBTITLE>
<EDITION>3</EDITION>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>Judity</FIRSTNAME>
<SURNAME>Bowman</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>Sandra</FIRSTNAME>
<SURNAME>Emerson</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>Marcy</FIRSTNAME>
<SURNAME>Damovsky</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<ISBN>0-201-44787-8</ISBN>
<PUBDATE>1996</PUBDATE>
<PUBLISHER>
<PUBLISHERNAME>Addison-Wesley</PUBLISHERNAME>
</PUBLISHER>
<COPYRIGHT>
<YEAR>1997</YEAR>
<HOLDER>Addison-Wesley Longman, Inc.</HOLDER>
</COPYRIGHT>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="DATE97">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="DATE97">
-->
<TITLE>A Guide to The <Acronym>SQL</Acronym> Standard</TITLE>
<TITLEABBREV>The <Acronym>SQL</Acronym> Standard</TITLEABBREV>
<SUBTITLE>A user's guide to the standard database language <Acronym>SQL</Acronym></SUBTITLE>
<EDITION>4</EDITION>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>C. J.</FIRSTNAME>
<SURNAME>Date</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>Hugh</FIRSTNAME>
<SURNAME>Darwen</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<ISBN>0-201-96426-0</ISBN>
<PUBDATE>1997</PUBDATE>
<PUBLISHER>
<PUBLISHERNAME>Addison-Wesley</PUBLISHERNAME>
</PUBLISHER>
<COPYRIGHT>
<YEAR>1997</YEAR>
<HOLDER>Addison-Wesley Longman, Inc.</HOLDER>
</COPYRIGHT>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="MELT93">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="MELT93">
-->
<TITLE>Understanding the New <Acronym>SQL</Acronym></TITLE>
<SUBTITLE>A complete guide</SUBTITLE>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>Jim</FIRSTNAME>
<SURNAME>Melton</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>Alan R.</FIRSTNAME>
<SURNAME>Simon</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<ISBN>1-55860-245-3</ISBN>
<PUBDATE>1993</PUBDATE>
<PUBLISHER>
<PUBLISHERNAME>Morgan Kaufmann</PUBLISHERNAME>
</PUBLISHER>
<COPYRIGHT>
<YEAR>1993</YEAR>
<HOLDER>Morgan Kaufmann Publishers, Inc.</HOLDER>
</COPYRIGHT>
<ABSTRACT>
<TITLE>Abstract</TITLE>
<PARA>Accessible reference for <Acronym>SQL</Acronym> features.</PARA>
</ABSTRACT>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
</BIBLIODIV>
<BIBLIODIV>
<TITLE>PostgreSQL-Specific Documentation</TITLE>
<PARA>This section is for related documentation.</PARA>
<BIBLIOENTRY ID="ADMIN-GUIDE">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="ADMIN-GUIDE">
-->
<TITLE>The <ProductName>PostgreSQL</ProductName> Administrator's Guide</TITLE>
<Editor>
<FIRSTNAME>Thomas</FIRSTNAME>
<SURNAME>Lockhart</SURNAME>
</Editor>
<PUBDATE>1998-03-01</PUBDATE>
<PUBLISHER>
<PUBLISHERNAME>The PostgreSQL Global Development Group</PUBLISHERNAME>
</PUBLISHER>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="PROGRAMMERS-GUIDE">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="PROGRAMMERS-GUIDE">
-->
<TITLE>The <ProductName>PostgreSQL</ProductName> Programmer's Guide</TITLE>
<Editor>
<FIRSTNAME>Thomas</FIRSTNAME>
<SURNAME>Lockhart</SURNAME>
</Editor>
<PUBDATE>1998-03-01</PUBDATE>
<PUBLISHER>
<PUBLISHERNAME>The PostgreSQL Global Development Group</PUBLISHERNAME>
</PUBLISHER>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="TUTORIAL">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="REFERENCE">
-->
<TITLE>The <ProductName>PostgreSQL</ProductName> Reference Manual</TITLE>
<Editor>
<FIRSTNAME>Thomas</FIRSTNAME>
<SURNAME>Lockhart</SURNAME>
</Editor>
<PUBDATE>1998-03-01</PUBDATE>
<PUBLISHER>
<PUBLISHERNAME>The PostgreSQL Global Development Group</PUBLISHERNAME>
</PUBLISHER>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="USERS-GUIDE">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="TUTORIAL">
-->
<TITLE>The <ProductName>PostgreSQL</ProductName> Tutorial Introduction</TITLE>
<Editor>
<FIRSTNAME>Thomas</FIRSTNAME>
<SURNAME>Lockhart</SURNAME>
</Editor>
<PUBDATE>1998-03-01</PUBDATE>
<PUBLISHER>
<PUBLISHERNAME>The PostgreSQL Global Development Group</PUBLISHERNAME>
</PUBLISHER>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="REFERENCE">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="USERS-GUIDE">
-->
<TITLE>The <ProductName>PostgreSQL</ProductName> User's Guide</TITLE>
<Editor>
<FIRSTNAME>Thomas</FIRSTNAME>
<SURNAME>Lockhart</SURNAME>
</Editor>
<PUBDATE>1998-03-01</PUBDATE>
<PUBLISHER>
<PUBLISHERNAME>The PostgreSQL Global Development Group</PUBLISHERNAME>
</PUBLISHER>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="YU95">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="YU95">
-->
<TITLE>The <ProductName>Postgres95</ProductName> User Manual</TITLE>
<TITLEABBREV>YU95</TITLEABBREV>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>A.</FIRSTNAME>
<SURNAME>Yu</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>J.</FIRSTNAME>
<SURNAME>Chen</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<AUTHORGROUP>
<COLLAB>
<COLLABNAME>
The POSTGRES Group
</COLLABNAME>
</COLLAB>
</AUTHORGROUP>
<PUBDATE>Sept. 5, 1995</PUBDATE>
<PUBLISHER>
<PUBLISHERNAME>University of California, Berkeley CA</PUBLISHERNAME>
</PUBLISHER>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
</BIBLIODIV>
<BIBLIODIV>
<TITLE>Proceedings and Articles</TITLE>
<PARA>This section is for articles and newsletters.</PARA>
<BIBLIOENTRY ID="ONG90">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="ONG90">
-->
<TITLE>A Unified Framework for Version Modeling Using Production Rules in a Database System</TITLE>
<TITLEABBREV>ONG90</TITLEABBREV>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>L.</FIRSTNAME>
<SURNAME>Ong</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>J.</FIRSTNAME>
<SURNAME>Goh</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<PUBDATE>April, 1990</PUBDATE>
<ISSN>ERL Technical Memorandum M90/33</ISSN>
<PUBLISHER>
<PUBLISHERNAME>University of California, Berkeley CA</PUBLISHERNAME>
</PUBLISHER>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="ROWE87">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="ROWE87">
-->
<TITLE>The <ProductName>Postgres</ProductName> Data Model</TITLE>
<TITLEABBREV>ROWE87</TITLEABBREV>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>L.</FIRSTNAME>
<SURNAME>Rowe</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>M.</FIRSTNAME>
<SURNAME>Stonebraker</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<CONFGROUP>
<CONFDATES>Sept. 1987</CONFDATES>
<CONFTITLE>VLDB Conference, Brighton, England</CONFTITLE>
<CONFNUM>1987</CONFNUM>
</CONFGROUP>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="STON86">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="STON86">
-->
<TITLE>The Design of <ProductName>Postgres</ProductName></TITLE>
<TITLEABBREV>STON86</TITLEABBREV>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>M.</FIRSTNAME>
<SURNAME>Stonebraker</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>L.</FIRSTNAME>
<SURNAME>Rowe</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<CONFGROUP>
<CONFDATES>May 1986</CONFDATES>
<CONFTITLE>Conference on Management of Data, Washington DC</CONFTITLE>
<CONFSPONSOR>ACM-SIGMOD</CONFSPONSOR>
<CONFNUM>1986</CONFNUM>
</CONFGROUP>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="STON87a">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="STON87a">
-->
<TITLE>The Design of the <ProductName>Postgres</ProductName> Rules System</TITLE>
<TITLEABBREV>STON87a</TITLEABBREV>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>M.</FIRSTNAME>
<SURNAME>Stonebraker</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>E.</FIRSTNAME>
<SURNAME>Hanson</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>C. H.</FIRSTNAME>
<SURNAME>Hong</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<CONFGROUP>
<CONFDATES>Feb. 1987</CONFDATES>
<CONFTITLE>Conference on Data Engineering, Los Angeles, CA</CONFTITLE>
<CONFSPONSOR>IEEE</CONFSPONSOR>
<CONFNUM>1987</CONFNUM>
</CONFGROUP>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="STON87b">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="STON87b">
-->
<TITLE>The <ProductName>Postgres</ProductName> Storage System</TITLE>
<TITLEABBREV>STON87b</TITLEABBREV>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>M.</FIRSTNAME>
<SURNAME>Stonebraker</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<CONFGROUP>
<CONFDATES>Sept. 1987</CONFDATES>
<CONFTITLE>VLDB Conference, Brighton, England</CONFTITLE>
<CONFNUM>1987</CONFNUM>
</CONFGROUP>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="STON89">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="STON89">
-->
<TITLE>A Commentary on the <ProductName>Postgres</ProductName> Rules System</TITLE>
<TITLEABBREV>STON89</TITLEABBREV>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>M.</FIRSTNAME>
<SURNAME>Stonebraker</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>M.</FIRSTNAME>
<SURNAME>Hearst</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>S.</FIRSTNAME>
<SURNAME>Potamianos</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<CONFGROUP>
<CONFDATES>Sept. 1989</CONFDATES>
<CONFTITLE>Record 18(3)</CONFTITLE>
<CONFSPONSOR>SIGMOD</CONFSPONSOR>
<CONFNUM>1987</CONFNUM>
</CONFGROUP>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="STON90a">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="STON90a">
-->
<TITLE>The Implementation of <ProductName>Postgres</ProductName></TITLE>
<TITLEABBREV>STON90a</TITLEABBREV>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>M.</FIRSTNAME>
<SURNAME>Stonebraker</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>L. A.</FIRSTNAME>
<SURNAME>Rowe</SURNAME>
</AUTHOR>
<AUTHOR>
<FIRSTNAME>M.</FIRSTNAME>
<SURNAME>Hirohama</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<CONFGROUP>
<CONFDATES>March 1990</CONFDATES>
<CONFTITLE>Transactions on Knowledge and Data Engineering 2(1)</CONFTITLE>
<CONFSPONSOR>IEEE</CONFSPONSOR>
</CONFGROUP>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
<BIBLIOENTRY ID="STON90b">
<!--
<BIBLIOMISC>&dash;</BIBLIOMISC>
<BOOKBIBLIO ID="STON90b">
-->
<TITLE>On Rules, Procedures, Caching and Views in Database Systems</TITLE>
<TITLEABBREV>STON90b</TITLEABBREV>
<AUTHORGROUP>
<AUTHOR>
<FIRSTNAME>M.</FIRSTNAME>
<SURNAME>Stonebraker</SURNAME>
</AUTHOR>
<AUTHOR>
<SURNAME>et. al.</SURNAME>
</AUTHOR>
</AUTHORGROUP>
<CONFGROUP>
<CONFDATES>June 1990</CONFDATES>
<CONFTITLE>Conference on Management of Data</CONFTITLE>
<CONFSPONSOR>ACM-SIGMOD</CONFSPONSOR>
</CONFGROUP>
<!--
</BOOKBIBLIO>
-->
</BIBLIOENTRY>
</BIBLIODIV>
</BIBLIOGRAPHY>
<Chapter>
<DocInfo>
<AuthorGroup>
<Author>
<FirstName>Brian</FirstName>
<Surname>Gallew</Surname>
</Author>
</AuthorGroup>
<Date>Transcribed 1998-02-12</Date>
</DocInfo>
<Title>GCC Default Optimizations</Title>
<Para>
<Note>
<Para>
Contributed by <ULink url="mailto:geek+@cmu.edu">Brian Gallew</ULink>
</Para>
</Note>
<Para>
Configuring gcc to use certain flags by default is a simple matter of
editing the
<FileName>/usr/local/lib/gcc-lib/<Replaceable>platform</Replaceable>/<Replaceable>version</Replaceable>/specs</FileName>
file.
The format of this file pretty simple. The file is broken into
sections, each of which is three lines long. The first line is
"*<Replaceable>section_name</Replaceable>:" (e.g. "*asm:").
The second line is a list of flags,
and the third line is blank.
<Para>
The easiest change to make is to append
the desired default flags to the list in the appropriate section. As
an example, let's suppose that I have linux running on a '486 with gcc
2.7.2 installed in the default location. In the file
/usr/local/lib/gcc-lib/i486-linux/2.7.2/specs, 13 lines down I find
the following section:
<ProgramListing>
- ----------SECTION----------
*cc1:
- ----------SECTION----------
</ProgramListing>
As you can see, there aren't any default flags. If I always wanted
compiles of C code to use "-m486 -fomit-frame-pointer", I would
change it to look like:
<ProgramListing>
- ----------SECTION----------
*cc1:
- -m486 -fomit-frame-pointer
- ----------SECTION----------
</ProgramListing>
If I wanted to be able to generate 386 code for another, older linux
box lying around, I'd have to make it look like this:
<ProgramListing>
- ----------SECTION----------
*cc1:
%{!m386:-m486} -fomit-frame-pointer
- ----------SECTION----------
</ProgramListing>
This will always omit frame pointers, any will build 486-optimized
code unless -m386 is specified on the command line.
<Para>
You can actually do quite a lot of customization with the specs file.
Always remember, however, that these changes are global, and affect
all users of the system.
</Chapter>
<Appendix label="B">
<Title>Contacts</Title>
<Sect1>
<Title>Introduction</Title>
<Para>
</Para>
<Sect1>
<Title>People</Title>
<Para>
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
<ULink url="http://alumni.caltech.edu/~lockhart">Thomas Lockhart</ULink>
works on SQL standards compliance and documentation.
</Para>
</ListItem>
</ItemizedList>
</Para>
</Appendix>
<Chapter>
<Title>Data Types</Title>
<Abstract>
<Para>
Describes the built-in data types available in <ProductName>Postgres</ProductName>.
</Para>
</Abstract>
<Para>
<ProductName>Postgres</ProductName> has a rich set of native data types available to users.
Users may add new types to <ProductName>Postgres</ProductName> using the
<Command>define type</Command>
command described elsewhere.
<Para>
In the context of data types, the following sections will discuss SQL standards
compliance, porting issues, and usage.
Some <ProductName>Postgres</ProductName> types correspond directly to SQL92-compatible types. In other
cases, data types defined by SQL92 syntax are mapped directly
into native <ProductName>Postgres</ProductName> types.
Many of the built-in types have obvious external formats. However, several
types are either unique to <ProductName>Postgres</ProductName>, such as open and closed paths, or have
several possibilities for formats, such as date and time types.
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Data Types</TITLE>
<TITLEABBREV>Data Types</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY><ProductName>Postgres</ProductName> Type</ENTRY>
<ENTRY><Acronym>SQL92</Acronym> or <Acronym>SQL3</Acronym> Type</ENTRY>
<ENTRY>Description</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>bool</ENTRY>
<ENTRY>boolean</ENTRY>
<ENTRY>logical boolean (true/false)</ENTRY>
</ROW>
<ROW>
<ENTRY>box</ENTRY>
<ENTRY></ENTRY>
<ENTRY>rectangular box in 2D plane</ENTRY>
</ROW>
<ROW>
<ENTRY>char(n)</ENTRY>
<ENTRY>character(n)</ENTRY>
<ENTRY>fixed-length character string</ENTRY>
</ROW>
<ROW>
<ENTRY>circle</ENTRY>
<ENTRY></ENTRY>
<ENTRY>circle in 2D plane</ENTRY>
</ROW>
<ROW>
<ENTRY>date</ENTRY>
<ENTRY>date</ENTRY>
<ENTRY>calendar date without time of day</ENTRY>
</ROW>
<ROW>
<ENTRY>float4/8</ENTRY>
<ENTRY>float(p)</ENTRY>
<ENTRY>floating-point number with precision p</ENTRY>
</ROW>
<ROW>
<ENTRY>float8</ENTRY>
<ENTRY>real, double precision</ENTRY>
<ENTRY>double-precision floating-point number</ENTRY>
</ROW>
<ROW>
<ENTRY>int2</ENTRY>
<ENTRY>smallint</ENTRY>
<ENTRY>signed two-byte integer</ENTRY>
</ROW>
<ROW>
<ENTRY>int4</ENTRY>
<ENTRY>int, integer</ENTRY>
<ENTRY>signed 4-byte integer</ENTRY>
</ROW>
<ROW>
<ENTRY>int4</ENTRY>
<ENTRY>decimal(p,s)</ENTRY>
<ENTRY>exact numeric for p <= 9, s = 0</ENTRY>
</ROW>
<ROW>
<ENTRY>int4</ENTRY>
<ENTRY>numeric(p,s)</ENTRY>
<ENTRY>exact numeric for p == 9, s = 0</ENTRY>
</ROW>
<ROW>
<ENTRY>line</ENTRY>
<ENTRY></ENTRY>
<ENTRY>infinite line in 2D plane</ENTRY>
</ROW>
<ROW>
<ENTRY>lseg</ENTRY>
<ENTRY></ENTRY>
<ENTRY>line segment in 2D plane</ENTRY>
</ROW>
<ROW>
<ENTRY>money</ENTRY>
<ENTRY>decimal(9,2)</ENTRY>
<ENTRY>US-style currency</ENTRY>
</ROW>
<ROW>
<ENTRY>path</ENTRY>
<ENTRY></ENTRY>
<ENTRY>open and closed geometric path in 2D plane</ENTRY>
</ROW>
<ROW>
<ENTRY>point</ENTRY>
<ENTRY></ENTRY>
<ENTRY>geometric point in 2D plane</ENTRY>
</ROW>
<ROW>
<ENTRY>polygon</ENTRY>
<ENTRY></ENTRY>
<ENTRY>closed geometric path in 2D plane</ENTRY>
</ROW>
<ROW>
<ENTRY>time</ENTRY>
<ENTRY>time</ENTRY>
<ENTRY>time of day</ENTRY>
</ROW>
<ROW>
<ENTRY>timespan</ENTRY>
<ENTRY>interval</ENTRY>
<ENTRY>general-use time span</ENTRY>
</ROW>
<ROW>
<ENTRY>timestamp</ENTRY>
<ENTRY>timestamp with time zone</ENTRY>
<ENTRY>date/time</ENTRY>
</ROW>
<ROW>
<ENTRY>varchar(n)</ENTRY>
<ENTRY>character varying(n)</ENTRY>
<ENTRY>variable-length character string</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Function Constants</TITLE>
<TITLEABBREV>Constants</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY><ProductName>Postgres</ProductName> Function</ENTRY>
<ENTRY><Acronym>SQL92</Acronym> Constant</ENTRY>
<ENTRY>Description</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>getpgusername()</ENTRY>
<ENTRY>current_user</ENTRY>
<ENTRY>user name in current session</ENTRY>
</ROW>
<ROW>
<ENTRY>date('now')</ENTRY>
<ENTRY>current_date</ENTRY>
<ENTRY>date of current transaction</ENTRY>
</ROW>
<ROW>
<ENTRY>time('now')</ENTRY>
<ENTRY>current_time</ENTRY>
<ENTRY>time of current transaction</ENTRY>
</ROW>
<ROW>
<ENTRY>timestamp('now')</ENTRY>
<ENTRY>current_timestamp</ENTRY>
<ENTRY>date and time of current transaction</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
<ProductName>Postgres</ProductName> has features at the forefront of ORDBMS development. In addition to
SQL3 conformance, substantial portions of SQL92 are also supported.
Although we strive for SQL92 compliance, there are some cases in the standard
which are ill considered and which should not live through subsequent standards.
<ProductName>Postgres</ProductName> will not make great efforts to conform to these cases. However, these
cases tend to be little-used and obsure, and a typical user is not likely to
run into them.
<Para>
Although most of the input and output functions corresponding to the
base types (e.g., integers and floating point numbers) do some
error-checking, some are not particularly rigorous about it. More
importantly, few of the operators and functions (e.g.,
addition and multiplication) perform any error-checking at all.
Consequently, many of the numeric operators can (for example)
silently underflow or overflow.
</Para>
<Para>
Some of the input and output functions are not invertible. That is,
the result of an output function may lose precision when compared to
the original input.
</Para>
<Sect1>
<Title>Numeric Types</Title>
<Para>
Numeric types consist of two- and four-byte integers and four- and eight-byte
floating point numbers.
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Numeric Types</TITLE>
<TITLEABBREV>Numerics</TITLEABBREV>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY>Numeric Type</ENTRY>
<ENTRY>Storage</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Range</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>int2</ENTRY>
<ENTRY>2 bytes</ENTRY>
<ENTRY>Fixed-precision</ENTRY>
<ENTRY>-32768 to +32767</ENTRY>
</ROW>
<ROW>
<ENTRY>int4</ENTRY>
<ENTRY>4 bytes</ENTRY>
<ENTRY>Usual choice for fixed-precision</ENTRY>
<ENTRY>-2147483648 to +2147483647</ENTRY>
</ROW>
<ROW>
<ENTRY>float4</ENTRY>
<ENTRY>4 bytes</ENTRY>
<ENTRY>Variable-precision</ENTRY>
<ENTRY>7 decimal places</ENTRY>
</ROW>
<ROW>
<ENTRY>float8</ENTRY>
<ENTRY>8 bytes</ENTRY>
<ENTRY>Variable-precision</ENTRY>
<ENTRY>14 decimal places</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
The <FirstTerm>exact numerics</FirstTerm> <Type>decimal</Type> and <Type>numeric</Type>
have fully implemented syntax but currently (<ProductName>Postgres</ProductName> v6.3)
support only a small range of precision and/or range values.
</Para>
</Sect1>
<Sect1>
<Title>Monetary Type</Title>
<Para>
The <Type>money</Type> type supports US-style currency with fixed decimal point representation.
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Numeric Types</TITLE>
<TITLEABBREV>Numerics</TITLEABBREV>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY>Monetary Type</ENTRY>
<ENTRY>Storage</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Range</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>money</ENTRY>
<ENTRY>4 bytes</ENTRY>
<ENTRY>Fixed-precision</ENTRY>
<ENTRY>-21474836.48 to +21474836.47</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
The <FirstTerm>exact numerics</FirstTerm> <Type>decimal</Type> and <Type>numeric</Type>
have fully implemented syntax but currently (<ProductName>Postgres</ProductName> v6.3)
support only a small range of precision and/or range values.
</Para>
</Sect1>
<Sect1>
<Title>Character Types</Title>
<Para>
<Acronym>SQL92</Acronym> defines two primary character types: <Type>char</Type> and
<Type>varchar</Type>. <ProductName>Postgres</ProductName> supports these types, in
addition to the more general <Type>text</Type> type, which unlike <Type>varchar</Type>
does not require an upper
limit to be declared on the size of the field.
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Character Types</TITLE>
<TITLEABBREV>Characters</TITLEABBREV>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY>Character Type</ENTRY>
<ENTRY>Storage</ENTRY>
<ENTRY>Recommendation</ENTRY>
<ENTRY>Description</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>char</ENTRY>
<ENTRY>1 byte</ENTRY>
<ENTRY>SQL92-compatible</ENTRY>
<ENTRY>Single character</ENTRY>
</ROW>
<ROW>
<ENTRY>char(n)</ENTRY>
<ENTRY>(4+n) bytes</ENTRY>
<ENTRY>SQL92-compatible</ENTRY>
<ENTRY>Fixed-length blank padded</ENTRY>
</ROW>
<ROW>
<ENTRY>text</ENTRY>
<ENTRY>(4+x) bytes</ENTRY>
<ENTRY>Best choice</ENTRY>
<ENTRY>Variable-length</ENTRY>
</ROW>
<ROW>
<ENTRY>varchar(n)</ENTRY>
<ENTRY>(4+n) bytes</ENTRY>
<ENTRY>SQL92-compatible</ENTRY>
<ENTRY>Variable-length with limit</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
There are currently other fixed-length character types. These provide no additional
functionality and are likely to be deprecated in the future.
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Specialty Character Types</TITLE>
<TITLEABBREV>Specialty Characters</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Character Type</ENTRY>
<ENTRY>Storage</ENTRY>
<ENTRY>Description</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>char2</ENTRY>
<ENTRY>2 bytes</ENTRY>
<ENTRY>Two characters</ENTRY>
</ROW>
<ROW>
<ENTRY>char4</ENTRY>
<ENTRY>4 bytes</ENTRY>
<ENTRY>Four characters</ENTRY>
</ROW>
<ROW>
<ENTRY>char8</ENTRY>
<ENTRY>8 bytes</ENTRY>
<ENTRY>Eight characters</ENTRY>
</ROW>
<ROW>
<ENTRY>char16</ENTRY>
<ENTRY>16 bytes</ENTRY>
<ENTRY>Sixteen characters</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
</Sect1>
<Sect1>
<Title>Date/Time Types</Title>
<Para>
There are two fundamental kinds of date and time measurements: clock time and time interval.
Both quantities have continuity and smoothness, as does time itself.
<ProductName>Postgres</ProductName> supplies two primary user-oriented date and time types,
<Type>datetime</Type> and timespan, as well as the related SQL92 types date and time.
</Para>
<Para>
Other date and time types are available
also, mostly
for historical reasons.
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Date/Time Types</TITLE>
<TITLEABBREV>Date/Time</TITLEABBREV>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY>Date/Time Type</ENTRY>
<ENTRY>Storage</ENTRY>
<ENTRY>Recommendation</ENTRY>
<ENTRY>Description</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>abstime</ENTRY>
<ENTRY>4 bytes</ENTRY>
<ENTRY>original date and time</ENTRY>
<ENTRY>limited range</ENTRY>
</ROW>
<ROW>
<ENTRY>date</ENTRY>
<ENTRY>4 bytes</ENTRY>
<ENTRY>SQL92 type</ENTRY>
<ENTRY>wide range</ENTRY>
</ROW>
<ROW>
<ENTRY>datetime</ENTRY>
<ENTRY>8 bytes</ENTRY>
<ENTRY>best general date and time</ENTRY>
<ENTRY>wide range, high precision</ENTRY>
</ROW>
<ROW>
<ENTRY>interval</ENTRY>
<ENTRY>12 bytes</ENTRY>
<ENTRY>SQL92 type</ENTRY>
<ENTRY>equivalent to timespan</ENTRY>
</ROW>
<ROW>
<ENTRY>reltime</ENTRY>
<ENTRY>4 bytes</ENTRY>
<ENTRY>original time interval</ENTRY>
<ENTRY>limited range, low precision</ENTRY>
</ROW>
<ROW>
<ENTRY>time</ENTRY>
<ENTRY>4 bytes</ENTRY>
<ENTRY>SQL92 type</ENTRY>
<ENTRY>wide range</ENTRY>
</ROW>
<ROW>
<ENTRY>timespan</ENTRY>
<ENTRY>12 bytes</ENTRY>
<ENTRY>best general time interval</ENTRY>
<ENTRY>wide range, high precision</ENTRY>
</ROW>
<ROW>
<ENTRY>timestamp</ENTRY>
<ENTRY>4 bytes</ENTRY>
<ENTRY>SQL92 type</ENTRY>
<ENTRY>limited range</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Date/Time Ranges</TITLE>
<TITLEABBREV>Ranges</TITLEABBREV>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY>Date/Time Type</ENTRY>
<ENTRY>Earliest</ENTRY>
<ENTRY>Latest</ENTRY>
<ENTRY>Resolution</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>abstime</ENTRY>
<ENTRY>1901-12-14</ENTRY>
<ENTRY>2038-01-19</ENTRY>
<ENTRY>1 sec</ENTRY>
</ROW>
<ROW>
<ENTRY>date</ENTRY>
<ENTRY>4713 BC</ENTRY>
<ENTRY>no limit</ENTRY>
<ENTRY>1 day</ENTRY>
</ROW>
<ROW>
<ENTRY>datetime</ENTRY>
<ENTRY>4713 BC</ENTRY>
<ENTRY>no limit</ENTRY>
<ENTRY>1 microsec to 14 digits</ENTRY>
</ROW>
<ROW>
<ENTRY>interval</ENTRY>
<ENTRY>no limit</ENTRY>
<ENTRY>no limit</ENTRY>
<ENTRY>1 microsec</ENTRY>
</ROW>
<ROW>
<ENTRY>reltime</ENTRY>
<ENTRY>-68 years</ENTRY>
<ENTRY>+68 years</ENTRY>
<ENTRY>1 sec</ENTRY>
</ROW>
<ROW>
<ENTRY>time</ENTRY>
<ENTRY>00:00:00.00</ENTRY>
<ENTRY>23:59:59.99</ENTRY>
<ENTRY>1 microsec</ENTRY>
</ROW>
<ROW>
<ENTRY>timespan</ENTRY>
<ENTRY>no limit</ENTRY>
<ENTRY>no limit</ENTRY>
<ENTRY>1 microsec (14 digits)</ENTRY>
</ROW>
<ROW>
<ENTRY>timestamp</ENTRY>
<ENTRY>1901-12-14</ENTRY>
<ENTRY>2038-01-19</ENTRY>
<ENTRY>1 sec</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
<ProductName>Postgres</ProductName> endevours to be compatible with
<Acronym>SQL92</Acronym> definitions for typical usage.
The <Acronym>SQL92</Acronym> standard has an odd mix of date and
time types and capabilities. For example, although the date type does not have an associated time zone, the
time type can. The default time zone is specified as a constant offset from GMT/UTC;
however, time zones in the real world can have no meaning unless associated with a
date as well
as a time since the offset will vary through the year.
<Para>
To obviate these difficulties, <ProductName>Postgres</ProductName> associates time zones
only with date and time
types which contain both date and time, and assumes local time for any type containing only
date or time. Further, time zone support is derived from the underlying operating system
time zone capabilities, and hence can handle daylight savings time and other expected behavior.
<Para>
In future releases, the number of date/time types will decrease, with the current
implementation of <Type>datetime</Type> becoming <Type>timestamp</Type>, timespan becoming interval,
and (possibly) abstime
and reltime being deprecated in favor of <Type>timestamp</Type> and interval.
The more arcane features
of the date/time definitions from the <Acronym>SQL92</Acronym> standard are not likely to be pursued.
</Para>
<Sect2>
<Title>Date/Time Styles</Title>
<Para>
Output formats can be set to one of four styles:
ISO-8601, SQL (Ingres), traditional
Postgres, and German.
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Date Styles</TITLE>
<TITLEABBREV>Styles</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Style Specification</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Example</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>ISO</ENTRY>
<ENTRY>ISO-8601 standard</ENTRY>
<ENTRY>1997-12-17 07:37:16-08</ENTRY>
</ROW>
<ROW>
<ENTRY>SQL</ENTRY>
<ENTRY>Traditional style</ENTRY>
<ENTRY>12/17/1997 07:37:16.00 PST</ENTRY>
</ROW>
<ROW>
<ENTRY>Postgres</ENTRY>
<ENTRY>Original style</ENTRY>
<ENTRY>Wed Dec 17 07:37:16 1997 PST</ENTRY>
</ROW>
<ROW>
<ENTRY>German</ENTRY>
<ENTRY>Regional style</ENTRY>
<ENTRY>17.12.1997 07:37:16.00 PST</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
The SQL style has European and non-European (US) variants, which determines whether
month follows day or vica versa.
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Date Order Conventions</TITLE>
<TITLEABBREV>Order</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Style Specification</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Example</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>European</ENTRY>
<ENTRY>Regional convention</ENTRY>
<ENTRY>17/12/1997 15:37:16.00 MET</ENTRY>
</ROW>
<ROW>
<ENTRY>NonEuropean</ENTRY>
<ENTRY>Regional convention</ENTRY>
<ENTRY>12/17/1997 07:37:16.00 PST</ENTRY>
</ROW>
<ROW>
<ENTRY>US</ENTRY>
<ENTRY>Regional convention</ENTRY>
<ENTRY>12/17/1997 07:37:16.00 PST</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
There are several ways to affect the appearance of date/time types:
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
The PGDATESTYLE environment variable used by the backend directly on postmaster startup.
</Para>
</ListItem>
<ListItem>
<Para>
The PGDATESTYLE environment variable used by the frontend libpq on session startup.
</Para>
</ListItem>
<ListItem>
<Para>
SET DateStyle <Acronym>SQL</Acronym> command.
</Para>
</ListItem>
</ItemizedList>
<Para>
For <ProductName>Postgres</ProductName> v6.3 (and earlier) the default date/time style is
"traditional Postgres". In future releases, the default may become ISO-8601, which alleviates
date specification ambiguities and Y2K collation problems.
</Para>
</Sect2>
<Sect2>
<Title>Time Zones</Title>
<Para>
<ProductName>Postgres</ProductName> obtains time zone support from the underlying operating system.
All dates and times are stored internally in Universal Coordinated Time (UTC), alternately known as
Greenwich Mean Time (GMT). Times are converted to local time on the database server before being
sent to the client frontend, hence by default are in the server time zone.
<Para>
There are several ways to affect the time zone behavior:
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
The TZ environment variable used by the backend directly
on postmaster startup as the default time zone.
</Para>
</ListItem>
<ListItem>
<Para>
The PGTZ environment variable set at the client used by libpq to send time zone information to the backend upon connection.
</Para>
</ListItem>
<ListItem>
<Para>
<Command>set timezone</Command> <Acronym>SQL</Acronym> sets the time zone for the session.
</Para>
</ListItem>
</ItemizedList>
<Para>
If an invalid time zone is specified,
the time zone becomes GMT (on most systems anyway).
</Para>
</Sect2>
<Sect2>
<Title>Date/Time Input</Title>
<Para>
General-use date and time is input using a wide range of
styles, including ISO-compatible, SQL-compatible, traditional
<ProductName>Postgres</ProductName>
and other permutations of date and time. In cases where interpretation
can be ambiguous (quite possible with many traditional styles of date specification)
<ProductName>Postgres</ProductName> uses a style setting to resolve the ambiguity.
</Para>
<Para>
Most date and time types share code for data input. For those types
the input can have any of a wide variety of styles. For numeric date representations,
European and US conventions can differ, and the proper interpretation is obtained
by using the
<Command>set datestyle</Command>
command before entering data.
Note that the style setting does not preclude use of various styles for input; it is
used primarily to determine the output style and to resolve ambiguities.
</Para>
<Para>
The special values `current',
`infinity' and `-infinity' are provided.
`infinity' specifies a time later than any other valid time, and
`-infinity' specifies a time earlier than any other valid time.
`current' indicates that the current time should be
substituted whenever this value appears in a computation.
The strings
`now',
`today',
`yesterday',
`tomorrow',
and `epoch' can be used to specify
time values. `now' means the current transaction time, and differs from
`current' in that the current time is immediately substituted
for it. `epoch' means Jan 1 00:00:00 1970 GMT.
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Date/Time Special Constants</TITLE>
<TITLEABBREV>Constants</TITLEABBREV>
<TGROUP COLS="2">
<THEAD>
<ROW>
<ENTRY>Constant</ENTRY>
<ENTRY>Description</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>current</ENTRY>
<ENTRY>Current transaction time, deferred</ENTRY>
</ROW>
<ROW>
<ENTRY>epoch</ENTRY>
<ENTRY>1970-01-01 00:00:00+00 (Unix system time zero)</ENTRY>
</ROW>
<ROW>
<ENTRY>infinity</ENTRY>
<ENTRY>Later than other valid times</ENTRY>
</ROW>
<ROW>
<ENTRY>-infinity</ENTRY>
<ENTRY>Earlier than other valid times</ENTRY>
</ROW>
<ROW>
<ENTRY>invalid</ENTRY>
<ENTRY>Illegal entry</ENTRY>
</ROW>
<ROW>
<ENTRY>now</ENTRY>
<ENTRY>Current transaction time</ENTRY>
</ROW>
<ROW>
<ENTRY>today</ENTRY>
<ENTRY>Midnight today</ENTRY>
</ROW>
<ROW>
<ENTRY>tomorrow</ENTRY>
<ENTRY>Midnight tomorrow</ENTRY>
</ROW>
<ROW>
<ENTRY>yesterday</ENTRY>
<ENTRY>Midnight yesterday</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
</Sect2>
<Sect2>
<Title>datetime</Title>
<Para>
General-use date and time is input using a wide range of
styles, including ISO-compatible, SQL-compatible, traditional
<ProductName>Postgres</ProductName> (see section on "absolute time")
and other permutations of date and time. Output styles can be ISO-compatible,
SQL-compatible, or traditional <ProductName>Postgres</ProductName>, with the default set to be compatible
with <ProductName>Postgres</ProductName> v6.0.
</Para>
<Para>
<Type>datetime</Type> is specified using the following syntax:
<ProgramListing>
Year-Month-Day [ Hour : Minute : Second ] [AD,BC] [ Timezone ]
YearMonthDay [ Hour : Minute : Second ] [AD,BC] [ Timezone ]
Month Day [ Hour : Minute : Second ] Year [AD,BC] [ Timezone ]
where
Year is 4013 BC, ..., very large
Month is Jan, Feb, ..., Dec or 1, 2, ..., 12
Day is 1, 2, ..., 31
Hour is 00, 02, ..., 23
Minute is 00, 01, ..., 59
Second is 00, 01, ..., 59 (60 for leap second)
Timezone is 3 characters or ISO offset to GMT
</ProgramListing>
<Para>
Valid dates are from Nov 13 00:00:00 4013 BC GMT to far into the future.
Timezones are either three characters (e.g. "GMT" or "PST") or ISO-compatible
offsets to GMT (e.g. "-08" or "-08:00" when in Pacific Standard Time).
Dates are stored internally in Greenwich Mean Time. Input and output routines
translate time to the local time zone of the server.
</Para>
<Sect2>
<Title><Type>timespan</Type></Title>
<Para>
General-use time span is input using a wide range of
syntaxes, including ISO-compatible, SQL-compatible, traditional
<ProductName>Postgres</ProductName> (see section on "relative time")
and other permutations of time span. Output formats can be ISO-compatible,
SQL-compatible, or traditional <ProductName>Postgres</ProductName>, with the default set to be <ProductName>Postgres</ProductName>-compatible.
Months and years are a "qualitative" time interval, and are stored separately
from the other "quantitative" time intervals such as day or hour. For date arithmetic,
the qualitative time units are instantiated in the context of the relevant date or time.
<Para>
Time span is specified with the following syntax:
<ProgramListing>
Quantity Unit [Quantity Unit...] [Direction]
@ Quantity Unit [Direction]
where
Quantity is ..., `-1', `0', `1', `2', ...
Unit is `second', `minute', `hour', `day', `week', `month', `year',
'decade', 'century', millenium', or abbreviations or plurals of these units.
Direction is `ago'.
</ProgramListing>
</Para>
</Sect2>
<Sect2>
<Title>abstime</Title>
<Para>
Absolute time (abstime) is a limited-range (+/- 68 years) and limited-precision (1 sec)
date data type. <Type>datetime</Type> may be preferred, since it
covers a larger range with greater precision.
<Para>
Absolute time is specified using the following syntax:
<ProgramListing>
Month Day [ Hour : Minute : Second ] Year [ Timezone ]
where
Month is Jan, Feb, ..., Dec
Day is 1, 2, ..., 31
Hour is 01, 02, ..., 24
Minute is 00, 01, ..., 59
Second is 00, 01, ..., 59
Year is 1901, 1902, ..., 2038
</ProgramListing>
</Para>
<Para>
Valid dates are from Dec 13 20:45:53 1901 GMT to Jan 19 03:14:04
2038 GMT. As of Version 3.0, times are no longer read and written
using Greenwich Mean Time; the input and output routines default to
the local time zone.
All special values allowed for <Type>datetime</Type> are also allowed for "absolute time".
</Para>
</Sect2>
<Sect2>
<Title>reltime</Title>
<Para>
Relative time <Type>reltime</Type> is a limited-range (+/- 68 years)
and limited-precision (1 sec) time span data type.
<Type>timespan</Type> should be preferred, since it
covers a larger range with greater precision and, more importantly, can distinguish between
relative units (months and years) and quantitative units (days, hours, etc). Instead, reltime
must force months to be exactly 30 days, so time arithmetic does not always work as expected.
For example, adding one reltime year to abstime today does not produce today's date one year from
now, but rather a date 360 days from today.
</Para>
<Para>
<Type>reltime</Type> shares input and output routines with the other time span types.
The section on <Type>timespan</Type> covers this in more detail.
</Para>
</Sect2>
<Sect2>
<Title><Type>timestamp</Type></Title>
<Para>
This is currently a limited-range absolute time which closely resembles the
abstime
data type. It shares the general input parser with the other date/time types.
In future releases this type will absorb the capabilities of the <Type>datetime</Type> type
and will move toward SQL92 compliance.
</Para>
<Para>
<Type>timestamp</Type> is specified using the same syntax as for <Type>datetime</Type>.
</Para>
</Sect2>
<Sect2>
<Title><Type>interval</Type></Title>
<Para>
<Type>interval</Type> is an <Acronym>SQL92</Acronym> data type which is
currently mapped to the <Type>timespan</Type> <ProductName>Postgres</ProductName>
data type.
</Para>
</Sect2>
<Sect2>
<Title>tinterval</Title>
<Para>
Time ranges are specified as:
<ProgramListing>
[ 'abstime' 'abstime']
where
abstime is a time in the absolute time format.
</ProgramListing>
Special abstime values such as
`current', `infinity' and `-infinity' can be used.
</Para>
</Sect1>
<Sect1>
<Title>Boolean Type</Title>
<Para>
<ProductName>Postgres</ProductName> supports <Type>bool</Type> as
the <Acronym>SQL3</Acronym> boolean type.
<Type>bool</Type> can have one of only two states: 'true' or 'false'. A third state, 'unknown', is not
implemented and is not suggested in <Acronym>SQL3</Acronym>; <Acronym>NULL</Acronym> is an
effective substitute. <Type>bool</Type> can be used in any boolean expression, and boolean expressions
always evaluate to a result compatible with this type.
<Para>
<Type>bool</Type> uses 4 bytes of storage.
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Boolean Type</TITLE>
<TITLEABBREV>Booleans</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>State</ENTRY>
<ENTRY>Output</ENTRY>
<ENTRY>Input</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>True</ENTRY>
<ENTRY>'t'</ENTRY>
<ENTRY>TRUE, 't', 'true', 'y', 'yes', '1'</ENTRY>
</ROW>
<ROW>
<ENTRY>False</ENTRY>
<ENTRY>'f'</ENTRY>
<ENTRY>FALSE, 'f', 'false', 'n', 'no', '0'</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
</Sect1>
<Sect1>
<Title>Geometric Types</Title>
<Para>
Geometric types represent two-dimensional spatial objects. The most fundamental type,
the point, forms the basis for all of the other types.
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Geometric Types</TITLE>
<TITLEABBREV>Geometrics</TITLEABBREV>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY>Geometric Type</ENTRY>
<ENTRY>Storage</ENTRY>
<ENTRY>Representation</ENTRY>
<ENTRY>Description</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>point</ENTRY>
<ENTRY>16 bytes</ENTRY>
<ENTRY>(x,y)</ENTRY>
<ENTRY>Point in space</ENTRY>
</ROW>
<ROW>
<ENTRY>line</ENTRY>
<ENTRY>32 bytes</ENTRY>
<ENTRY>((x1,y1),(x2,y2))</ENTRY>
<ENTRY>Infinite line</ENTRY>
</ROW>
<ROW>
<ENTRY>lseg</ENTRY>
<ENTRY>32 bytes</ENTRY>
<ENTRY>((x1,y1),(x2,y2))</ENTRY>
<ENTRY>Finite line segment</ENTRY>
</ROW>
<ROW>
<ENTRY>box</ENTRY>
<ENTRY>32 bytes</ENTRY>
<ENTRY>((x1,y1),(x2,y2))</ENTRY>
<ENTRY>Rectangular box</ENTRY>
</ROW>
<ROW>
<ENTRY>path</ENTRY>
<ENTRY>4+32n bytes</ENTRY>
<ENTRY>((x1,y1),...)</ENTRY>
<ENTRY>Closed path (similar to polygon)</ENTRY>
</ROW>
<ROW>
<ENTRY>path</ENTRY>
<ENTRY>4+32n bytes</ENTRY>
<ENTRY>[(x1,y1),...]</ENTRY>
<ENTRY>Open path</ENTRY>
</ROW>
<ROW>
<ENTRY>polygon</ENTRY>
<ENTRY>4+32n bytes</ENTRY>
<ENTRY>((x1,y1),...)</ENTRY>
<ENTRY>Polygon (similar to closed path)</ENTRY>
</ROW>
<ROW>
<ENTRY>circle</ENTRY>
<ENTRY>24 bytes</ENTRY>
<ENTRY><(x,y),r></ENTRY>
<ENTRY>Circle (center and radius)</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
A rich set of functions and operators is available to perform various geometric
operations such as scaling, translation, rotation, and determining intersections.
</Para>
<Sect2>
<Title>Point</Title>
<Para>
Points are specified using the following syntax:
<ProgramListing>
( x , y )
x , y
where
x is the x-axis coordinate as a floating point number
y is the y-axis coordinate as a floating point number
</ProgramListing>
</Para>
</Sect2>
<Sect2>
<Title>Line Segment</Title>
<Para>
Line segments (lseg) are represented by pairs of points.
</Para>
<Para>
lseg is specified using the following syntax:
<ProgramListing>
( ( x1 , y1 ) , ( x2 , y2 ) )
( x1 , y1 ) , ( x2 , y2 )
x1 , y1 , x2 , y2
where
(x1,y1) and (x2,y2) are the endpoints of the segment
</ProgramListing>
</Para>
</Sect2>
<Sect2>
<Title>Box</Title>
<Para>
Boxes are represented by pairs of points which are opposite
corners of the box.
</Para>
<Para>
box is specified using the following syntax:
<ProgramListing>
( ( x1 , y1 ) , ( x2 , y2 ) )
( x1 , y1 ) , ( x2 , y2 )
x1 , y1 , x2 , y2
where
(x1,y1) and (x2,y2) are opposite corners
</ProgramListing>
Boxes are output using the first syntax.
The corners are reordered on input to store
the lower left corner first and the upper right corner last.
Other corners of the box can be entered, but the lower
left and upper right corners are determined from the input and stored.
</Para>
</Sect2>
<Sect2>
<Title>Path</Title>
<Para>
Paths are represented by connected sets of points. Paths can be "open", where
the first and last points in the set are not connected, and "closed",
where the first and last point are connected. Functions
<Function>popen(p)</Function>
and
<Function>pclose(p)</Function>
are supplied to force a path to be open or closed, and functions
<Function>isopen(p)</Function>
and
<Function>isclosed(p)</Function>
are supplied to select either type in a query.
</Para>
<Para>
path is specified using the following syntax:
<ProgramListing>
( ( x1 , y1 ) , ... , ( xn , yn ) )
[ ( x1 , y1 ) , ... , ( xn , yn ) ]
( x1 , y1 ) , ... , ( xn , yn )
( x1 , y1 , ... , xn , yn )
x1 , y1 , ... , xn , yn
where
(x1,y1),...,(xn,yn) are points 1 through n
a leading "[" indicates an open path
a leading "(" indicates a closed path
</ProgramListing>
Paths are output using the first syntax.
Note that <ProductName>Postgres</ProductName> versions prior to
v6.1 used a format for paths which had a single leading parenthesis, a "closed" flag,
an integer count of the number of points, then the list of points followed by a
closing parenthesis. The built-in function <Function>upgradepath</Function> is supplied to convert
paths dumped and reloaded from pre-v6.1 databases.
</Para>
</Sect2>
<Sect2>
<Title>Polygon</Title>
<Para>
Polygons are represented by sets of points. Polygons should probably be
considered
equivalent to closed paths, but are stored differently and have their own
set of support routines.
</Para>
<Para>
polygon is specified using the following syntax:
<ProgramListing>
( ( x1 , y1 ) , ... , ( xn , yn ) )
( x1 , y1 ) , ... , ( xn , yn )
( x1 , y1 , ... , xn , yn )
x1 , y1 , ... , xn , yn
where
(x1,y1),...,(xn,yn) are points 1 through n
</ProgramListing>
Polygons are output using the first syntax.
Note that <ProductName>Postgres</ProductName> versions prior to
v6.1 used a format for polygons which had a single leading parenthesis, the list
of x-axis coordinates, the list of y-axis coordinates, followed by a closing parenthesis.
The built-in function <Function>upgradepoly</Function> is supplied to convert
polygons dumped and reloaded from pre-v6.1 databases.
</Para>
</Sect2>
<Sect2>
<Title>Circle</Title>
<Para>
Circles are represented by a center point and a radius.
</Para>
<Para>
circle is specified using the following syntax:
<ProgramListing>
< ( x , y ) , r >
( ( x , y ) , r )
( x , y ) , r
x , y , r
where
(x,y) is the center of the circle
r is the radius of the circle
</ProgramListing>
Circles are output using the first syntax.
</Para>
</Sect2>
</Sect1>
<Chapter>
<Title>Operators</Title>
<Para>
<ProductName>Postgres</ProductName> provides a large number of built-in operators on system types.
These operators are declared in the system catalog
pg_operator. Every entry in pg_operator includes
the name of the procedure that implements the operator and the
class <Acronym>OIDs</Acronym> of the input and output types.
<Para>
To view all variations of the <Quote>||</Quote> string concatenation operator, try
<ProgramListing>
SELECT oprleft, oprright, oprresult, oprcode
FROM pg_operator WHERE oprname = '||';
oprleft|oprright|oprresult|oprcode
-------+--------+---------+-------
25| 25| 25|textcat
1042| 1042| 1042|textcat
1043| 1043| 1043|textcat
(3 rows)
</ProgramListing>
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Operators</TITLE>
<TITLEABBREV>Operators</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Operator</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Usage</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> &lt; </ENTRY>
<ENTRY>Less than?</ENTRY>
<ENTRY>1 &lt; 2</ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;= </ENTRY>
<ENTRY>Less than or equal to?</ENTRY>
<ENTRY>1 &lt;= 2</ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;&gt; </ENTRY>
<ENTRY>Not equal?</ENTRY>
<ENTRY>1 &lt;&gt; 2</ENTRY>
</ROW>
<ROW>
<ENTRY> = </ENTRY>
<ENTRY>Equal?</ENTRY>
<ENTRY>1 = 1</ENTRY>
</ROW>
<ROW>
<ENTRY> &gt; </ENTRY>
<ENTRY>Greater than?</ENTRY>
<ENTRY>2 &gt; 1</ENTRY>
</ROW>
<ROW>
<ENTRY> &gt;= </ENTRY>
<ENTRY>Greater than or equal to?</ENTRY>
<ENTRY>2 &gt;= 1</ENTRY>
</ROW>
<ROW>
<ENTRY> || </ENTRY>
<ENTRY>Concatenate strings</ENTRY>
<ENTRY>'Postgre' || 'SQL'</ENTRY>
</ROW>
<ROW>
<ENTRY> !!= </ENTRY>
<ENTRY>NOT IN</ENTRY>
<ENTRY>3 !!= i</ENTRY>
</ROW>
<ROW>
<ENTRY> ~~ </ENTRY>
<ENTRY>LIKE</ENTRY>
<ENTRY>'scrappy,marc,hermit' ~~ '%scrappy%'</ENTRY>
</ROW>
<ROW>
<ENTRY> !~~ </ENTRY>
<ENTRY>NOT LIKE</ENTRY>
<ENTRY>'bruce' !~~ '%al%'</ENTRY>
</ROW>
<ROW>
<ENTRY> ~ </ENTRY>
<ENTRY>Match (regex), case sensitive</ENTRY>
<ENTRY>'thomas' ~ '*.thomas*.'</ENTRY>
</ROW>
<ROW>
<ENTRY> ~* </ENTRY>
<ENTRY>Match (regex), case insensitive</ENTRY>
<ENTRY>'thomas' ~* '*.Thomas*.'</ENTRY>
</ROW>
<ROW>
<ENTRY> !~ </ENTRY>
<ENTRY>Does not match (regex), case sensitive</ENTRY>
<ENTRY>'thomas' !~ '*.Thomas*.'</ENTRY>
</ROW>
<ROW>
<ENTRY> !~* </ENTRY>
<ENTRY>Does not match (regex), case insensitive</ENTRY>
<ENTRY>'thomas' !~ '*.vadim*.'</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Numerical Operators</TITLE>
<TITLEABBREV>Operators</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Operator</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Usage</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> ! </ENTRY>
<ENTRY>Factorial</ENTRY>
<ENTRY>3 !</ENTRY>
</ROW>
<ROW>
<ENTRY> !! </ENTRY>
<ENTRY>Factorial (left operator)</ENTRY>
<ENTRY>!! 3</ENTRY>
</ROW>
<ROW>
<ENTRY> % </ENTRY>
<ENTRY>Modulo</ENTRY>
<ENTRY>5 % 4</ENTRY>
</ROW>
<ROW>
<ENTRY> % </ENTRY>
<ENTRY>Truncate</ENTRY>
<ENTRY>% 4.5</ENTRY>
</ROW>
<ROW>
<ENTRY> * </ENTRY>
<ENTRY>Multiplication</ENTRY>
<ENTRY>2 * 3</ENTRY>
</ROW>
<ROW>
<ENTRY> + </ENTRY>
<ENTRY>Addition</ENTRY>
<ENTRY>2 + 3</ENTRY>
</ROW>
<ROW>
<ENTRY> - </ENTRY>
<ENTRY>Subtraction</ENTRY>
<ENTRY>2 - 3</ENTRY>
</ROW>
<ROW>
<ENTRY> / </ENTRY>
<ENTRY>Division</ENTRY>
<ENTRY>4 / 2</ENTRY>
</ROW>
<ROW>
<ENTRY> : </ENTRY>
<ENTRY>Natural Exponentiation</ENTRY>
<ENTRY>: 3.0</ENTRY>
</ROW>
<ROW>
<ENTRY> ; </ENTRY>
<ENTRY>Natural Logarithm</ENTRY>
<ENTRY>(; 5.0)</ENTRY>
</ROW>
<ROW>
<ENTRY> @ </ENTRY>
<ENTRY>Absolute value</ENTRY>
<ENTRY>@ -5.0</ENTRY>
</ROW>
<ROW>
<ENTRY> ^ </ENTRY>
<ENTRY>Exponentiation</ENTRY>
<ENTRY>2.0 ^ 3.0</ENTRY>
</ROW>
<ROW>
<ENTRY> |/ </ENTRY>
<ENTRY>Square root</ENTRY>
<ENTRY>|/ 25.0</ENTRY>
</ROW>
<ROW>
<ENTRY> ||/ </ENTRY>
<ENTRY>Cube root</ENTRY>
<ENTRY>||/ 27.0</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Geometric Operators</TITLE>
<TITLEABBREV>Operators</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Operator</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Usage</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> + </ENTRY>
<ENTRY>Translation</ENTRY>
<ENTRY>'((0,0),(1,1))'::box + '(2.0,0)'::point</ENTRY>
</ROW>
<ROW>
<ENTRY> - </ENTRY>
<ENTRY>Translation</ENTRY>
<ENTRY>'((0,0),(1,1))'::box - '(2.0,0)'::point</ENTRY>
</ROW>
<ROW>
<ENTRY> * </ENTRY>
<ENTRY>Scaling/rotation</ENTRY>
<ENTRY>'((0,0),(1,1))'::box * '(2.0,0)'::point</ENTRY>
</ROW>
<ROW>
<ENTRY> / </ENTRY>
<ENTRY>Scaling/rotation</ENTRY>
<ENTRY>'((0,0),(2,2))'::box / '(2.0,0)'::point</ENTRY>
</ROW>
<ROW>
<ENTRY> # </ENTRY>
<ENTRY>Intersection</ENTRY>
<ENTRY>'((1,-1),(-1,1))' # '((1,1),(-1,-1))'</ENTRY>
</ROW>
<ROW>
<ENTRY> # </ENTRY>
<ENTRY>Number of points in polygon</ENTRY>
<ENTRY># '((1,0),(0,1),(-1,0))'</ENTRY>
</ROW>
<ROW>
<ENTRY> ## </ENTRY>
<ENTRY>Point of closest proximity</ENTRY>
<ENTRY>'(0,0)'::point ## '((2,0),(0,2))'::lseg</ENTRY>
</ROW>
<ROW>
<ENTRY> &amp;&amp; </ENTRY>
<ENTRY>Overlaps?</ENTRY>
<ENTRY>'((0,0),(1,1))'::box &amp;&amp; '((0,0),(2,2))'::box</ENTRY>
</ROW>
<ROW>
<ENTRY> &amp;&lt; </ENTRY>
<ENTRY>Overlaps to left?</ENTRY>
<ENTRY>'((0,0),(1,1))'::box &amp;&lt; '((0,0),(2,2))'::box</ENTRY>
</ROW>
<ROW>
<ENTRY> &amp;&gt; </ENTRY>
<ENTRY>Overlaps to right?</ENTRY>
<ENTRY>'((0,0),(3,3))'::box &amp;&gt; '((0,0),(2,2))'::box</ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;-&gt; </ENTRY>
<ENTRY>Distance between</ENTRY>
<ENTRY>'((0,0),1)'::circle &lt;-&gt; '((5,0),1)'::circle</ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;&lt; </ENTRY>
<ENTRY>Left of?</ENTRY>
<ENTRY>'((0,0),1)'::circle &lt;&lt; '((5,0),1)'::circle</ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;^ </ENTRY>
<ENTRY>Is below?</ENTRY>
<ENTRY>'((0,0),1)'::circle &lt;^ '((0,5),1)'::circle</ENTRY>
</ROW>
<ROW>
<ENTRY> &gt;&gt; </ENTRY>
<ENTRY>Is right of?</ENTRY>
<ENTRY>'((5,0),1)'::circle &gt;&gt; '((0,0),1)'::circle</ENTRY>
</ROW>
<ROW>
<ENTRY> &gt;^ </ENTRY>
<ENTRY>Is above?</ENTRY>
<ENTRY>'((0,5),1)'::circle >^ '((0,0),1)'::circle</ENTRY>
</ROW>
<ROW>
<ENTRY> ?# </ENTRY>
<ENTRY>Intersects or overlaps</ENTRY>
<ENTRY>'((-1,0),(1,0))'::lseg ?# '((-2,-2),(2,2))'::box;</ENTRY>
</ROW>
<ROW>
<ENTRY> ?- </ENTRY>
<ENTRY>Is horizontal?</ENTRY>
<ENTRY>'(1,0)'::point ?- '(0,0)'::point</ENTRY>
</ROW>
<ROW>
<ENTRY> ?-| </ENTRY>
<ENTRY>Is perpendicular?</ENTRY>
<ENTRY>'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg</ENTRY>
</ROW>
<ROW>
<ENTRY> @-@ </ENTRY>
<ENTRY>Length or circumference</ENTRY>
<ENTRY>@-@ '((0,0),(1,0))'::path</ENTRY>
</ROW>
<ROW>
<ENTRY> ?| </ENTRY>
<ENTRY>Is vertical?</ENTRY>
<ENTRY>'(0,1)'::point ?| '(0,0)'::point</ENTRY>
</ROW>
<ROW>
<ENTRY> ?|| </ENTRY>
<ENTRY>Is parallel?</ENTRY>
<ENTRY>'((-1,0),(1,0))'::lseg ?|| '((-1,2),(1,2))'::lseg</ENTRY>
</ROW>
<ROW>
<ENTRY> @ </ENTRY>
<ENTRY>Contained or on</ENTRY>
<ENTRY>'(1,1)'::point @ '((0,0),2)'::circle</ENTRY>
</ROW>
<ROW>
<ENTRY> @@ </ENTRY>
<ENTRY>Center of</ENTRY>
<ENTRY>@@ '((0,0),10)'::circle</ENTRY>
</ROW>
<ROW>
<ENTRY> ~= </ENTRY>
<ENTRY>Same as</ENTRY>
<ENTRY>'((0,0),(1,1))'::polygon ~= '((1,1),(0,0))'::polygon</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
The time interval data type <Type>tinterval</Type> is a legacy from the original
date/time types and is not as well supported as the more modern types. There
are several operators for this type.
<TABLE TOCENTRY="1">
<TITLE><ProductName>Postgres</ProductName> Time Interval Operators</TITLE>
<TITLEABBREV>Operators</TITLEABBREV>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Operator</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Usage</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> #&lt; </ENTRY>
<ENTRY>Interval less than?</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> #&lt;= </ENTRY>
<ENTRY>Interval less than or equal to?</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> #&lt;&gt; </ENTRY>
<ENTRY>Interval not equal?</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> #= </ENTRY>
<ENTRY>Interval equal?</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> #&gt; </ENTRY>
<ENTRY>Interval greater than?</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> #&gt;= </ENTRY>
<ENTRY>Interval greater than or equal to?</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;#&gt; </ENTRY>
<ENTRY>Convert to time interval</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;&lt; </ENTRY>
<ENTRY>Interval less than?</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> | </ENTRY>
<ENTRY>Start of interval</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> ~= </ENTRY>
<ENTRY>Same as</ENTRY>
<ENTRY></ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;?&gt; </ENTRY>
<ENTRY>Time inside interval?</ENTRY>
<ENTRY></ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
Users may invoke operators using the operator name, as in:
<ProgramListing>
select * from emp where salary < 40000;
</ProgramListing>
Alternatively, users may call the functions that implement the
operators directly. In this case, the query above would be expressed
as:
<ProgramListing>
select * from emp where int4lt(salary, 40000);
</ProgramListing>
<Para>
<Application>psql</Application>
has a <Command>\dd</Command> command to show these operators.
</Chapter>
<Chapter>
<Title>Functions</Title>
<Para>
Many data types have functions available for conversion to other related types.
In addition, there are some type-specific functions. Functions which are also
available through operators are documented as operators only.
</Para>
<Para>
Some functions defined for text are also available for char() and varchar().
</Para>
<Para>
For the
<Function>date_part</Function> and <Function>date_trunc</Function>
functions, arguments can be
`year', `month', `day', `hour', `minute', and `second',
as well as the more specialized quantities
`decade', `century', `millenium', `millisecond', and `microsecond'.
<Function>date_part</Function> allows `dow'
to return day of week and `epoch' to return seconds since 1970 (for <Type>datetime</Type>)
or 'epoch' to return total elapsed seconds (for <Type>timespan</Type>).
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE>Mathematical Functions</TITLE>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY>Function</ENTRY>
<ENTRY>Returns</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Example</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> float(int) </ENTRY>
<ENTRY> float8 </ENTRY>
<ENTRY> convert integer to floating point </ENTRY>
<ENTRY> float(2) </ENTRY>
</ROW>
<ROW>
<ENTRY> float4(int) </ENTRY>
<ENTRY> float4 </ENTRY>
<ENTRY> convert integer to floating point </ENTRY>
<ENTRY> float4(2) </ENTRY>
</ROW>
<ROW>
<ENTRY> int </ENTRY>
<ENTRY> integer(float) </ENTRY>
<ENTRY> convert floating point to integer </ENTRY>
<ENTRY> integer(2.0) </ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
Many of the string functions are available for text, varchar(), and char() types.
At the moment, some functions are available only for the text type.
<TABLE TOCENTRY="1">
<TITLE>String Functions</TITLE>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY>Function</ENTRY>
<ENTRY>Returns</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Example</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> lower(text) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> convert text to lower case </ENTRY>
<ENTRY> lower('TOM') </ENTRY>
</ROW>
<ROW>
<ENTRY> lpad(text,int,text) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> left pad string to specified length </ENTRY>
<ENTRY> lpad('hi',4,'??') </ENTRY>
</ROW>
<ROW>
<ENTRY> ltrim(text,text) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> left trim characters from text </ENTRY>
<ENTRY> ltrim('xxxxtrim','x') </ENTRY>
</ROW>
<ROW>
<ENTRY> position(text,text) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> extract specified substring </ENTRY>
<ENTRY> position('high','ig') </ENTRY>
</ROW>
<ROW>
<ENTRY> rpad(text,int,text) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> right pad string to specified length </ENTRY>
<ENTRY> rpad('hi',4,'x') </ENTRY>
</ROW>
<ROW>
<ENTRY> rtrim(text,text) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> right trim characters from text </ENTRY>
<ENTRY> rtrim('trimxxxx','x') </ENTRY>
</ROW>
<ROW>
<ENTRY> substr(text,int[,int]) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> extract specified substring </ENTRY>
<ENTRY> substr('hi there',3,5) </ENTRY>
</ROW>
<ROW>
<ENTRY> upper(text) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> convert text to upper case </ENTRY>
<ENTRY> upper('tom') </ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE>Date/Time Functions</TITLE>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY>Function</ENTRY>
<ENTRY>Returns</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Example</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> isfinite(abstime) </ENTRY>
<ENTRY> bool </ENTRY>
<ENTRY> TRUE if this is a finite time </ENTRY>
<ENTRY> isfinite('now'::abstime) </ENTRY>
</ROW>
<ROW>
<ENTRY> datetime(abstime) </ENTRY>
<ENTRY> datetime </ENTRY>
<ENTRY> convert to datetime </ENTRY>
<ENTRY> datetime('now'::abstime) </ENTRY>
</ROW>
<ROW>
<ENTRY> datetime(date) </ENTRY>
<ENTRY> datetime </ENTRY>
<ENTRY> convert to datetime </ENTRY>
<ENTRY> datetime('today'::date) </ENTRY>
</ROW>
<ROW>
<ENTRY> datetime(date,time) </ENTRY>
<ENTRY> datetime </ENTRY>
<ENTRY> convert to datetime </ENTRY>
<ENTRY> datetime('1998-02-24':datetime, '23:07'::time);
</ROW>
<ROW>
<ENTRY> age(datetime,datetime) </ENTRY>
<ENTRY> timespan </ENTRY>
<ENTRY> span preserving months and years </ENTRY>
<ENTRY> age('now','1957-06-13':datetime) </ENTRY>
</ROW>
<ROW>
<ENTRY> date_part(text,datetime) </ENTRY>
<ENTRY> float8 </ENTRY>
<ENTRY> specified portion of date field </ENTRY>
<ENTRY> date_part('dow','now'::datetime) </ENTRY>
</ROW>
<ROW>
<ENTRY> date_trunc(text,datetime) </ENTRY>
<ENTRY> datetime </ENTRY>
<ENTRY> truncate date at specified units </ENTRY>
<ENTRY> date_trunc('month','now'::abstime) </ENTRY>
</ROW>
<ROW>
<ENTRY> isfinite(datetime) </ENTRY>
<ENTRY> bool </ENTRY>
<ENTRY> TRUE if this is a finite time </ENTRY>
<ENTRY> isfinite('now'::datetime) </ENTRY>
</ROW>
<ROW>
<ENTRY> abstime(datetime) </ENTRY>
<ENTRY> abstime </ENTRY>
<ENTRY> convert to abstime </ENTRY>
<ENTRY> abstime('now'::datetime) </ENTRY>
</ROW>
<ROW>
<ENTRY> timespan(reltime) </ENTRY>
<ENTRY> timespan </ENTRY>
<ENTRY> convert to timespan </ENTRY>
<ENTRY> timespan('4 hours'::reltime) </ENTRY>
</ROW>
<ROW>
<ENTRY> datetime(date,time) </ENTRY>
<ENTRY> datetime </ENTRY>
<ENTRY> convert to datetime </ENTRY>
<ENTRY> datetime('1998-02-25'::date,'06:41'::time) </ENTRY>
</ROW>
<ROW>
<ENTRY> date_part(text,timespan) </ENTRY>
<ENTRY> float8 </ENTRY>
<ENTRY> specified portion of time field </ENTRY>
<ENTRY> date_part('hour','4 hrs 3 mins'::timespan) </ENTRY>
</ROW>
<ROW>
<ENTRY> isfinite(timespan) </ENTRY>
<ENTRY> bool </ENTRY>
<ENTRY> TRUE if this is a finite time </ENTRY>
<ENTRY> isfinite('4 hrs'::timespan) </ENTRY>
</ROW>
<ROW>
<ENTRY> reltime(timespan) </ENTRY>
<ENTRY> reltime </ENTRY>
<ENTRY> convert to reltime </ENTRY>
<ENTRY> reltime('4 hrs'::timespan) </ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE>Geometric Functions</TITLE>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Function</ENTRY>
<ENTRY>Returns</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Example</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> box(point,point) </ENTRY>
<ENTRY> box </ENTRY>
<ENTRY> convert points to box </ENTRY>
<ENTRY> box('(0,0)'::point,'(1,1)'::point) </ENTRY>
</ROW>
<ROW>
<ENTRY> area(box) </ENTRY>
<ENTRY> float8 </ENTRY>
<ENTRY> area of box </ENTRY>
<ENTRY> area('((0,0),(1,1))'::box) </ENTRY>
</ROW>
<ROW>
<ENTRY> isopen(path) </ENTRY>
<ENTRY> bool </ENTRY>
<ENTRY> TRUE if this is an open path </ENTRY>
<ENTRY> isopen('[(0,0),(1,1),(2,0)]'::path) </ENTRY>
</ROW>
<ROW>
<ENTRY> isclosed(path) </ENTRY>
<ENTRY> bool </ENTRY>
<ENTRY> TRUE if this is a closed path </ENTRY>
<ENTRY> isclosed('((0,0),(1,1),(2,0))'::path) </ENTRY>
</ROW>
<ROW>
<ENTRY> circle(point,float8) </ENTRY>
<ENTRY> circle </ENTRY>
<ENTRY> convert to circle </ENTRY>
<ENTRY> circle('(0,0)'::point,2.0) </ENTRY>
</ROW>
<ROW>
<ENTRY> polygon(npts,circle) </ENTRY>
<ENTRY> polygon </ENTRY>
<ENTRY> convert to polygon with npts points </ENTRY>
<ENTRY> polygon(12,'((0,0),2.0)'::circle) </ENTRY>
</ROW>
<ROW>
<ENTRY> center(circle) </ENTRY>
<ENTRY> float8 </ENTRY>
<ENTRY> center of object </ENTRY>
<ENTRY> center('((0,0),2.0)'::circle) </ENTRY>
</ROW>
<ROW>
<ENTRY> radius(circle) </ENTRY>
<ENTRY> float8 </ENTRY>
<ENTRY> radius of circle </ENTRY>
<ENTRY> radius('((0,0),2.0)'::circle) </ENTRY>
</ROW>
<ROW>
<ENTRY> diameter(circle) </ENTRY>
<ENTRY> float8 </ENTRY>
<ENTRY> diameter of circle </ENTRY>
<ENTRY> diameter('((0,0),2.0)'::circle) </ENTRY>
</ROW>
<ROW>
<ENTRY> area(circle) </ENTRY>
<ENTRY> float8 </ENTRY>
<ENTRY> area of circle </ENTRY>
<ENTRY> area('((0,0),2.0)'::circle) </ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
SQL92 defines functions with specific syntax. Some of these
are implemented using other <ProductName>Postgres</ProductName> functions.
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE><Acronym>SQL92</Acronym> Text Functions</TITLE>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Function</ENTRY>
<ENTRY>Returns</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Example</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> position(text in text) </ENTRY>
<ENTRY> int4 </ENTRY>
<ENTRY> extract specified substring </ENTRY>
<ENTRY> position('o' in 'Tom') </ENTRY>
</ROW>
<ROW>
<ENTRY> substring(text [from int] [for int]) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> extract specified substring </ENTRY>
<ENTRY> substring('Tom' from 2 for 2) </ENTRY>
</ROW>
<ROW>
<ENTRY> trim([leading|trailing|both] [text] from text) </ENTRY>
<ENTRY> text </ENTRY>
<ENTRY> trim characters from text </ENTRY>
<ENTRY> trim(both 'x' from 'xTomx') </ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Chapter>
<Title>Linking Dynamically-Loaded Functions</Title>
<Para>
After you have created and registered a user-defined
function, your work is essentially done. <ProductName>Postgres</ProductName>,
however, must load the object code (e.g., a <FileName>.o</FileName> file, or
a shared library) that implements your function. As
previously mentioned, <ProductName>Postgres</ProductName> loads your code at
runtime, as required. In order to allow your code to be
dynamically loaded, you may have to compile and
linkedit it in a special way. This section briefly
describes how to perform the compilation and
linkediting required before you can load your user-defined
functions into a running <ProductName>Postgres</ProductName> server. Note that
this process has changed as of Version 4.2.
<Tip>
<Para>
The old <ProductName>Postgres</ProductName> dynamic
loading mechanism required
in-depth knowledge in terms of executable format, placement
and alignment of executable instructions within memory, etc.
on the part of the person writing the dynamic loader. Such
loaders tended to be slow and buggy. As of Version 4.2, the
<ProductName>Postgres</ProductName> dynamic loading mechanism has been rewritten to use
the dynamic loading mechanism provided by the operating
system. This approach is generally faster, more reliable and
more portable than our previous dynamic loading mechanism.
The reason for this is that nearly all modern versions of
UNIX use a dynamic loading mechanism to implement shared
libraries and must therefore provide a fast and reliable
mechanism. On the other hand, the object file must be
postprocessed a bit before it can be loaded into <ProductName>Postgres</ProductName>. We
hope that the large increase in speed and reliability will
make up for the slight decrease in convenience.
<Para>
</Tip>
You should expect to read (and reread, and re-reread) the
manual pages for the C compiler, cc(1), and the link
editor, ld(1), if you have specific questions. In
addition, the regression test suites in the directory
<FileName>PGROOT/src/regress</FileName> contain several
working examples of this process. If you copy what these
tests do, you should not have any problems.
The following terminology will be used below:
<ItemizedList>
<ListItem>
<Para>
<FirstTerm>Dynamic loading</FirstTerm>
is what <ProductName>Postgres</ProductName> does to an object file. The
object file is copied into the running <ProductName>Postgres</ProductName>
server and the functions and variables within the
file are made available to the functions within
the <ProductName>Postgres</ProductName> process. <ProductName>Postgres</ProductName> does this using
the dynamic loading mechanism provided by the
operating system.
</Para>
</ListItem>
<ListItem>
<Para>
<FirstTerm>Loading and link editing</FirstTerm>
is what you do to an object file in order to produce
another kind of object file (e.g., an executable
program or a shared library). You perform
this using the link editing program, ld(1).
</Para>
</ListItem>
</ItemizedList>
</Para>
<Para>
The following general restrictions and notes also apply
to the discussion below:
<ItemizedList>
<ListItem>
<Para>
Paths given to the create function command must be
absolute paths (i.e., start with "/") that refer to
directories visible on the machine on which the
<ProductName>Postgres</ProductName> server is running.
<Tip>
<Para>
Relative paths do in fact work,
but are relative to
the directory where the database resides (which is generally
invisible to the frontend application). Obviously, it makes
no sense to make the path relative to the directory in which
the user started the frontend application, since the server
could be running on a completely different machine!
</Para>
</Tip>
</Para>
</ListItem>
<ListItem>
<Para>
The <ProductName>Postgres</ProductName> user must be able to traverse the path
given to the create function command and be able to
read the object file. This is because the <ProductName>Postgres</ProductName>
server runs as the <ProductName>Postgres</ProductName> user, not as the user
who starts up the frontend process. (Making the
file or a higher-level directory unreadable and/or
unexecutable by the "postgres" user is an extremely
common mistake.)
</Para>
</ListItem>
<ListItem>
<Para>
Symbol names defined within object files must not
conflict with each other or with symbols defined in
<ProductName>Postgres</ProductName>.
</Para>
</ListItem>
<ListItem>
<Para>
The GNU C compiler usually does not provide the special
options that are required to use the operating
system's dynamic loader interface. In such cases,
the C compiler that comes with the operating system
must be used.
</Para>
</ListItem>
</ItemizedList>
<Sect1>
<Title><Acronym>ULTRIX</Acronym></Title>
<Para>
It is very easy to build dynamically-loaded object
files under ULTRIX. ULTRIX does not have any sharedlibrary
mechanism and hence does not place any restrictions on
the dynamic loader interface. On the other
hand, we had to (re)write a non-portable dynamic loader
ourselves and could not use true shared libraries.
Under ULTRIX, the only restriction is that you must
produce each object file with the option -G 0. (Notice
that that's the numeral ``0'' and not the letter
``O''). For example,
<ProgramListing>
# simple ULTRIX example
% cc -G 0 -c foo.c
</ProgramListing>
produces an object file called foo.o that can then be
dynamically loaded into <ProductName>Postgres</ProductName>. No additional loading or link-editing must be performed.
</Para>
</Sect1>
<Sect1>
<Title><Acronym>DEC OSF/1</Acronym></Title>
<Para>
Under DEC OSF/1, you can take any simple object file
and produce a shared object file by running the ld command over it with the correct options. The commands to
do this look like:
<ProgramListing>
# simple DEC OSF/1 example
% cc -c foo.c
% ld -shared -expect_unresolved '*' -o foo.so foo.o
</ProgramListing>
The resulting shared object file can then be loaded
into <ProductName>Postgres</ProductName>. When specifying the object file name to
the create function command, one must give it the name
of the shared object file (ending in .so) rather than
the simple object file.
<Tip>
<Para>
Actually, <ProductName>Postgres</ProductName> does not care
what you name the
file as long as it is a shared object file. If you prefer
to name your shared object files with the extension .o, this
is fine with <ProductName>Postgres</ProductName> so long as you make sure that the correct
file name is given to the create function command. In
other words, you must simply be consistent. However, from a
pragmatic point of view, we discourage this practice because
you will undoubtedly confuse yourself with regards to which
files have been made into shared object files and which have
not. For example, it's very hard to write Makefiles to do
the link-editing automatically if both the object file and
the shared object file end in .o!
</Para>
</Tip>
If the file you specify is
not a shared object, the backend will hang!
</Para>
</Sect1>
<Sect1>
<Title>
<Acronym>SunOS 4.x</Acronym>, <Acronym>Solaris 2.x</Acronym> and <Acronym>HP-UX</Acronym></Title>
<Para>
Under SunOS 4.x, Solaris 2.x and HP-UX, the simple
object file must be created by compiling the source
file with special compiler flags and a shared library
must be produced.
The necessary steps with HP-UX are as follows. The +z
flag to the HP-UX C compiler produces so-called
"Position Independent Code" (PIC) and the +u flag
removes
some alignment restrictions that the PA-RISC architecture
normally enforces. The object file must be turned
into a shared library using the HP-UX link editor with
the -b option. This sounds complicated but is actually
very simple, since the commands to do it are just:
<ProgramListing>
# simple HP-UX example
&percnt; cc +z +u -c foo.c
&percnt; ld -b -o foo.sl foo.o
</ProgramListing>
</Para>
<Para>
As with the .so files mentioned in the last subsection,
the create function command must be told which file is
the correct file to load (i.e., you must give it the
location of the shared library, or .sl file).
Under SunOS 4.x, the commands look like:
<ProgramListing>
# simple SunOS 4.x example
&percnt; cc -PIC -c foo.c
&percnt; ld -dc -dp -Bdynamic -o foo.so foo.o
</ProgramListing>
and the equivalent lines under Solaris 2.x are:
<ProgramListing>
# simple Solaris 2.x example
&percnt; cc -K PIC -c foo.c
or
&percnt; gcc -fPIC -c foo.c
&percnt; ld -G -Bdynamic -o foo.so foo.o
</ProgramListing>
</Para>
<Para>
When linking shared libraries, you may have to specify
some additional shared libraries (typically system
libraries, such as the C and math libraries) on your ld
command line.
</Para>
</Sect1>
</Chapter>
<Appendix label="A">
<DocInfo>
<AuthorGroup>
<Author>
<FirstName>Thomas</FirstName>
<Surname>Lockhart</Surname>
</Author>
</AuthorGroup>
<Date>1998-02-26</Date>
</DocInfo>
<Title>Documentation</Title>
<Para>
<ProductName>Postgres</ProductName> documentation is written using
the <FirstTerm>Standard Generalized Markup Language</FirstTerm>
(<Acronym>SGML</Acronym>)
<ULink url="http://www.ora.com/davenport/"><ProductName>DocBook</ProductName></ULink>
<FirstTerm>Document Type Definition</FirstTerm> (<Acronym>DTD</Acronym>).
<Para>
Packaged documentation is available in both <FirstTerm>HTML</FirstTerm> and <FirstTerm>Postscript</FirstTerm>
formats. These are available as part of the standard <ProductName>Postgres</ProductName> installation.
We discuss here working with the documentation sources and generating documentation packages.
<Note>
<Para>
This is the first release of new <ProductName>Postgres</ProductName> documentation in three years.
The content and environment are in flux and still evolving.
</Para>
</Note>
<Sect1>
<Title>Introduction</Title>
<Para>
The purpose of <Acronym>SGML</Acronym> is to allow an author to specify the structure and content of
a document (e.g. using the <ProductName>DocBook</ProductName> <Acronym>DTD</Acronym>),
and to have the document style define
how that content is rendered into a final form
(e.g. using Norm Walsh's stylesheets).
<Para>
See
<ULink url="http://nis-www.lanl.gov/~rosalia/mydocs/docbook-intro.html">Introduction to DocBook</ULink>
for a nice "quickstart" summary of DocBook features.
<ULink url="http://www.ora.com/homepages/dtdparse/docbook/3.0/">DocBook Elements</ULink>
provides a powerful cross-reference for features of <ProductName>DocBook</ProductName>.
<Para>
This documentation set is constructed using several tools,
including James Clark's
<ULink url="http://www.jclark.com/jade/"><ProductName>jade</ProductName></ULink>
and Norm Walsh's
<ULink url="http://www.berkshire.net/~norm/docbook/dsssl">Modular DocBook Stylesheets</ULink>.
<Para>
Currently, hardcopy is produced by importing <FirstTerm>Rich Text Format</FirstTerm> (<Acronym>RTF</Acronym>)
output from <Application>jade</Application> to <ProductName>ApplixWare</ProductName>
for minor formatting fixups then exporting as a Postscript file.
<Para>
<ULink url="http://sunsite.unc.edu/pub/packages/TeX/systems/unix/"><ProductName>TeX</ProductName></ULink>
is a supported format for <Application>jade</Application> output, but was not used at this time for
several reasons, including the inability to make minor format fixes before committing to hardcopy and
generally inadequate table support in the <ProductName>TeX</ProductName> stylesheets.
<Sect1>
<Title>Styles and Conventions</Title>
<Para>
<ProductName>DocBook</ProductName> has a rich set of tags and constructs, and a suprisingly large
percentage are directly and obviously useful for well-formed documentation.
The <ProductName>Postgres</ProductName> documentation set has only recently
been adapted to <Acronym>SGML</Acronym>, and in the near future several sections of the set
will be selected and maintained as prototypical examples of <ProductName>DocBook</ProductName>
usage. Also, a short summary of <ProductName>DocBook</ProductName> tags will be included below.
<!--
<Para>
<TABLE TOCENTRY="1">
<TITLE>SGML Constructs</TITLE>
<TITLEABBREV>SGML Constructs</TITLEABBREV>
<TGROUP COLS="2">
<THEAD>
<ROW>
<ENTRY>SGML Tag</ENTRY>
<ENTRY>Usage</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
-->
</Sect1>
<Sect1>
<Title>Building Documentation</Title>
<Para>
HTML documentation packages can be generated from the SGML source by typing
<ProgramListing>
% cd doc/src
% make tutorial.tar.gz
% make user.tar.gz
% make admin.tar.gz
% make programmer.tar.gz
% make postgres.tar.gz
% make install
</ProgramListing>
</Para>
<Para>
These packages can be installed from the main documentation directory by typing
<ProgramListing>
% cd doc
% make install
</ProgramListing>
</Para>
<Sect1>
<Title>Toolsets</Title>
<Sect2>
<Title><ProductName>jade</ProductName></Title>
<Para>
The current stable release of <ProductName>jade</ProductName> is version 1.0.1.
</Para>
<Sect3>
<Title>Installation for Linux</Title>
<Para>
Install <ULink url="ftp://ftp.cygnus.com/pub/home/rosalia/"><Acronym>RPMs</Acronym></ULink>
for <ProductName>jade</ProductName> and related packages.
</Para>
</Sect3>
<Sect3>
<Title>Installation for non-Linux Platforms</Title>
<Para>
There are some other packaged distributions for jade. <ProductName>FreeBSD</ProductName> seems
to have one available. Please report package status to the docs mailing list and we will
include that information here.
<Para>
For other platforms, install <ULink url="ftp://ftp.cygnus.com/pub/eichin/docware/SOURCES/">sources</ULink>
for <ProductName>jade</ProductName> and related packages and build from scratch.
</Para>
</Sect3>
<Sect2>
<Title><ProductName>Modular Style Sheets</ProductName></Title>
<Para>
The current stable release of the <ProductName>Modular Style Sheets</ProductName> is version 1.0.7.
</Para>
<Sect1>
<Title>Hardcopy Generation for v6.3</Title>
<Para>
The hardcopy Postscript documentation is generated by converting the <Acronym>SGML</Acronym>
source code to <Acronym>RTF</Acronym>, then importing into Applixware. After a little cleanup
(see the following section) the output is "printed" to a postscript file.
<Para>
Some figures were redrawn to avoid having bitmap <Acronym>GIF</Acronym> files in the hardcopy
documentation. One figure, of the system catalogs, was sufficiently complex that there was
not time to redraw it. It was converted to fit using the following commands:
<ProgramListing>
% convert -v -geometry 400x400'>' figure03.gif con.gif
% convert -v -crop 400x380 con.gif connections.gif
</ProgramListing>
<Sect2>
<Title>RTF Cleanup Procedure</Title>
<Para>
Several items must be addressed in generating Postscript hardcopy:
<Procedure>
<Title>Applixware RTF Cleanup</Title>
<Para>
Applixware does not seem to do a complete job of importing RTF generated by jade/MSS. In particular,
all text is given the <Quote>Header1</Quote> style attribute label, although the text formatting itself
is acceptable. Also, the Table of Contents page numbers do not refer to the section listed in the
table, but rather refer to the page of the ToC itself.
<Step Performance="required">
<Para>
Generate the <Acronym>RTF</Acronym> input by typing
<ProgramListing>
% cd doc/src/sgml
% make tutorial.rtf
</ProgramListing>
</Para>
</Step>
<Step Performance="required">
<Para>
Open a new document in <ProductName>Applix Words</ProductName> and then import the RTF file.
</Para>
</Step>
<Step Performance="required">
<Para>
Print out the existing Table of Contents, to mark up in the following few steps.
</Para>
</Step>
<Step Performance="required">
<Para>
Insert figures into the document. Center each figure on the page using the centering margins button.
<Para>
Not all documents have figures. You can grep the SGML source files for the string <Quote>Graphic</Quote>
to identify those parts of the documentation which may have figures. A few figures are replicated in
various parts of the documentation.
</Para>
</Step>
<Step Performance="required">
<Para>
Work through the document, adjusting page breaks and table column widths.
</Para>
</Step>
<Step Performance="required">
<Para>
If a bibliography is present, Applix Words seems to mark all remaining text after the first title
as having an underlined attribute. Select all remaining text, turn off underlining using the underlining button,
then explicitly underline each document and book title.
</Para>
</Step>
<Step Performance="required">
<Para>
Work through the document, marking up the ToC hardcopy with the actual page number of each ToC entry.
</Para>
</Step>
<Step Performance="required">
<Para>
Replace the right-justified incorrect page numbers in the ToC with correct values. This only takes a few
minutes per document.
</Para>
</Step>
<Step Performance="required">
<Para>
Save the document as native Applix Words format to allow easier last minute editing later.
</Para>
</Step>
<Step Performance="required">
<Para>
Export the document to a file in Postscript format.
</Para>
</Step>
<Step Performance="required">
<Para>
Compress the Postscript file using <Application>gzip</Application>. Place the compressed file into the
<FileName>doc</FileName> directory.
</Para>
</Step>
</Procedure>
</Sect2>
</Sect1>
<Sect1>
<Title>Alternate Toolsets</Title>
<Para>
The current stable release of <ProductName>sgml-tools</ProductName> is version 1.0.4.
The v1.0 release includes some restructuring of the directory tree
to more easily support additional document styles, possibly including <ProductName>DocBook</ProductName>.
The only version of <ProductName>sgml-tools</ProductName> evaluated for <ProductName>Postgres</ProductName> was v0.99.0.
</Para>
<Sect2>
<Title><ProductName>sgml-tools</ProductName></Title>
<Para>
Install
<ProductName>sgml-tools-0.99.0</ProductName>
</Para>
<Para>
Apply
<ULink url="http://alumni.caltech.edu/~lockhart/postgres/linuxdoc/sgml-tools-patches-0.99.0.tar.gz">
<ProductName>sgml-tools-patches</ProductName>
</ULink>
to the linuxdoc styles. These patches fix small problems with
table formatting and with figure file names on conversion to postscript or html.
</Para>
<Sect2>
<Title><ProductName>sgml2latex</ProductName></Title>
<Para>
The current stable release of <ProductName>sgml2latex</ProductName> is version 1.4.
I have misplaced the original reference
for this package, so will temporarily post it with this example.
</Para>
<Para>
Install <ULink url="http://alumni.caltech.edu/~lockhart/postgres/linuxdoc/sgml2latex-format.1.4.tar.gz">
<ProductName>sgml2latex</ProductName>
</ULink>.
</Para>
<Sect2>
<Title><ProductName>latex</ProductName></Title>
<Para>
Get and install <ProductName>texmf</ProductName>, <ProductName>teTeX</ProductName>,
or another package providing full tex/latex functionality.
</Para>
<Para>
Add the
<ULink url="http://alumni.caltech.edu/~lockhart/postgres/linuxdoc/latex-styles-0.99.0.tar.gz">required styles</ULink>
linuxdoc-sgml.sty, linuxdoc-sgml-a4.sty isolatin.sty, qwertz.sty, and null.sty
to texmf/tex/latex/tools/ or the appropriate area.
<ProgramListing>
% cat latex-styles-0.99.0.tar.gz | (cd texmf/tex/latex/tools/; tar zxvf -)
</ProgramListing>
Run <ProductName>texhash</ProductName> to update the tex database.
</Para>
</Appendix>
<Chapter>
<DocInfo>
<AuthorGroup>
<Author>
<FirstName>Linux</FirstName>
<Surname>Tolke</Surname>
</Author>
<Author>
<FirstName>Michael</FirstName>
<Surname>Meskes</Surname>
</Author>
</AuthorGroup>
<Copyright>
<Year>1996-1997</Year>
<Holder>Linus Tolke</Holder>
</Copyright>
<Copyright>
<Year>1998</Year>
<Holder>Michael Meskes</Holder>
</Copyright>
<Date>Transcribed 1998-02-12</Date>
</DocInfo>
<Title><Application>ecpg</Application> - Embedded <Acronym>SQL</Acronym> in <Acronym>C</Acronym></Title>
<Para>
This describes an embedded <Acronym>SQL</Acronym> in <Acronym>C</Acronym> package for <ProductName>Postgres</ProductName>.
It is written by <ULink url="mailto:linus@epact.se">Linus Tolke</ULink>
and <ULink url="mailto:meskes@debian.org">Michael Meskes</ULink>.
<Note>
<Para>
Permission is granted to copy and use in the same way as you are allowed
to copy and use the rest of the <ProductName>PostgreSQL</ProductName>.
</Para>
</Note>
<Sect1>
<Title>Why Embedded <Acronym>SQL</Acronym>?</Title>
<Para>
Embedded <Acronym>SQL</Acronym> has some small advantages over other ways to handle <Acronym>SQL</Acronym>
queries. It takes care of all the tedious moving of information to and
from variables in your <Acronym>C</Acronym> program. Many <Acronym>RDBMS</Acronym> packages
support this embedded language.
<Para>
There is an ANSI-standard describing how the embedded language should
work. Most embedded <Acronym>SQL</Acronym> preprocessors I have seen and heard of make
extensions so it is difficult to obtain portability between them
anyway. I have not read the standard but I hope that my implementation
does not deviate too much and that it would be possible to port programs
with embedded <Acronym>SQL</Acronym> written for other <Acronym>RDBMS</Acronym> packages
to <ProductName>Postgres</ProductName> and thus
promoting the spirit of free software.
<Sect1>
<Title>The Concept</Title>
<Para>
You write your program in <Acronym>C</Acronym> with some special <Acronym>SQL</Acronym> things.
For declaring variables that can be used in <Acronym>SQL</Acronym> statements you need to
put them in a special declare section.
You use a special syntax for the <Acronym>SQL</Acronym> queries.
<Para>
Before compiling you run the file through the embedded <Acronym>SQL</Acronym> <Acronym>C</Acronym>
preprocessor and it converts the <Acronym>SQL</Acronym> statements you used to function
calls with the variables used as arguments. Both variables that are used
as input to the <Acronym>SQL</Acronym> statements and variables that will contain the
result are passed.
<Para>
Then you compile and at link time you link with a special library that
contains the functions used. These functions (actually it is mostly one
single function) fetches the information from the arguments, performs
the <Acronym>SQL</Acronym> query using the ordinary interface (<FileName>libpq</FileName>) and puts back
the result in the arguments dedicated for output.
<Para>
Then you run your program and when the control arrives to the <Acronym>SQL</Acronym>
statement the <Acronym>SQL</Acronym> statement is performed against the database and you
can continue with the result.
<Sect1>
<Title>How To Use <Application>egpc</Application></Title>
<Para>
This section describes how to use the <Application>egpc</Application> tool.
<Sect2>
<Title>Preprocessor
<Para>
The preprocessor is called <Application>ecpg</Application>. After installation it resides in
the <ProductName>Postgres</ProductName> <FileName>bin/</FileName> directory.
<Sect2>
<Title>Library
<Para>
The <Application>ecpg</Application> library is called <FileName>libecpg.a</FileName> or
<FileName>libecpg.so</FileName>. Additionally, the library
uses the <FileName>libpq</FileName> library for communication to the
<ProductName>Postgres</ProductName> server so you will
have to link your program with <Parameter>-lecpg -lpq</Parameter>.
<Para>
The library has some methods that are "hidden" but that could prove very
useful sometime.
<VariableList>
<VarListEntry>
<Term>ECPGdebug(int, FILE *stream)</Term>
<ListItem>
<Para>
If this is called, with the first argument non-zero, then debuglogging is turned
on. Debuglogging is done on <Function>stream</Function>. Most <Acronym>SQL</Acronym> statement logs its
arguments and result.
<Para>
The most important one (<Function>ECPGdo</Function>) that is called on all <Acronym>SQL</Acronym>
statements except <Command>EXEC SQL COMMIT</Command>, <Command>EXEC SQL ROLLBACK</Command>,
<Command>EXEC SQL CONNECT</Command> logs both its expanded string, i.e. the string
with all the input variables inserted, and the result from the
<ProductName>Postgres</ProductName> server. This can be very useful when searching for errors
in your <Acronym>SQL</Acronym> statements.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>ECPGstatus()</Term>
<ListItem>
<Para>
This method returns TRUE if we are connected to a database and FALSE if not.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
<Sect2>
<Title>Error handling
<Para>
To be able to detect errors from the <ProductName>Postgres</ProductName> server you include a line
like
<ProgramListing>
exec sql include sqlca;
</ProgramListing>
in the include section of your file. This will define a struct and a
variable with the name <Parameter>sqlca</Parameter> as following:
<ProgramListing>
struct sqlca {
int sqlcode;
struct {
int sqlerrml;
char sqlerrmc[1000];
} sqlerrm;
} sqlca;
</ProgramListing>
<Para>
If an error occured in the last <Acronym>SQL</Acronym> statement then <Parameter>sqlca.sqlcode</Parameter>
will be non-zero. If <Parameter>sqlca.sqlcode</Parameter> is less that 0 then this is
some kind of serious error, like the database definition does not match
the query given. If it is bigger than 0 then this is a normal error like
the table did not contain the requested row.
<Para>
sqlca.sqlerrm.sqlerrmc will contain a string that describes the error.
The string ends with <Quote>line 23.</Quote> where the line is the line number
in the source file (actually the file generated by the preprocessor but
I hope I can fix this to be the line number in the input file.)
<Para>
List of errors that can occur:
<VariableList>
<VarListEntry>
<Term>-1, Unsupported type %s on line %d.</Term>
<ListItem>
<Para>
Does not normally occur. This is a sign that the preprocessor has
generated something that the library does not know about. Perhaps you
are running incompatible versions of the preprocessor and the library.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Too many arguments line %d.</Term>
<ListItem>
<Para>
The preprocessor has goofed up and generated some incorrect code.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Too few arguments line %d.</Term>
<ListItem>
<Para>
The preprocessor has goofed up and generated some incorrect code.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Error starting transaction line %d.</Term>
<ListItem>
<Para>
<ProductName>Postgres</ProductName> signalled to us that we cannot open the connection.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Postgres error: %s line %d.</Term>
<ListItem>
<Para>
Some <ProductName>Postgres</ProductName> error. The message contains the error message from the
<ProductName>Postgres</ProductName> backend.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>1, Data not found line %d.</Term>
<ListItem>
<Para>
This is a "normal" error that tells you that what you are quering cannot
be found or we have gone through the cursor.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, To many matches line %d.</Term>
<ListItem>
<Para>
This means that the query has returned several lines. The <Command>SELECT</Command>
you made probably was not unique.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Not correctly formatted int type: %s line %d.</Term>
<ListItem>
<Para>
This means that the host variable is of an <Type>int</Type> type and the field
in the <ProductName>Postgres</ProductName> database is of another type and contains a value that
cannot be interpreted as an <Type>int</Type>. The library uses <Function>strtol</Function>
for this conversion.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Not correctly formatted unsigned type: %s line %d.</Term>
<ListItem>
<Para>
This means that the host variable is of an <Type>unsigned int</Type> type and
the field in the <ProductName>Postgres</ProductName> database is of another type and contains a
value that cannot be interpreted as an <Type>unsigned int</Type>. The library
uses <Function>strtoul</Function> for this conversion.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Not correctly formatted floating point type: %s line %d.</Term>
<ListItem>
<Para>
This means that the host variable is of an <Type>float</Type> type and
the field in the <ProductName>Postgres</ProductName> database is of another type and contains a
value that cannot be interpreted as an <Type>float</Type>. The library
uses <Function>strtod</Function> for this conversion.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Too few arguments line %d.</Term>
<ListItem>
<Para>
This means that <ProductName>Postgres</ProductName> has returned more records than we have
matching variables. Perhaps you have forgotten a couple of the host
variables in the <Command>INTO :var1,:var2</Command>-list.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Too many arguments line %d.</Term>
<ListItem>
<Para>
This means that <ProductName>Postgres</ProductName> has returned fewer records than we have
host variables. Perhaps you have to many host variables in the
<Command>INTO :var1,:var2</Command>-list.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Empty query line %d.</Term>
<ListItem>
<Para>
<ProductName>Postgres</ProductName> returned PGRES_EMPTY_QUERY.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Error: %s line %d.</Term>
<ListItem>
<Para>
This means that <ProductName>Postgres</ProductName> returned on of the errors
PGRES_NONFATAL_ERROR, PGRES_FATAL_ERROR or PGRES_BAD_RESPONSE. Which one
and why is explained in the message.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Postgres error line %d.</Term>
<ListItem>
<Para>
<ProductName>Postgres</ProductName> returns something that the library does not know how to
handle. This is probably because the version of <ProductName>Postgres</ProductName> does not
match the version of the <Application>ecpg</Application> library.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Error committing line %d.</Term>
<ListItem>
<Para>
Error during <Command>COMMIT</Command>. <Command>EXEC SQL COMMIT</Command> is translated to an
<Command>end</Command> operation in <ProductName>Postgres</ProductName> and that is the operation that could
not be performed.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, Error rolling back line %d.</Term>
<ListItem>
<Para>
Error during <Command>ROLLBACK</Command>. <Command>EXEC SQL ROLLBACK</Command> is translated to
an <Command>abort</Command> operation in <ProductName>Postgres</ProductName> and that is the operation that
could not be performed.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>-1, ECPGconnect: could not open database %s.</Term>
<ListItem>
<Para>
The connect to the database did not work.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Sect2>
<Sect1>
<Title>Limitations</Title>
<Para>
What will never be included and why or what cannot be done with this
concept.
<VariableList>
<VarListEntry>
<Term>oracles single tasking possibility</Term>
<ListItem>
<Para>
Oracle version 7.0 on AIX 3 uses the OS-supported locks on the shared
memory segments and allows the application designer to link an
application in a so called single tasking way. Instead of starting one
client process per application process both the database part and the
application part is run in the same process. In later versions of oracle
this is no longer supported.
<Para>
This would require a total redesign of the <ProductName>Postgres</ProductName> access model and
that effort can not justify the performance gained.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
<Sect1>
<Title>Porting From Other <Acronym>RDBMS</Acronym> Packages</Title>
<Para>
To be written by persons that knows the different <Acronym>RDBMS</Acronym> packages and that
actually does port something...
<Sect1>
<Title>Installation</Title>
<Para>
Since version 0.5 <Application>ecpg</Application> is distributed together with <ProductName>Postgres</ProductName>. So you
should get your precompiler, libraries and header files compiled and
installed on the fly.
<Sect1>
<Title>For the Developer</Title>
<Para>
This section is for those that wants to develop the <Application>ecpg</Application> interface. It
describes how the things work. The ambition is to make this section
contain things for those that want to have a look inside and the section
on How to use it should be enough for all normal questions.
So, read this before looking at the internals of the <Application>ecpg</Application>. If
you are not interested in how it really works, skip this section.
<Sect2>
<Title>ToDo List</Title>
<Para>
This version the preprocessor has some flaws:
<VariableList>
<VarListEntry>
<Term>Preprocessor output</Term>
<ListItem>
<Para>
The variables should be static.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Preprocessor cannot do syntax checking on your <Acronym>SQL</Acronym> statements</Term>
<ListItem>
<Para>
Whatever you write is copied more or less exactly to the <ProductName>Postgres</ProductName> and
you will not be able to locate your errors until run-time.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>no restriction to strings only</Term>
<ListItem>
<Para>
The PQ interface, and most of all the PQexec function, that is used by
the <Application>ecpg</Application> relies on that the request is built up as a string. In some
cases, like when the data contains the null character, this will be a
serious problem.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>error codes</Term>
<ListItem>
<Para>
There should be different error numbers for the different errors instead
of just -1 for them all.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>library functions</Term>
<ListItem>
<Para>
to_date et al.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>records</Term>
<ListItem>
<Para>
Possibility to define records or structures in the declare section
in a way that the record can be filled from one row in the database.
<Para>
This is a simpler way to handle an entire row at a time.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>array operations</Term>
<ListItem>
<Para>
Oracle has array operations that enhances speed. When implementing it in
<Application>ecpg</Application> it is done for compatibility reasons only. For them to
improve speed would require a lot more insight in the <ProductName>Postgres</ProductName> internal
mechanisms than I possess.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>indicator variables</Term>
<ListItem>
<Para>
Oracle has indicator variables that tell if a value is <Type>null</Type> or if
it is empty. This largely simplifies array operations and provides for a
way to hack around some design flaws in the handling of <Type>VARCHAR2</Type>
(like that an empty string isn't distinguishable from a
<Type>null</Type> value). I am not sure if this is an Oracle extension or part
of the ANSI standard.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>typedefs</Term>
<ListItem>
<Para>
As well as complex types like records and arrays, typedefs would be
a good thing to take care of.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>conversion of scripts</Term>
<ListItem>
<Para>
To set up a database you need a few scripts with table definitions and
other configuration parameters. If you have these scripts for an old
database you would like to just apply them to get a <ProductName>Postgres</ProductName> database
that works in the same way.
<Para>
To set up a database you need a few scripts with table definitions and
The functionality could be accomplished with some conversion scripts.
Speed will never be accomplished in this way. To do this you need a
bigger insight in the database construction and the use of the database
than could be realised in a script.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
<Sect2>
<Title>The Preprocessor</Title>
<Para>
First four lines are written to the output. Two comments and two include
lines necessary for the interface to the library.
<Para>
Then the preprocessor works in one pass only reading the input file and
writing to the output as it goes along. Normally it just echoes
everything to the output without looking at it further.
<Para>
When it comes to an <Command>EXEC SQL</Command> statements it interviens and
changes them depending on what iit is. The <Command>EXEC SQL</Command> statement can
be one of these:
<VariableList>
<VarListEntry>
<Term>Declare sections</Term>
<ListItem>
<Para>
Declare sections begins with
<ProgramListing>
exec sql begin declare section;
</ProgramListing>
and ends with
<ProgramListing>
exec sql end declare section;
</ProgramListing>
In the section only variable declarations are allowed. Every variable
declare within this section is also entered in a list of variables
indexed on their name together with the corresponding type.
<Para>
The declaration is echoed to the file to make the variable a normal
C-variable also.
<Para>
The special types VARCHAR and VARCHAR2 are converted into a named struct
for every variable. A declaration like:
<ProgramListing>
VARCHAR var[180];
</ProgramListing>
is converted into
<ProgramListing>
struct varchar_var { int len; char arr[180]; } var;
</ProgramListing>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Include statements</Term>
<ListItem>
<Para>
An include statement looks like:
<ProgramListing>
exec sql include filename;
</ProgramListing>
It is converted into
<ProgramListing>
#include &lt;filename.h&gt;
</ProgramListing>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Connect statement</Term>
<ListItem>
<Para>
A connect statement looks like:
<ProgramListing>
exec sql connect '<Replaceable>database</Replaceable>';
</ProgramListing>
That statement is converted into
<ProgramListing>
ECPGconnect("<Replaceable>database</Replaceable>");
</ProgramListing>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Open cursor statement</Term>
<ListItem>
<Para>
An open cursor statement looks like:
<ProgramListing>
exec sql open <Replaceable>cursor</Replaceable>;
</ProgramListing>
and is ignore and not copied from the output.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Commit statement</Term>
<ListItem>
<Para>
A commit statement looks like
<ProgramListing>
exec sql commit;
</ProgramListing>
and is translated on the output to
<ProgramListing>
ECPGcommit(__LINE__);
</ProgramListing>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Rollback statement</Term>
<ListItem>
<Para>
A rollback statement looks like
<ProgramListing>
exec sql rollback;
</ProgramListing>
and is translated on the output to
<ProgramListing>
ECPGrollback(__LINE__);
</ProgramListing>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Other statements</Term>
<ListItem>
<Para>
Other <Acronym>SQL</Acronym> statements are other statements that start with
<Command>exec sql</Command> and ends with <Command>;</Command>. Everything inbetween is treated
as an <Acronym>SQL</Acronym> statement and parsed for variable substitution.
<Para>
Variable substitution occur when a symbol starts with a colon
(<Command>:</Command>). Then a variable with that name is found among the variables
that were previously declared within a declare section and depending on
whether or not the <Acronym>SQL</Acronym> statements knows it to be a variable for input or
output the pointers to the variables are written to the output to allow
for access by the function.
<Para>
For every variable that is part of the <Acronym>SQL</Acronym> request the function gets
another five arguments.
<SimpleList>
<Member>The type as a special symbol</Member>
<Member>A pointer to the value</Member>
<Member>The size of the variable if it is a varchar</Member>
<Member>Number of elements in the array (for array fetches)</Member>
<Member>The offset to the next element in the array (for array fetches)</Member>
</SimpleList>
<Para>
Since the array fetches are not implemented yet the two last arguments
are not really important. They could perhaps have been left out.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Sect2>
<Sect2>
<Title>A Complete Example</Title>
<Para>
Here is a complete example describing the output of the preprocessor:
<ProgramListing>
exec sql begin declare section;
int index;
int result;
exec sql end declare section;
...
exec sql select res into :result from mytable where index = :index;
</ProgramListing>
is translated into:
<ProgramListing>
/* These two include files are added by the preprocessor */
#include &lt;ecpgtype.h&gt;
#include &lt;ecpglib.h&gt;
/* exec sql begin declare section */
int index;
int result;
/* exec sql end declare section */
...
ECPGdo(__LINE__, "select res from mytable where index = ;;",
ECPGt_int,&amp;index,0,0,sizeof(int),
ECPGt_EOIT,
ECPGt_int,&amp;result,0,0,sizeof(int),
ECPGt_EORT );
</ProgramListing>
(the indentation in this manual is added for readability and not
something that the preprocessor can do.)
<Sect2>
<Title>The Library</Title>
<Para>
The most important function in the library is the <Function>ECPGdo</Function>
function. It takes a variable amount of arguments. Hopefully we wont run
into machines with limits on the amount of variables that can be
accepted by a varchar function. This could easily add up to 50 or so
arguments.
<Para>
The arguments are:
<VariableList>
<VarListEntry>
<Term>A line number</Term>
<ListItem>
<Para>
This is a line number for the original line used in error messages only.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>A string</Term>
<ListItem>
<Para>
This is the <Acronym>SQL</Acronym> request that is to be issued. This request is modified
by the input variables, i.e. the variables that where not known at
compile time but are to be entered in the request. Where the variables
should go the string contains <Quote>;</Quote>.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Input variables</Term>
<ListItem>
<Para>
As described in the section about the preprocessor every input variable
gets five arguments.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>ECPGt_EOIT</Term>
<ListItem>
<Para>
An enum telling that there are no more input variables.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Output variables</Term>
<ListItem>
<Para>
As described in the section about the preprocessor every input variable
gets five arguments. These variables are filled by the function.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>ECPGt_EORT</Term>
<ListItem>
<Para>
An enum telling that there are no more variables.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
<Para>
All the <Acronym>SQL</Acronym> statements are performed in one transaction unless you issue
a commit transaction. This works so that the first transaction or the
first after a commit or rollback always begins a transaction.
<Para>
To be completed: entries describing the other entries.
</Chapter>
<Chapter>
<Title>Setting Up Your Environment</Title>
<Para>
This section discusses how to set up
your own environment so that you can use frontend
applications. We assume <ProductName>Postgres</ProductName> has already been
successfully installed and started; refer to the Administrator's Guide
and the installation notes
for how to install Postgres.
</Para>
<Para>
<ProductName>Postgres</ProductName> is a client/server application. As a user,
you only need access to the client portions of the installation (an example
of a client application is the interactive monitor <Application>psql</Application>).
For simplicity,
we will assume that <ProductName>Postgres</ProductName> has been installed in the
directory <FileName>/usr/local/pgsql</FileName>. Therefore, wherever
you see the directory <FileName>/usr/local/pgsql</FileName> you should
substitute the name of the directory where <ProductName>Postgres</ProductName> is
actually installed.
All <ProductName>Postgres</ProductName> commands are installed in the directory
<FileName>/usr/local/pgsql/bin</FileName>. Therefore, you should add
this directory to your shell command path. If you use
a variant of the Berkeley C shell, such as <Application>csh</Application> or <Application>tcsh</Application>,
you would add
<ProgramListing>
set path = ( /usr/local/pgsql/bin path )
</ProgramListing>
in the <FileName>.login</FileName> file in your home directory. If you use
a variant of the Bourne shell, such as <Application>sh</Application>, <Application>ksh</Application>, or
<Application>bash</Application>, then you would add
<ProgramListing>
PATH=/usr/local/pgsql/bin PATH
export PATH
</ProgramListing>
to the <FileName>.profile</FileName> file in your home directory.
From now on, we will assume that you have added the
<ProductName>Postgres</ProductName> bin directory to your path. In addition, we
will make frequent reference to <Quote>setting a shell
variable</Quote> or <Quote>setting an environment variable</Quote> throughout
this document. If you did not fully understand the
last paragraph on modifying your search path, you
should consult the UNIX manual pages that describe your
shell before going any further.
</Para>
<Para>
If your site administrator has not set things up in the
default way, you may have some more work to do. For example, if the database
server machine is a remote machine, you
will need to set the <Acronym>PGHOST</Acronym> environment variable to the name
of the database server machine. The environment variable
<Acronym>PGPORT</Acronym> may also have to be set. The bottom line is this: if
you try to start an application program and it complains
that it cannot connect to the <Application>postmaster</Application>,
you should immediately consult your site administrator to make sure that your
environment is properly set up.
</Para>
</Chapter>
<Chapter>
<Title>Extending <Acronym>SQL</Acronym>: An Overview</Title>
<Para>
In the sections that follow, we will discuss how you
can extend the <ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> query language by adding:
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
functions
</Para>
</ListItem>
<ListItem>
<Para>
types
</Para>
</ListItem>
<ListItem>
<Para>
operators
</Para>
</ListItem>
<ListItem>
<Para>
aggregates
</Para>
</ListItem>
</ItemizedList>
</Para>
<Sect1>
<Title>How Extensibility Works</Title>
<Para>
<ProductName>Postgres</ProductName> is extensible because its operation is
catalog-driven. If you are familiar with standard
relational systems, you know that they store information
about databases, tables, columns, etc., in what are
commonly known as system catalogs. (Some systems call
this the data dictionary). The catalogs appear to the
user as classes, like any other, but the <Acronym>DBMS</Acronym> stores
its internal bookkeeping in them. One key difference
between <ProductName>Postgres</ProductName> and standard relational systems is
that <ProductName>Postgres</ProductName> stores much more information in its
catalogs -- not only information about tables and columns,
but also information about its types, functions, access
methods, and so on. These classes can be modified by
the user, and since <ProductName>Postgres</ProductName> bases its internal operation
on these classes, this means that <ProductName>Postgres</ProductName> can be
extended by users. By comparison, conventional
database systems can only be extended by changing hardcoded
procedures within the <Acronym>DBMS</Acronym> or by loading modules
specially-written by the <Acronym>DBMS</Acronym> vendor.
</Para>
<Para>
<ProductName>Postgres</ProductName> is also unlike most other data managers in
that the server can incorporate user-written code into
itself through dynamic loading. That is, the user can
specify an object code file (e.g., a compiled .o file
or shared library) that implements a new type or function
and <ProductName>Postgres</ProductName> will load it as required. Code written
in <Acronym>SQL</Acronym> are even more trivial to add to the server.
This ability to modify its operation "on the fly" makes
<ProductName>Postgres</ProductName> uniquely suited for rapid prototyping of new
applications and storage structures.
</Para>
</Sect1>
<Sect1>
<Title>The <ProductName>Postgres</ProductName> Type System</Title>
<Para>
The <ProductName>Postgres</ProductName> type system can be broken down in several ways.
Types are divided into base types and composite types.
Base types are those, like <FirstTerm>int4</FirstTerm>, that are implemented
in a language such as <ProductName>C</ProductName>. They generally correspond to
what are often known as "abstract data types"; <ProductName>Postgres</ProductName>
can only operate on such types through methods provided
by the user and only understands the behavior of such
types to the extent that the user describes them.
Composite types are created whenever the user creates a
class. EMP is an example of a composite type.
</Para>
<Para>
<ProductName>Postgres</ProductName> stores these types in only one way (within the
file that stores all instances of the class) but the
user can "look inside" at the attributes of these types
from the query language and optimize their retrieval by
(for example) defining indices on the attributes.
<ProductName>Postgres</ProductName> base types are further divided into built-in
types and user-defined types. Built-in types (like
<FirstTerm>int4</FirstTerm>) are those that are compiled into the system.
User-defined types are those created by the user in the
manner to be described below.
</Para>
</Sect1>
<Sect1>
<Title>About the <ProductName>Postgres</ProductName> System Catalogs</Title>
<Para>
Having introduced the basic extensibility concepts, we
can now take a look at how the catalogs are actually
laid out. You can skip this section for now, but some
later sections will be incomprehensible without the
information given here, so mark this page for later
reference.
All system catalogs have names that begin with <FirstTerm>pg_</FirstTerm>.
The following classes contain information that may be
useful to the end user. (There are many other system
catalogs, but there should rarely be a reason to query
them directly.)
<TABLE TOCENTRY="1">
<TITLE>Postgres System Catalogs</TITLE>
<TITLEABBREV>Catalogs</TITLEABBREV>
<TGROUP COLS="2">
<THEAD>
<ROW>
<ENTRY>Catalog Name</ENTRY>
<ENTRY>Description</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>pg_database</ENTRY>
<ENTRY> databases</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_class</ENTRY>
<ENTRY> classes</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_attribute</ENTRY>
<ENTRY> class attributes</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_index</ENTRY>
<ENTRY> secondary indices</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_proc</ENTRY>
<ENTRY> procedures (both C and SQL)</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_type</ENTRY>
<ENTRY> types (both base and complex)</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_operator</ENTRY>
<ENTRY> operators</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_aggregate</ENTRY>
<ENTRY> aggregates and aggregate functions</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_am</ENTRY>
<ENTRY> access methods</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_amop</ENTRY>
<ENTRY> access method operators</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_amproc</ENTRY>
<ENTRY> access method support functions</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_opclass</ENTRY>
<ENTRY> access method operator classes</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
<Figure Id="EXTEND-CATALOGS" Float="1">
<Title>The major <ProductName>Postgres</ProductName> system catalogs</Title>
<Graphic Align="center" FileRef="catalogs.gif" Format="GIF"></Graphic>
</Figure>
The Reference Manual gives a more detailed explanation
of these catalogs and their attributes. However,
<XRef LinkEnd="EXTEND-CATALOGS" EndTerm="EXTEND-CATALOGS">
shows the major entities and their relationships
in the system catalogs. (Attributes that do not refer
to other entities are not shown unless they are part of
a primary key.)
This diagram is more or less incomprehensible until you
actually start looking at the contents of the catalogs
and see how they relate to each other. For now, the
main things to take away from this diagram are as follows:
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
In several of the sections that follow, we will
present various join queries on the system
catalogs that display information we need to extend
the system. Looking at this diagram should make
some of these join queries (which are often
three- or four-way joins) more understandable,
because you will be able to see that the
attributes used in the queries form foreign keys
in other classes.
</Para>
</ListItem>
<ListItem>
<Para> Many different features (classes, attributes,
functions, types, access methods, etc.) are
tightly integrated in this schema. A simple
create command may modify many of these catalogs.
</Para>
</ListItem>
<ListItem>
<Para> Types and procedures
are central to the schema.
<Note>
<Para>
We use the words <FirstTerm>procedure</FirstTerm> and <FirstTerm>function</FirstTerm> more or less
interchangably.
</Para>
</Note>
Nearly every catalog contains some reference to
instances in one or both of these classes. For
example, <ProductName>Postgres</ProductName> frequently uses type
signatures (e.g., of functions and operators) to
identify unique instances of other catalogs.
</Para>
</ListItem>
<ListItem>
<Para> There are many attributes and relationships that
have obvious meanings, but there are many
(particularly those that have to do with access
methods) that do not. The relationships between
pg_am, pg_amop, pg_amproc, pg_operator and
pg_opclass are particularly hard to understand
and will be described in depth (in the section
on interfacing types and operators to indices)
after we have discussed basic extensions.
</ListItem>
</ItemizedList>
</Para>
</Chapter>
<Chapter>
<Title>Functions</Title>
<Abstract>
<Para>
Reference information for user-callable functions.
</Para>
</Abstract>
<Note>
<Para>
This section needs to be written. Volunteers?
</Para>
</Note>
<Para>
</Para>
</Chapter>
<Chapter>
<DocInfo>
<Author>
<FirstName>Martin</FirstName>
<SurName>Utesch</SurName>
</Author>
</DocInfo>
<Title>Genetic Query Optimization in Database Systems</Title>
<Para>
<ProgramListing>
<ULink url="utesch@aut.tu-freiberg.de">Martin Utesch</ULink>
Institute of Automatic Control
University of Mining and Technology
Freiberg, Germany
02/10/1997
1.) Query Handling as a Complex Optimization Problem
====================================================
Among all relational operators the most difficult one to process and
optimize is the JOIN. The number of alternative plans to answer a query
grows exponentially with the number of JOINs included in it. Further
optimization effort is caused by the support of a variety of *JOIN
methods* (e.g., nested loop, index scan, merge join in Postgres) to
process individual JOINs and a diversity of *indices* (e.g., r-tree,
b-tree, hash in Postgres) as access paths for relations.
The current Postgres optimizer implementation performs a *near-
exhaustive search* over the space of alternative strategies. This query
optimization technique is inadequate to support database application
domains that involve the need for extensive queries, such as artificial
intelligence.
The Institute of Automatic Control at the University of Mining and
Technology, in Freiberg, Germany, encountered the described problems as its
folks wanted to take the Postgres DBMS as the backend for a decision
support knowledge based system for the maintenance of an electrical
power grid. The DBMS needed to handle large JOIN queries for the
inference machine of the knowledge based system.
Performance difficulties within exploring the space of possible query
plans arose the demand for a new optimization technique being developed.
In the following we propose the implementation of a *Genetic
Algorithm* as an option for the database query optimization problem.
2.) Genetic Algorithms (GA)
===========================
The GA is a heuristic optimization method which operates through
determined, randomized search. The set of possible solutions for the
optimization problem is considered as a *population* of *individuals*.
The degree of adaption of an individual to its environment is specified
by its *fitness*.
The coordinates of an individual in the search space are represented
by *chromosomes*, in essence a set of character strings. A *gene* is a
subsection of a chromosome which encodes the value of a single parameter
being optimized. Typical encodings for a gene could be *binary* or
*integer*.
Through simulation of the evolutionary operations *recombination*,
*mutation*, and *selection* new generations of search points are found
that show a higher average fitness than their ancestors.
According to the "comp.ai.genetic" FAQ it cannot be stressed too
strongly that a GA is not a pure random search for a solution to a
problem. A GA uses stochastic processes, but the result is distinctly
non-random (better than random).
Structured Diagram of a GA:
---------------------------
P(t) generation of ancestors at a time t
P''(t) generation of descendants at a time t
+=========================================+
|>>>>>>>>>>> Algorithm GA <<<<<<<<<<<<<<|
+=========================================+
| INITIALIZE t := 0 |
+=========================================+
| INITIALIZE P(t) |
+=========================================+
| evalute FITNESS of P(t) |
+=========================================+
| while not STOPPING CRITERION do |
| +-------------------------------------+
| | P'(t) := RECOMBINATION{P(t)} |
| +-------------------------------------+
| | P''(t) := MUTATION{P'(t)} |
| +-------------------------------------+
| | P(t+1) := SELECTION{P''(t) + P(t)} |
| +-------------------------------------+
| | evalute FITNESS of P''(t) |
| +-------------------------------------+
| | t := t + 1 |
+===+=====================================+
3.) Genetic Query Optimization (GEQO) in PostgreSQL
===================================================
The GEQO module is intended for the solution of the query
optimization problem similar to a traveling salesman problem (TSP).
Possible query plans are encoded as integer strings. Each string
represents the JOIN order from one relation of the query to the next.
E. g., the query tree /\
/\ 2
/\ 3
4 1 is encoded by the integer string '4-1-3-2',
which means, first join relation '4' and '1', then '3', and
then '2', where 1, 2, 3, 4 are relids in PostgreSQL.
Parts of the GEQO module are adapted from D. Whitley's Genitor
algorithm.
Specific characteristics of the GEQO implementation in PostgreSQL
are:
o usage of a *steady state* GA (replacement of the least fit
individuals in a population, not whole-generational replacement)
allows fast convergence towards improved query plans. This is
essential for query handling with reasonable time;
o usage of *edge recombination crossover* which is especially suited
to keep edge losses low for the solution of the TSP by means of a GA;
o mutation as genetic operator is deprecated so that no repair
mechanisms are needed to generate legal TSP tours.
The GEQO module gives the following benefits to the PostgreSQL DBMS
compared to the Postgres query optimizer implementation:
o handling of large JOIN queries through non-exhaustive search;
o improved cost size approximation of query plans since no longer
plan merging is needed (the GEQO module evaluates the cost for a
query plan as an individual).
References
==========
J. Heitk"otter, D. Beasley:
---------------------------
"The Hitch-Hicker's Guide to Evolutionary Computation",
FAQ in 'comp.ai.genetic',
'ftp://ftp.Germany.EU.net/pub/research/softcomp/EC/Welcome.html'
Z. Fong:
--------
"The Design and Implementation of the Postgres Query Optimizer",
file 'planner/Report.ps' in the 'postgres-papers' distribution
R. Elmasri, S. Navathe:
-----------------------
"Fundamentals of Database Systems",
The Benjamin/Cummings Pub., Inc.
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
* Things left to done for the PostgreSQL *
= Genetic Query Optimization (GEQO) =
* module implementation *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
* Martin Utesch * Institute of Automatic Control *
= = University of Mining and Technology =
* utesch@aut.tu-freiberg.de * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
1.) Basic Improvements
===============================================================
a) improve freeing of memory when query is already processed:
-------------------------------------------------------------
with large JOIN queries the computing time spent for the genetic query
optimization seems to be a mere *fraction* of the time Postgres
needs for freeing memory via routine 'MemoryContextFree',
file 'backend/utils/mmgr/mcxt.c';
debugging showed that it get stucked in a loop of routine
'OrderedElemPop', file 'backend/utils/mmgr/oset.c';
the same problems arise with long queries when using the normal
Postgres query optimization algorithm;
b) improve genetic algorithm parameter settings:
------------------------------------------------
file 'backend/optimizer/geqo/geqo_params.c', routines
'gimme_pool_size' and 'gimme_number_generations';
we have to find a compromise for the parameter settings
to satisfy two competing demands:
1. optimality of the query plan
2. computing time
c) find better solution for integer overflow:
---------------------------------------------
file 'backend/optimizer/geqo/geqo_eval.c', routine
'geqo_joinrel_size';
the present hack for MAXINT overflow is to set the Postgres integer
value of 'rel->size' to its logarithm;
modifications of 'struct Rel' in 'backend/nodes/relation.h' will
surely have severe impacts on the whole PostgreSQL implementation.
d) find solution for exhausted memory:
--------------------------------------
that may occur with more than 10 relations involved in a query,
file 'backend/optimizer/geqo/geqo_eval.c', routine
'gimme_tree' which is recursively called;
maybe I forgot something to be freed correctly, but I dunno what;
of course the 'rel' data structure of the JOIN keeps growing and
growing the more relations are packed into it;
suggestions are welcome :-(
2.) Further Improvements
===============================================================
Enable bushy query tree processing within PostgreSQL;
that may improve the quality of query plans.
</ProgramListing>
</Para>
</Chapter>
<Chapter>
<DocInfo>
<AuthorGroup>
<Author>
<FirstName>Gene</FirstName>
<Surname>Selkov</Surname>
</Author>
</AuthorGroup>
<Date>Transcribed 1998-02-19</Date>
</DocInfo>
<Title>GiST Indices</Title>
<Para>
<Note>
<Title>Caveat</Title>
<Para>
This extraction from an e-mail sent by
<ULink url="mailto:selkovjr@mcs.anl.gov">Eugene Selkov Jr.</ULink>
contains good information
on GiST. Hopefully we will learn more in the future and update this information.
- thomas
</Para>
</Note>
<Para>
Well, I can't say I quite understand what's going on, but at least
I (almost) succeeded in porting GiST examples to linux. The GiST access
method is already in the postgres tree (<FileName>src/backend/access/gist</FileName>).
<Para>
<ULink url="ftp://s2k-ftp.cs.berkeley.edu/pub/gist/pggist/pggist.tgz">Examples at Berkeley</ULink>
come with an overview of the methods and demonstrate spatial index
mechanisms for 2D boxes, polygons, integer intervals and text
(see also <ULink url="http://gist.cs.berkeley.edu:8000/gist/">GiST at Berkeley</ULink>).
In the box example, we
are supposed to see a performance gain when using the GiST index; it did
work for me but I do not have a reasonably large collection of boxes
to check that. Other examples also worked, except polygons: I got an
error doing
<ProgramListing>
test=> create index pix on polytmp using gist (p:box gist_poly_ops) with
(islossy);
ERROR: cannot open pix
(PostgreSQL 6.3 Sun Feb 1 14:57:30 EST 1998)
</ProgramListing>
<Para>
I could not get sense of this error message; it appears to be something
we'd rather ask the developers about (see also Note 4 below). What I
would suggest here is that someone of you linux guys (linux==gcc?) fetch the
original sources quoted above and apply my patch (see attachment) and
tell us what you feel about it. Looks cool to me, but I would not like
to hold it up while there are so many competent people around.
<Para>
A few notes on the sources:
<Para>
1. I failed to make use of the original (HPUX) Makefile and rearranged
the Makefile from the ancient postgres95 tutorial to do the job. I
tried
to keep it generic, but I am a very poor makefile writer -- just did
some monkey work. Sorry about that, but I guess it is now a little
more portable that the original makefile.
<Para>
2. I built the example sources right under pgsql/src (just extracted the
tar file there). The aforementioned Makefile assumes it is one level
below pgsql/src (in our case, in pgsql/src/pggist).
<Para>
3. The changes I made to the *.c files were all about #include's,
function prototypes and typecasting. Other than that, I just threw
away a bunch of unused vars and added a couple parentheses to please
gcc. I hope I did not screw up too much :)
<Para>
4. There is a comment in polyproc.sql:
<ProgramListing>
-- -- there's a memory leak in rtree poly_ops!!
-- -- create index pix2 on polytmp using rtree (p poly_ops);
</ProgramListing>
Roger that!! I thought it could be related to a number of
<ProductName>Postgres</ProductName> versions
back and tried the query. My system went nuts and I had to shoot down
the postmaster in about ten minutes.
<Para>
I will continue to look into GiST for a while, but I would also
appreciate
more examples of R-tree usage.
</Chapter>
<Chapter>
<Title>Inheritance</Title>
<Para>
Let's create two classes. The capitals class contains
state capitals which are also cities. Naturally, the
capitals class should inherit from cities.
<ProgramListing>
CREATE TABLE cities (
name text,
population float,
altitude int -- (in ft)
);
CREATE TABLE capitals (
state char2
) INHERITS (cities);
</ProgramListing>
In this case, an instance of capitals <FirstTerm>inherits</FirstTerm> all
attributes (name, population, and altitude) from its
parent, cities. The type of the attribute name is
<Type>text</Type>, a native <ProductName>Postgres</ProductName> type for variable length
ASCII strings. The type of the attribute population is
<Type>float</Type>, a native <ProductName>Postgres</ProductName> type for double precision
floating point numbers. State capitals have an extra
attribute, state, that shows their state. In <ProductName>Postgres</ProductName>,
a class can inherit from zero or more other classes,
and a query can reference either all instances of a
class or all instances of a class plus all of its
descendants.
<Note>
<Para>
The inheritance hierarchy is a actually a directed acyclic graph.
</Para>
</Note>
For example, the following query finds
all the cities that are situated at an attitude of 500ft or higher:
<ProgramListing>
SELECT name, altitude
FROM cities
WHERE altitude &gt; 500;
+----------+----------+
|name | altitude |
+----------+----------+
|Las Vegas | 2174 |
+----------+----------+
|Mariposa | 1953 |
+----------+----------+
</ProgramListing>
<Para>
On the other hand, to find the names of all cities,
including state capitals, that are located at an altitude
over 500ft, the query is:
<ProgramListing>
SELECT c.name, c.altitude
FROM cities* c
WHERE c.altitude > 500;
</ProgramListing>
which returns:
<ProgramListing>
+----------+----------+
|name | altitude |
+----------+----------+
|Las Vegas | 2174 |
+----------+----------+
|Mariposa | 1953 |
+----------+----------+
|Madison | 845 |
+----------+----------+
</ProgramListing>
Here the <Quote>*</Quote> after cities indicates that the query should
be run over cities and all classes below cities in the
inheritance hierarchy. Many of the commands that we
have already discussed -- <Command>select</Command>, <Command>update</Command> and <Command>delete</Command> --
support this <Quote>*</Quote> notation, as do others, like <Command>alter</Command>.
</Para>
</Chapter>
<Chapter>
<Title>Installation</Title>
<Abstract>
<Para>
Complete installation instructions for <ProductName>Postgres</ProductName> v6.3.
</Para>
</Abstract>
<Para>
This procedure is
This is based on the installation instructions
for <ProductName>Postgres</ProductName> v6.3
found in <FileName>&dollar;PGROOT/INSTALL</FileName>.
Up to date information on <ProductName>Postgres</ProductName> may be found at
<ULink url="http://www.postgresql.org">www.postgresql.org</ULink>.
</Para>
<Para>
The installation notes below assume the following (except where noted):
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
Commands are Unix-compatible. See note below.
</Para>
</ListItem>
<ListItem>
<Para>
Defaults are used except where noted.
</Para>
</ListItem>
<ListItem>
<Para>
User postgres is the <ProductName>Postgres</ProductName> superuser.
</Para>
</ListItem>
<ListItem>
<Para>
The source path is /usr/src/pgsql (other paths are possible).
</Para>
</ListItem>
<ListItem>
<Para>
The runtime path is /usr/local/pgsql (other paths are possible).
</Para>
</ListItem>
</ItemizedList>
<Para>
Commands were tested on RedHat Linux version 4.2 using the tcsh shell.
Except where noted, they will probably work on most systems. Commands
like ps and tar vary wildly on what options you should use on each
platform. <Emphasis>Use common sense</Emphasis> before typing in these commands.
</Para>
<Para>
Our Makefiles require GNU <Application>make</Application> (called <Quote>gmake</Quote> in this document) and
also assume that <Application>install</Application> accepts BSD options. The INSTALL
variable in the Makefiles is set to the BSD-compatible version of
<Application>install</Application>. On some systems, you will have to find a BSD-compatible
<Application>install</Application> (eg. <Application>bsdinst</Application>, which comes with the MIT X Window System
distribution).
</Para>
<Sect1>
<Title>Requirements to Run <ProductName>Postgres</ProductName></Title>
<Para>
Information on supported platforms is another chapter. In general, most Unix-compatible
platforms with modern libraries should be able to run <ProductName>Postgres</ProductName>.
<Para>
You should have at least 8 MB of memory and at least 45 MB of disk space
to hold the source, binaries, and user databases. After installation
you may reduce this to about 3 Mbytes plus space for user databases.
</Para>
</Sect1>
<Sect1>
<Title>Installation Procedure</Title>
<Para>
<Procedure>
<Title><ProductName>Postgres</ProductName> Installation</Title>
<Para>
For a fresh install or upgrading from previous releases of
<ProductName>Postgres</ProductName>:
</Para>
<Step Performance="required">
<Para>
Read any last minute information and platform specific porting
notes. There are some platform specific notes at the end of this
file for Ultrix4.x, Linux, BSD/OS and NeXT. There are other
files in directory <FileName>/usr/src/pgsql/doc</FileName>, including files FAQ-Irix
and FAQ-Linux. Also look in directory
<ULink url="ftp://ftp.postgresql.org/pub">ftp://ftp.postgresql.org/pub</ULink>.
If there is a file called INSTALL in this directory then this
file will contain the latest installation information.
</Para>
<Para>
Please note that a "tested" platform in the list given earlier
simply means that someone went to the effort at some point of making
sure that a <ProductName>Postgres</ProductName> distribution would compile and run on this
platform without modifying the code. Since the current developers
will not have access to all of these platforms, some of them may not
compile cleanly and pass the regression tests in the current
release due to minor problems. Any such known problems and their
solutions will be posted in
<ULink url="ftp://ftp.postgresql.org/pub/INSTALL">ftp://ftp.postgresql.org/pub/INSTALL</ULink>.
</Para>
</Step>
<Step Performance="optional">
<Para>
Create account postgres if it does not already exist.
</Para>
</Step>
<Step Performance="required">
<Para>
Log into account postgres.
</Para>
<SubSteps>
<Step Performance="required">
<Para>
Check that you have sufficient disk space. You will need about
17 Mbytes for /usr/src/pgsql, about 2 Mbytes for /usr/local/pgsql
(excluding your database) and 1 Mbyte for an empty database.
The database will temporarily grow to about 20 Mbytes during the
regression tests. You will also need about 3 Mbytes for the
distribution tar file.
</Para>
<Para>
We therefore recommend that during installation and testing you
have well over 20 Mbytes free under /usr/local and another 25 Mbytes
free on the disk partition containing your database. Once you
delete the source files, tar file and regression database, you
will need 2 Mbytes for /usr/local/pgsql, 1 Mbyte for the empty
database, plus about five times the space you would require to
store your database data in a flat file.
</Para>
<Para>
To check for disk space, use <Command>df -k</Command>.
</Para>
</Step>
</SubSteps>
</Step>
<Step Performance="required">
<Para>
Ftp file ftp://ftp.postgresql.org/pub/postgresql-v6.3.tar.gz from the
Internet. Store it in your home directory.
</Para>
</Step>
<Step Performance="required">
<Para>
Some platforms use flex. If your system uses flex then make sure
you have a good version. To check, type <Command>flex --version</Command>.
</Para>
<Para>
If the flex command is not found then you probably do not need it.
If the version is 2.5.2 or 2.5.4 or greater then you are okay. If it
is 2.5.3 or before 2.5.2 then you will have to upgrade flex. You may
get it at ftp://prep.ai.mit.edu/pub/gnu/flex-2.5.4.tar.gz.
</Para>
<Para>
If you need flex and don't have it or have the wrong version, then
you will be told so when you attempt to compile the program. Feel
free to skip this step if you aren't sure you need it. If you do
need it then you will be told to install/upgrade flex when you try to
compile.
</Para>
<Para>
To install it, type the following:
<ProgramListing>
cd
gunzip -c flex-2.5.4.tar.gz | tar xvf -
cd flex-2.5.4
configure --prefix=/usr
make
make check
# You must be root when typing the next line.
make install
cd
rm -rf flex-2.5.4
</ProgramListing>
</Para>
<Para>
This will update files /usr/man/man1/flex.1, /usr/bin/flex,
/usr/lib/libfl.a, /usr/include/FlexLexer.h and will add link
/usr/bin/flex++ which points to flex.
</Para>
</Step>
<Step Performance="required">
<Para>
If you are upgrading an existing system then back up your database.
For alpha- and beta-level releases, the database format is liable
to change often every few weeks with no notice besides a quick comment
in the HACKERS mailing list. Full releases always require a dump/reload
from previous releases. It is therefore a bad idea to skip this
step. Also, do not use the pg_dumpall script from v6.0 or everything
will be owned by the <ProductName>Postgres</ProductName> super user.
Type (with the gunzip line
and the following line typed as one line):
<ProgramListing>
cd
gunzip -c postgresql-v6.3.tar.gz |
tar xvf - src/bin/pg_dump/pg_dumpall
chmod a+x src/bin/pg_dump/pg_dumpall
src/bin/pg_dump/pg_dumpall > db.out
rm -rf src
</ProgramListing>
</Para>
<Para>
If you wish to preserve object id's (oids), then use the -o
option when running pg_dumpall. However, unless you have a
special reason for doing this, don't do it.
</Para>
<Para>
If the pg_dumpall command seems to take a long time and you think
it might have died, then, from another terminal, use "ls -l db.out"
several times to see if the size of the file is growing.
</Para>
<Para>
Please note that if you are upgrading from a version prior to
<ProductName>Postgres95</ProductName> v1.09 then you must back up your database, install
<ProductName>Postgres95</ProductName> v1.09, restore your database, then back it up again.
You should also read files /usr/src/pgsql/migration/*.
</Para>
<Para>
You must make sure that your database is not updated in the middle of
your backup. If necessary, bring down postmaster, edit the permissions
in file /usr/local/pgsql/data/pg_hba.conf to allow only you on, then
bring postmaster back up.
</Para>
</Step>
<Step Performance="required">
<Para>
If you are upgrading an existing system then kill the postmaster. Type
<ProgramListing>
ps -ax | grep postmaster
</ProgramListing>
This should list the process numbers for a number of processes. Type
the following line, with "???" replaced by the process id for process
"postmaster". (Do not use the id for process "grep postmaster".) Type
kill ???
with "???" modified as indicated.
</Para>
</Step>
<Step Performance="required">
<Para>
If you are upgrading an existing system then move the old directories
out of the way. If you are short of disk space then you may have to
back up and delete the directories instead. If you do this, save the
old database in the /usr/local/pgsql/data directory tree. At a
minimum, save file /usr/local/pgsql/data/pg_hba.conf.
</Para>
<Para>
Type the following:
su
cd /usr/src
mv pgsql pgsql_6_0
cd /usr/local
mv pgsql pgsql_6_0
exit
</Para>
<Para>
If you are not using /usr/local/pgsql/data as your data directory
(check to see if environment variable PGDATA is set to something
else) then you will also want to move this directory in the same
manner.
</Para>
</Step>
<Step Performance="required">
<Para>
Make new source and install directories. The actual paths can be
different for your installation; be consistant throughout this procedure.
Type
<ProgramListing>
su
cd /usr/src
mkdir pgsql
chown postgres:postgres pgsql
cd /usr/local
mkdir pgsql
chown postgres:postgres pgsql
exit
</ProgramListing>
</Para>
</Step>
<Step Performance="required">
<Para>
Unzip and untar the new source file. Type
<ProgramListing>
cd /usr/src/pgsql
gunzip -c ~/postgresql-v6.3.tar.gz | tar xvf -
</ProgramListing>
</Para>
</Step>
<Step Performance="required">
<Para>
Configure the source code for your system. It is this step at which
you can specify your actual source path and installation paths for
the build process (see the --prefix option below). Type
<ProgramListing>
cd /usr/src/pgsql/src
./configure
</ProgramListing>
</Para>
<Para>
The configure program will list the template files available and
ask you to choose one. A lot of times, an appropriate template
file is chosen for you, and you can just press Enter to accept the
default. If the default is not appropriate, then type in the
appropriate template file and press Enter. (If you do this, then
send email to scrappy@hub.org stating the output of the program
'./config.guess' and what the template file should be.)
</Para>
<Para>
Once you have entered the template file, you will be asked a
number of questions about your particular configuration. These
can be skipped by adding parameters to the configure command above.
The following parameters can be tagged onto the end of the configure
command:
<ProgramListing>
--prefix=BASEDIR Selects a different base directory for the
installation of the <ProductName>Postgres</ProductName> configuration.
The default is /usr/local/pgsql.
--enable-hba Enables Host Based Authentication (DEFAULT)
--disable-hba Disables Host Based Authentication
--enable-locale Enables USE_LOCALE
--disable-locale Disables USE_LOCALE (DEFAULT)
--enable-cassert Enables ASSERT_CHECKING
--disable-cassert Disables ASSERT_CHECKING (DEFAULT)
--with-template=TEMPLATE
Use template file TEMPLATE - the template
files are assumed to be in the directory
src/template, so look there for proper values.
(If the configure script cannot find the
specified template file, it will ask you for
one).
--with-pgport=PORT Sets the port that the postmaster process
listens for incoming connections on. The
default for this is port 5432.
</ProgramListing>
</Para>
<Para>
As an example, here is the configure script I use on a Sparc
Solaris 2.5 system with /opt/postgres being the install base.
<ProgramListing>
./configure --prefix=/opt/postgres \
--with-template=sparc_solaris-gcc --with-pgport=5432 \
--enable-hba --disable-locale
</ProgramListing>
Of course, in a real shell, you would type these three lines all
on the same line.
</Para>
</Step>
<Step Performance="required">
<Para>
Compile the program. Type
<ProgramListing>
cd /usr/src/pgsql/src
gmake all >& make.log &
tail -f make.log
</ProgramListing>
</Para>
<Para>
The last line displayed will hopefully be "All of PostgreSQL is
successfully made. Ready to install." At this point, or earlier
if you wish, type control-C to get out of tail. (If you have
problems later on you may wish to examine file make.log for
warning and error messages.)
</Para>
<Para>
If your computer does not have gmake (GNU make) then try running
make instead throughout the rest of these notes.
</Para>
<Para>
Please note that you will probably find a number of warning
messages in make.log. Unless you have problems later on, these
messages may be safely ignored.
</Para>
<Para>
If the compiler fails with an error stating that the flex command
cannot be found then install flex as described earlier. Next,
change directory back to this directory, type "make clean", then
recompile again.
</Para>
</Step>
<Step Performance="required">
<Para>
Install the program. Type
<ProgramListing>
cd /usr/src/pgsql/src
gmake install >& make.install.log &
tail -f make.install.log
</ProgramListing>
</Para>
<Para>
The last line displayed will be "gmake[1]: Leaving directory
`/usr/src/pgsql/src/man'". At this point, or earlier if you wish,
type control-C to get out of tail.
</Para>
</Step>
<Step Performance="required">
<Para>
If necessary, tell UNIX how to find your shared libraries. If you
are using Linux-ELF do ONE of the following, preferably the first:
<SubSteps>
<Step Performance="optional">
<Para>
As root, edit file /etc/ld.so.conf. Add line
<FileName>/usr/local/pgsql/lib</FileName>
to the file. Then run command <Command>/sbin/ldconfig</Command>.
</Para>
</Step>
<Step Performance="optional">
<Para>
In a bash shell, type
<ProgramListing>
export LD_LIBRARY_PATH=/usr/local/pgsql/lib
</ProgramListing>
</Para>
</Step>
<Step Performance="optional">
<Para>
In a csh shell, type
<ProgramListing>
setenv LD_LIBRARY_PATH /usr/local/pgsql/lib
</ProgramListing>
</Step>
</SubSteps>
<Para>
Please note that the above commands may vary wildly for different
operating systems. Check the platform specific notes, such as
those for Ultrix4.x or and for non-ELF Linux.
</Para>
<Para>
If, when you create the database, you get the message "pg_id: can't
load library 'libpq.so'" then the above step was necessary. Simply
do this step, then try to create the database again.
</Para>
</Step>
<Step Performance="required">
<Para>
If it has not already been done, then prepare account postgres
for using <ProductName>Postgres</ProductName>. Any account that will use <ProductName>Postgres</ProductName> must
be similarily prepared. (The following instructions are for a
bash shell. Adapt accordingly for other shells.)
</Para>
<Para>
Add the following lines to your login shell, ~/.bash_profile:
<ProgramListing>
PATH=$PATH:/usr/local/pgsql/bin
MANPATH=$MANPATH:/usr/local/pgsql/man
PGLIB=/usr/local/pgsql/lib
PGDATA=/usr/local/pgsql/data
export PATH MANPATH PGLIB PGDATA
</ProgramListing>
</Para>
<Para>
Make sure that you have defined these variables before continuing
with the remaining steps. The easiest way to do this is to type:
<ProgramListing>
source ~/.bash_profile
</ProgramListing>
</Para>
</Step>
<Step Performance="required">
<Para>
Create the database. <Emphasis>Do not do the following as root!</Emphasis>
This would be a major security hole. Type
<ProgramListing>
initdb
</ProgramListing>
</Para>
</Step>
<Step Performance="required">
<Para>
Set up permissions to access the database system. Do this by editing
file /usr/local/pgsql/data/pg_hba.conf. The instructions are
included in the file. (If your database is not located in the
default location, i.e. if PGDATA is set to point elsewhere, then the
location of this file will change accordingly.) This file should be
made read only again once you are finsihed.
If you are upgrading from v6.0 you can copy file pg_hba.conf from
your old database on top of the one in your new database, rather than
redoing this from scratch.
</Para>
</Step>
<Step Performance="required">
<Para>
You may wish to skip the regression tests.
However, we think skipping the tests is a BAD idea!
</Para>
<Para>
The file /usr/src/pgsql/src/test/regress/README has detailed
instructions for running and interpreting the regression tests.
A short version follows here:
</Para>
<Para>
Start the postmaster daemon running in the background by typing
<ProgramListing>
cd
nohup postmaster > regress.log 2>&1 &
</ProgramListing>
</Para>
<Para>
Run postmaster from your <ProductName>Postgres</ProductName> super user account (typically
account postgres). DO NOT RUN POSTMASTER FROM THE ROOT ACCOUNT.
</Para>
</Step>
<Step Performance="required">
<Para>
Run the regression tests. Type
<ProgramListing>
cd
cd /usr/src/pgsql/src/test/regress
gmake clean
gmake all runtest
</ProgramListing>
</Para>
<Para>
You do not need to type "gmake clean" if this is the first time you
are running the tests.
</Para>
<Para>
You should get on the screen (and also written to file ./regress.out)
a series of statements stating which tests passed and which tests
failed. Please note that it can be normal for some of the tests to
"fail". For the failed tests, use diff to compare the files in
directories ./results and ./expected. If float8 failed, type
something like:
<ProgramListing>
cd /usr/src/pgsql/src/test/regress
diff -w expected/float8.out results
</ProgramListing>
</Para>
<Para>
"Failed" tests may have failed due to slightly different error messages,
output formatting, failure to set the timezone correctly for your
platform, etc. "Failures" of this type do not indicate a problem with
<ProductName>Postgres</ProductName>.
</Para>
<Para>
For a i686/Linux-ELF platform, no tests failed since this is the
v6.3 regression testing reference platform.
</Para>
<Para>
For the SPARC/Linux-ELF platform, using the 970525 beta version of
<ProductName>Postgres</ProductName> v6.2 the following tests "failed":
float8 and geometry "failed" due to minor precision differences in
floating point numbers. select_views produces massively different output,
but the differences are due to minor floating point differences.
</Para>
<Para>
Conclusion? If you do see failures, try to understand the nature of
the differences and then decide if those differences will affect your
intended use of <ProductName>Postgres</ProductName>. However, keep in mind that this is likely
to be the most solid release of <ProductName>Postgres</ProductName> to date, incorporating many
bug fixes from v6.2.1, and that previous versions of <ProductName>Postgres</ProductName> have been
in use successfully for some time now.
</Para>
<Para>
After running the tests, type
<ProgramListing>
destroydb regression
cd /usr/src/pgsql/src/test/regress
gmake clean
</ProgramListing>
</Para>
</Step>
<Step Performance="required">
<Para>
Stop the postmaster as described in step 7. Then restore the
timezone to it's normal setting. If you changed the timezone by
modifying environment variable TZ then one way to do this is to
log out of, then back into, account postgres.
</Para>
</Step>
<Step Performance="required">
<Para>
Start the postmaster daemon running. Type
<ProgramListing>
cd
nohup postmaster > server.log 2>&1 &
</ProgramListing>
Run postmaster from your <ProductName>Postgres</ProductName> super user account (typically
account postgres). DO NOT RUN POSTMASTER FROM THE ROOT ACCOUNT.
</Para>
</Step>
<Step Performance="required">
<Para>
If you haven't already done so, this would be a good time to modify
your computer so that it will automatically start postmaster whenever
you boot your computer.
Here are some suggestions on how to do this, contributed by various
users.
Whatever you do, postmaster must be run by user postgres AND NOT BY
ROOT. This is why all of the examples below start by switching user
(su) to postgres. These commands also take into account the fact
that environment variables like PATH and PGDATA may not be set properly.
The examples are as follows. Use them with extreme caution.
a) Edit file rc.local on NetBSD or file rc2.d on SPARC Solaris
2.5.1 to contain the following single line:
su postgres -c "/usr/local/pgsql/bin/postmaster -S -D
/usr/local/pgsql/data"
b) In FreeBSD 2.2-RELEASE edit /usr/local/etc/rc.d/pgsql.sh to
contain the following lines and make it chmod 755 and chown
root:bin.
#!/bin/sh
[ -x /usr/local/pgsql/bin/postmaster ] && {
su -l pgsql -c 'exec /usr/local/pgsql/bin/postmaster
-D/usr/local/pgsql/data
-S -o -F > /usr/local/pgsql/errlog' &
echo -n ' pgsql'
}
You may put the line breaks as shown above. The shell is smart
enough to keep parsing beyond end-of-line if there is an
expression unfinished. The exec saves one layer of shell under
the postmaster process so the parent is init. Note: Unlike most
other examples, this one has been tested.
c) In RedHat v4.0 Linux edit file /etc/inittab to contain the
following single line:
pg:2345:respawn:/bin/su - postgres -c
"/usr/local/pgsql/bin/postmaster -D/usr/local/pgsql/data
>> /usr/local/pgsql/server.log 2>&1" /dev/null
(The author of this example says this example will revive the
postmaster if it dies, but he doesn't know if there are other side
effects.)
d) The contrib/linux area of the <ProductName>Postgres</ProductName> distribution has an example
init.d script compatible with and tested using recent RedHat packages.
</Para>
</Step>
<Step Performance="required">
<Para>
If you haven't already done so, this would be a good time to modify
your computer to do regular maintainence. The following should be
done at regular intervals:
a) Run the SQL command vacuum. This will clean up your database.
b) Back up your system. (You should probably keep the last few
backups on hand.) Ideally, no one else should be using the
system at the time.
Ideally, the above tasks should be done by a shell script that is
run nightly or weekly by cron. Look at the man page for crontab
for a starting point on how to do this. (If you do it, please
e-mail us a copy of your shell script. We would like to set up
our own systems to do this too.)
</Para>
</Step>
<Step Performance="required">
<Para>
If you are upgrading an existing system then install your old database.
Type
<ProgramListing>
cd
psql -e template1 < db.out
</ProgramListing>
If your pre-v6.2 database uses either path or polygon geometric data types,
then you will need to upgrade any columns containing those types. To
do so, type (from within psql)
<ProgramListing>
update YourTable set PathCol = UpgradePath(PathCol);
update YourTable set PolyCol = UpgradePoly(PolyCol);
...
vacuum;
</ProgramListing>
UpgradePath() checks to see that a path value is consistant with the
old syntax, and will not update a column which fails that examination.
UpgradePoly() cannot verify that a polygon is in fact from an old
syntax, but RevertPoly() is provided to reverse the effects of a
mis-applied upgrade.
</Para>
</Step>
<Step Performance="required">
<Para>
If you are a new user, you may wish to play with <ProductName>Postgres</ProductName> as described
below.
</Para>
</Step>
<Step Performance="required">
<Para>
Clean up after yourself. Type
<ProgramListing>
rm -rf /usr/src/pgsql_6_0
rm -rf /usr/local/pgsql_6_0
# Also delete old database directory tree if it is not in
# /usr/local/pgsql_6_0/data
rm ~/postgresql-v6.2.1.tar.gz
</ProgramListing>
</Para>
</Step>
<Step Performance="required">
<Para>
You will probably want to print out the documentation. Here is how
you might do it if you have Ghostscript on your system and are
writing to a laserjet printer.
alias gshp='gs -sDEVICE=laserjet -r300 -dNOPAUSE'
export GS_LIB=/usr/share/ghostscript:/usr/share/ghostscript/fonts
# Print out the man pages.
man -a -t /usr/local/pgsql/man/*/* > manpage.ps
gshp -sOUTPUTFILE=manpage.hp manpage.ps
rm manpage.ps
lpr -l -s -r manpage.hp
# Print out the Postgres95 User Manual, version 1.0,
# Sept. 5, 1996.
cd /usr/src/pgsql/doc
gshp -sOUTPUTFILE=userguide.hp userguide.ps
lpr -l -s -r userguide.hp
If you are a developer, you will probably want to also print out
the Postgres Implemention Guide, version 1.0, October 1, 1995.
This is a WWW document located at
http://www.postgresql.org/docs/impguide.
</Para>
</Step>
<Step Performance="required">
<Para>
The <ProductName>Postgres</ProductName> team wants to keep <ProductName>Postgres</ProductName> working on all of the
supported platforms. We therefore ask you to let us know if you did
or did not get <ProductName>Postgres</ProductName> to work on you system. Please send a
mail message to pgsql-ports@postgresql.org telling us the following:
- The version of <ProductName>Postgres</ProductName> (v6.2.1, 6.1.1, beta 970703, etc.).
- Your operating system (i.e. RedHat v4.0 Linux v2.0.26).
- Your hardware (SPARC, i486, etc.).
- Did you compile, install and run the regression tests cleanly?
If not, what source code did you change (i.e. patches you
applied, changes you made, etc.), what tests failed, etc.
It is normal to get many warning when you compile. You do
not need to report these.
</Para>
</Step>
<Step Performance="required">
<Para>
Now create, access and manipulate databases as desired. Write client
programs to access the database server. In other words, ENJOY!
</Para>
</Step>
</Procedure>
<Sect1>
<Title>Playing with <ProductName>Postgres</ProductName></Title>
<Para>
After <ProductName>Postgres</ProductName> is installed, a database system is created, a postmaster
daemon is running, and the regression tests have passed, you'll want to
see <ProductName>Postgres</ProductName> do something. That's easy. Invoke the interactive interface
to <ProductName>Postgres</ProductName>, <Application>psql</Application>:
<ProgramListing>
% psql template1
</ProgramListing>
(psql has to open a particular database, but at this point the only one
that exists is the template1 database, which always exists. We will connect
to it only long enough to create another one and switch to it.)
</Para>
<Para>
The response from psql is:
<ProgramListing>
Welcome to the POSTGRESQL interactive sql monitor:
Please read the file COPYRIGHT for copyright terms of POSTGRESQL
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: template1
template1=>
</ProgramListing>
</Para>
<Para>
Create the database foo:
<ProgramListing>
template1=> create database foo;
CREATEDB
</ProgramListing>
(Get in the habit of including those SQL semicolons. Psql won't execute
anything until it sees the semicolon or a "\g" and the semicolon is required
to delimit multiple statements.)
</Para>
<Para>
Now connect to the new database:
<ProgramListing>
template1=> \c foo
connecting to new database: foo
</ProgramListing>
("slash" commands aren't SQL, so no semicolon. Use \? to see all the slash commands.)
</Para>
<Para>
And create a table:
<ProgramListing>
foo=> create table bar (i int4, c char(16));
CREATE
</ProgramListing>
</Para>
<Para>
Then inspect the new table:
<ProgramListing>
foo=> \d bar
Table = bar
+----------------------------------+----------------------------------+-------+
| Field | Type | Length|
+----------------------------------+----------------------------------+-------+
| i | int4 | 4 |
| c | (bp)char | 16 |
+----------------------------------+----------------------------------+-------+
</ProgramListing>
</Para>
<Para>
And so on. You get the idea.
</Para>
</Sect1>
<Sect1>
<Title>The Next Step</Title>
<Para>
Questions? Bugs? Feedback?
First, read the files in directory /usr/src/pgsql/doc. The FAQ in
this directory may be particularly useful.
</Para>
<Para>
If <ProductName>Postgres</ProductName> failed to compile on your computer then fill out the form
in file /usr/src/pgsql/doc/bug.template and mail it to the location
indicated at the top of the form.
</Para>
<Para>
Mail questions to
<ULink url="pgsql-questions@postgresql.org">pgsql-questions@postgresql.org</ULink>.
For more information on the various mailing lists, see
<ULink url="http://www.postgresql.org">http://www.postgresql.org</ULink>
and look for the mailing lists.
</Para>
</Sect1>
<Sect1>
<Title>Porting Notes</Title>
<Note>
<Para>
For some ports, these notes may be out of date.
</Para>
</Note>
<Sect2>
<Title>Ultrix4.x</Title>
<Para>
You need to install the libdl-1.1 package since Ultrix 4.x doesn't
have a dynamic loader. It's available in
s2k-ftp.CS.Berkeley.EDU:pub/personal/andrew/libdl-1.1.tar.Z
</Para>
</Sect2>
<Sect2>
<Title>Linux</Title>
<Sect3>
<Sect3Info>
<Author>
<FirstName>Thomas G.</FirstName>
<SurName>Lockhart</SurName>
</Author>
<Date>1998-02-19</Date>
</Sect3Info>
<Title>Linux ELF</Title>
<Para>
The regression test reference machine is
a linux-2.0.30/libc-5.3.12/RedHat-4.2 installation running on a dual processor i686.
The linux-elf port installs cleanly. See the Linux FAQ for more details.
</Para>
</Sect3>
<Sect3>
<Sect3Info>
<Date>1995-05-11</Date>
</Sect3Info>
<Title>Linux a.out</Title>
<Para>
For non-ELF Linux, the dld library MUST be obtained and installed on
the system. It enables dynamic link loading capability to the <ProductName>Postgres</ProductName>
port. The dld library can be obtained from the sunsite linux
distributions. The current name is dld-3.2.5.
<ULink url="sneaker@powergrid.electriciti.com">Jalon Q. Zimmerman</ULink>
</Para>
</Sect3>
</Sect2>
<Sect2>
<Title>BSD/OS</Title>
<Para>
For BSD/OS 2.0 and 2.01, you will need to get the GNU dld library.
</Para>
</Sect2>
<Sect2>
<Title>NeXT</Title>
<Para>
The NeXT port for v1.09 was supplied by
<ULink url="mailto:tom@basil.icce.rug.nl">Tom R. Hageman</ULink>.
It requires a SysV IPC emulation library and header files for
shared libary and semaphore stuff. Tom just happens to sell such
a product so contact him for information. He has also indicated that
binary releases of <ProductName>Postgres</ProductName> for NEXTSTEP will be made available to
the general public. Contact Info@RnA.nl for information.
<Para>
We have no recent reports of successful NeXT installations (for v6.2.1).
However, the client-side libraries should work even
if the backend is not supported.
</Para>
</Sect2>
</Sect1>
</Chapter>
<Chapter>
<TITLE>Introduction</TITLE>
<Para>
This document is the programmer's manual for the
<Ulink url="http://postgresql.org/"><ProductName>PostgreSQL</ProductName></Ulink>
database management system, originally developed at the University
of California at Berkeley. <ProductName>PostgreSQL</ProductName> is based on
<Ulink url="http://s2k-ftp.CS.Berkeley.EDU:8000/postgres/postgres.html">
<ProductName>Postgres release 4.2</ProductName></Ulink>.
The <ProductName>Postgres</ProductName> project,
led by Professor Michael Stonebraker, has been sponsored by the
Defense Advanced Research Projects Agency (<Acronym>DARPA</Acronym>), the
Army Research Office (<Acronym>ARO</Acronym>), the National Science
Foundation (<Acronym>NSF</Acronym>), and ESL, Inc.
</Para>
<Para>
The first part of this manual
explains the
<ProductName>Postgres</ProductName> approach to extensibility and describe how
users can extend <ProductName>Postgres</ProductName> by adding user-defined types,
operators, aggregates, and both query language and programming language functions.
After an extremely brief
overview of the <ProductName>Postgres</ProductName> rule system, we discuss
the trigger and SPI interfaces.
The manual concludes with a detailed description of the programming interfaces and
support libraries for various languages.
</Para>
<Para>
We assume proficiency with UNIX and C programming.
</Para>
<Sect1>
<Title>Copyrights and Trademarks</Title>
<Para>
<ProductName>PostgreSQL</ProductName> is copyright (C) 1996-8 by the PostgreSQL Global Development Group,
and is distributed under the terms of the Berkeley license.
<Para>
<ProductName>Postgres95</ProductName> is copyright (C) 1994-5 by the Regents of the University of California.
Permission to use, copy, modify, and distribute this software and its documentation
for any purpose, without fee, and without a written agreement is hereby granted,
provided that the above copyright notice and this paragraph and the following two
paragraphs appear in all copies.
</Para>
<Para>
In no event shall the University of California be liable to
any party for direct, indirect, special, incidental, or consequential
damages, including lost profits, arising out of the use of this
software and its documentation, even if the University of California
has been advised of the possibility of such damage.
</Para>
<Para>
The University of California specifically disclaims any
warranties, including, but not limited to, the implied warranties
of merchantability and fitness for a particular purpose.
The software provided hereunder is on an "as-is" basis, and
the University of California has no obligations to provide
maintainance, support, updates, enhancements, or modifications.
</Para>
<Para>
<Acronym>UNIX</Acronym> is a trademark of X/Open, Ltd. Sun4, SPARC, SunOS
and Solaris are trademarks of Sun Microsystems, Inc. DEC,
DECstation, Alpha AXP and ULTRIX are trademarks of Digital
Equipment Corp. PA-RISC and HP-UX are trademarks of
Hewlett-Packard Co. OSF/1 is a trademark of the Open
Software Foundation.
</Para>
</Chapter>
<Chapter>
<TITLE>Introduction</TITLE>
<Para>
This document is the user manual for the
<Ulink url="http://postgresql.org/"><ProductName>PostgreSQL</ProductName></Ulink>
database management system, originally developed at the University
of California at Berkeley. <ProductName>PostgreSQL</ProductName> is based on
<Ulink url="http://s2k-ftp.CS.Berkeley.EDU:8000/postgres/postgres.html">
<ProductName>Postgres release 4.2</ProductName></Ulink>.
The <ProductName>Postgres</ProductName> project,
led by Professor Michael Stonebraker, has been sponsored by the
Defense Advanced Research Projects Agency (<Acronym>DARPA</Acronym>), the
Army Research Office (<Acronym>ARO</Acronym>), the National Science
Foundation (<Acronym>NSF</Acronym>), and ESL, Inc.
</Para>
<Sect1>
<Title> What is <ProductName>Postgres</ProductName>?</Title>
<Para>
Traditional relational database management systems
(DBMSs) support a data model consisting of a collection
of named relations, containing attributes of a specific
type. In current commercial systems, possible types
include floating point numbers, integers, character
strings, money, and dates. It is commonly recognized
that this model is inadequate for future data
processing applications.
The relational model successfully replaced previous
models in part because of its "Spartan simplicity".
However, as mentioned, this simplicity often makes the
implementation of certain applications very difficult.
<ProductName>Postgres</ProductName> offers substantial additional
power by incorporating the following four additional
basic concepts in such a way that users can easily
extend the system:
<SimpleList>
<Member>classes</Member>
<Member>inheritance</Member>
<Member>types</Member>
<Member>functions</Member>
</SimpleList>
</Para>
<Para>
Other features provide additional power and flexibility:
<SimpleList>
<Member>constraints</Member>
<Member>triggers</Member>
<Member>rules</Member>
<Member>transaction integrity</Member>
</SimpleList>
</Para>
<Para>
These features put <ProductName>Postgres</ProductName> into the category of databases
referred to as <FirstTerm>object-relational</FirstTerm>. Note that this is distinct
from those referred to as <FirstTerm>object-oriented</FirstTerm>, which in general
are not as well suited to supporting the traditional relational database languages.
So, although <ProductName>Postgres</ProductName> has some object-oriented features,
it is firmly in the relational database world. In fact, some commercial databases
have recently incorporated features pioneered by <ProductName>Postgres</ProductName>.
</Sect1>
<Sect1>
<Title>A Short History of <ProductName>Postgres</ProductName></Title>
<Sect2>
<Title>The Berkeley <ProductName>Postgres</ProductName> Project</Title>
<Para>
Implementation of the <ProductName>Postgres</ProductName> <Acronym>DBMS</Acronym> began in 1986. The
initial concepts for the system were presented in
<!--
<XRef LinkEnd="STON86">
-->
<Citation>[STON86]</Citation>
and the definition of the initial data model
appeared in
<!--
<XRef LinkEnd="ROWE87">.
-->
<Citation>[ROWE87]</Citation>.
The design of the rule system at
that time was described in
<!--
<XRef LinkEnd="STON87a">.
-->
<Citation>[STON87a]</Citation>.
The rationale
and architecture of the storage manager were detailed in
<!--
<XRef LinkEnd="STON87b">.
-->
<Citation>[STON87b]</Citation>.
</Para>
<Para>
<ProductName>Postgres</ProductName> has undergone several major releases since
then. The first "demoware" system became operational
in 1987 and was shown at the 1988 <Acronym>ACM-SIGMOD</Acronym>
Conference. We released Version 1, described in
<!--
<XRef LinkEnd="STON90a">,
-->
<Citation>[STON90a]</Citation>,
to a few external users in June 1989. In response to a
critique of the first rule system
<!--
(<XRef LinkEnd="STON89">),
-->
(<Citation>[STON89]</Citation>),
the rule
system was redesigned
<!--
(<XRef LinkEnd="STON90b">)
-->
(<Citation>[STON90b]</Citation>)
and Version 2 was
released in June 1990 with the new rule system.
Version 3 appeared in 1991 and added support for multiple
storage managers, an improved query executor, and a
rewritten rewrite rule system. For the most part,
releases since then have focused on portability and
reliability.
</Para>
<Para>
<ProductName>Postgres</ProductName> has been used to implement many different
research and production applications. These include: a
financial data analysis system, a jet engine
performance monitoring package, an asteroid tracking
database, a medical information database, and several
geographic information systems. <ProductName>Postgres</ProductName> has also been
used as an educational tool at several universities.
Finally, <Ulink url="http://www.illustra.com/">Illustra Information Technologies</Ulink> picked up
the code and commercialized it.
<ProductName>Postgres</ProductName> became the primary data manager for the
<Ulink url="http://www.sdsc.edu/0/Parts_Collabs/S2K/s2k_home.html">Sequoia 2000</Ulink>
scientific computing project in late 1992.
Furthermore, the size of the external user community
nearly doubled during 1993. It became increasingly
obvious that maintenance of the prototype code and
support was taking up large amounts of time that should
have been devoted to database research. In an effort
to reduce this support burden, the project officially
ended with Version 4.2.
</Para>
</Sect2>
<Sect2>
<Title><ProductName>Postgres95</ProductName></Title>
<Para>
In 1994,
<ULink url="mailto:ayu@informix.com">Andrew Yu</ULink>
and
<ULink url="http://http.cs.berkeley.edu/~jolly/">Jolly Chen</ULink>
added a SQL language interpreter to <ProductName>Postgres</ProductName>, and the code was subsequently released to
the Web to find its own way in the world. <ProductName>Postgres95</ProductName> was a public-domain, open source descendant
of this original Berkeley code.
</Para>
<Para>
<ProductName>Postgres95</ProductName> is a derivative of the last official release
of <ProductName>Postgres</ProductName> (version 4.2). The code is now completely
ANSI C and the code size has been trimmed by 25%. There
are a lot of internal changes that improve performance
and code maintainability. <ProductName>Postgres95</ProductName> v1.0.x runs about 30-50%
faster on the Wisconsin Benchmark compared to v4.2.
Apart from bug fixes, these are the major enhancements:
<ItemizedList>
<ListItem>
<Para>
The query language <ProductName>Postquel</ProductName> has been replaced with
<Acronym>SQL</Acronym> (implemented in the server). We do not yet support
subqueries (which can be imitated with user defined
<Acronym>SQL</Acronym> functions). Aggregates have been
re-implemented. We also added support for ``GROUP BY''.
The <FileName>libpq</FileName> interface is still available for <Acronym>C</Acronym>
programs.
</Para>
</ListItem>
<ListItem>
<Para>
In addition to the monitor program, we provide a new
program (<Application>psql</Application>) which supports <Acronym>GNU</Acronym> <FileName>readline</FileName>.
</Para>
</ListItem>
<ListItem>
<Para>
We added a new front-end library, <FileName>libpgtcl</FileName>, that
supports <Acronym>Tcl</Acronym>-based clients. A sample shell,
pgtclsh, provides new Tcl commands to interface <Application>tcl</Application>
programs with the <ProductName>Postgres95</ProductName> backend.
</Para>
</ListItem>
<ListItem>
<Para>
The large object interface has been overhauled. We
kept Inversion large objects as the only mechanism
for storing large objects. (This is not to be
confused with the Inversion file system which has been
removed.)
</Para>
</ListItem>
<ListItem>
<Para>
The instance-level rule system has been removed.
Rules are still available as rewrite rules.
</Para>
</ListItem>
<ListItem>
<Para>
A short tutorial introducing regular <Acronym>SQL</Acronym> features as
well as those of ours is distributed with the source
code.
</Para>
</ListItem>
<ListItem>
<Para>
<Acronym>GNU</Acronym> make (instead of <Acronym>BSD</Acronym> make) is used for the
build. Also, <ProductName>Postgres95</ProductName> can be compiled with an
unpatched <ProductName>gcc</ProductName> (data alignment of doubles has been
fixed).
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect2>
<Sect2>
<Title><ProductName>PostgreSQL</ProductName></Title>
<Para>
By 1996, it became clear that the name <Quote>Postgres95</Quote> would not stand
the test of time. A new name, <ProductName>PostgreSQL</ProductName>, was chosen to reflect the
relationship between original <ProductName>Postgres</ProductName> and the more recent
versions with <Acronym>SQL</Acronym> capability. At the same time, the version numbering
was reset to start at 6.0, putting the numbers back into the sequence originally begun by
the <ProductName>Postgres</ProductName> Project.
<Para>
The emphasis on development for the v1.0.x releases of <ProductName>Postgres95</ProductName>
was on stabilizing the backend code.
With the v6.x series of <ProductName>PostgreSQL</ProductName>, the emphasis has shifted from
identifying and understanding existing problems in the backend to augmenting features and capabilities, although
work continues in all areas.
<Para>
Major enhancements include:
<ItemizedList>
<ListItem>
<Para>
Important backend features, including subselects, defaults, constraints, and triggers, have been implemented.
</Para>
</ListItem>
<ListItem>
<Para>
Additional <Acronym>SQL92</Acronym>-compliant language features have been added,
including primary keys, quoted identifiers, literal string type coersion, type casting,
and binary and hexadecimal integer input.
</Para>
</ListItem>
<ListItem>
<Para>
Built-in types have been improved, including new wide-range date/time types and additional geometric type support.
</Para>
</ListItem>
<ListItem>
<Para>
Overall backend code speed has been increased by approximately 20%, and backend startup speed has decreased 80%.
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect2>
<Sect1>
<Title>About This Release</Title>
<Para>
From now on, We will use <ProductName>Postgres</ProductName> to mean <ProductName>PostgreSQL</ProductName>.
<Para>
<ProductName>PostgreSQL</ProductName> is available without cost. This manual
describes version 6.3 of <ProductName>PostgreSQL</ProductName>.
<Para>
Check the Administrator's Guide for a list of currently supported machines. In general,
<ProductName>PostgreSQL</ProductName> is portable to any Unix/Posix-compatible system
with full libc library support.
</Sect1>
<Sect1>
<Title>Resources</Title>
<Para>
This manual set is organized into several parts:
<VariableList>
<VarListEntry>
<Term>Tutorial</Term>
<ListItem>
<Para>
An introduction for new users. Does not cover advanced features.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>User's Guide</Term>
<ListItem>
<Para>
General information for users, including available commands and data types.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Programmer's Guide</Term>
<ListItem>
<Para>
Advanced information for application programmers. Topics include
type and function extensibility, library interfaces, and application design issues.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Administrator's Guide</Term>
<ListItem>
<Para>
Installation and management information. List of supported machines.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Developer's Guide</Term>
<ListItem>
<Para>
Information for <ProductName>Postgres</ProductName> developers. This is intended
for those who are contributing to the <ProductName>Postgres</ProductName>
project; application development information should appear in the Programmer's Guide.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Reference Manual</Term>
<ListItem>
<Para>
Detailed reference information on command syntax.
At the moment, this manual is very sparse, but eventually should contain
information similar to that in the man pages.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
<Para>
In addition to this manual set, there are other resources to help you with
<ProductName>Postgres</ProductName> installation and use:
<VariableList>
<VarListEntry>
<Term>man pages</Term>
<ListItem>
<Para>
The man pages have general information on command syntax.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>FAQs</Term>
<ListItem>
<Para>
The Frequently Asked Questions (FAQ) documents address both general issues
and some platform-specific issues.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>READMEs</Term>
<ListItem>
<Para>
README files are available for some contributed packages.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Web Site</Term>
<ListItem>
<Para>
The <ULink url="postgresql.org"><ProductName>Postgres</ProductName></ULink> web site has some information
not appearing in the distribution. There is a <ProductName>mhonarc</ProductName> catalog of mailing list traffic
which is a rich resource for many topics.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Mailing Lists</Term>
<ListItem>
<Para>
The <ULink url="mailto:questions@postgresql.org"><ProductName>Postgres</ProductName> Questions</ULink>
mailing list is a good place to have user questions answered. Other mailing lists are available; consult
the web page for details.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>Yourself!</Term>
<ListItem>
<Para>
<ProductName>Postgres</ProductName> is an open source product. As such, it depends on the user community for
ongoing support. As you begin to use <ProductName>Postgres</ProductName>, you will rely on others
for help, either through the documentation or through the mailing lists. Consider contributing your
knowledge back. If you learn something which is not in the documentation, write it up and contribute it.
If you add features to the code, contribute it. Even those without a lot of experience can provide
corrections and minor changes in the documentation, and that is a good way to start.
The <ULink url="mailto:docs@postgresql.org"><ProductName>Postgres</ProductName> Documentation</ULink>
mailing list is the place to get going.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Sect1>
<Sect1>
<Title>Copyrights and Trademarks</Title>
<Para>
<ProductName>PostgreSQL</ProductName> is copyright (C) 1996-8 by the PostgreSQL Global Development Group,
and is distributed under the terms of the Berkeley license.
<Para>
<ProductName>Postgres95</ProductName> is copyright (C) 1994-5 by the Regents of the University of California.
Permission to use, copy, modify, and distribute this software and its documentation
for any purpose, without fee, and without a written agreement is hereby granted,
provided that the above copyright notice and this paragraph and the following two
paragraphs appear in all copies.
</Para>
<Para>
In no event shall the University of California be liable to
any party for direct, indirect, special, incidental, or consequential
damages, including lost profits, arising out of the use of this
software and its documentation, even if the University of California
has been advised of the possibility of such damage.
</Para>
<Para>
The University of California specifically disclaims any
warranties, including, but not limited to, the implied warranties
of merchantability and fitness for a particular purpose.
The software provided hereunder is on an "as-is" basis, and
the University of California has no obligations to provide
maintainance, support, updates, enhancements, or modifications.
</Para>
<Para>
<Acronym>UNIX</Acronym> is a trademark of X/Open, Ltd. Sun4, SPARC, SunOS
and Solaris are trademarks of Sun Microsystems, Inc. DEC,
DECstation, Alpha AXP and ULTRIX are trademarks of Digital
Equipment Corp. PA-RISC and HP-UX are trademarks of
Hewlett-Packard Co. OSF/1 is a trademark of the Open
Software Foundation.
</Para>
</Chapter>
<Chapter>
<Title>JDBC Interface</Title>
<Para>
There is a JDBC interface available for Postgres. It is documented elsewhere using
the accepted tool for Java-language code.
</Chapter>
<Chapter>
<Title>pgtcl</Title>
<Para>
pgtcl is a tcl package for front-end programs to interface with <ProductName>Postgres</ProductName>
backends. pgtcl does not use the libpq library but communicates to
the backend directly via the frontend-backend protocol. Thus, it is
more efficient than previous postgres->tcl bindings which are layered
on top of libpq. In addition, pgtcl can handle multiple backend
connections from a single frontend application.
</Para>
<Para>
This package was originally written by Jolly Chen.
</Para>
<Sect1>
<Title>Commands</Title>
<Para>
The pg_lo* routines are interfaces to the Inversion Large Objects in <ProductName>Postgres</ProductName>.
The functions are designed to mimic the analogous file system functions in
the standard Unix file system interface.
</Para>
<Para>
<TABLE TOCENTRY="1">
<TITLE>PGTCL Commands</TITLE>
<TGROUP COLS="2">
<THEAD>
<ROW>
<ENTRY>Command</ENTRY>
<ENTRY>Description</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>pg_connect</ENTRY>
<ENTRY>opens a connection to the backend server</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_disconnect</ENTRY>
<ENTRY>closes a connection</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_exec</ENTRY>
<ENTRY>send a query to the backend</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_select</ENTRY>
<ENTRY>loop over the result of a select statement</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_result</ENTRY>
<ENTRY>manipulate the results of a query</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_creat</ENTRY>
<ENTRY>create a large object</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_open</ENTRY>
<ENTRY>open a large object</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_close</ENTRY>
<ENTRY>close a large object</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_read</ENTRY>
<ENTRY>read a large object</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_write</ENTRY>
<ENTRY>write a large object</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_lseek</ENTRY>
<ENTRY>seek to a position on a large object</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_tell</ENTRY>
<ENTRY>return the current seek position of a large object</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_unlink</ENTRY>
<ENTRY>delete a large object</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_import</ENTRY>
<ENTRY>import a Unix file into a large object</ENTRY>
</ROW>
<ROW>
<ENTRY>pg_lo_export</ENTRY>
<ENTRY>export a large object into a Unix file</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</Para>
<Para>
Some commands equivalent to libpq commands are provided for connection
and query operations.
</Para>
<Para>
The pg_lo* routines should typically be used within a BEGIN/END transaction
block because the file descriptor returned by pg_lo_open is only valid for
the current transaction. pg_lo_import and pg_lo_export MUST be used
in a BEGIN/END transaction block.
</Para>
</Sect1>
<Sect1>
<Title>Examples</Title>
<Para>
Here's a small example of how to use the routines:
<ProgramListing>
# getDBs :
# get the names of all the databases at a given host and port number
# with the defaults being the localhost and port 5432
# return them in alphabetical order
proc getDBs { {host "localhost"} {port "5432"} } {
# datnames is the list to be result
set conn [pg_connect template1 -host $host -port $port]
set res [pg_exec $conn "SELECT datname FROM pg_database ORDER BY datname"]
set ntups [pg_result $res -numTuples]
for {set i 0} {$i < $ntups} {incr i} {
lappend datnames [pg_result $res -getTuple $i]
}
pg_disconnect $conn
return $datnames
}
</ProgramListing>
</Para>
</Sect1>
<Sect1>
<Title>Reference Information</Title>
<REFENTRY ID="PGTCL-PGCONNECT-1">
<REFMETA>
<REFENTRYTITLE>pg_connect</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Connection Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_connect
</REFNAME>
<REFPURPOSE>opens a connection to the backend server
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGCONNECT-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGCONNECT-2"><PRIMARY>pg_connect</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_connect <REPLACEABLE CLASS="PARAMETER">dbName</REPLACEABLE> <OPTIONAL>-host <REPLACEABLE CLASS="PARAMETER">hostName</REPLACEABLE></OPTIONAL>
<OPTIONAL>-port <REPLACEABLE CLASS="PARAMETER">portNumber</REPLACEABLE></OPTIONAL> <OPTIONAL>-tty <REPLACEABLE CLASS="PARAMETER">pqtty</REPLACEABLE></OPTIONAL> <OPTIONAL>-options <REPLACEABLE CLASS="PARAMETER">optionalBackendArgs</REPLACEABLE></OPTIONAL>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGCONNECT-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">dbName</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database name.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<OPTIONAL>-host <REPLACEABLE CLASS="PARAMETER">hostName</REPLACEABLE></OPTIONAL>
</TERM>
<LISTITEM>
<PARA>Specifies the domain name of the backend server for <REPLACEABLE CLASS="PARAMETER">dbName</REPLACEABLE>.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<OPTIONAL>-port <REPLACEABLE CLASS="PARAMETER">portNumber</REPLACEABLE></OPTIONAL>
</TERM>
<LISTITEM>
<PARA>Specifies the IP port number of the backend server for <REPLACEABLE CLASS="PARAMETER">dbName</REPLACEABLE>.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<OPTIONAL>-tty <REPLACEABLE CLASS="PARAMETER">pqtty</REPLACEABLE></OPTIONAL>
</TERM>
<LISTITEM>
<PARA>(need information thomas 1997-12-24)
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<OPTIONAL>-options <REPLACEABLE CLASS="PARAMETER">optionalBackendArgs</REPLACEABLE></OPTIONAL>
</TERM>
<LISTITEM>
<PARA>Specifies options for the backend server for <REPLACEABLE CLASS="PARAMETER">dbName</REPLACEABLE>.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGCONNECT-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
The return result is either an error message or a handle for a database
connection. Handles start with the prefix "pgp"
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<!-- ********************************************************** -->
<REFSECT1 ID="R1-PGTCL-PGCONNECT-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_connect</FUNCTION> opens a connection to the <ProductName>Postgres</ProductName> backend.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGCONNECT-2">
<TITLE>Usage
</TITLE>
<PARA>XXX thomas 1997-12-24
</PARA>
</REFSECT1>
</REFENTRY>
<REFENTRY ID="PGTCL-PGDISCONNECT-1">
<REFMETA>
<REFENTRYTITLE>pg_disconnect</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Connection Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_disconnect
</REFNAME>
<REFPURPOSE>closes a connection to the backend server
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGDISCONNECT-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGDISCONNECT-2"><PRIMARY>pg_connect</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_disconnect <REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGDISCONNECT-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database handle.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGDISCONNECT-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
None
</TERM>
<LISTITEM>
<PARA>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGDISCONNECT-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_disconnect</FUNCTION> closes a connection to the <ProductName>Postgres</ProductName> backend.
</PARA>
</REFSECT1>
</REFENTRY>
<REFENTRY ID="PGTCL-PGEXEC-1">
<REFMETA>
<REFENTRYTITLE>pg_exec</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Connection Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_exec
</REFNAME>
<REFPURPOSE>
send a query string to the backend
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGEXEC-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGEXEC-2"><PRIMARY>pg_connect</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_exec <REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">queryString</REPLACEABLE>
</SYNOPSIS>
<!-- ********************************************************** -->
<REFSECT2 ID="R2-PGTCL-PGEXEC-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database handle.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">queryString</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid SQL query.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGEXEC-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">queryHandle</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
the return result is either an error message or a handle for a query result.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2></REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGEXEC-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>pg_exec</FUNCTION> submits a query to the <ProductName>Postgres</ProductName> backend and returns a result.
Handles start with the prefix "pgp".
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGSELECT-1">
<REFMETA>
<REFENTRYTITLE>pg_select</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Connection Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_select
</REFNAME>
<REFPURPOSE>
loop over the result of a select statement
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGSELECT-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGSELECT-2"><PRIMARY>pg_connect</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_select <REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">queryString</REPLACEABLE>
<REPLACEABLE CLASS="PARAMETER">arrayVar</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">queryProcedure</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGSELECT-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">dbHandle</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database handle.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">queryString</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid SQL select query.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">arrayVar</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Array variable for tuples returned.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">queryProcedure</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Procedure run on each tuple found.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGSELECT-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">queryHandle</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
the return result is either an error message or a handle for a query result.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2></REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGSELECT-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>pg_select</FUNCTION> submits a query to the <ProductName>Postgres</ProductName> backend.
and returns the results.
The <REPLACEABLE CLASS="PARAMETER">queryString</REPLACEABLE>
must be a select statement. Anything else returns an error.
The <REPLACEABLE CLASS="PARAMETER">arrayVar</REPLACEABLE>
variable is an array name used in the loop. It is filled
out with the result of the query for each tuple using the field
names as the associative indices.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGSELECT-2">
<TITLE>Usage
</TITLE>
<PARA>
<ProgramListing>
set DB "mydb"
set conn [pg_connect $DB]
pg_select $conn "SELECT * from table" array {
puts [format "%5d %s" array(control) array(name)]
}
pg_disconnect $conn
</ProgramListing>
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGRESULT-1">
<REFMETA>
<REFENTRYTITLE>pg_result</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Connection Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_result
</REFNAME>
<REFPURPOSE>
get information about a query result
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGRESULT-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGRESULT-2"><PRIMARY>pg_connect</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_result <REPLACEABLE CLASS="PARAMETER">queryHandle</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">resultOption</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGRESULT-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">queryHandle</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
The handle for a query result.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">resultOption</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Specifies one of several possible options.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
<REFSECT3>
<TITLE>Options</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
-status
</TERM>
<LISTITEM>
<PARA>
the status of the result.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
-oid
</TERM>
<LISTITEM>
<PARA>
if the last query was an insert, returns the oid of the
inserted tuple
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
-conn
</TERM>
<LISTITEM>
<PARA>
the connection that produced the result
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
-assign arrayName
</TERM>
<LISTITEM>
<PARA>
assign the results to an array
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
-numTuples
</TERM>
<LISTITEM>
<PARA>
the number of tuples in the query
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
-attributes
</TERM>
<LISTITEM>
<PARA>
returns a list of the name/type pairs of the tuple attributes
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
-getTuple tupleNumber
</TERM>
<LISTITEM>
<PARA>
returns the values of the tuple in a list
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
-clear
</TERM>
<LISTITEM>
<PARA>
clear the result buffer. Do not reuse after this
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT3>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGRESULT-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">queryHandle</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
the return result is either an error message or a handle for a query result.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2></REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGRESULT-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>pg_result</FUNCTION> returns information about a query.
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOCREAT-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_creat</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_creat
</REFNAME>
<REFPURPOSE>create a large object
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOCREAT-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>creating</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOCREAT-2"><PRIMARY>pg_lo_creat</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_creat <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">mode</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOCREAT-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">mode</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies the access mode for the large object</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOCREAT-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">objOid</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
The oid of the large object created.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOCREAT-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_creat</FUNCTION> creates an Inversion Large Object.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOCREAT-2">
<TITLE>Usage
</TITLE>
<PARA>
mode can be any OR'ing together of INV_READ, INV_WRITE, and INV_ARCHIVE.
The OR delimiter character is "|".
<ProgramListing>
[pg_lo_creat $conn "INV_READ|INV_WRITE"]
</ProgramListing>
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOOPEN-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_open</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_open
</REFNAME>
<REFPURPOSE>open a large object
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOOPEN-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>opening</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOOPEN-2"><PRIMARY>pg_lo_open</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_open <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">objOid</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">mode</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOOPEN-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">objOid</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid large object oid.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">mode</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies the access mode for the large object</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOOPEN-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
A file descriptor for use in later pg_lo* routines.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOOPEN-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_open</FUNCTION> open an Inversion Large Object.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOOPEN-2">
<TITLE>Usage
</TITLE>
<PARA>
Mode can be either "r", "w", or "rw".
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOCLOSE-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_close</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_close
</REFNAME>
<REFPURPOSE>close a large object
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOCLOSE-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>closing</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOCLOSE-2"><PRIMARY>pg_lo_close</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_close <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOCLOSE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
A file descriptor for use in later pg_lo* routines.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOCLOSE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<PARA>None</PARA>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOCLOSE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_close</FUNCTION> closes an Inversion Large Object.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOCLOSE-2">
<TITLE>Usage
</TITLE>
<PARA>
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOREAD-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_read</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_read
</REFNAME>
<REFPURPOSE>read a large object
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOREAD-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>reading</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOREAD-2"><PRIMARY>pg_lo_read</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_read <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">bufVar</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">len</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOREAD-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
File descriptor for the large object from pg_lo_open.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">bufVar</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid buffer variable to contain the large object segment.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">len</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies the maximum allowable size of the large object segment.</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOREAD-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<PARA>None</PARA>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOREAD-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_read</FUNCTION> reads
at most <REPLACEABLE CLASS="PARAMETER">len</REPLACEABLE> bytes from a large object into a variable
named <REPLACEABLE CLASS="PARAMETER">bufVar</REPLACEABLE>.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOREAD-2">
<TITLE>Usage
</TITLE>
<PARA>
<REPLACEABLE CLASS="PARAMETER">bufVar</REPLACEABLE> must be a valid variable name.
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOWRITE-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_write</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_write
</REFNAME>
<REFPURPOSE>write a large object
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOWRITE-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>writing</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOWRITE-2"><PRIMARY>pg_lo_write</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_write <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">buf</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">len</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOWRITE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
File descriptor for the large object from pg_lo_open.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">buf</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid string variable to write to the large object.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">len</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies the maximum size of the string to write.</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOWRITE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<PARA>None</PARA>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOWRITE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_write</FUNCTION> writes
at most <REPLACEABLE CLASS="PARAMETER">len</REPLACEABLE> bytes to a large object from a variable
<REPLACEABLE CLASS="PARAMETER">buf</REPLACEABLE>.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOWRITE-2">
<TITLE>Usage
</TITLE>
<PARA>
<REPLACEABLE CLASS="PARAMETER">buf</REPLACEABLE> must be
the actual string to write, not a variable name.
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOLSEEK-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_lseek</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_lseek
</REFNAME>
<REFPURPOSE>seek to a position on a large object
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOLSEEK-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>positioning</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOLSEEK-2"><PRIMARY>pg_lo_lseek</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_lseek <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">offset</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">whence</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOLSEEK-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
File descriptor for the large object from pg_lo_open.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">offset</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a zero-based offset in bytes.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">whence</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA> whence can be "SEEK_CUR", "SEEK_END", or "SEEK_SET" </PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOLSEEK-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<PARA>None</PARA>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOLSEEK-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_lseek</FUNCTION> positions
to <REPLACEABLE CLASS="PARAMETER">offset</REPLACEABLE> bytes from the beginning of the large object.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOLSEEK-2">
<TITLE>Usage
</TITLE>
<PARA>
<REPLACEABLE CLASS="PARAMETER">whence</REPLACEABLE>
can be "SEEK_CUR", "SEEK_END", or "SEEK_SET".
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOTELL-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_tell</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_tell
</REFNAME>
<REFPURPOSE>return the current seek position of a large object
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOTELL-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>positioning</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOTELL-2"><PRIMARY>pg_lo_tell</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_tell <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOTELL-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">fd</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
File descriptor for the large object from pg_lo_open.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOTELL-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">offset</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>A zero-based offset in bytes suitable for input to <Function>pg_lo_lseek</Function>.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOTELL-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_tell</FUNCTION> returns the current
to <REPLACEABLE CLASS="PARAMETER">offset</REPLACEABLE> in bytes from the beginning of the large object.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOTELL-2">
<TITLE>Usage
</TITLE>
<PARA>
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOUNLINK-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_unlink</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_unlink
</REFNAME>
<REFPURPOSE>delete a large object
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOUNLINK-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>delete</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOUNLINK-2"><PRIMARY>pg_lo_unlink</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_unlink <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">lobjId</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOUNLINK-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">lobjId</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Identifier for a large object.
XXX Is this the same as objOid in other calls?? - thomas 1998-01-11
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOUNLINK-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<PARA>
None
</PARA>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOUNLINK-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_unlink</FUNCTION> deletes the specified large object.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOUNLINK-2">
<TITLE>Usage
</TITLE>
<PARA>
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOIMPORT-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_import</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_import
</REFNAME>
<REFPURPOSE>import a large object from a Unix file
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOIMPORT-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>import</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOIMPORT-2"><PRIMARY>pg_lo_import</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_import <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">filename</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOIMPORT-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">filename</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Unix file name.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOIMPORT-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<PARA>
None
XXX Does this return a lobjId? Is that the same as the objOid in other calls? thomas - 1998-01-11
</PARA>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOIMPORT-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_import</FUNCTION> reads the specified file and places the contents into a large object.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOIMPORT-2">
<TITLE>Usage
</TITLE>
<PARA>
<Function>pg_lo_import</Function> must be called within a BEGIN/END transaction block.
</PARA>
</REFSECT1>
</REFENTRY>
<!-- ********************************************************** -->
<REFENTRY ID="PGTCL-PGLOEXPORT-1">
<REFMETA>
<REFENTRYTITLE>pg_lo_export</REFENTRYTITLE>
<REFMISCINFO>PGTCL - Large Objects</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>pg_lo_export
</REFNAME>
<REFPURPOSE>export a large object to a Unix file
</REFPURPOSE>
<INDEXTERM ID="IX-PGTCL-PGLOEXPORT-1"><PRIMARY>pgtcl</PRIMARY><SECONDARY>export</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-PGTCL-PGLOEXPORT-2"><PRIMARY>pg_lo_export</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
pg_lo_export <REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">lobjId</REPLACEABLE> <REPLACEABLE CLASS="PARAMETER">filename</REPLACEABLE>
</SYNOPSIS>
<REFSECT2 ID="R2-PGTCL-PGLOEXPORT-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">conn</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>Specifies a valid database connection.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">lobjId</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Large object identifier.
XXX Is this the same as the objOid in other calls?? thomas - 1998-01-11
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">filename</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Unix file name.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-PGTCL-PGLOEXPORT-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<PARA>
None
XXX Does this return a lobjId? Is that the same as the objOid in other calls? thomas - 1998-01-11
</PARA>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-PGTCL-PGLOEXPORT-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA><FUNCTION>pg_lo_export</FUNCTION> writes the specified large object into a Unix file.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-PGTCL-PGLOEXPORT-2">
<TITLE>Usage
</TITLE>
<PARA>
<Function>pg_lo_export</Function> must be called within a BEGIN/END transaction block.
</PARA>
</REFSECT1>
</REFENTRY>
</Sect1>
</Chapter>
<Chapter>
<Title><FileName>libpq</FileName></Title>
<Para>
<FileName>libpq</FileName> is the application programming interface to <ProductName>Postgres</ProductName>.
<FileName>libpq</FileName> is a set of library routines which allows
client programs to pass queries to the <ProductName>Postgres</ProductName> backend
server and to receive the results of these queries.
This version of the documentation describes the <Acronym>C</Acronym>
interface library. Three short programs are included
at the end of this section to show how to write programs that use <FileName>libpq</FileName>.
There are several examples of <FileName>libpq</FileName> applications in the
following directories:
<ProgramListing>
../src/test/regress
../src/test/examples
../src/bin/psql
</ProgramListing>
<Para>
Frontend programs which use <FileName>libpq</FileName> must include the
header file <FileName>libpq-fe.h</FileName> and must link with the <FileName>libpq</FileName>
library.
</Para>
<Sect1>
<Title>Control and Initialization</Title>
<Para>
The following environment variables can be used to set
up default environment values to avoid hard-coding
database names into an application program:
<ItemizedList>
<ListItem>
<Para>
<Acronym>PGHOST</Acronym> sets the default server name.
</Para>
</ListItem>
<ListItem>
<Para>
<Acronym>PGOPTIONS</Acronym> sets additional runtime options for the <ProductName>Postgres</ProductName> backend.
</Para>
</ListItem>
<ListItem>
<Para>
<Acronym>PGPORT</Acronym> sets the default port for communicating with the <ProductName>Postgres</ProductName> backend.
</Para>
</ListItem>
<ListItem>
<Para>
<Acronym>PGTTY</Acronym> sets the file or tty on which debugging messages from the backend server are displayed.
</Para>
</ListItem>
<ListItem>
<Para>
<Acronym>PGDATABASE</Acronym> sets the default <ProductName>Postgres</ProductName> database name.
</Para>
</ListItem>
<ListItem>
<Para>
<Acronym>PGREALM</Acronym> sets the Kerberos realm to use with <ProductName>Postgres</ProductName>,
if it is different from the local realm. If
<Acronym>PGREALM</Acronym> is set, <ProductName>Postgres</ProductName> applications will attempt
authentication with servers for this realm and use
separate ticket files to avoid conflicts with local
ticket files. This environment variable is only
used if Kerberos authentication is enabled.
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect1>
<Sect1>
<Title>Database Connection Functions</Title>
<Para>
The following routines deal with making a connection to
a backend from a <Acronym>C</Acronym> program.
<ItemizedList>
<ListItem>
<Para>
<Function>PQsetdb</Function>
Makes a new connection to a backend.
<ProgramListing>
PGconn *PQsetdb(char *pghost,
char *pgport,
char *pgoptions,
char *pgtty,
char *dbName);
</ProgramListing>
If any argument is NULL, then the corresponding
environment variable is checked. If the environment variable is also not set, then hardwired
defaults are used.
PQsetdb always returns a valid PGconn pointer.
The PQstatus (see below) command should be called
to ensure that a connection was properly made
before queries are sent via the connection. <FileName>libpq</FileName>
programmers should be careful to maintain the
PGconn abstraction. Use the accessor functions
below to get at the contents of PGconn. Avoid
directly referencing the fields of the PGconn
structure as they are subject to change in the
future.
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQdb</Function>
Returns the database name of the connection.
<ProgramListing>
char *PQdb(PGconn *conn)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQhost</Function>
Returns the host name of the connection.
<ProgramListing>
char *PQhost(PGconn *conn)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQoptions</Function>
Returns the pgoptions used in the connection.
<ProgramListing>
char *PQoptions(PGconn *conn)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQport</Function>
Returns the pgport of the connection.
<ProgramListing>
char *PQport(PGconn *conn)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQtty</Function>
Returns the pgtty of the connection.
<ProgramListing>
char *PQtty(PGconn *conn)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQstatus</Function>
Returns the status of the connection.
The status can be CONNECTION_OK or CONNECTION_BAD.
<ProgramListing>
ConnStatusType *PQstatus(PGconn *conn)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQerrorMessage</Function>
Returns the error message associated with the connection
<ProgramListing>
char *PQerrorMessage(PGconn* conn);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQfinish</Function>
Close the connection to the backend. Also frees
memory used by the PGconn structure. The PGconn
pointer should not be used after PQfinish has been
called.
<ProgramListing>
void PQfinish(PGconn *conn)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQreset</Function>
Reset the communication port with the backend.
This function will close the IPC socket connection
to the backend and attempt to reestablish a new
connection to the same backend.
<ProgramListing>
void PQreset(PGconn *conn)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQtrace</Function>
Enables tracing of messages passed between the
frontend and the backend. The messages are echoed
to the debug_port file stream.
<ProgramListing>
void PQtrace(PGconn *conn,
FILE* debug_port);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQuntrace</Function>
Disables tracing of messages passed between the
frontend and the backend.
<ProgramListing>
void PQuntrace(PGconn *conn);
</ProgramListing>
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect1>
<Sect1>
<Title>Query Execution Functions</Title>
<Para>
<ItemizedList>
<ListItem>
<Para>
<Function>PQexec</Function>
Submit a query to <ProductName>Postgres</ProductName>. Returns a PGresult
pointer if the query was successful or a NULL otherwise. If a NULL is returned, PQerrorMessage can
be used to get more information about the error.
<ProgramListing>
PGresult *PQexec(PGconn *conn,
char *query);
</ProgramListing>
The <Function>PGresult</Function> structure encapsulates the query
result returned by the backend. <Function>libpq</Function> programmers
should be careful to maintain the PGresult
abstraction. Use the accessor functions described
below to retrieve the results of the query. Avoid
directly referencing the fields of the PGresult
structure as they are subject to change in the
future.
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQresultStatus</Function>
Returns the result status of the query. PQresultStatus can return one of the following values:
<ProgramListing>
PGRES_EMPTY_QUERY,
PGRES_COMMAND_OK, /* the query was a command */
PGRES_TUPLES_OK, /* the query successfully returned tuples */
PGRES_COPY_OUT,
PGRES_COPY_IN,
PGRES_BAD_RESPONSE, /* an unexpected response was received */
PGRES_NONFATAL_ERROR,
PGRES_FATAL_ERROR
</ProgramListing>
If the result status is PGRES_TUPLES_OK, then the
following routines can be used to retrieve the
tuples returned by the query.
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQntuples</Function> returns the number of tuples (instances)
in the query result.
<ProgramListing>
int PQntuples(PGresult *res);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQnfields</Function>
Returns the number of fields
(attributes) in the query result.
<ProgramListing>
int PQnfields(PGresult *res);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQfname</Function>
Returns the field (attribute) name associated with the given field index. Field indices
start at 0.
<ProgramListing>
char *PQfname(PGresult *res,
int field_index);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQfnumber</Function>
Returns the field (attribute) index
associated with the given field name.
<ProgramListing>
int PQfnumber(PGresult *res,
char* field_name);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQftype</Function>
Returns the field type associated with the
given field index. The integer returned is an
internal coding of the type. Field indices start
at 0.
<ProgramListing>
Oid PQftype(PGresult *res,
int field_num);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQfsize</Function>
Returns the size in bytes of the field
associated with the given field index. If the size
returned is -1, the field is a variable length
field. Field indices start at 0.
<ProgramListing>
int2 PQfsize(PGresult *res,
int field_index);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQgetvalue</Function>
Returns the field (attribute) value.
For most queries, the value returned by PQgetvalue
is a null-terminated ASCII string representation
of the attribute value. If the query was a result
of a <Acronym>BINARY</Acronym> cursor, then the value returned by
PQgetvalue is the binary representation of the
type in the internal format of the backend server.
It is the programmer's responsibility to cast and
convert the data to the correct C type. The value
returned by PQgetvalue points to storage that is
part of the PGresult structure. One must explicitly
copy the value into other storage if it is to
be used past the lifetime of the PGresult structure itself.
<ProgramListing>
char* PQgetvalue(PGresult *res,
int tup_num,
int field_num);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQgetlength</Function>
Returns the length of a field
(attribute) in bytes. If the field is a struct
varlena, the length returned here does not include
the size field of the varlena, i.e., it is 4 bytes
less.
<ProgramListing>
int PQgetlength(PGresult *res,
int tup_num,
int field_num);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQcmdStatus</Function>
Returns the command status associated with the
last query command.
<ProgramListing>
char *PQcmdStatus(PGresult *res);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQoidStatus</Function>
Returns a string with the object id of the tuple
inserted if the last query is an INSERT command.
Otherwise, returns an empty string.
<ProgramListing>
char* PQoidStatus(PGresult *res);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQprintTuples</Function>
Prints out all the tuples and, optionally, the
attribute names to the specified output stream.
The programs psql and monitor both use PQprintTuples for output.
<ProgramListing>
void PQprintTuples(
PGresult* res,
FILE* fout, /* output stream */
int printAttName,/* print attribute names or not*/
int terseOutput, /* delimiter bars or not?*/
int width /* width of column, variable width if 0*/
);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQclear</Function>
Frees the storage associated with the PGresult.
Every query result should be properly freed when
it is no longer used. Failure to do this will
result in memory leaks in the frontend application.
<ProgramListing>
void PQclear(PQresult *res);
</ProgramListing>
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect1>
<Sect1>
<Title>Fast Path</Title>
<Para>
<ItemizedList>
<ListItem>
<Para>
<ProductName>Postgres</ProductName> provides a fast path interface to send function
calls to the backend. This is a trapdoor into
system internals and can be a potential security hole.
Most users will not need this feature.
<ProgramListing>
PGresult* PQfn(PGconn* conn,
int fnid,
int *result_buf,
int *result_len,
int result_is_int,
PQArgBlock *args,
int nargs);
</ProgramListing>
The fnid argument is the object identifier of the function to be executed. result_buf is the buffer in which
to load the return value. The caller must have allocated sufficient space to store the return value. The
result length will be returned in the storage pointed
to by result_len. If the result is to be an integer
value, than result_is_int should be set to 1; otherwise
it should be set to 0. args and nargs specify the
arguments to the function.
<ProgramListing>
typedef struct {
int len;
int isint;
union {
int *ptr;
int integer;
} u;
} PQArgBlock;
</ProgramListing>
PQfn always returns a valid PGresult*. The resultStatus should be checked before the result is used. The
caller is responsible for freeing the PGresult with
PQclear when it is not longer needed.
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect1>
<Sect1>
<Title>Asynchronous Notification</Title>
<Para>
<ProductName>Postgres</ProductName> supports asynchronous notification via the
LISTEN and NOTIFY commands. A backend registers its
interest in a particular relation with the LISTEN command. All backends listening on a particular relation
will be notified asynchronously when a NOTIFY of that
relation name is executed by another backend. No
additional information is passed from the notifier to
the listener. Thus, typically, any actual data that
needs to be communicated is transferred through the
relation.
<FileName>libpq</FileName> applications are notified whenever a connected
backend has received an asynchronous notification.
However, the communication from the backend to the
frontend is not asynchronous. Notification comes
piggy-backed on other query results. Thus, an application must submit queries, even empty ones, in order to
receive notice of backend notification. In effect, the
<FileName>libpq</FileName> application must poll the backend to see if there
is any pending notification information. After the
execution of a query, a frontend may call PQNotifies to
see if any notification data is available from the
backend.
</Para>
<Para>
<ItemizedList>
<ListItem>
<Para>
<Function>PQNotifies</Function>
returns the notification from a list of unhandled
notifications from the backend. Returns NULL if
there are no pending notifications from the backend. PQNotifies behaves like the popping of a
stack. Once a notification is returned from PQnotifies, it is considered handled and will be
removed from the list of notifications.
<ProgramListing>
PGnotify* PQNotifies(PGconn *conn);
</ProgramListing>
The second sample program gives an example of the use
of asynchronous notification.
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect1>
<Sect1>
<Title>Functions Associated with the COPY Command</Title>
<Para>
The copy command in <ProductName>Postgres</ProductName> has options to read from
or write to the network connection used by <FileName>libpq</FileName>.
Therefore, functions are necessary to access this network connection directly so applications may take full
advantage of this capability.
</Para>
<Para>
<ItemizedList>
<ListItem>
<Para>
<Function>PQgetline</Function>
Reads a newline-terminated line of characters
(transmitted by the backend server) into a buffer
string of size length. Like fgets(3), this routine copies up to length-1 characters into string.
It is like gets(3), however, in that it converts
the terminating newline into a null character.
PQgetline returns EOF at EOF, 0 if the entire line
has been read, and 1 if the buffer is full but the
terminating newline has not yet been read.
Notice that the application must check to see if a
new line consists of the single character ".",
which indicates that the backend server has finished sending the results of the copy command.
Therefore, if the application ever expects to
receive lines that are more than length-1 characters long, the application must be sure to check
the return value of PQgetline very carefully.
The code in
<FileName>
../src/bin/psql/psql.c
</FileName>
contains routines that correctly handle the copy
protocol.
<ProgramListing>
int PQgetline(PGconn *conn,
char *string,
int length)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQputline</Function>
Sends a null-terminated string to the backend
server.
The application must explicitly send the single
character "." to indicate to the backend that it
has finished sending its data.
<ProgramListing>
void PQputline(PGconn *conn,
char *string);
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQendcopy</Function>
Syncs with the backend. This function waits until
the backend has finished the copy. It should
either be issued when the last string has been
sent to the backend using PQputline or when the
last string has been received from the backend
using PGgetline. It must be issued or the backend
may get "out of sync" with the frontend. Upon
return from this function, the backend is ready to
receive the next query.
The return value is 0 on successful completion,
nonzero otherwise.
<ProgramListing>
int PQendcopy(PGconn *conn);
</ProgramListing>
<ProgramListing>
PQexec(conn, "create table foo (a int4, b char16, d float8)");
PQexec(conn, "copy foo from stdin");
PQputline(conn, "3&lt;TAB&gt;hello world&lt;TAB&gt;4.5\n");
PQputline(conn,"4&lt;TAB&gt;goodbye world&lt;TAB&gt;7.11\n");
...
PQputline(conn,".\n");
PQendcopy(conn);
</ProgramListing>
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect1>
<Sect1>
<Title><FileName>libpq</FileName> Tracing Functions</Title>
<Para>
<ItemizedList>
<ListItem>
<Para>
<Function>PQtrace</Function>
Enable tracing of the frontend/backend communication to a debugging file stream.
<ProgramListing>
void PQtrace(PGconn *conn
FILE *debug_port)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>PQuntrace</Function>
Disable tracing started by PQtrace
<ProgramListing>
void PQuntrace(PGconn *conn)
</ProgramListing>
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect1>
<Sect1>
<Title>User Authentication Functions</Title>
<Para>
If the user has generated the appropriate authentication credentials
(e.g., obtaining <Acronym>Kerberos</Acronym> tickets),
the frontend/backend authentication process is handled
by <Function>PQexec</Function> without any further intervention.
The following routines may be called by <FileName>libpq</FileName> programs to tailor the behavior of the authentication process.
</Para>
<Para>
<ItemizedList>
<ListItem>
<Para>
<Function>fe_getauthname</Function>
Returns a pointer to static space containing whatever name the user has authenticated. Use of this
routine in place of calls to getenv(3) or getpwuid(3) by applications is highly recommended, as
it is entirely possible that the authenticated
user name is not the same as value of the <Acronym>USER</Acronym>
environment variable or the user's entry in
<FileName>/etc/passwd</FileName>.
<ProgramListing>
char *fe_getauthname(char* errorMessage)
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
<Function>fe_setauthsvc</Function>
Specifies that <FileName>libpq</FileName> should use authentication
service name rather than its compiled-in default.
This value is typically taken from a command-line
switch.
<ProgramListing>
void fe_setauthsvc(char *name,
char* errorMessage)
</ProgramListing>
Any error messages from the authentication
attempts are returned in the errorMessage argument.
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect1>
<Sect1>
<Title>BUGS</Title>
<Para>
The query buffer is 8192 bytes long, and queries over
that length will be silently truncated.
</Para>
</Sect1>
<Sect1>
<Title>Sample Programs</Title>
<Sect2>
<Title>Sample Program 1</Title>
<Para>
<ProgramListing>
/*
* testlibpq.c
* Test the C version of LIBPQ, the <ProductName>Postgres</ProductName> frontend library.
*
*
*/
#include &lt;stdio.h&gt;
#include "libpq-fe.h"
void
exit_nicely(PGconn* conn)
{
PQfinish(conn);
exit(1);
}
main()
{
char *pghost, *pgport, *pgoptions, *pgtty;
char* dbName;
int nFields;
int i,j;
/* FILE *debug; */
PGconn* conn;
PGresult* res;
/* begin, by setting the parameters for a backend connection
if the parameters are null, then the system will try to use
reasonable defaults by looking up environment variables
or, failing that, using hardwired constants */
pghost = NULL; /* host name of the backend server */
pgport = NULL; /* port of the backend server */
pgoptions = NULL; /* special options to start up the backend server */
pgtty = NULL; /* debugging tty for the backend server */
dbName = "template1";
/* make a connection to the database */
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '&percnt;s' failed.0, dbName);
fprintf(stderr,"&percnt;s",PQerrorMessage(conn));
exit_nicely(conn);
}
/* debug = fopen("/tmp/trace.out","w"); */
/* PQtrace(conn, debug); */
/* start a transaction block */
res = PQexec(conn,"BEGIN");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr,"BEGIN command failed0);
PQclear(res);
exit_nicely(conn);
}
/* should PQclear PGresult whenever it is no longer needed to avoid
memory leaks */
PQclear(res);
/* fetch instances from the pg_database, the system catalog of databases*/
res = PQexec(conn,"DECLARE myportal CURSOR FOR select * from pg_database");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr,"DECLARE CURSOR command failed0);
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
res = PQexec(conn,"FETCH ALL in myportal");
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
fprintf(stderr,"FETCH ALL command didn't return tuples properly0);
PQclear(res);
exit_nicely(conn);
}
/* first, print out the attribute names */
nFields = PQnfields(res);
for (i=0; i &lt; nFields; i++) {
printf("&percnt;-15s",PQfname(res,i));
}
printf("0);
/* next, print out the instances */
for (i=0; i &lt; PQntuples(res); i++) {
for (j=0 ; j &lt; nFields; j++) {
printf("&percnt;-15s", PQgetvalue(res,i,j));
}
printf("0);
}
PQclear(res);
/* close the portal */
res = PQexec(conn, "CLOSE myportal");
PQclear(res);
/* end the transaction */
res = PQexec(conn, "END");
PQclear(res);
/* close the connection to the database and cleanup */
PQfinish(conn);
/* fclose(debug); */
}
</ProgramListing>
</Para>
</Sect2>
<Sect2>
<Title>Sample Program 2</Title>
<Para>
<ProgramListing>
/*
* testlibpq2.c
* Test of the asynchronous notification interface
*
populate a database with the following:
CREATE TABLE TBL1 (i int4);
CREATE TABLE TBL2 (i int4);
CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2];
* Then start up this program
* After the program has begun, do
INSERT INTO TBL1 values (10);
*
*
*/
#include &lt;stdio.h&gt;
#include "libpq-fe.h"
void exit_nicely(PGconn* conn)
{
PQfinish(conn);
exit(1);
}
main()
{
char *pghost, *pgport, *pgoptions, *pgtty;
char* dbName;
int nFields;
int i,j;
PGconn* conn;
PGresult* res;
PGnotify* notify;
/* begin, by setting the parameters for a backend connection
if the parameters are null, then the system will try to use
reasonable defaults by looking up environment variables
or, failing that, using hardwired constants */
pghost = NULL; /* host name of the backend server */
pgport = NULL; /* port of the backend server */
pgoptions = NULL; /* special options to start up the backend server */
pgtty = NULL; /* debugging tty for the backend server */
dbName = getenv("USER"); /* change this to the name of your test database*/
/* make a connection to the database */
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '&percnt;s' failed.0, dbName);
fprintf(stderr,"&percnt;s",PQerrorMessage(conn));
exit_nicely(conn);
}
res = PQexec(conn, "LISTEN TBL2");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr,"LISTEN command failed0);
PQclear(res);
exit_nicely(conn);
}
/* should PQclear PGresult whenever it is no longer needed to avoid
memory leaks */
PQclear(res);
while (1) {
/* async notification only come back as a result of a query*/
/* we can send empty queries */
res = PQexec(conn, " ");
/* printf("res-&gt;status = &percnt;s0, pgresStatus[PQresultStatus(res)]); */
/* check for asynchronous returns */
notify = PQnotifies(conn);
if (notify) {
fprintf(stderr,
"ASYNC NOTIFY of '&percnt;s' from backend pid '&percnt;d' received0,
notify-&gt;relname, notify-&gt;be_pid);
free(notify);
break;
}
PQclear(res);
}
/* close the connection to the database and cleanup */
PQfinish(conn);
}
</ProgramListing>
</Para>
</Sect2>
<Sect2>
<Title>Sample Program 3</Title>
<Para>
<ProgramListing>
/*
* testlibpq3.c
* Test the C version of LIBPQ, the <ProductName>Postgres</ProductName> frontend library.
* tests the binary cursor interface
*
*
*
populate a database by doing the following:
CREATE TABLE test1 (i int4, d float4, p polygon);
INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0, 2.0)'::polygon);
INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0, 1.0)'::polygon);
the expected output is:
tuple 0: got
i = (4 bytes) 1,
d = (4 bytes) 3.567000,
p = (4 bytes) 2 points boundbox = (hi=3.000000/4.000000, lo = 1.000000,2.000000)
tuple 1: got
i = (4 bytes) 2,
d = (4 bytes) 89.050003,
p = (4 bytes) 2 points boundbox = (hi=4.000000/3.000000, lo = 2.000000,1.000000)
*
*/
#include &lt;stdio.h&gt;
#include "libpq-fe.h"
#include "utils/geo-decls.h" /* for the POLYGON type */
void exit_nicely(PGconn* conn)
{
PQfinish(conn);
exit(1);
}
main()
{
char *pghost, *pgport, *pgoptions, *pgtty;
char* dbName;
int nFields;
int i,j;
int i_fnum, d_fnum, p_fnum;
PGconn* conn;
PGresult* res;
/* begin, by setting the parameters for a backend connection
if the parameters are null, then the system will try to use
reasonable defaults by looking up environment variables
or, failing that, using hardwired constants */
pghost = NULL; /* host name of the backend server */
pgport = NULL; /* port of the backend server */
pgoptions = NULL; /* special options to start up the backend server */
pgtty = NULL; /* debugging tty for the backend server */
dbName = getenv("USER"); /* change this to the name of your test database*/
/* make a connection to the database */
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '&percnt;s' failed.0, dbName);
fprintf(stderr,"&percnt;s",PQerrorMessage(conn));
exit_nicely(conn);
}
/* start a transaction block */
res = PQexec(conn,"BEGIN");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr,"BEGIN command failed0);
PQclear(res);
exit_nicely(conn);
}
/* should PQclear PGresult whenever it is no longer needed to avoid
memory leaks */
PQclear(res);
/* fetch instances from the pg_database, the system catalog of databases*/
res = PQexec(conn,"DECLARE mycursor BINARY CURSOR FOR select * from test1");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr,"DECLARE CURSOR command failed0);
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
res = PQexec(conn,"FETCH ALL in mycursor");
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
fprintf(stderr,"FETCH ALL command didn't return tuples properly0);
PQclear(res);
exit_nicely(conn);
}
i_fnum = PQfnumber(res,"i");
d_fnum = PQfnumber(res,"d");
p_fnum = PQfnumber(res,"p");
for (i=0;i&lt;3;i++) {
printf("type[&percnt;d] = &percnt;d, size[&percnt;d] = &percnt;d0,
i, PQftype(res,i),
i, PQfsize(res,i));
}
for (i=0; i &lt; PQntuples(res); i++) {
int *ival;
float *dval;
int plen;
POLYGON* pval;
/*/
ival = (int*)PQgetvalue(res,i,i_fnum);
dval = (float*)PQgetvalue(res,i,d_fnum);
plen = PQgetlength(res,i,p_fnum);
/* plen doesn't include the length field so need to increment by VARHDSZ*/
pval = (POLYGON*) malloc(plen + VARHDRSZ);
pval-&gt;size = plen;
memmove((char*)&amp;pval-&gt;npts, PQgetvalue(res,i,p_fnum), plen);
printf("tuple &percnt;d: got0, i);
printf(" i = (&percnt;d bytes) &percnt;d,0,
PQgetlength(res,i,i_fnum), *ival);
printf(" d = (&percnt;d bytes) &percnt;f,0,
PQgetlength(res,i,d_fnum), *dval);
printf(" p = (&percnt;d bytes) &percnt;d points boundbox = (hi=&percnt;f/&percnt;f, lo = &percnt;f,&percnt;f)0,
PQgetlength(res,i,d_fnum),
pval-&gt;npts,
pval-&gt;boundbox.xh,
pval-&gt;boundbox.yh,
pval-&gt;boundbox.xl,
pval-&gt;boundbox.yl);
}
PQclear(res);
/* close the portal */
res = PQexec(conn, "CLOSE mycursor");
PQclear(res);
/* end the transaction */
res = PQexec(conn, "END");
PQclear(res);
/* close the connection to the database and cleanup */
PQfinish(conn);
}
</ProgramListing>
<Para>
</Sect2>
</Sect1>
</Chapter>
<Chapter>
<Title>Large Objects</Title>
<Para>
In <ProductName>Postgres</ProductName>, data values are stored in tuples and
individual tuples cannot span data pages. Since the size of
a data page is 8192 bytes, the upper limit on the size
of a data value is relatively low. To support the storage
of larger atomic values, <ProductName>Postgres</ProductName> provides a large
object interface. This interface provides file
oriented access to user data that has been declared to
be a large type.
This section describes the implementation and the
programmatic and query language interfaces to <ProductName>Postgres</ProductName>
large object data.
</Para>
<Sect1>
<Title>Historical Note</Title>
<Para>
Originally, <ProductName>Postgres 4.2</ProductName> supported three standard
implementations of large objects: as files external
to <ProductName>Postgres</ProductName>, as <Acronym>UNIX</Acronym> files managed by <ProductName>Postgres</ProductName>, and as data
stored within the <ProductName>Postgres</ProductName> database. It causes
considerable confusion among users. As a result, we only
support large objects as data stored within the <ProductName>Postgres</ProductName>
database in <ProductName>PostgreSQL</ProductName>. Even though is is slower to
access, it provides stricter data integrity.
For historical reasons, this storage scheme is referred to as
Inversion large objects. (We will use Inversion and large
objects interchangeably to mean the same thing in this
section.)
</Para>
</Sect1>
<Sect1>
<Title>Inversion Large Objects</Title>
<Para>
The Inversion large object implementation breaks large
objects up into "chunks" and stores the chunks in
tuples in the database. A B-tree index guarantees fast
searches for the correct chunk number when doing random
access reads and writes.
</Para>
</Sect1>
<Sect1>
<Title>Large Object Interfaces</Title>
<Para>
The facilities <ProductName>Postgres</ProductName> provides to access large
objects, both in the backend as part of user-defined
functions or the front end as part of an application
using the interface, are described below. (For users
familiar with <ProductName>Postgres 4.2</ProductName>, <ProductName>PostgreSQL</ProductName> has a new set of
functions providing a more coherent interface. The
interface is the same for dynamically-loaded C
functions as well as for XXX LOST TEXT? WHAT SHOULD GO HERE??.
The <ProductName>Postgres</ProductName> large object interface is modeled after
the <Acronym>UNIX</Acronym> file system interface, with analogues of
<Function>open(2)</Function>, <Function>read(2)</Function>, <Function>write(2)</Function>,
<Function>lseek(2)</Function>, etc. User
functions call these routines to retrieve only the data of
interest from a large object. For example, if a large
object type called mugshot existed that stored
photographs of faces, then a function called beard could
be declared on mugshot data. Beard could look at the
lower third of a photograph, and determine the color of
the beard that appeared there, if any. The entire
large object value need not be buffered, or even
examined, by the beard function.
Large objects may be accessed from dynamically-loaded <Acronym>C</Acronym>
functions or database client programs that link the
library. <ProductName>Postgres</ProductName> provides a set of routines that
support opening, reading, writing, closing, and seeking on
large objects.
</Para>
<Sect2>
<Title>Creating a Large Object</Title>
<Para>
The routine
<ProgramListing>
Oid lo_creat(PGconn *conn, int mode)
</ProgramListing>
creates a new large object. The mode is a bitmask
describing several different attributes of the new
object. The symbolic constants listed here are defined
in
<FileName>
PGROOT/src/backend/libpq/libpq-fs.h
</FileName>
The access type (read, write, or both) is controlled by
OR ing together the bits <Acronym>INV_READ</Acronym> and <Acronym>INV_WRITE</Acronym>. If
the large object should be archived -- that is, if
historical versions of it should be moved periodically to
a special archive relation -- then the <Acronym>INV_ARCHIVE</Acronym> bit
should be set. The low-order sixteen bits of mask are
the storage manager number on which the large object
should reside. For sites other than Berkeley, these
bits should always be zero.
The commands below create an (Inversion) large object:
<ProgramListing>
inv_oid = lo_creat(INV_READ|INV_WRITE|INV_ARCHIVE);
</ProgramListing>
</Para>
</Sect2>
<Sect2>
<Title>Importing a Large Object</Title>
<Para>
To import a <Acronym>UNIX</Acronym> file as
a large object, call
<ProgramListing>
Oid lo_import(PGconn *conn, text *filename)
</ProgramListing>
The filename argument specifies the <Acronym>UNIX</Acronym> pathname of
the file to be imported as a large object.
</Para>
</Sect2>
<Sect2>
<Title>Exporting a Large Object</Title>
<Para>
To export a large object
into <Acronym>UNIX</Acronym> file, call
<ProgramListing>
int lo_export(PGconn *conn, Oid lobjId, text *filename)
</ProgramListing>
The lobjId argument specifies the Oid of the large
object to export and the filename argument specifies
the <Acronym>UNIX</Acronym> pathname of the file.
</Para>
</Sect2>
<Sect2>
<Title>Opening an Existing Large Object</Title>
<Para>
To open an existing large object, call
<ProgramListing>
int lo_open(PGconn *conn, Oid lobjId, int mode, ...)
</ProgramListing>
The lobjId argument specifies the Oid of the large
object to open. The mode bits control whether the
object is opened for reading INV_READ), writing or
both.
A large object cannot be opened before it is created.
lo_open returns a large object descriptor for later use
in lo_read, lo_write, lo_lseek, lo_tell, and lo_close.
</Para>
</Sect2>
<Sect2>
<Title>Writing Data to a Large Object</Title>
<Para>
The routine
<ProgramListing>
int lo_write(PGconn *conn, int fd, char *buf, int len)
</ProgramListing>
writes len bytes from buf to large object fd. The fd
argument must have been returned by a previous lo_open.
The number of bytes actually written is returned. In
the event of an error, the return value is negative.
</Para>
</Sect2>
<Sect2>
<Title>Seeking on a Large Object</Title>
<Para>
To change the current read or write location on a large
object, call
<ProgramListing>
int lo_lseek(PGconn *conn, int fd, int offset, int whence)
</ProgramListing>
This routine moves the current location pointer for the
large object described by fd to the new location specified
by offset. The valid values for .i whence are
SEEK_SET SEEK_CUR and SEEK_END.
</Para>
</Sect2>
<Sect2>
<Title>Closing a Large Object Descriptor</Title>
<Para>
A large object may be closed by calling
<ProgramListing>
int lo_close(PGconn *conn, int fd)
</ProgramListing>
where fd is a large object descriptor returned by
lo_open. On success, <Acronym>lo_close</Acronym> returns zero. On error,
the return value is negative.
</Para>
</Sect1>
<Sect1>
<Title>Built in registered functions</Title>
<Para>
There are two built-in registered functions, <Acronym>lo_import</Acronym>
and <Acronym>lo_export</Acronym> which are convenient for use in <Acronym>SQL</Acronym>
queries.
Here is an example of their use
<ProgramListing>
CREATE TABLE image (
name text,
raster oid
);
INSERT INTO image (name, raster)
VALUES ('beautiful image', lo_import('/etc/motd'));
SELECT lo_export(image.raster, "/tmp/motd") from image
WHERE name = 'beautiful image';
</ProgramListing>
</Para>
</Sect1>
<Sect1>
<Title>Accessing Large Objects from LIBPQ</Title>
<Para>
Below is a sample program which shows how the large object
interface
in LIBPQ can be used. Parts of the program are
commented out but are left in the source for the readers
benefit. This program can be found in
<FileName>
../src/test/examples
</FileName>
Frontend applications which use the large object interface
in LIBPQ should include the header file
libpq/libpq-fs.h and link with the libpq library.
</Para>
</Sect1>
<Sect1>
<Title>Sample Program</Title>
<Para>
<ProgramListing>
/*--------------------------------------------------------------
*
* testlo.c--
* test using large objects with libpq
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* /usr/local/devel/pglite/cvs/src/doc/manual.me,v 1.16 1995/09/01 23:55:00 jolly Exp
*
*--------------------------------------------------------------
*/
#include &lt;stdio.h&gt;
#include "libpq-fe.h"
#include "libpq/libpq-fs.h"
#define BUFSIZE 1024
/*
* importFile * import file "in_filename" into database as large object "lobjOid"
*
*/
Oid importFile(PGconn *conn, char *filename)
{
Oid lobjId;
int lobj_fd;
char buf[BUFSIZE];
int nbytes, tmp;
int fd;
/*
* open the file to be read in
*/
fd = open(filename, O_RDONLY, 0666);
if (fd &lt; 0) { /* error */
fprintf(stderr, "can't open unix file
}
/*
* create the large object
*/
lobjId = lo_creat(conn, INV_READ|INV_WRITE);
if (lobjId == 0) {
fprintf(stderr, "can't create large object");
}
lobj_fd = lo_open(conn, lobjId, INV_WRITE);
/*
* read in from the Unix file and write to the inversion file
*/
while ((nbytes = read(fd, buf, BUFSIZE)) &gt; 0) {
tmp = lo_write(conn, lobj_fd, buf, nbytes);
if (tmp &lt; nbytes) {
fprintf(stderr, "error while reading
}
}
(void) close(fd);
(void) lo_close(conn, lobj_fd);
return lobjId;
}
void pickout(PGconn *conn, Oid lobjId, int start, int len)
{
int lobj_fd;
char* buf;
int nbytes;
int nread;
lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd &lt; 0) {
fprintf(stderr,"can't open large object %d",
lobjId);
}
lo_lseek(conn, lobj_fd, start, SEEK_SET);
buf = malloc(len+1);
nread = 0;
while (len - nread &gt; 0) {
nbytes = lo_read(conn, lobj_fd, buf, len - nread);
buf[nbytes] = ' ';
fprintf(stderr,"&gt;&gt;&gt; %s", buf);
nread += nbytes;
}
fprintf(stderr,"0);
lo_close(conn, lobj_fd);
}
void overwrite(PGconn *conn, Oid lobjId, int start, int len)
{
int lobj_fd;
char* buf;
int nbytes;
int nwritten;
int i;
lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd &lt; 0) {
fprintf(stderr,"can't open large object %d",
lobjId);
}
lo_lseek(conn, lobj_fd, start, SEEK_SET);
buf = malloc(len+1);
for (i=0;i&lt;len;i++)
buf[i] = 'X';
buf[i] = ' ';
nwritten = 0;
while (len - nwritten &gt; 0) {
nbytes = lo_write(conn, lobj_fd, buf + nwritten, len - nwritten);
nwritten += nbytes;
}
fprintf(stderr,"0);
lo_close(conn, lobj_fd);
}
/*
* exportFile * export large object "lobjOid" to file "out_filename"
*
*/
void exportFile(PGconn *conn, Oid lobjId, char *filename)
{
int lobj_fd;
char buf[BUFSIZE];
int nbytes, tmp;
int fd;
/*
* create an inversion "object"
*/
lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd &lt; 0) {
fprintf(stderr,"can't open large object %d",
lobjId);
}
/*
* open the file to be written to
*/
fd = open(filename, O_CREAT|O_WRONLY, 0666);
if (fd &lt; 0) { /* error */
fprintf(stderr, "can't open unix file
filename);
}
/*
* read in from the Unix file and write to the inversion file
*/
while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) &gt; 0) {
tmp = write(fd, buf, nbytes);
if (tmp &lt; nbytes) {
fprintf(stderr,"error while writing
filename);
}
}
(void) lo_close(conn, lobj_fd);
(void) close(fd);
return;
}
void
exit_nicely(PGconn* conn)
{
PQfinish(conn);
exit(1);
}
int
main(int argc, char **argv)
{
char *in_filename, *out_filename;
char *database;
Oid lobjOid;
PGconn *conn;
PGresult *res;
if (argc != 4) {
fprintf(stderr, "Usage: %s database_name in_filename out_filename0,
argv[0]);
exit(1);
}
database = argv[1];
in_filename = argv[2];
out_filename = argv[3];
/*
* set up the connection
*/
conn = PQsetdb(NULL, NULL, NULL, NULL, database);
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '%s' failed.0, database);
fprintf(stderr,"%s",PQerrorMessage(conn));
exit_nicely(conn);
}
res = PQexec(conn, "begin");
PQclear(res);
printf("importing file
/* lobjOid = importFile(conn, in_filename); */
lobjOid = lo_import(conn, in_filename);
/*
printf("as large object %d.0, lobjOid);
printf("picking out bytes 1000-2000 of the large object0);
pickout(conn, lobjOid, 1000, 1000);
printf("overwriting bytes 1000-2000 of the large object with X's0);
overwrite(conn, lobjOid, 1000, 1000);
*/
printf("exporting large object to file
/* exportFile(conn, lobjOid, out_filename); */
lo_export(conn, lobjOid,out_filename);
res = PQexec(conn, "end");
PQclear(res);
PQfinish(conn);
exit(0);
}
</ProgramListing>
</Para>
</Sect1>
</Chapter>
<Chapter>
<Title>Managing a Database</Title>
<Para>
<Note>
<Para>
This section is currently a thinly disguised copy of the Tutorial. Needs to be augmented.
- thomas 1998-01-12
</Para>
</Note>
</Para>
<Para>
Although the <FirstTerm>site administrator</FirstTerm> is responsible for overall management of the
<ProductName>Postgres</ProductName> installation, some databases within the
installation may be managed by another person, designated the <FirstTerm>database administrator</FirstTerm>.
This assignment of responsibilities occurs when a database is created. A user may be assigned
explicit privileges to create databases and/or to create new users. A user assigned both privileges
can perform most administrative task within <ProductName>Postgres</ProductName>, but will
not by default have the same operating system privileges as the site administrator.
</Para>
<Para>
The Database Administrator's Guide covers these topics in more detail.
</Para>
<Sect1>
<Title>Database Creation</Title>
<Para>
Databases are created by the <Command>create database</Command> issued from
within <ProductName>Postgres</ProductName>. <Application>createdb</Application> is a command-line
utility provided to give the same functionality from outside <ProductName>Postgres</ProductName>.
</Para>
<Para>
The <ProductName>Postgres</ProductName> backend must be running for either method
to succeed, and the user issuing the command must be the <ProductName>Postgres</ProductName>
<FirstTerm>superuser</FirstTerm> or have been assigned database creation privileges by the
superuser.
</Para>
<Para>
To create a new database named <Quote>mydb</Quote> from the command line, type
<ProgramListing>
% createdb mydb
</ProgramListing>
and to do the same from within <Application>psql</Application> type
<ProgramListing>
* CREATE DATABASE mydb;
</ProgramListing>
</Para>
<Para>
If you do not have the privileges required to create a database, you will see
the following:
<ProgramListing>
% createdb mydb
WARN:user "your username" is not allowed to create/destroy databases
createdb: database creation failed on mydb.
</ProgramListing>
</Para>
<Para>
<ProductName>Postgres</ProductName> allows you to create any number of databases
at a given site and you automatically become the
database administrator of the database you just created.
Database names must have an alphabetic first
character and are limited to 32 characters in length.
</Para>
</Sect1>
<Sect1>
<Title>Alternate Database Locations</Title>
<Para>
It is possible to create a database in a location other than the default
location for the installation. Remember that all database access actually
occurs through the database backend, so that any location specified must
be accessible by the backend.
<Para>
Either an absolute path name or an environment variable
may be specified as a location.
Any environment variable specifying an alternate location must have
been defined before the backend was started.
Consult with the site administrator
regarding preconfigured alternate database locations.
<Note>
<Para>
The environment variable style of specification
is to be preferred since it allows the site administrator more flexibility in
managing disk storage.
</Para>
</Note>
<Para>
For security and integrity reasons,
any path or environment variable specified has some
additional path fields appended.
<Para>
Alternate database locations must be prepared by running <Application>initlocation</Application>.
<Para>
To create a data storage area in <FileName>/alt/postgres/data</FileName>, ensure
that <FileName>/alt/postgres</FileName> already exists.
From the command line, type
<ProgramListing>
% initlocation /alt/postgres/data
Creating Postgres database system directory /alt/postgres/data
Creating Postgres database system directory /alt/postgres/data/base
</ProgramListing>
<Para>
To do the same using an environment variable PGDATA2, type
<ProgramListing>
% initlocation $PGDATA2
Creating Postgres database system directory /alt/postgres/data
Creating Postgres database system directory /alt/postgres/data/base
</ProgramListing>
<Para>
To create a database in the alternate storage area <FileName>/alt/postgres/data</FileName>
from the command line,
type
<ProgramListing>
% createdb -D /alt/postgres/data mydb
</ProgramListing>
or
<ProgramListing>
% createdb -D PGDATA2 mydb
</ProgramListing>
and to do the same from within <Application>psql</Application> type
<ProgramListing>
* CREATE DATABASE mydb WITH LOCATION = 'PGDATA2';
</ProgramListing>
</Para>
<Para>
If you do not have the privileges required to create a database, you will see
the following:
<ProgramListing>
% createdb mydb
WARN:user "your username" is not allowed to create/destroy databases
createdb: database creation failed on mydb.
</ProgramListing>
</Para>
<Para>
If the specified location does not exist or the database backend does not have
permission to access it or to write to directories under it, you will see
the following:
<ProgramListing>
% createdb -D /alt/postgres/data mydb
ERROR: Unable to create database directory /alt/postgres/data/base/mydb
createdb: database creation failed on mydb.
</ProgramListing>
</Sect1>
<Sect1>
<Title>Accessing a Database</Title>
<Para>
Once you have constructed a database, you can access it
by:
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
running the <ProductName>Postgres</ProductName> terminal monitor programs (e.g.
<Application>psql</Application>) which allows you to interactively
enter, edit, and execute <Acronym>SQL</Acronym> commands.
</Para>
</ListItem>
<ListItem>
<Para>
writing a C program using the LIBPQ subroutine
library. This allows you to submit <Acronym>SQL</Acronym> commands
from C and get answers and status messages back to
your program. This interface is discussed further
in section ??.
</Para>
</ListItem>
</ItemizedList>
You might want to start up <Application>psql</Application>, to try out the examples in this manual.
It can be activated for the <Database>mydb</Database>
database by typing the command:
<ProgramListing>
% psql mydb
</ProgramListing>
You will be greeted with the following message:
<ProgramListing>
Welcome to the POSTGRESQL interactive sql monitor:
Please read the file COPYRIGHT for copyright terms of POSTGRESQL
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: template1
mydb=>
</ProgramListing>
</Para>
<Para>
This prompt indicates that the terminal monitor is listening
to you and that you can type <Acronym>SQL</Acronym> queries into a
workspace maintained by the terminal monitor.
The <Application>psql</Application> program responds to escape codes that begin
with the backslash character, <Quote>\</Quote> For example, you
can get help on the syntax of various
<ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> commands by typing:
<ProgramListing>
mydb=> \h
</ProgramListing>
Once you have finished entering your queries into the
workspace, you can pass the contents of the workspace
to the <ProductName>Postgres</ProductName> server by typing:
<ProgramListing>
mydb=> \g
</ProgramListing>
This tells the server to process the query. If you
terminate your query with a semicolon, the <Quote>\g</Quote> is not
necessary. <Application>psql</Application> will automatically process semicolon terminated queries.
To read queries from a file, say myFile, instead of
entering them interactively, type:
<ProgramListing>
mydb=> \i fileName
</ProgramListing>
To get out of <Application>psql</Application> and return to UNIX, type
<ProgramListing>
mydb=> \q
</ProgramListing>
and <Application>psql</Application> will quit and return you to your command
shell. (For more escape codes, type <Command>\h</Command> at the monitor
prompt.)
White space (i.e., spaces, tabs and newlines) may be
used freely in <Acronym>SQL</Acronym> queries. Single-line comments are denoted by
<Quote>--</Quote>. Everything after the dashes up to the end of the
line is ignored. Multiple-line comments, and comments within a line,
are denoted by <Quote>/* ... */</Quote>
</Para>
<Sect2>
<Title>Database Privileges</Title>
<Para>
</Sect2>
<Sect2>
<Title>Table Privileges</Title>
<Para>
TBD
</Para>
</Sect2>
</Sect1>
<Sect1>
<Title>Destroying a Database</Title>
<Para>
If you are the database administrator for the database
<Database>mydb</Database>, you can destroy it using the following UNIX command:
<ProgramListing>
% destroydb mydb
</ProgramListing>
This action physically removes all of the UNIX files
associated with the database and cannot be undone, so
this should only be done with a great deal of forethought.
</Para>
</Sect1>
</Chapter>
<Chapter>
<DocInfo>
<AuthorGroup>
<Author>
<FirstName>Tim</FirstName>
<Surname>Goeke</Surname>
</Author>
</AuthorGroup>
<Date>Transcribed 1998-02-12</Date>
</DocInfo>
<Title>ODBC Interface</Title>
<Para>
<Note>
<Para>
Contributed by <ULink url="mailto:tgoeke@xpressway.com">Tim Goeke</ULink>
</Para>
</Note>
<Para>
ODBC is an abstract API which allows you to write standard "ODBC" code,
using the ODBC API.
<Sect1>
<Title>Background</Title>
<Para>
The ODBC API matches up on the backend to an ODBC compatible data source.
This could be anything from a text file to an Oracle RDBMS.
<Para>
The backend access come from ODBC drivers, or vendor specifc drivers that
allow data access. PostODBC is such a driver, along with others that are
available, such as the OpenLink ODBC drivers.
<Para>
Once you write an ODBC application, you SHOULD be able to connect to ANY
back end database, regardless of the vendor, as long as the database schema
is the same.
<Para>
For example. you could have MS SQL Server and PostgreSQL servers which have
exactly the same data. Using ODBC, your Windows app would make exactly the
same calls and the back end data source would look the same (to the windows
app).
<Para>
In the real world, differences in drivers and the level of ODBC support
lessens the potential of ODBC:
<SimpleList>
<Member>
Access, Delphi, and Visual Basic all support ODBC directly.
<Member>
Under C++, such as Visual C++, you can use the C++ ODBC API.
<Member>
In Visual C++, you can use the CRecordSet class, which wraps the ODBC API
set within and MFC 4.2 class. This is the easiest route if you are doing
Windows C++ development under Windows NT.
</SimpleList>
<Para>
If I write an app for PostgreSQL can I write it using ODBC calls
to the PostgreSQL server, or is that only when another database program
like MS SQL Server or Access needs to access the data?
<Para>
Again, the ODBC API set is the way to go. You can find out more at
Microsoft's web site or in your Visual C++ docs (if that's what you are
using.)
<Para>
Visual Basic and the other RAD tools have Recordset objects that use ODBC
directly to access data. Using the data-aware controls, you can quickly
link to the ODBC back end database (<Emphasis>very</Emphasis> quickly).
<Para>
Playing around with MS Access will help you sort this out. Try using
File->Get External Data
<Para>
<Tip>
<Para>
You'll have to set up a DSN first.
</Para>
</Tip>
<Para>
<Tip>
<Para>
The PostgreSQL datetime type will break MS Access.
</Para>
</Tip>
</Chapter>
<Chapter>
<Title><Command>pgaccess</Command></Title>
<Para>
This section needs to be written. Volunteers?
</Para>
</Chapter>
<Chapter>
<Title>Ports</Title>
<Sect1>
<Title>Currently Supported Platforms</Title>
<Para>
<ProductName>Postgres</ProductName> is available free of charge. This manual
describes version 6.3 of <ProductName>Postgres</ProductName>. The authors have
compiled and tested <ProductName>Postgres</ProductName> on the following
platforms:
<TABLE TOCENTRY="1">
<TITLE>Supported Platforms</TITLE>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY><Acronym>OS</Acronym></ENTRY>
<ENTRY>Processor</ENTRY>
<ENTRY>Version</ENTRY>
<ENTRY>Reported</ENTRY>
<ENTRY>Remarks</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>AIX 4.1.x-4.2</ENTRY>
<ENTRY>RS6000</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>4.1.4.0,4.2 (<ULink url="mailto:darrenk@insightdist.com">Darren King</ULink>),
4.1.5 (<ULink url="mailto:Andreas.Zeugswetter@telecom.at">Andreas Zeugswetter</ULink>);
3.2.5 confirmed on v6.2.1 (<ULink url="mailto:danaf@ans.net">Frank Dana</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>BSDi</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:maillist@candle.pha.pa.us">Bruce Momjian</ULink></ENTRY>
</ROW>
<ROW>
<ENTRY>FreeBSD 2.2.x-3.x</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:t-ishii@sra.co.jp">Tatsuo Ishii</ULink>,
<ULink url="mailto:scrappy@hub.org">Marc Fournier</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>NetBSD 1.3</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:brook@trillium.NMSU.Edu">Brook Milligan</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>NetBSD 1.3</ENTRY>
<ENTRY>Sparc</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:tih@hamartun.priv.no">Tom I Helbekkmo</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>NetBSD 1.3</ENTRY>
<ENTRY>VAX</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:tih@hamartun.priv.no">Tom I Helbekkmo</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>DGUX 5.4R4.11</ENTRY>
<ENTRY>m88k</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:geek+@cmu.edu">Brian E Gallew</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>HPUX 10.20</ENTRY>
<ENTRY>PA-RISC</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>9.0.x confirmed on v6.2.1 (<ULink url="mailto:stanb@awod.com">Stan Brown</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>IRIX 6.x</ENTRY>
<ENTRY>MIPS</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>5.x is different (<ULink url="mailto:martin@biochemistry.ucl.ac.uk">Andrew Martin</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>Digital 4.0</ENTRY>
<ENTRY>Alpha</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>in progress; v6.2.1 confirmed working (<ULink url="mailto:pjlobo@euitt.upm.es">Pedro J. Lobo</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>linux 2.0.x</ENTRY>
<ENTRY>Alpha</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>partial success (<ULink url="mailto:rkirkpat@nag.cs.colorado.edu">Ryan Kirkpatrick</ULink>,
<ULink url="mailto:jsturm@zenacomp.com"> Jeff Sturm </ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>linux 2.0.x</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:lockhart@alumni.caltech.edu">Thomas Lockhart</ULink>,
<ULink url="mailto:t-ishii@sra.co.jp">Tatsuo Ishii</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>linux 2.0.x</ENTRY>
<ENTRY>Sparc</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:szybist@boxhill.com">Tom Szybist</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>mklinux</ENTRY>
<ENTRY>PPC</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:t-ishii@sra.co.jp">Tatsuo Ishii</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>SCO</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>partial success (<ULink url="mailto:Bill.Allie@mug.org">Billy G. Allie</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>Solaris</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:scrappy@hub.org">Marc Fournier</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>Solaris 2.5.1-2.6</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>(<ULink url="mailto:scrappy@hub.org">Marc Fournier</ULink>,
<ULink url="mailto:t-ishii@sra.co.jp">Tatsuo Ishii</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>SunOS 4.1.4</ENTRY>
<ENTRY>Sparc</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>patches submitted (<ULink url="mailto:t-ishii@sra.co.jp">Tatsuo Ishii</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>SVR4</ENTRY>
<ENTRY>MIPS</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>similar to v6.2.1; "mostly working" (<ULink url="mailto:ridderbusch.pad@sni.de">Frank Ridderbusch</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>SVR4 4.4</ENTRY>
<ENTRY>m88k</ENTRY>
<ENTRY>v6.2.1</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>confirmed with patching (<ULink url="mailto:dlw@seavme.xroads.com">Doug Winterburn</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>Unixware</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>aka UNIVEL (<ULink url="mailto:Bill.Allie@mug.org">Billy G. Allie</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>NextStep</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.x</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>client-only support; v1.0.9 worked with patches (<ULink url="mailto:dave@turbocat.de">David Wetzel</ULink>)</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
<Sect1>
<Title>Unsupported Platforms</Title>
<Para>
A few platforms which have been attempted and which have been
reported to not work with the standard distribution.
Others listed here do not provide sufficient library support for an attempt.
<TABLE TOCENTRY="1">
<TITLE>Possibly Incompatible Platforms</TITLE>
<TITLEABBREV>Incompatibles</TITLEABBREV>
<TGROUP COLS="4">
<THEAD>
<ROW>
<ENTRY><Acronym>OS</Acronym></ENTRY>
<ENTRY>Processor</ENTRY>
<ENTRY>Version</ENTRY>
<ENTRY>Reported</ENTRY>
<ENTRY>Remarks</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY>MacOS</ENTRY>
<ENTRY>all</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>not library compatible; use ODBC/JDBC</ENTRY>
</ROW>
<ROW>
<ENTRY>NetBSD</ENTRY>
<ENTRY>arm32</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>not yet working (<ULink url="mailto:dmill@globalnet.co.uk">Dave Millen</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>NetBSD</ENTRY>
<ENTRY>m68k</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>Amiga, HP300, Mac; not yet working (<ULink url="mailto:hotz@jpl.nasa.gov">Henry Hotz</ULink>)</ENTRY>
</ROW>
<ROW>
<ENTRY>Ultrix</ENTRY>
<ENTRY>MIPS,VAX?</ENTRY>
<ENTRY>v6.x</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>no recent reports; obsolete?</ENTRY>
</ROW>
<ROW>
<ENTRY>Windows NT</ENTRY>
<ENTRY>all</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>not library compatible; client side maybe; use ODBC/JDBC</ENTRY>
</ROW>
<ROW>
<ENTRY>Windows</ENTRY>
<ENTRY>x86</ENTRY>
<ENTRY>v6.3</ENTRY>
<ENTRY>1998-03-01</ENTRY>
<ENTRY>not library compatible; client side maybe; use ODBC/JDBC</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
<Para>
Note that Windows ports of the frontend are apparently possible
using third-party Posix porting tools and libraries.
</Para>
</Sect1>
</Chapter>
<!-- postgres.sgml
-
- Postgres integrated documentation.
- Other subset docs should be copied and shrunk from here.
- thomas 1998-02-23
-
- -->
<!doctype book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
<!entity intro SYSTEM "intro.sgml">
<!entity arch SYSTEM "arch.sgml">
<!entity start SYSTEM "start.sgml">
<!entity query SYSTEM "query.sgml">
<!entity advanced SYSTEM "advanced.sgml">
<!entity environ SYSTEM "environ.sgml">
<!entity manage SYSTEM "manage.sgml">
<!entity datatype SYSTEM "datatype.sgml">
<!entity array SYSTEM "array.sgml">
<!entity inherit SYSTEM "inherit.sgml">
<!entity query-ug SYSTEM "query-ug.sgml">
<!entity storage SYSTEM "storage.sgml">
<!entity psql SYSTEM "psql.sgml">
<!entity pgaccess SYSTEM "pgaccess.sgml">
<!entity start-ag SYSTEM "start-ag.sgml">
<!entity install SYSTEM "install.sgml">
<!entity recovery SYSTEM "recovery.sgml">
<!entity regress SYSTEM "regress.sgml">
<!entity ports SYSTEM "ports.sgml">
<!entity release SYSTEM "release.sgml">
<!entity intro-pg SYSTEM "intro-pg.sgml">
<!entity arch-pg SYSTEM "arch-pg.sgml">
<!entity extend SYSTEM "extend.sgml">
<!entity rules SYSTEM "rules.sgml">
<!entity xfunc SYSTEM "xfunc.sgml">
<!entity xtypes SYSTEM "xtypes.sgml">
<!entity xoper SYSTEM "xoper.sgml">
<!entity xaggr SYSTEM "xaggr.sgml">
<!entity xindex SYSTEM "xindex.sgml">
<!entity gist SYSTEM "gist.sgml">
<!entity dfunc SYSTEM "dfunc.sgml">
<!entity lobj SYSTEM "lobj.sgml">
<!entity trigger SYSTEM "trigger.sgml">
<!entity spi SYSTEM "spi.sgml">
<!entity func-ref SYSTEM "func-ref.sgml">
<!entity libpq SYSTEM "libpq.sgml">
<!entity libpgtcl SYSTEM "libpgtcl.sgml">
<!entity ecpg SYSTEM "ecpg.sgml">
<!entity odbc SYSTEM "odbc.sgml">
<!entity jdbc SYSTEM "jdbc.sgml">
<!entity arch-dev SYSTEM "arch-dev.sgml">
<!entity geqo SYSTEM "geqo.sgml">
<!entity protocol SYSTEM "protocol.sgml">
<!entity compiler SYSTEM "compiler.sgml">
<!entity docguide SYSTEM "docguide.sgml">
<!entity biblio SYSTEM "biblio.sgml">
<!entity contacts SYSTEM "contacts.sgml">
]>
<!-- entity manpages SYSTEM "man/manpages.sgml" subdoc -->
<Book>
<!-- Title information -->
<Title>PostgreSQL</Title>
<BookInfo>
<ReleaseInfo>Covering v6.3 for general release</ReleaseInfo>
<BookBiblio>
<AuthorGroup>
<CorpAuthor>The PostgreSQL Development Team</CorpAuthor>
</AuthorGroup>
<!-- editor in authorgroup is not supported
<AuthorGroup>
-->
<Editor>
<FirstName>Thomas</FirstName>
<SurName>Lockhart</SurName>
<Affiliation>
<OrgName>Caltech/JPL</OrgName>
</Affiliation>
</Editor>
<!--
</AuthorGroup>
-->
<!--
<AuthorInitials>TGL</AuthorInitials>
-->
<Date>(last updated 1998-02-23)</Date>
</BookBiblio>
<LegalNotice>
<Para>
<ProductName>PostgreSQL</ProductName> is copyright (C) 1998 by the Postgres Global Development Group.
</Para>
</LegalNotice>
</BookInfo>
<!--
<TOC> </TOC>
<LOT> </LOT>
-->
<!--
<Dedication>
<Para>
Your name here...
</Para>
</Dedication>
-->
<Preface>
<Title>Summary</Title>
<Para>
<ProductName>Postgres</ProductName>,
developed originally in the UC Berkeley Computer Science Department,
pioneered many of the object-relational concepts
now becoming available in some commercial databases.
It provides SQL92/SQL3 language support,
transaction integrity, and type extensibility.
<ProductName>PostgreSQL</ProductName> is a public-domain, open source descendant
of this original Berkeley code.
</Para>
</Preface>
<Part>
<Title>Tutorial</Title>
<PartIntro>
<Para>
Introduction for new users.
</Para>
</PartIntro>
&intro;
&arch;
&start;
&query;
&advanced;
</Part>
<Part>
<Title>User's Guide</Title>
<PartIntro>
<Para>
Information for users.
</Para>
</PartIntro>
&environ;
&manage;
&datatype;
&array;
&inherit;
&query-ug;
&storage;
&psql;
&pgaccess;
</Part>
<Part>
<Title>Administrator's Guide</Title>
<PartIntro>
<Para>
Installation and maintenance information.
</Para>
</PartIntro>
&ports;
&install;
&start-ag;
&recovery;
&regress;
&release;
</Part>
<Part>
<Title>Programmer's Guide</Title>
<PartIntro>
<Para>
Information for extending <ProductName>Postgres</ProductName>.
</Para>
</PartIntro>
&intro-pg;
&arch-pg;
&extend;
&xfunc;
&xtypes;
&xoper;
&xaggr;
&xindex;
&gist;
&dfunc;
&trigger;
&spi;
&libpq;
</Part>
<Part>
<Title>Reference</Title>
<PartIntro>
<Para>
User and programmer interfaces.
</Para>
</PartIntro>
&func-ref;
&lobj;
&ecpg;
&libpq;
&libpgtcl;
&odbc;
&jdbc;
</Part>
<Part>
<Title>Developer's Guide</Title>
<PartIntro>
<Para>
The Developer's Guide includes discussion of design decisions and suggestions for
future development.
</Para>
</PartIntro>
&arch-dev;
&geqo;
&protocol;
&compiler;
</Part>
<Part>
<Title>Appendices</Title>
<PartIntro>
<Para>
Additional related information.
</Para>
</PartIntro>
&docguide;
&contacts;
&biblio;
</Part>
<INDEX> </INDEX>
</Book>
<!-- programmer.sgml
-
- Postgres programmer's guide.
- Derived from postgres.sgml.
- thomas 1998-02-24
-
- -->
<!doctype book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
<!entity intro SYSTEM "intro.sgml">
<!entity arch SYSTEM "arch.sgml">
<!entity start SYSTEM "start.sgml">
<!entity query SYSTEM "query.sgml">
<!entity advanced SYSTEM "advanced.sgml">
<!entity environ SYSTEM "environ.sgml">
<!entity manage SYSTEM "manage.sgml">
<!entity datatype SYSTEM "datatype.sgml">
<!entity array SYSTEM "array.sgml">
<!entity inherit SYSTEM "inherit.sgml">
<!entity query-ug SYSTEM "query-ug.sgml">
<!entity storage SYSTEM "storage.sgml">
<!entity psql SYSTEM "psql.sgml">
<!entity pgaccess SYSTEM "pgaccess.sgml">
<!entity start-ag SYSTEM "start-ag.sgml">
<!entity install SYSTEM "install.sgml">
<!entity recovery SYSTEM "recovery.sgml">
<!entity regress SYSTEM "regress.sgml">
<!entity ports SYSTEM "ports.sgml">
<!entity release SYSTEM "release.sgml">
<!entity intro-pg SYSTEM "intro-pg.sgml">
<!entity arch-pg SYSTEM "arch-pg.sgml">
<!entity extend SYSTEM "extend.sgml">
<!entity rules SYSTEM "rules.sgml">
<!entity xfunc SYSTEM "xfunc.sgml">
<!entity xtypes SYSTEM "xtypes.sgml">
<!entity xoper SYSTEM "xoper.sgml">
<!entity xaggr SYSTEM "xaggr.sgml">
<!entity xindex SYSTEM "xindex.sgml">
<!entity gist SYSTEM "gist.sgml">
<!entity dfunc SYSTEM "dfunc.sgml">
<!entity lobj SYSTEM "lobj.sgml">
<!entity trigger SYSTEM "trigger.sgml">
<!entity spi SYSTEM "spi.sgml">
<!entity func-ref SYSTEM "func-ref.sgml">
<!entity libpq SYSTEM "libpq.sgml">
<!entity libpgtcl SYSTEM "libpgtcl.sgml">
<!entity ecpg SYSTEM "ecpg.sgml">
<!entity odbc SYSTEM "odbc.sgml">
<!entity jdbc SYSTEM "jdbc.sgml">
<!entity arch-dev SYSTEM "arch-dev.sgml">
<!entity geqo SYSTEM "geqo.sgml">
<!entity protocol SYSTEM "protocol.sgml">
<!entity compiler SYSTEM "compiler.sgml">
<!entity docguide SYSTEM "docguide.sgml">
<!entity biblio SYSTEM "biblio.sgml">
<!entity contacts SYSTEM "contacts.sgml">
]>
<!-- entity manpages SYSTEM "man/manpages.sgml" subdoc -->
<Book>
<!-- Title information -->
<Title>PostgreSQL Programmer's Guide</Title>
<BookInfo>
<ReleaseInfo>Covering v6.3 for general release</ReleaseInfo>
<BookBiblio>
<AuthorGroup>
<CorpAuthor>The PostgreSQL Development Team</CorpAuthor>
</AuthorGroup>
<!-- editor in authorgroup is not supported
<AuthorGroup>
-->
<Editor>
<FirstName>Thomas</FirstName>
<SurName>Lockhart</SurName>
<Affiliation>
<OrgName>Caltech/JPL</OrgName>
</Affiliation>
</Editor>
<!--
</AuthorGroup>
-->
<!--
<AuthorInitials>TGL</AuthorInitials>
-->
<Date>(last updated 1998-02-24)</Date>
</BookBiblio>
<LegalNotice>
<Para>
<ProductName>PostgreSQL</ProductName> is copyright (C) 1998 by the Postgres Global Development Group.
</Para>
</LegalNotice>
</BookInfo>
<!--
<TOC> </TOC>
<LOT> </LOT>
-->
<!--
<Dedication>
<Para>
Your name here...
</Para>
</Dedication>
-->
<Preface>
<Title>Summary</Title>
<Para>
<ProductName>Postgres</ProductName>,
developed originally in the UC Berkeley Computer Science Department,
pioneered many of the object-relational concepts
now becoming available in some commercial databases.
It provides SQL92/SQL3 language support,
transaction integrity, and type extensibility.
<ProductName>PostgreSQL</ProductName> is a public-domain, open source descendant
of this original Berkeley code.
</Para>
</Preface>
&intro-pg;
&arch-pg;
&extend;
&xfunc;
&xtypes;
&xoper;
&xaggr;
&xindex;
&gist;
&dfunc;
&trigger;
&spi;
<!-- reference -->
&func-ref;
&lobj;
&ecpg;
&libpq;
&libpgtcl;
&odbc;
&jdbc;
<!-- development -->
&arch-dev;
&geqo;
&protocol;
&compiler;
<!-- appendices -->
&docguide;
<!--
&contacts;
-->
&biblio;
<!--
<INDEX> </INDEX>
-->
</Book>
<Chapter>
<DocInfo>
<Author>
<FirstName>Phil</FirstName>
<Surname>Thompson</Surname>
</Author>
<Date>1998-02-02</Date>
</DocInfo>
<Title>Frontend/Backend Protocol</Title>
<Para>
<Note>
<Para>
Written by <ULink url="mailto:phil@river-bank.demon.co.uk">Phil Thompson</ULink>
</Para>
</Note>
<Para>
<ProductName>Postgres</ProductName> uses a message-based protocol for communication between frontends
and backends. The protocol is implemented over <Acronym>TCP/IP</Acronym> and also on Unix sockets.
<ProductName>Postgres</ProductName> v6.3 introduced version numbers into the protocol.
This was done in such
a way as to still allow connections from earlier versions of frontends, but
this document does not cover the protocol used by those earlier versions.
<Para>
This document describes the initial version-numbered protocol, designated v1.0.
Higher level features built on this protocol (for example, how <FileName>libpq</FileName> passes
certain environment variables after the connection is established)
are covered elsewhere.
<Sect1>
<Title>Overview</Title>
<Para>
The three major components are the frontend (running on the client) and the
postmaster and backend (running on the server). The postmaster and backend
have different roles but may be implemented by the same executable.
<Para>
A frontend sends a startup packet to the postmaster. This includes the names
of the user and the database the user wants to connect to. The postmaster then
uses this, and the information in the pg_hba.conf(5) file to determine what
further authentication information it requires the frontend to send (if any)
and responds to the frontend accordingly.
<Para>
The frontend then sends any required authentication information. Once the
postmaster validates this it responds to the frontend that it is authenticated
and hands over to a backend.
<Para>
Subsequent communications are query and result packets exchanged between the
frontend and the backend. The postmaster takes no further part in the
communication.
<Para>
When the frontend wishes to disconnect it sends an appropriate packet and
closes the connection without waiting for a response for the backend.
<Para>
Packets are sent as a data stream. The first byte determines what should be
expected in the rest of the packet. The exception is packets send from a
frontend to the postmaster, which comprise a packet length then the packet
itself. The difference is historical.
<Sect1>
<Title>Protocol</Title>
<Para>
This section describes the message flow. There are four different types of
flows depending on the state of the connection:
authentication, query, function call, and termination.
<Sect2>
<Title>Authentication</Title>
<Para>
The frontend sends a StartupPacket. The postmaster uses this and the contents
of the pg_hba.conf(5) file to determine what authentication method the frontend
must use. The postmaster then responds with one of the following messages:
<Para>
<VariableList>
<VarListEntry>
<Term>
ErrorResponse
</Term>
<ListItem>
<Para>
The postmaster then immediately closes the connection.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationOk
</Term>
<ListItem>
<Para>
The postmaster then hands over to the backend. The postmaster
takes no further part in the communication.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationKerberosV4
</Term>
<ListItem>
<Para>
The frontend must then take part in a Kerberos V4
authentication dialog (not described here) with the postmaster.
If this is successful, the postmaster responds with an
AuthenticationOk, otherwise it responds with an ErrorResponse.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationKerberosV5
</Term>
<ListItem>
<Para>
The frontend must then take part in a Kerberos V5
authentication dialog (not described here) with the postmaster.
If this is successful, the postmaster responds with an
AuthenticationOk, otherwise it responds with an ErrorResponse.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationUnencryptedPassword
</Term>
<ListItem>
<Para>
The frontend must then send an UnencryptedPasswordPacket.
If this is the correct password, the postmaster responds with
an AuthenticationOk, otherwise it responds with an
ErrorResponse.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationEncryptedPassword
</Term>
<ListItem>
<Para>
The frontend must then send an EncryptedPasswordPacket.
If this is the correct password, the postmaster responds with
an AuthenticationOk, otherwise it responds with an
ErrorResponse.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
<Para>
If the frontend does not support the authentication method requested by the
postmaster, then it should immediately close the connection.
<Sect2>
<Title>Query</Title>
<Para>
The frontend sends a Query message to the backend. The response sent by the
backend depends on the contents of the query. The possible responses are as
follows.
<Para>
<VariableList>
<VarListEntry>
<Term>
CompletedResponse
</Term>
<ListItem>
<Para>
The query completed normally.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
CopyInResponse
</Term>
<ListItem>
<Para>
The backend is ready to copy data from the frontend to a
relation. The frontend should then send a CopyDataRows
message. The backend will then respond with a
CompletedResponse message with a tag of "COPY".
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
CopyOutResponse
</Term>
<ListItem>
<Para>
The backend is ready to copy data from a relation to the
frontend. It then sends a CopyDataRows message, and then a
CompletedResponse message with a tag of "COPY".
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
CursorResponse
</Term>
<ListItem>
<Para>
The query was either an insert(l), delete(l), update(l),
fetch(l) or a select(l) command.
If the transaction has been
aborted then the backend sends a CompletedResponse message with
a tag of "*ABORT STATE*". Otherwise the following responses
are sent.
</Para>
<Para>
For an insert(l) command, the backend then sends a
CompletedResponse message with a tag of "INSERT <Replaceable>oid</Replaceable> <Replaceable>rows</Replaceable>"
where <Replaceable>rows</Replaceable> is the number of rows inserted, and <Replaceable>oid</Replaceable> is the
object ID of the inserted row if <Replaceable>rows</Replaceable> is 1, otherwise <Replaceable>oid</Replaceable>
is 0.
</Para>
<Para>
For a delete(l) command, the backend then sends a
CompletedResponse message with a tag of "DELETE <Replaceable>rows</Replaceable>" where
<Replaceable>rows</Replaceable> is the number of rows deleted.
</Para>
<Para>
For an update(l) command, the backend then sends a
CompletedResponse message with a tag of "UPDATE <Replaceable>rows</Replaceable>" where
<Replaceable>rows</Replaceable> is the number of rows deleted.
</Para>
<Para>
For a fetch(l) or select(l) command, the backend sends a
RowDescription message. This is then followed by an AsciiRow
or BinaryRow message (depending on if a binary cursor was
specified) for each row being returned to the frontend.
Finally, the backend sends a CompletedResponse message with a
tag of "SELECT".
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
EmptyQueryResponse
</Term>
<ListItem>
<Para>
The query was empty.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
ErrorResponse
</Term>
<ListItem>
<Para>
An error has occurred.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
NoticeResponse
</Term>
<ListItem>
<Para>
A warning message has been issued in relation to the query.
Notices are in addition to other responses, ie. the backend
will send another response message immediately afterwards.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
NotificationResponse
</Term>
<ListItem>
<Para>
A notify(l) command has been executed for a relation for
which a previous listen(l) command was executed. Notifications
are in addition to other responses, ie. the backend will send
another response message immediately afterwards.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
<Para>
A frontend must be prepared to accept ErrorResponse and NoticeResponse
messages whenever it is expecting any other type of message.
<Sect2>
<Title>Function Call</Title>
<Para>
The frontend sends a FunctionCall message to the backend. The response sent by
the backend depends on the result of the function call. The possible responses
are as follows.
<Para>
<VariableList>
<VarListEntry>
<Term>
ErrorResponse
</Term>
<ListItem>
<Para>
An error has occurred.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
FunctionResultResponse
</Term>
<ListItem>
<Para>
The function call was executed and returned a result.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
FunctionVoidResponse
</Term>
<ListItem>
<Para>
The function call was executed and returned no result.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
NoticeResponse
</Term>
<ListItem>
<Para>
A warning message has been issued in relation to the function
call. Notices are in addition to other responses, ie. the
backend will send another response message immediately
afterwards.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
<Para>
A frontend must be prepared to accept ErrorResponse and NoticeResponse
messages whenever it is expecting any other type of message.
<Sect2>
<Title>Termination</Title>
<Para>
The frontend sends a Terminate message and immediately closes the connection.
On receipt of the message, the backend immediately closes the connection and
terminates.
<Sect1>
<Title>Message Data Types</Title>
<Para>
This section describes the base data types used in messages.
<Para>
<VariableList>
<VarListEntry>
<Term>
Int<Replaceable>n</Replaceable>(<Replaceable>i</Replaceable>)
</Term>
<ListItem>
<Para>
An <Replaceable>n</Replaceable> bit integer in network byte order.
If <Replaceable>i</Replaceable> is specified it
is the literal value. Eg. Int16, Int32(42).
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
LimString<Replaceable>n</Replaceable>(<Replaceable>s</Replaceable>)
</Term>
<ListItem>
<Para>
A character array of exactly <Replaceable>n</Replaceable> bytes interpreted as a '\0'
terminated string. The '\0' is omitted if there is
insufficient room. If <Replaceable>s</Replaceable> is specified it is the literal value.
Eg. LimString32, LimString64("user").
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String(<Replaceable>s</Replaceable>)
</Term>
<ListItem>
<Para>
A conventional C '\0' terminated string with no length
limitation. A frontend should always read the full string
even though it may have to discard characters if it's buffers
aren't big enough.
<Note>
<Para>
Is 8193 bytes the largest allowed size?
</Para>
</Note>
If <Replaceable>s</Replaceable> is specified it is the literal value.
Eg. String, String("user").
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte<Replaceable>n</Replaceable>(<Replaceable>c</Replaceable>)
</Term>
<ListItem>
<Para>
Exactly <Replaceable>n</Replaceable> bytes. If <Replaceable>c</Replaceable> is specified it is the literal
value. Eg. Byte, Byte1('\n').
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
<Sect1>
<Title>Message Formats</Title>
<Para>
This section describes the detailed format of each message. Each can be sent
by either a frontend (F), a postmaster/backend (B), or both (F & B).
<Para>
<VariableList>
<VarListEntry>
<Term>
AsciiRow (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('D')
</Term>
<ListItem>
<Para>
Identifies the message, in the context in which it is sent (see
CopyInResponse), as an <Acronym>ASCII</Acronym> row.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte<Replaceable>n</Replaceable>
</Term>
<ListItem>
<Para>
A bit map with one bit for each field in the row. The 1st
field corresponds to bit 7 of the 1st byte, the 2nd field
corresponds to bit 6 of the 1st byte, the 8th field corresponds
to bit 0 of the 1st byte, the 9th field corresponds to bit 8 of
the 2nd byte, and so on. The bit is set if the value of the
corresponding field is not NULL.
</Para>
<Para>
Then, for each field, there is the following:
<VariableList>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
Specifies the size of the value of the field, including
this size.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte<Replaceable>n</Replaceable>
</Term>
<ListItem>
<Para>
Specifies the value of the field itself in <Acronym>ASCII</Acronym>
characters. <Replaceable>n</Replaceable> is the above size minus 4.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationOk (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('R')
</Term>
<ListItem>
<Para>
Identifies the message as an authentication request.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32(0)
</Term>
<ListItem>
<Para>
Specifies that the authentication was successful.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationKerberosV4 (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('R')
</Term>
<ListItem>
<Para>
Identifies the message as an authentication request.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32(1)
</Term>
<ListItem>
<Para>
Specifies that Kerberos V4 authentication is required.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationKerberosV5 (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('R')
</Term>
<ListItem>
<Para>
Identifies the message as an authentication request.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32(2)
</Term>
<ListItem>
<Para>
Specifies that Kerberos V5 authentication is required.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationUnencryptedPassword (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('R')
</Term>
<ListItem>
<Para>
Identifies the message as an authentication request.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32(3)
</Term>
<ListItem>
<Para>
Specifies that an unencrypted password is required.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
AuthenticationEncryptedPassword (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('R')
</Term>
<ListItem>
<Para>
Identifies the message as an authentication request.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32(4)
</Term>
<ListItem>
<Para>
Specifies that an encrypted password is required.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte2
</Term>
<ListItem>
<Para>
The salt to use when encrypting the password.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
BinaryRow (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('B')
</Term>
<ListItem>
<Para>
Identifies the message, in the context in which it is sent (see
CopyOutResponse), as a binary row.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte<Replaceable>n</Replaceable>
</Term>
<ListItem>
<Para>
A bit map with one bit for each field in the row. The 1st
field corresponds to bit 7 of the 1st byte, the 2nd field
corresponds to bit 6 of the 1st byte, the 8th field corresponds
to bit 0 of the 1st byte, the 9th field corresponds to bit 8 of
the 2nd byte, and so on. The bit is set if the value of the
corresponding field is not NULL.
</Para>
<Para>
Then, for each field, there is the following:
<VariableList>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
Specifies the size of the value of the field, excluding
this size.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte<Replaceable>n</Replaceable>
</Term>
<ListItem>
<Para>
Specifies the value of the field itself in binary
format. <Replaceable>n</Replaceable> is the above size.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
CompletedResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('C')
</Term>
<ListItem>
<Para>
Identifies the message as a completed response.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The command tag. This is usually (but not always) a single
word that identifies which SQL command was completed.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
CopyDataRows (B & F)
</Term>
<ListItem>
<Para>
This is a stream of rows where each row is terminated by a Char1('\n').
This is then followed by the sequence Char1('\\'), Char1('.'),
Char1('\n').
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
CopyInResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('D')
</Term>
<ListItem>
<Para>
Identifies the message, in the context in which it is sent (see
AsciiRow), as a copy in started response.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
CopyOutResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('B')
</Term>
<ListItem>
<Para>
Identifies the message, in the context in which it is sent (see
BinaryRow), as a copy out started response.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
CursorResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('P')
</Term>
<ListItem>
<Para>
Identifies the message as a cursor response.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The name of the cursor. This will be "blank" if the cursor is
implicit.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
EmptyQueryResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('I')
</Term>
<ListItem>
<Para>
Identifies the message as an empty query response.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String("")
</Term>
<ListItem>
<Para>
Unused.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
EncryptedPasswordPacket (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The size of the packet in bytes.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The encrypted (using crypt()) password.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
ErrorResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('E')
</Term>
<ListItem>
<Para>
Identifies the message as an error.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The error message itself.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
FunctionCall (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('F')
</Term>
<ListItem>
<Para>
Identifies the message as a function call.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String("")
</Term>
<ListItem>
<Para>
Unused.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
Specifies the object ID of the function to call.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
Specifies the number of arguments being supplied to the
function.
</Para>
<Para>
Then, for each argument, there is the following:
<VariableList>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
Specifies the size of the value of the argument,
excluding this size.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte<Replaceable>n</Replaceable>
</Term>
<ListItem>
<Para>
Specifies the value of the field itself in binary
format. <Replaceable>n</Replaceable> is the above size.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
</VariableList>
<Para>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
FunctionResultResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('V')
</Term>
<ListItem>
<Para>
Identifies the message as a function call result.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte1('G')
</Term>
<ListItem>
<Para>
Specifies that an actual result was returned.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
Specifies the size of the value of the result, excluding this
size.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte<Replaceable>n</Replaceable>
</Term>
<ListItem>
<Para>
Specifies the value of the result itself in binary format.
<Replaceable>n</Replaceable> is the above size.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte1('0')
</Term>
<ListItem>
<Para>
Unused. (Strictly speaking, FunctionResultResponse and
FunctionVoidResponse are the same thing but with some optional
parts to the message.)
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
FunctionVoidResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('V')
</Term>
<ListItem>
<Para>
Identifies the message as a function call result.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Byte1('0')
</Term>
<ListItem>
<Para>
Specifies that no actual result was returned.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
NoticeResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('N')
</Term>
<ListItem>
<Para>
Identifies the message as a notice.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The notice message itself.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
NotificationResponse (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('A')
</Term>
<ListItem>
<Para>
Identifies the message as a notification response.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The process ID of the backend process.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The name of the relation that the notify has been raised on.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Query (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('Q')
</Term>
<ListItem>
<Para>
Identifies the message as query.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The query itself.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
RowDescription (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('T')
</Term>
<ListItem>
<Para>
Identifies the message as a row description.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int16
</Term>
<ListItem>
<Para>
Specifies the number of fields in a row (and may be zero).
</Para>
<Para>
Then, for each field, there is the following:
<VariableList>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
Specifies the field name.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
Specifies the object ID of the field type.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int16
</Term>
<ListItem>
<Para>
Specifies the type size.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
StartupPacket (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Int32(296)
</Term>
<ListItem>
<Para>
The size of the packet in bytes.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The protocol version number. The most significant 16 bits are
the major version number. The least 16 significant bits are
the minor version number.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
LimString64
</Term>
<ListItem>
<Para>
The database name, defaults to the user name if omitted.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
LimString32
</Term>
<ListItem>
<Para>
The user name.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
LimString64
</Term>
<ListItem>
<Para>
Any additional command line arguments to be passed to the
backend by the postmaster.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
LimString64
</Term>
<ListItem>
<Para>
Unused.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
LimString64
</Term>
<ListItem>
<Para>
The optional tty the backend should use for debugging messages.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Terminate (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('X')
</Term>
<ListItem>
<Para>
Identifies the message as a termination.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
UnencryptedPasswordPacket (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The size of the packet in bytes.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
String
</Term>
<ListItem>
<Para>
The unencrypted password.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</Chapter>
<Chapter>
<Title><Command>psql</Command></Title>
<Para>
This section needs to be written. Volunteers?
</Para>
</Chapter>
<Chapter>
<TITLE>The Query Language</TITLE>
<Para>
<Note>
<Para>
This chapter must go into depth on each area of the query language. Currently a copy of the tutorial.
- thomas 1998-01-12
</Para>
</Note>
</Para>
<Para>
The <ProductName>Postgres</ProductName> query language is a variant of
<Acronym>SQL3</Acronym>. It
has many extensions such as an extensible type system,
inheritance, functions and production rules. Those are
features carried over from the original <ProductName>Postgres</ProductName> query
language, <ProductName>PostQuel</ProductName>. This section provides an overview
of how to use <ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> to perform simple operations.
This manual is only intended to give you an idea of our
flavor of <Acronym>SQL</Acronym> and is in no way a complete tutorial on
<Acronym>SQL</Acronym>. Numerous books have been written on <Acronym>SQL</Acronym>. For
instance, consult <Ulink url="refs.html#MELT93">[MELT93]</ULink> or
<Ulink url="refs.html#DATE93">[DATE93]</ULink>. You should also
be aware that some features are not part of the <Acronym>ANSI</Acronym>
standard.
</Para>
<Sect1>
<Title>Concepts</Title>
<Para>
The fundamental notion in <ProductName>Postgres</ProductName> is that of a class,
which is a named collection of object instances. Each
instance has the same collection of named attributes,
and each attribute is of a specific type. Furthermore,
each instance has a permanent <FirstTerm>object identifier</FirstTerm> (<Acronym>OID</Acronym>)
that is unique throughout the installation. Because
<Acronym>SQL</Acronym> syntax refers to tables, we will use the terms
<FirstTerm>table</FirstTerm> and <FirstTerm>class</FirstTerm> interchangeably.
Likewise, an <Acronym>SQL</Acronym> <FirstTerm>row</FirstTerm> is an
<FirstTerm>instance</FirstTerm> and <Acronym>SQL</Acronym> <FirstTerm>columns</FirstTerm>
are <FirstTerm>attributes</FirstTerm>.
As previously discussed, classes are grouped into
databases, and a collection of databases managed by a
single <FileName>postmaster</FileName> process constitutes an installation
or site.
</Para>
<Sect1>
<Title>Creating a New Class</Title>
<Para>
You can create a new class by specifying the class
name, along with all attribute names and their types:
<ProgramListing>
CREATE TABLE weather (
city varchar(80),
temp_lo int, -- low temperature
temp_hi int, -- high temperature
prcp real, -- precipitation
date date
);
</ProgramListing>
<Para>
Note that keywords are case-insensitive and identifiers
are usually case-insensitive.
<Acronym>Postgres</Acronym> allows <Acronym>SQL92</Acronym> <FirstTerm>delimited identifiers</FirstTerm>
(identifiers surrounded by double-quotes) to include mixed-case and spaces, tabs, etc.
<Para>
<ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> supports the usual
<Acronym>SQL</Acronym> types <Type>int</Type>,
<Type>float</Type>, <Type>real</Type>, <Type>smallint</Type>, <Type>char(N)</Type>,
<Type>varchar(N)</Type>, <Type>date</Type>, <Type>time</Type>,
and <Type>timestamp</Type>, as well as other types of general utility and
a rich set of geometric types. As we will
see later, <ProductName>Postgres</ProductName> can be customized with an
arbitrary number of
user-defined data types. Consequently, type names are
not syntactical keywords, except where required to support special cases in the <Acronym>SQL92</Acronym> standard.
So far, the <ProductName>Postgres</ProductName> create command looks exactly like
the command used to create a table in a traditional
relational system. However, we will presently see that
classes have properties that are extensions of the
relational model.
</Para>
<Sect1>
<Title>Populating a Class with Instances</Title>
<Para>
The <Command>insert</Command> statement is used to populate a class with
instances:
<ProgramListing>
INSERT INTO weather
VALUES ('San Francisco', 46, 50, 0.25, '11/27/1994')
</ProgramListing>
<Para>
You can also use the <Command>copy</Command> command to perform load large
amounts of data from flat (<Acronym>ASCII</Acronym>) files.
</Para>
<Sect1>
<Title>Querying a Class</Title>
<Para>
The weather class can be queried with normal relational
selection and projection queries. A <Acronym>SQL</Acronym> <Command>select</Command>
statement is used to do this. The statement is divided into
a target list (the part that lists the attributes to be
returned) and a qualification (the part that specifies
any restrictions). For example, to retrieve all the
rows of weather, type:
<ProgramListing>
SELECT * FROM WEATHER;
</ProgramListing>
and the output should be:
<ProgramListing>
+--------------+---------+---------+------+------------+
|city | temp_lo | temp_hi | prcp | date |
+--------------+---------+---------+------+------------+
|San Francisco | 46 | 50 | 0.25 | 11-27-1994 |
+--------------+---------+---------+------+------------+
|San Francisco | 43 | 57 | 0 | 11-29-1994 |
+--------------+---------+---------+------+------------+
|Hayward | 37 | 54 | | 11-29-1994 |
+--------------+---------+---------+------+------------+
</ProgramListing>
You may specify any arbitrary expressions in the target list. For example, you can do:
<ProgramListing>
SELECT city, (temp_hi+temp_lo)/2 AS temp_avg, date FROM weather;
</ProgramListing>
<Para>
Arbitrary Boolean operators
(<Command>and</Command>, <Command>or</Command> and <Command>not</Command>) are
allowed in the qualification of any query. For example,
<ProgramListing>
SELECT * FROM weather
WHERE city = 'San Francisco'
AND prcp > 0.0;
+--------------+---------+---------+------+------------+
|city | temp_lo | temp_hi | prcp | date |
+--------------+---------+---------+------+------------+
|San Francisco | 46 | 50 | 0.25 | 11-27-1994 |
+--------------+---------+---------+------+------------+
</ProgramListing>
</Para>
<Para>
As a final note, you can specify that the results of a
select can be returned in a <FirstTerm>sorted order</FirstTerm>
or with <FirstTerm>duplicate instances</FirstTerm> removed.
<ProgramListing>
SELECT DISTINCT city
FROM weather
ORDER BY city;
</ProgramListing>
</Para>
<Sect1>
<Title>Redirecting SELECT Queries</Title>
<Para>
Any select query can be redirected to a new class
<ProgramListing>
SELECT * INTO TABLE temp FROM weather;
</ProgramListing>
<Para>
This forms an implicit <Command>create</Command> command, creating a new
class temp with the attribute names and types specified
in the target list of the <Command>select into</Command> command. We can
then, of course, perform any operations on the resulting
class that we can perform on other classes.
</Para>
<Sect1>
<Title>Joins Between Classes</Title>
<Para>
Thus far, our queries have only accessed one class at a
time. Queries can access multiple classes at once, or
access the same class in such a way that multiple
instances of the class are being processed at the same
time. A query that accesses multiple instances of the
same or different classes at one time is called a join
query.
As an example, say we wish to find all the records that
are in the temperature range of other records. In
effect, we need to compare the temp_lo and temp_hi
attributes of each EMP instance to the temp_lo and
temp_hi attributes of all other EMP instances.
<Note>
<Para>
This is only a conceptual model. The actual join may
be performed in a more efficient manner, but this is invisible to the user.
</Para>
</Note>
We can do this with the following query:
<ProgramListing>
SELECT W1.city, W1.temp_lo, W1.temp_hi,
W2.city, W2.temp_lo, W2.temp_hi
FROM weather W1, weather W2
WHERE W1.temp_lo < W2.temp_lo
AND W1.temp_hi > W2.temp_hi;
+--------------+---------+---------+---------------+---------+---------+
|city | temp_lo | temp_hi | city | temp_lo | temp_hi |
+--------------+---------+---------+---------------+---------+---------+
|San Francisco | 43 | 57 | San Francisco | 46 | 50 |
+--------------+---------+---------+---------------+---------+---------+
|San Francisco | 37 | 54 | San Francisco | 46 | 50 |
+--------------+---------+---------+---------------+---------+---------+
</ProgramListing>
<Note>
<Para>
The semantics of such a join are
that the qualification
is a truth expression defined for the Cartesian product of
the classes indicated in the query. For those instances in
the Cartesian product for which the qualification is true,
<ProductName>Postgres</ProductName> computes and returns the values specified in the
target list. <ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> does not assign any meaning to
duplicate values in such expressions. This means that <ProductName>Postgres</ProductName>
sometimes recomputes the same target list several times;
this frequently happens when Boolean expressions are connected
with an "or". To remove such duplicates, you must use
the <Command>select distinct</Command> statement.
</Para>
</Note>
<Para>
In this case, both W1 and W2 are surrogates for an
instance of the class weather, and both range over all
instances of the class. (In the terminology of most
database systems, W1 and W2 are known as <FirstTerm>range variables</FirstTerm>.)
A query can contain an arbitrary number of
class names and surrogates.
</Para>
<Sect1>
<Title>Updates</Title>
<Para>
You can update existing instances using the update command.
Suppose you discover the temperature readings are
all off by 2 degrees as of Nov 28, you may update the
data as follow:
<ProgramListing>
UPDATE weather
SET temp_hi = temp_hi - 2, temp_lo = temp_lo - 2
WHERE date > '11/28/1994';
</ProgramListing>
</Para>
<Sect1>
<Title>Deletions</Title>
<Para>
Deletions are performed using the <Command>delete</Command> command:
<ProgramListing>
DELETE FROM weather WHERE city = 'Hayward';
</ProgramListing>
All weather recording belongs to Hayward is removed.
One should be wary of queries of the form
<ProgramListing>
DELETE FROM classname;
</ProgramListing>
Without a qualification, <Command>delete</Command> will simply
remove all instances of the given class, leaving it
empty. The system will not request confirmation before
doing this.
</Para>
<Sect1>
<Title>Using Aggregate Functions</Title>
<Para>
Like most other query languages, <ProductName>PostgreSQL</ProductName> supports
aggregate functions.
The current implementation of <ProductName>Postgres</ProductName> aggregate functions have some limitations.
Specifically, while there are aggregates to compute
such functions as the <Function>count</Function>, <Function>sum</Function>,
<Function>avg</Function> (average), <Function>max</Function> (maximum) and
<Function>min</Function> (minimum) over a set of instances, aggregates can only
appear in the target list of a query and not directly in the
qualification (the <FirstTerm>where</FirstTerm> clause). As an example,
<ProgramListing>
SELECT max(temp_lo) FROM weather;
</ProgramListing>
is allowed, while
<ProgramListing>
SELECT city FROM weather WHERE temp_lo = max(temp_lo);
</ProgramListing>
is not. However, as is often the case the query can be restated to accomplish
the intended result; here by using a <FirstTerm>subselect</FirstTerm>:
<ProgramListing>
SELECT city FROM weather WHERE temp_lo = (SELECT max(temp_lo) FROM weather);
</ProgramListing>
</Para>
<Para>
Aggregates may also have <FirstTerm>group by</FirstTerm> clauses:
<ProgramListing>
SELECT city, max(temp_lo)
FROM weather
GROUP BY city;
</ProgramListing>
</Para>
</Chapter>
<Chapter ID="QUERY">
<TITLE>The Query Language</TITLE>
<Para>
The <ProductName>Postgres</ProductName> query language is a variant of
the <Acronym>SQL3</Acronym> draft next-generation standard. It
has many extensions such as an extensible type system,
inheritance, functions and production rules. These are
features carried over from the original <ProductName>Postgres</ProductName> query
language, <ProductName>PostQuel</ProductName>. This section provides an overview
of how to use <ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> to perform simple operations.
This manual is only intended to give you an idea of our
flavor of <Acronym>SQL</Acronym> and is in no way a complete tutorial on
<Acronym>SQL</Acronym>. Numerous books have been written on <Acronym>SQL</Acronym>, including
<!--
<XRef LinkEnd="MELT93"> and <XRef LinkEnd="DATE97">.
-->
[MELT93] and [DATE97].
You should be aware that some language features
are not part of the <Acronym>ANSI</Acronym> standard.
</Para>
<Sect1>
<Title>Interactive Monitor</Title>
<Para>
In the examples that follow, we assume that you have
created the mydb database as described in the previous
subsection and have started <Application>psql</Application>.
Examples in this manual can also be found in
<FileName>/usr/local/pgsql/src/tutorial/</FileName>. Refer to the
<FileName>README</FileName> file in that directory for how to use them. To
start the tutorial, do the following:
<ProgramListing>
% cd /usr/local/pgsql/src/tutorial
% psql -s mydb
Welcome to the POSTGRESQL interactive sql monitor:
Please read the file COPYRIGHT for copyright terms of POSTGRESQL
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: postgres
mydb=> \i basics.sql
</ProgramListing>
</Para>
<Para>
The <Literal>\i</Literal> command read in queries from the specified
files. The <Literal>-s</Literal> option puts you in single step mode which
pauses before sending a query to the backend. Queries
in this section are in the file <FileName>basics.sql</FileName>.
</Para>
<Para>
<Application>psql</Application>
has a variety of <Literal>\d</Literal> commands for showing system information.
Consult these commands for more details;
for a listing, type <Literal>\?</Literal> at the <Application>psql</Application> prompt.
</Para>
<Sect1>
<Title>Concepts</Title>
<Para>
The fundamental notion in <ProductName>Postgres</ProductName> is that of a class,
which is a named collection of object instances. Each
instance has the same collection of named attributes,
and each attribute is of a specific type. Furthermore,
each instance has a permanent <FirstTerm>object identifier</FirstTerm> (<Acronym>OID</Acronym>)
that is unique throughout the installation. Because
<Acronym>SQL</Acronym> syntax refers to tables, we will use the terms
<FirstTerm>table</FirstTerm> and <FirstTerm>class</FirstTerm> interchangeably.
Likewise, an <Acronym>SQL</Acronym> <FirstTerm>row</FirstTerm> is an
<FirstTerm>instance</FirstTerm> and <Acronym>SQL</Acronym> <FirstTerm>columns</FirstTerm>
are <FirstTerm>attributes</FirstTerm>.
As previously discussed, classes are grouped into
databases, and a collection of databases managed by a
single <Application>postmaster</Application> process constitutes an installation
or site.
</Para>
<Sect1>
<Title>Creating a New Class</Title>
<Para>
You can create a new class by specifying the class
name, along with all attribute names and their types:
<ProgramListing>
CREATE TABLE weather (
city varchar(80),
temp_lo int, -- low temperature
temp_hi int, -- high temperature
prcp real, -- precipitation
date date
);
</ProgramListing>
<Para>
Note that both keywords and identifiers are case-insensitive; identifiers can become
case-sensitive by surrounding them with double-quotes as allowed by <Acronym>SQL92</Acronym>.
<ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> supports the usual
<Acronym>SQL</Acronym> types <Type>int</Type>,
<Type>float</Type>, <Type>real</Type>, <Type>smallint</Type>, <Type>char(N)</Type>,
<Type>varchar(N)</Type>, <Type>date</Type>, <Type>time</Type>,
and <Type>timestamp</Type>, as well as other types of general utility and
a rich set of geometric types. As we will
see later, <ProductName>Postgres</ProductName> can be customized with an
arbitrary number of
user-defined data types. Consequently, type names are
not syntactical keywords, except where required to support special cases in the <Acronym>SQL92</Acronym> standard.
So far, the <ProductName>Postgres</ProductName> create command looks exactly like
the command used to create a table in a traditional
relational system. However, we will presently see that
classes have properties that are extensions of the
relational model.
</Para>
<Sect1>
<Title>Populating a Class with Instances</Title>
<Para>
The <Command>insert</Command> statement is used to populate a class with
instances:
<ProgramListing>
INSERT INTO weather
VALUES ('San Francisco', 46, 50, 0.25, '11/27/1994')
</ProgramListing>
<Para>
You can also use the <Command>copy</Command> command to perform load large
amounts of data from flat (<Acronym>ASCII</Acronym>) files.
</Para>
<Sect1>
<Title>Querying a Class</Title>
<Para>
The weather class can be queried with normal relational
selection and projection queries. A <Acronym>SQL</Acronym> <Command>select</Command>
statement is used to do this. The statement is divided into
a target list (the part that lists the attributes to be
returned) and a qualification (the part that specifies
any restrictions). For example, to retrieve all the
rows of weather, type:
<ProgramListing>
SELECT * FROM WEATHER;
</ProgramListing>
and the output should be:
<ProgramListing>
+--------------+---------+---------+------+------------+
|city | temp_lo | temp_hi | prcp | date |
+--------------+---------+---------+------+------------+
|San Francisco | 46 | 50 | 0.25 | 11-27-1994 |
+--------------+---------+---------+------+------------+
|San Francisco | 43 | 57 | 0 | 11-29-1994 |
+--------------+---------+---------+------+------------+
|Hayward | 37 | 54 | | 11-29-1994 |
+--------------+---------+---------+------+------------+
</ProgramListing>
You may specify any arbitrary expressions in the target list. For example, you can do:
<ProgramListing>
SELECT city, (temp_hi+temp_lo)/2 AS temp_avg, date FROM weather;
</ProgramListing>
<Para>
Arbitrary Boolean operators
(<Command>and</Command>, <Command>or</Command> and <Command>not</Command>) are
allowed in the qualification of any query. For example,
<ProgramListing>
SELECT * FROM weather
WHERE city = 'San Francisco'
AND prcp > 0.0;
+--------------+---------+---------+------+------------+
|city | temp_lo | temp_hi | prcp | date |
+--------------+---------+---------+------+------------+
|San Francisco | 46 | 50 | 0.25 | 11-27-1994 |
+--------------+---------+---------+------+------------+
</ProgramListing>
</Para>
<Para>
As a final note, you can specify that the results of a
select can be returned in a <FirstTerm>sorted order</FirstTerm>
or with <FirstTerm>duplicate instances</FirstTerm> removed.
<ProgramListing>
SELECT DISTINCT city
FROM weather
ORDER BY city;
</ProgramListing>
</Para>
<Sect1>
<Title>Redirecting SELECT Queries</Title>
<Para>
Any select query can be redirected to a new class
<ProgramListing>
SELECT * INTO TABLE temp FROM weather;
</ProgramListing>
<Para>
This forms an implicit <Command>create</Command> command, creating a new
class temp with the attribute names and types specified
in the target list of the <Command>select into</Command> command. We can
then, of course, perform any operations on the resulting
class that we can perform on other classes.
</Para>
<Sect1>
<Title>Joins Between Classes</Title>
<Para>
Thus far, our queries have only accessed one class at a
time. Queries can access multiple classes at once, or
access the same class in such a way that multiple
instances of the class are being processed at the same
time. A query that accesses multiple instances of the
same or different classes at one time is called a join
query.
As an example, say we wish to find all the records that
are in the temperature range of other records. In
effect, we need to compare the temp_lo and temp_hi
attributes of each EMP instance to the temp_lo and
temp_hi attributes of all other EMP instances.
<Note>
<Para>
This is only a conceptual model. The actual join may
be performed in a more efficient manner, but this is invisible to the user.
</Para>
</Note>
We can do this with the following query:
<ProgramListing>
SELECT W1.city, W1.temp_lo AS low, W1.temp_hi AS high,
W2.city, W2.temp_lo AS low, W2.temp_hi AS high
FROM weather W1, weather W2
WHERE W1.temp_lo < W2.temp_lo
AND W1.temp_hi > W2.temp_hi;
+--------------+-----+------+---------------+-----+------+
|city | low | high | city | low | high |
+--------------+-----+------+---------------+-----+------+
|San Francisco | 43 | 57 | San Francisco | 46 | 50 |
+--------------+-----+------+---------------+-----+------+
|San Francisco | 37 | 54 | San Francisco | 46 | 50 |
+--------------+-----+------+---------------+-----+------+
</ProgramListing>
<Note>
<Para>
The semantics of such a join are
that the qualification
is a truth expression defined for the Cartesian product of
the classes indicated in the query. For those instances in
the Cartesian product for which the qualification is true,
<ProductName>Postgres</ProductName> computes and returns the values specified in the
target list. <ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> does not assign any meaning to
duplicate values in such expressions. This means that <ProductName>Postgres</ProductName>
sometimes recomputes the same target list several times;
this frequently happens when Boolean expressions are connected
with an "or". To remove such duplicates, you must use
the <Command>select distinct</Command> statement.
</Para>
</Note>
<Para>
In this case, both W1 and W2 are surrogates for an
instance of the class weather, and both range over all
instances of the class. (In the terminology of most
database systems, W1 and W2 are known as <FirstTerm>range variables</FirstTerm>.)
A query can contain an arbitrary number of
class names and surrogates.
</Para>
<Sect1>
<Title>Updates</Title>
<Para>
You can update existing instances using the update command.
Suppose you discover the temperature readings are
all off by 2 degrees as of Nov 28, you may update the
data as follow:
<ProgramListing>
UPDATE weather
SET temp_hi = temp_hi - 2, temp_lo = temp_lo - 2
WHERE date > '11/28/1994';
</ProgramListing>
</Para>
<Sect1>
<Title>Deletions</Title>
<Para>
Deletions are performed using the <Command>delete</Command> command:
<ProgramListing>
DELETE FROM weather WHERE city = 'Hayward';
</ProgramListing>
All weather recording belongs to Hayward is removed.
One should be wary of queries of the form
<ProgramListing>
DELETE FROM classname;
</ProgramListing>
Without a qualification, <Command>delete</Command> will simply
remove all instances of the given class, leaving it
empty. The system will not request confirmation before
doing this.
</Para>
<Sect1>
<Title>Using Aggregate Functions</Title>
<Para>
Like most other query languages, <ProductName>PostgreSQL</ProductName> supports
aggregate functions.
The current implementation of <ProductName>Postgres</ProductName> aggregate functions have some limitations.
Specifically, while there are aggregates to compute
such functions as the <Function>count</Function>, <Function>sum</Function>,
<Function>avg</Function> (average), <Function>max</Function> (maximum) and
<Function>min</Function> (minimum) over a set of instances, aggregates can only
appear in the target list of a query and not directly in the
qualification (the where clause). As an example,
<ProgramListing>
SELECT max(temp_lo) FROM weather;
</ProgramListing>
is allowed, while
<ProgramListing>
SELECT city FROM weather WHERE temp_lo = max(temp_lo);
</ProgramListing>
is not. However, as is often the case the query can be restated to accomplish
the intended result; here by using a <FirstTerm>subselect</FirstTerm>:
<ProgramListing>
SELECT city FROM weather WHERE temp_lo = (SELECT max(temp_lo) FROM weather);
</ProgramListing>
</Para>
<Para>
Aggregates may also have <FirstTerm>group by</FirstTerm> clauses:
<ProgramListing>
SELECT city, max(temp_lo)
FROM weather
GROUP BY city;
</ProgramListing>
</Para>
</Chapter>
<Chapter>
<Title>Database Recovery</Title>
<Para>
This section needs to be written. Volunteers?
</Para>
</Chapter>
<Chapter>
<Title>Regression Test</Title>
<Abstract>
<Para>
Regression test instructions and analysis.
</Para>
</Abstract>
<Para>
The PostgreSQL regression tests are a comprehensive set of tests for the
SQL implementation embedded in PostgreSQL developed by Jolly Chen and
Andrew Yu. It tests standard SQL operations as well as the extended
capabilities of PostgreSQL.
</Para>
<Para>
These tests have recently been revised by Marc Fournier and Thomas Lockhart
and are now packaged as
functional units which should make them easier to run and easier to interpret.
From <ProductName>PostgreSQL</ProductName> v6.1 onward
the regression tests are current for every official release.
</Para>
<Para>
Some properly installed and fully functional PostgreSQL installations
can fail some of these regression tests due to artifacts of floating point
representation and time zone support. The current tests are evaluated
using a simple "diff" algorithm, and are sensitive to small system
differences. For apparently failed tests, examining the differences
may reveal that the differences are not significant.
</Para>
<Para>
The regression testing notes below assume the following (except where noted):
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
Commands are Unix-compatible. See note below.
</Para>
</ListItem>
<ListItem>
<Para>
Defaults are used except where noted.
</Para>
</ListItem>
<ListItem>
<Para>
User postgres is the <ProductName>Postgres</ProductName> superuser.
</Para>
</ListItem>
<ListItem>
<Para>
The source path is /usr/src/pgsql (other paths are possible).
</Para>
</ListItem>
<ListItem>
<Para>
The runtime path is /usr/local/pgsql (other paths are possible).
</Para>
</ListItem>
</ItemizedList>
</Para>
<Sect1>
<Title>Regression Environment</Title>
<Para>
The regression test is invoked by the <Command>make</Command> command which compiles
a <Acronym>C</Acronym> program into a shared library
in the current directory. Localized shell scripts are also created in
the current directory. The output file templates are massaged into the
<FileName>./expected/*.out</FileName> files. The localization replaces macros in the source
files with absolute pathnames and user names.
</Para>
<Para>
Normally, the regression test should be run as the pg_superuser since
the 'src/test/regress' directory and sub-directories are owned by the
pg_superuser. If you run the regression test as another user the
'src/test/regress' directory tree should be writeable to that user.
</Para>
<Para>
The postmaster should be invoked with the system time zone set for
Berkeley, California. This is done automatically by the regression
test script. However, it does require machine support for the PST8PDT
time zone.
</Para>
<Para>
To verify that your machine does have this support, type
the following:
<ProgramListing>
setenv TZ PST8PDT
date
</ProgramListing>
</Para>
<Para>
The "date" command above should have returned the current system time
in the PST8PDT time zone. If the PST8PDT database is not available, then
your system may have returned the time in GMT. If the PST8PDT time zone
is not available, you can set the time zone rules explicitly:
<ProgramListing>
setenv PGTZ PST8PDT7,M04.01.0,M10.05.03
</ProgramListing>
</Para>
<Sect1>
<Title>Directory Layout</Title>
<Para>
<Note>
<Para>
This should become a table in the previous section.
</Para>
</Note>
</Para>
<Para>
<ProgramListing>
input/ .... .source files that are converted using 'make all' into
some of the .sql files in the 'sql' subdirectory
output/ ... .source files that are converted using 'make all' into
.out files in the 'expected' subdirectory
sql/ ...... .sql files used to perform the regression tests
expected/ . .out files that represent what we *expect* the results to
look like
results/ .. .out files that represent what the results *actually* look
like. Also used as temporary storage for table copy testing.
</ProgramListing>
</Para>
</Sect1>
<Sect1>
<Title>Regression Test Procedure</Title>
<Para>
Commands were tested on RedHat Linux version 4.2 using the bash shell.
Except where noted, they will probably work on most systems. Commands
like <FileName>ps</FileName> and <FileName>tar</FileName> vary wildly on what options you should use on each
platform. <Emphasis>Use common sense</Emphasis> before typing in these commands.
</Para>
<Para>
<Procedure>
<Title><ProductName>Postgres</ProductName> Regression Configuration</Title>
<Para>
For a fresh install or upgrading from previous releases of
<ProductName>Postgres</ProductName>:
</Para>
<Step Performance="required">
<Para>
Build the regression test. Type
<ProgramListing>
cd /usr/src/pgsql/src/test/regress
gmake all
</ProgramListing>
</Para>
</Step>
<Step Performance="optional">
<Para>
If you have prevously invoked the regression test, clean up the
working directory with:
<ProgramListing>
cd /usr/src/pgsql/src/test/regress
make clean
</ProgramListing>
<Step Performance="required">
<Para>
The file /usr/src/pgsql/src/test/regress/README has detailed
instructions for running and interpreting the regression tests.
A short version follows here:
</Para>
<Para>
If the postmaster is not already running, start the postmaster on an
available window by typing
<ProgramListing>
postmaster
</ProgramListing>
or start the postmaster daemon running in the background by typing
<ProgramListing>
cd
nohup postmaster > regress.log 2>&1 &
</ProgramListing>
</Para>
<Para>
Run postmaster from your <ProductName>Postgres</ProductName> super user account (typically
account postgres).
<Note>
<Para>
Do not run <FileName>postmaster</FileName> from the root account.
</Para>
</Note>
</Para>
</Step>
<Step Performance="required">
<Para>
Run the regression tests. Type
<ProgramListing>
cd /usr/src/pgsql/src/test/regress
gmake runtest
</ProgramListing>
</Para>
<Para>
You do not need to type "gmake clean" if this is the first time you
are running the tests.
</Para>
</Step>
<Step Performance="required">
<Para>
You should get on the screen (and also written to file ./regress.out)
a series of statements stating which tests passed and which tests
failed. Please note that it can be normal for some of the tests to
"fail". For the failed tests, use diff to compare the files in
directories ./results and ./expected. If float8 failed, type
something like:
<ProgramListing>
cd /usr/src/pgsql/src/test/regress
diff -w expected/float8.out results
</ProgramListing>
</Para>
</Step>
<Step Performance="required">
<Para>
After running the tests, type
<ProgramListing>
destroydb regression
cd /usr/src/pgsql/src/test/regress
gmake clean
</ProgramListing>
</Para>
</Step>
</Procedure>
</Sect1>
<Sect1>
<Title>Regression Analysis</Title>
<Para>
<Quote>Failed</Quote> tests may have failed due to slightly different error messages,
math libraries, or output formatting.
"Failures" of this type do not indicate a problem with
<ProductName>Postgres</ProductName>.
</Para>
<Para>
For a i686/Linux-ELF platform, no tests failed since this is the
v6.2.1 regression testing reference platform.
</Para>
<Para>
For the SPARC/Linux-ELF platform, using the 970525 beta version of
<ProductName>Postgres</ProductName> v6.2 the following tests "failed":
float8 and geometry "failed" due to minor precision differences in
floating point numbers. select_views produces massively different output,
but the differences are due to minor floating point differences.
</Para>
<Para>
Conclusion? If you do see failures, try to understand the nature of
the differences and then decide if those differences will affect your
intended use of <ProductName>Postgres</ProductName>. However, keep in mind that this is likely
to be the most solid release of <ProductName>Postgres</ProductName> to date, incorporating many
bug fixes from v6.1, and that previous versions of <ProductName>Postgres</ProductName> have been
in use successfully for some time now.
</Para>
<Sect2>
<Title>Comparing expected/actual output</Title>
<Para>
The results are in files in the ./results directory. These results
can be compared with results in the ./expected directory using 'diff'.
The files might not compare exactly. The following paragraphs attempt
to explain the differences.
</Para>
</Sect2>
<Sect2>
<Title>Error message differences</Title>
<Para>
Some of the regression tests involve intentional invalid input values.
Error messages can come from either the Postgres code or from the host
platform system routines. In the latter case, the messages may vary
between platforms, but should reflect similar information. These
differences in messages will result in a "failed" regression test which
can be validated by inspection.
</Para>
</Sect2>
<Sect2>
<Title>OID differences</Title>
<Para>
There are several places where PostgreSQL OID (object identifiers) appear
in 'regress.out'. OID's are unique 32-bit integers which are generated
by the PostgreSQL backend whenever a table row is inserted or updated.
If you run the regression test on a non-virgin database or run it multiple
times, the OID's reported will have different values.
The following SQL statements in 'misc.out' have shown this behavior:
QUERY: SELECT user_relns() AS user_relns ORDER BY user_relns;
The 'a,523676' row is composed from an OID.
</Para>
</Sect2>
<Sect2>
<Title>Date and time differences</Title>
<Para>
On many supported platforms, you can force PostgreSQL to believe that it
is running in the same time zone as Berkeley, California. See details in
the section on how to run the regression tests.
If you do not explicitly set your time zone environment to PST8PDT, then
most of the date and time results will reflect your local time zone and
will fail the regression testing.
There appears to be some systems which do not accept the recommended syntax
for explicitly setting the local time zone rules. Some systems using the
public domain time zone package exhibit minor problems with pre-1970 PDT
times, representing them in PST instead.
</Para>
</Sect2>
<Sect2>
<Title>Floating point differences</Title>
<Para>
Some of the tests involve computing 64-bit (<Type>float8</Type>) number from table
columns. Differences in results involving mathematical functions of
<Type>float8</Type> columns have been observed. These differences occur where
different operating systems are used on the same platform ie:
BSDI and SOLARIS on Intel/86, and where the same operating system is
used used on different platforms, ie: SOLARIS on SPARC and Intel/86.
Human eyeball comparison is needed to determine the real significance
of these differences which are usually 10 places to the right of
the decimal point.
Some systems signal errors from pow() and exp() differently from
the mechanism expected by the current Postgres code.
</Para>
</Sect2>
<Sect2>
<Title>Polygon differences</Title>
<Para>
Several of the tests involve operations on geographic date about the
Oakland/Berkley CA street map. The map data is expressed as polygons
whose vertices are represented as pairs of <Type>float8</Type> numbers (decimal
latitude and longitude). Initially, some tables are created and
loaded with geographic data, then some views are created which join
two tables using the polygon intersection operator (##), then a select
is done on the view.
When comparing the results from different platforms, differences occur
in the 2nd or 3rd place to the right of the decimal point. The SQL
statements where these problems occur are the folowing:
<ProgramListing>
QUERY: SELECT * from street;
QUERY: SELECT * from iexit;
</ProgramListing>
</Para>
</Sect2>
<Sect2>
<Title>Random differences</Title>
<Para>
There is at least one test case in random.out which is intended to produce
random results. This causes random to fail the regression testing.
Typing
<ProgramListing>
diff results/random.out expected/random.out
</ProgramListing>
should produce only
one or a few lines of differences for this reason, but other floating
point differences on dissimilar architectures might cause many more
differences. See the release notes below.
</Para>
</Sect2>
<Sect2>
<Title>The <Quote>expected</Quote> files</Title>
<Para>
The <FileName>./expected/*.out</FileName> files were adapted from the original monolithic
<FileName>expected.input</FileName> file provided by Jolly Chen et al. Newer versions of these
files generated on various development machines have been substituted after
careful (?) inspection. Many of the development machines are running a
Unix OS variant (FreeBSD, Linux, etc) on Ix86 hardware.
The original <FileName>expected.input</FileName> file was created on a SPARC Solaris 2.4
system using the <FileName>postgres5-1.02a5.tar.gz</FileName> source tree. It was compared
with a file created on an I386 Solaris 2.4 system and the differences
were only in the floating point polygons in the 3rd digit to the right
of the decimal point. (see below)
The original <FileName>sample.regress.out</FileName> file was from the postgres-1.01 release
constructed by Jolly Chen and is included here for reference. It may
have been created on a DEC ALPHA machine as the <FileName>Makefile.global</FileName>
in the postgres-1.01 release has PORTNAME=alpha.
</Para>
</Sect2>
</Sect1>
</Chapter>
<Chapter>
<Title>Release Notes</Title>
<Para>
<Note>
<Para>
Should include the migration notes from <FileName>migration/</FileName>.
</Para>
</Note>
</Para>
<Para>
The release notes have not yet been integrated into the new documentation.
Check for plain text files in the top of the distribution directory tree
and in the <FileName>migration/</FileName> directory for current information.
<Sect1>
<Title>Release 6.3</Title>
<Para>
TBD
</Para>
</Sect1>
<Sect1>
<Title>Release 6.2.1</Title>
<Para>
<Note>
<Para>
v6.2.1 was a bug-fix and usability release on v6.2. Needs only a few notes.
</Para>
</Note>
</Para>
</Sect1>
<Sect1>
<Title>Release 6.2</Title>
<Para>
<Note>
<Para>
This should include information based on Bruce's release summary.
</Para>
</Note>
</Para>
</Sect1>
<Sect1>
<Title>Release 6.1</Title>
<Para>
<Note>
<Para>
This should include information based on Bruce's release summary.
</Para>
</Note>
</Para>
<Para>
The regression tests have been adapted and extensively modified for the
v6.1 release of PostgreSQL.
</Para>
<Para>
Three new data types (datetime, timespan, and circle) have been added to
the native set of PostgreSQL types. Points, boxes, paths, and polygons
have had their output formats made consistant across the data types.
The polygon output in misc.out has only been spot-checked for correctness
relative to the original regression output.
</Para>
<Para>
PostgreSQL v6.1 introduces a new, alternate optimizer which uses <FirstTerm>genetic</FirstTerm>
algorithms. These algorithms introduce a random behavior in the ordering
of query results when the query contains multiple qualifiers or multiple
tables (giving the optimizer a choice on order of evaluation). Several
regression tests have been modified to explicitly order the results, and
hence are insensitive to optimizer choices. A few regression tests are
for data types which are inherently unordered (e.g. points and time
intervals) and tests involving those types are explicitly bracketed with
<Command>set geqo to 'off'</Command> and <Command>reset geqo</Command>.
</Para>
<Para>
The interpretation of array specifiers (the curly braces around atomic
values) appears to have changed sometime after the original regression
tests were generated. The current <FileName>./expected/*.out</FileName> files reflect this
new interpretation, which may not be correct!
</Para>
<Para>
The float8 regression test fails on at least some platforms. This is due
to differences in implementations of pow() and exp() and the signaling
mechanisms used for overflow and underflow conditions.
</Para>
<Para>
The "random" results in the random test should cause the "random" test
to be "failed", since the regression tests are evaluated using a simple
diff. However, "random" does not seem to produce random results on my
test machine (Linux/gcc/i686).
</Para>
<Sect1>
<Title>Timing Results</Title>
<Para>
These timing results are from running the regression test with the command
<ProgramListing>
% time make runtest
</ProgramListing>
<Para>
Timing under Linux 2.0.27 seems to have a roughly 5% variation from run
to run, presumably due to the timing vagaries of multitasking systems.
<Sect2>
<Title>v6.3</Title>
<Para>
<ProgramListing>
Time System
02:30 Dual Pentium Pro 180, 96MB, UW-SCSI, Linux 2.0.30, gcc 2.7.2.1 -O2 -m486
04:12 Dual Pentium Pro 180, 96MB, EIDE, Linux 2.0.30, gcc 2.7.2.1 -O2 -m486
</ProgramListing>
<Sect2>
<Title>v6.1</Title>
<Para>
<ProgramListing>
Time System
06:12 Pentium Pro 180, 32MB, Linux 2.0.30, gcc 2.7.2 -O2 -m486
12:06 P-100, 48MB, Linux 2.0.29, gcc
39:58 Sparc IPC 32MB, Solaris 2.5, gcc 2.7.2.1 -O -g
</ProgramListing>
</Chapter>
<Chapter>
<Title>The <ProductName>Postgres</ProductName> Rule System</Title>
<Para>
Production rule systems are conceptually simple, but
there are many subtle points involved in actually using
them. Consequently, we will not attempt to explain the
actual syntax and operation of the <ProductName>Postgres</ProductName> rule system
here. Instead, you should read
<XRef LinkEnd="STON90b" EndTerm="[STON90b]"> to understand
some of these points and the theoretical foundations of
the <ProductName>Postgres</ProductName> rule system before trying to use rules.
The discussion in this section is intended to provide
an overview of the <ProductName>Postgres</ProductName> rule system and point the
user at helpful references and examples.
The "query rewrite" rule system modifies queries to
take rules into consideration, and then passes the modified
query to the query optimizer for execution. It
is very powerful, and can be used for many things such
as query language procedures, views, and versions. The
power of this rule system is discussed in
<XRef LinkEnd="ONG90" EndTerm="[ONG90]">
as well as
<XRef LinkEnd="STON90b" EndTerm="[STON90b]">.
</Para>
</Chapter>
<Chapter>
<DocInfo>
<AuthorGroup>
<Author>
<FirstName>Vadim</FirstName>
<Surname>Mikheev</Surname>
</Author>
</AuthorGroup>
<Date>Transcribed 1998-01-16</Date>
</DocInfo>
<Title>Server Programming Interface</Title>
<Para>
The <FirstTerm>Server Programming Interface</FirstTerm> (<Acronym>SPI</Acronym>) is an attempt to give users the
ability to run <Acronym>SQL</Acronym> queries inside user-defined <Acronym>C</Acronym> functions.
Given the lack
of a proper <FirstTerm>Procedural Language</FirstTerm> (<Acronym>PL</Acronym>) in the current version of
<ProductName>Postgres</ProductName>,
<Acronym>SPI</Acronym> is the only way to write server-stored procedures and triggers. In the future
<Acronym>SPI</Acronym> will be used as the "workhorse" for a <Acronym>PL</Acronym>.
</Para>
<Para>
In fact, <Acronym>SPI</Acronym> is just a set of native interface functions to simplify
access to the Parser, Planner, Optimizer and Executor. <Acronym>SPI</Acronym> also does some
memory management.
</Para>
<Para>
To avoid misunderstanding we'll use <FirstTerm>function</FirstTerm> to mean <Acronym>SPI</Acronym> interface
functions and <FirstTerm>procedure</FirstTerm> for user-defined C-functions using <Acronym>SPI</Acronym>.
</Para>
<Para>
<Acronym>SPI</Acronym> procedures are always called by some (upper) Executor and the <Acronym>SPI</Acronym>
manager uses the Executor to run your queries. Other procedures may be
called by the Executor running queries from your procedure.
</Para>
<Para>
Note, that if during execution of a query from a procedure the transaction
is aborted then control will not be returned to your procedure. Rather, all work
will be rolled back and the server will wait for the next command from the
client. This will be changed in future versions.
</Para>
<Para>
Other restrictions are the inability to execute BEGIN, END and ABORT
(transaction control statements) and cursor operations. This will also be
changed in the future.
</Para>
<Para>
If successful, <Acronym>SPI</Acronym> functions return a non-negative result (either via
a returned integer value or in SPI_result global variable, as described below).
On error, a negative or NULL result will be returned.
</Para>
<Sect1>
<Title>Interface Functions</Title>
<REFENTRY ID="SPI-SPICONNECT-1">
<REFMETA>
<REFENTRYTITLE>SPI_connect</REFENTRYTITLE>
<REFMISCINFO>SPI - Connection Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_connect
</REFNAME>
<REFPURPOSE>
Connects your procedure to the SPI manager.
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPICONNECT-1"><PRIMARY>SPI</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICONNECT-2"><PRIMARY>SPI_connect</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
int SPI_connect(void)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPICONNECT-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<PARA>None
</PARA>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPICONNECT-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>int
</TERM>
<LISTITEM>
<PARA>
Return status
<VARIABLELIST>
<VARLISTENTRY>
<TERM><ReturnValue>SPI_OK_CONNECT</ReturnValue>
</TERM>
<LISTITEM>
<PARA>
if connected
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM><ReturnValue>SPI_ERROR_CONNECT</ReturnValue>
</TERM>
<LISTITEM>
<PARA>
if not connected
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPICONNECT-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_connect</FUNCTION> opens a connection to the <ProductName>Postgres</ProductName> backend.
You should call this function if you will need to execute queries. Some
utility SPI functions may be called from un-connected procedures.
</PARA>
<PARA>
You may get <ReturnValue>SPI_ERROR_CONNECT</ReturnValue> error if <Function>SPI_connect</Function> is
called from an already connected procedure - e.g. if you directly call one
procedure from another connected one. Actually, while the child procedure
will be able to use SPI, your parent procedure will not be able to continue
to use SPI after the child returns (if <Function>SPI_finish</Function> is called by the child).
It's bad practice.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICONNECT-2">
<TITLE>Usage
</TITLE>
<PARA>XXX thomas 1997-12-24
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICONNECT-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_connect</FUNCTION> performs the following:
</PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>&bull;
</TERM>
<LISTITEM>
<PARA>
Initializes the SPI internal
structures for query execution and memory management.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
<PARA>
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPICONNECT-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIFINISH-1">
<REFMETA>
<REFENTRYTITLE>SPI_finish</REFENTRYTITLE>
<REFMISCINFO>SPI - Connection Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_finish
</REFNAME>
<REFPURPOSE>
Disconnects your procedure from the SPI manager.
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIFINISH-1"><PRIMARY>SPI</PRIMARY><SECONDARY>disconnecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIFINISH-2"><PRIMARY>SPI_finish</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_finish(void)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIFINISH-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<PARA>None
</PARA>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIFINISH-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>int
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_OK_FINISH</ReturnValue>
if properly disconnected
</Member>
<Member>
<ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue>
if called from an un-connected procedure
</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIFINISH-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_finish</FUNCTION> closes an existing connection to the <ProductName>Postgres</ProductName> backend.
You should call this function after completing operations through the SPI manager.
<PARA>
You may get the error return <ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if <Function>SPI_finish</Function> is
called without having a current valid connection.
There is no fundamental problem
with this; it means that nothing was done by the SPI manager.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIFINISH-2">
<TITLE>Usage
</TITLE>
<PARA>
<Function>SPI_finish</Function> <Emphasis>must</Emphasis> be called as a final step by a connected procedure
or you may get
unpredictable results! Note that you can safely skip the call to <Function>SPI_finish</Function>
if you abort the transaction (via elog(ERROR)).
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIFINISH-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_finish</FUNCTION> performs the following:
</PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>&bull;
</TERM>
<LISTITEM>
<PARA>
Disconnects your procedure from the SPI manager and frees all memory
allocations made by your procedure via <Function>palloc</Function> since
the <Function>SPI_connect</Function>.
These allocations can't be used any more! See Memory management.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
<PARA>
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIFINISH-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIEXEC-1">
<REFMETA>
<REFENTRYTITLE>SPI_exec</REFENTRYTITLE>
<REFMISCINFO>SPI - Connection Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_exec
</REFNAME>
<REFPURPOSE>
Creates an execution plan (parser+planner+optimizer) and executes a query.
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIEXEC-1"><PRIMARY>SPI</PRIMARY><SECONDARY>executing</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIEXEC-2"><PRIMARY>SPI_exec</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_exec(<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIEXEC-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
char *<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
String containing query plan
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Maximum number of tuples to return
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIEXEC-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>int
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_OK_EXEC</ReturnValue> if properly disconnected
</Member>
<Member>
<ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if called from an un-connected procedure
</Member>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if query is NULL or <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> < 0.
</Member>
<Member>
<ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if procedure is unconnected.
</Member>
<Member>
<ReturnValue>SPI_ERROR_COPY</ReturnValue> if COPY TO/FROM stdin.
</Member>
<Member>
<ReturnValue>SPI_ERROR_CURSOR</ReturnValue> if DECLARE/CLOSE CURSOR, FETCH.
</Member>
<Member>
<ReturnValue>SPI_ERROR_TRANSACTION</ReturnValue> if BEGIN/ABORT/END.
</Member>
<Member>
<ReturnValue>SPI_ERROR_OPUNKNOWN</ReturnValue> if type of query is unknown (this shouldn't occur).
</Member>
</SimpleList>
<Para>
If execution of your query was successful then one of the following
(non-negative) values will be returned:
<SimpleList>
<Member>
<ReturnValue>SPI_OK_UTILITY</ReturnValue> if some utility (e.g. CREATE TABLE ...) was executed
</Member>
<Member>
<ReturnValue>SPI_OK_SELECT</ReturnValue> if SELECT (but not SELECT ... INTO!) was executed
</Member>
<Member>
<ReturnValue>SPI_OK_SELINTO</ReturnValue> if SELECT ... INTO was executed
</Member>
<Member>
<ReturnValue>SPI_OK_INSERT</ReturnValue> if INSERT (or INSERT ... SELECT) was executed
</Member>
<Member>
<ReturnValue>SPI_OK_DELETE</ReturnValue> if DELETE was executed
</Member>
<Member>
<ReturnValue>SPI_OK_UPDATE</ReturnValue> if UPDATE was executed
</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIEXEC-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_exec</FUNCTION> creates an execution plan (parser+planner+optimizer)
and executes the query for <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> tuples.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIEXEC-2">
<TITLE>Usage
</TITLE>
<PARA>
This should only be called from a connected procedure.
If <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> is zero then it executes the query for all tuples returned by the
query scan. Using <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> > 0 you may restrict the number of tuples for
which the query will be executed. For example,
<ProgramListing>
SPI_exec ("insert into table select * from table", 5);
</ProgramListing>
will allow at most 5 tuples to be inserted into table.
If execution of your query was successful then a non-negative value will be returned.
<Note>
<Para>
You may pass many queries in one string or query string may be
re-written by RULEs. <Function>SPI_exec</Function> returns the result for the last query
executed.
</Para>
</Note>
<Para>
The actual number of tuples for which the (last) query was executed is
returned in the global variable SPI_processed (if not <ReturnValue>SPI_OK_UTILITY</ReturnValue>).
If <ReturnValue>SPI_OK_SELECT</ReturnValue> returned and SPI_processed &gt; 0 then you may use global
pointer SPITupleTable *SPI_tuptable to access the selected tuples:
Also NOTE, that <Function>SPI_finish</Function> frees and makes all SPITupleTables
unusable! (See Memory management).
</Para>
<Para>
<Function>SPI_exec</Function> may return one of the following (negative) values:
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if query is NULL or <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> < 0.
</Member>
<Member>
<ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if procedure is unconnected.
</Member>
<Member>
<ReturnValue>SPI_ERROR_COPY</ReturnValue> if COPY TO/FROM stdin.
</Member>
<Member>
<ReturnValue>SPI_ERROR_CURSOR</ReturnValue> if DECLARE/CLOSE CURSOR, FETCH.
</Member>
<Member>
<ReturnValue>SPI_ERROR_TRANSACTION</ReturnValue> if BEGIN/ABORT/END.
</Member>
<Member>
<ReturnValue>SPI_ERROR_OPUNKNOWN</ReturnValue> if type of query is unknown (this shouldn't occur).
</Member>
</SimpleList>
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIEXEC-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_exec</FUNCTION> performs the following:
</PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>&bull;
</TERM>
<LISTITEM>
<PARA>
Disconnects your procedure from the SPI manager and frees all memory
allocations made by your procedure via <Function>palloc</Function> since the <Function>SPI_connect</Function>.
These allocations can't be used any more! See Memory management.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
<PARA>
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIEXEC-4">
<TITLE>Structures
</TITLE>
<PARA>
If <ReturnValue>SPI_OK_SELECT</ReturnValue> returned and SPI_processed > 0 then you may use the global
pointer SPITupleTable *SPI_tuptable to access the selected tuples.
<Para>
Structure SPITupleTable is defined in spi.h:
<ProgramListing>
typedef struct
{
uint32 alloced; /* # of alloced vals */
uint32 free; /* # of free vals */
TupleDesc tupdesc; /* tuple descriptor */
HeapTuple *vals; /* tuples */
} SPITupleTable;
</ProgramListing>
<Para>
HeapTuple *vals is an array of pointers to tuples. TupleDesc tupdesc is
a tuple descriptor which you may pass to SPI functions dealing with
tuples.
<Para>
NOTE! Functions <Function>SPI_exec</Function>, <Function>SPI_execp</Function> and <Function>SPI_prepare</Function> change both
SPI_processed and SPI_tuptable (just the pointer, not the contents of the
structure)! So, save them in local procedure variables if you need them.
<Para>
Also NOTE, that <Function>SPI_finish</Function> frees and makes all SPITupleTables
unusable! (See Memory management).
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIPREPARE-1">
<REFMETA>
<REFENTRYTITLE>SPI_prepare</REFENTRYTITLE>
<REFMISCINFO>SPI - Plan Preparation</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_prepare
</REFNAME>
<REFPURPOSE>
Connects your procedure to the SPI manager.
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIPREPARE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIPREPARE-2"><PRIMARY>SPI_prepare</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_prepare(<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">nargs</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">argtypes</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIPREPARE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Query string
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">nargs</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Number of input parameters ($1 ... $nargs - as in SQL-functions)
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<REPLACEABLE CLASS="PARAMETER">argtypes</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Pointer list of type <Acronym>OID</Acronym>s to input arguments
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIPREPARE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>void *
</TERM>
<LISTITEM>
<PARA>
Pointer to an execution plan (parser+planner+optimizer)
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIPREPARE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_prepare</FUNCTION>
creates and returns an execution plan (parser+planner+optimizer) but doesn't
execute the query. Should only be called from a connected procedure.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIPREPARE-2">
<TITLE>Usage
</TITLE>
<PARA>
nargs is number of parameters ($1 ... $nargs - as in SQL-functions),
and nargs may be 0 only if there is not any $1 in query.
<Para>
Execution of prepared execution plans is sometimes much faster so this
feature may be useful if the same query will be executed many times.
<Para>
The plan returned by <Function>SPI_prepare</Function> may be used only in current
invocation of the procedure since <Function>SPI_finish</Function> frees memory allocated for a plan.
See <Function>SPI_saveplan</Function>.
<Para>
If successful, a non-null pointer will be returned. Otherwise, you'll get
a NULL plan. In both cases SPI_result will be set like the value returned
by SPI_exec, except that it is set to
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if query is NULL or nargs < 0 or nargs > 0 && argtypes
is NULL.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIPREPARE-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_prepare</FUNCTION> performs the following:
</PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>&bull;
</TERM>
<LISTITEM>
<PARA>
TBD
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIPREPARE-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPISAVEPLAN-1">
<REFMETA>
<REFENTRYTITLE>SPI_saveplan</REFENTRYTITLE>
<REFMISCINFO>SPI - Plan Storage</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_saveplan
</REFNAME>
<REFPURPOSE>
Saves a passed plan
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPISAVEPLAN-1"><PRIMARY>SPI</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPISAVEPLAN-2"><PRIMARY>SPI_saveplan</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_saveplan(<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPISAVEPLAN-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
void *<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Passed plan
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPISAVEPLAN-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>void *
</TERM>
<LISTITEM>
<PARA>
Execution plan location. NULL if unsuccessful.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>SPI_result
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if plan is NULL
</Member>
<Member>
<ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if procedure is un-connected
</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_saveplan</FUNCTION>
stores a plan prepared by <Function>SPI_prepare</Function> in safe memory
protected from freeing by <Function>SPI_finish</Function> or the transaction manager.
<Para>
In the current version of <ProductName>Postgres</ProductName> there is no ability to
store prepared plans in the system
catalog and fetch them from there for execution. This will be implemented
in future versions.
As an alternative, there is the ability to reuse prepared plans in the
consequent invocations of your procedure in the current session.
Use <Function>SPI_execp</Function> to execute this saved plan.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-2">
<TITLE>Usage
</TITLE>
<Para>
<Function>SPI_saveplan</Function> saves a passed plan (prepared by <Function>SPI_prepare</Function>) in memory
protected from freeing by <Function>SPI_finish</Function> and by the transaction manager and
returns a pointer to the saved plan. You may save the pointer returned in
a local variable. Always check if this pointer is NULL or not either when
preparing a plan or using an already prepared plan in SPI_execp (see below).
<Note>
<Para>
If one of the objects (a relation, function, etc.) referenced by the prepared
plan is dropped during your session (by your backend or another process) then the
results of <Function>SPI_execp</Function> for this plan will be unpredictable.
</Para>
</Note>
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_saveplan</FUNCTION> performs the following:
</PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>&bull;
</TERM>
<LISTITEM>
<PARA>
TBD
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIEXECP-1">
<REFMETA>
<REFENTRYTITLE>SPI_execp</REFENTRYTITLE>
<REFMISCINFO>SPI - Plan Execution</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_execp
</REFNAME>
<REFPURPOSE>
Executes a plan prepared or returned by <Function>SPI_saveplan</Function>
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIEXECP-1"><PRIMARY>SPI</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIEXECP-2"><PRIMARY>SPI_execp</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_execp(<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">values</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIEXECP-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
void *<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Execution plan
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
Datum *<REPLACEABLE CLASS="PARAMETER">values</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Actual parameter values
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
char *<REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Array describing what parameters get NULLs
<SimpleList>
<Member>'n' indicates NULL allowed</Member>
<Member>' ' indicates NULL not allowed</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Number of tuples for which plan is to be executed
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIEXECP-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>int
</TERM>
<LISTITEM>
<PARA>
Returns the same value as <Function>SPI_exec</Function> as well as
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>
is NULL or <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> &lt; 0
</Member>
<Member>
<ReturnValue>SPI_ERROR_PARAM</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">values</REPLACEABLE>
is NULL
and <REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>
was prepared with some parameters.
</Member>
</SimpleList>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>SPI_tuptable
</TERM>
<LISTITEM>
<PARA>
initialized as in
<Function>SPI_exec</Function> if successful
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>SPI_processed
</TERM>
<LISTITEM>
<PARA>
initialized as in
<Function>SPI_exec</Function> if successful
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIEXECP-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_execp</FUNCTION>
stores a plan prepared by <Function>SPI_prepare</Function> in safe memory
protected from freeing by <Function>SPI_finish</Function> or the transaction manager.
<Para>
In the current version of <ProductName>Postgres</ProductName> there is no ability to
store prepared plans in the system
catalog and fetch them from there for execution. This will be implemented
in future versions.
As a work arround, there is the ability to reuse prepared plans in the
consequent invocations of your procedure in the current session.
Use <Function>SPI_execp</Function> to execute this saved plan.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIEXECP-2">
<TITLE>Usage
</TITLE>
<Para>
If <REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE>
is NULL then
<Function>SPI_execp</Function>
assumes that all values (if any) are NOT NULL.
<Note>
<Para>
If one of the objects (a relation, function, etc.) referenced by the prepared
plan is dropped during your session (by your backend or another process) then the
results of <Function>SPI_execp</Function> for this plan will be unpredictable.
</Para>
</Note>
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIEXECP-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_execp</FUNCTION> performs the following:
</PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>&bull;
</TERM>
<LISTITEM>
<PARA>
TBD
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIEXECP-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
</Sect1>
<Sect1>
<Title>Interface Support Functions</Title>
<Para>
All functions described below may be used by connected and unconnected
procedures.
</Para>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPICOPYTUPLE-1">
<REFMETA>
<REFENTRYTITLE>SPI_copytuple</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Copy</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_copytuple
</REFNAME>
<REFPURPOSE>
Makes copy of tuple in upper Executor context
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLE-2"><PRIMARY>SPI_copytuple</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_copytuple(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be copied
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple
</TERM>
<LISTITEM>
<PARA>
Copied tuple
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is not NULL and the copy was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is NULL
</Member>
</SimpleList>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_copytuple</FUNCTION>
makes a copy of tuple in upper Executor context. See the section on Memory Management.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIMODIFYTUPLE-1">
<REFMETA>
<REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Modify</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_modifytuple
</REFNAME>
<REFPURPOSE>
Modifies tuple of relation
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIMODIFYTUPLE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>modifying tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIMODIFYTUPLE-2"><PRIMARY>SPI_modifytuple</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_modifytuple(<REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE> , <REPLACEABLE CLASS="PARAMETER">nattrs</REPLACEABLE>
, <REPLACEABLE CLASS="PARAMETER">attnum</REPLACEABLE> , <REPLACEABLE CLASS="PARAMETER">Values</REPLACEABLE> , <REPLACEABLE CLASS="PARAMETER">Nulls</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIMODIFYTUPLE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
Relation <REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be modified
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">nattrs</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Number of attribute numbers in attnum
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int * <REPLACEABLE CLASS="PARAMETER">attnum</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Array of numbers of the attributes which are to be changed
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
Datum * <REPLACEABLE CLASS="PARAMETER">Values</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
New values for the attributes specified
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
char * <REPLACEABLE CLASS="PARAMETER">Nulls</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Which attributes are NULL, if any
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIMODIFYTUPLE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple
</TERM>
<LISTITEM>
<PARA>
New tuple with modifications
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is not NULL and the modify was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is NULL
</Member>
</SimpleList>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
SPI_result
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if rel is NULL or tuple is NULL or natts &le; 0 or
attnum is NULL or Values is NULL.
</Member>
<Member>
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> if there is an invalid
attribute number in attnum (attnum &le; 0 or &gt; number of
attributes in tuple)
</Member>
</SimpleList>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_modifytuple</FUNCTION>
Modifies a tuple in upper Executor context. See the section on Memory Management.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-2">
<TITLE>Usage
</TITLE>
<Para>
If successful, a pointer to the new tuple is returned. The new tuple is
allocated in upper Executor context (see Memory management). Passed tuple
is not changed.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIFNUMBER-1">
<REFMETA>
<REFENTRYTITLE>SPI_fnumber</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Information</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_fnumber
</REFNAME>
<REFPURPOSE>
Finds the attribute number for specified attribute
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIFNUMBER-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIFNUMBER-2"><PRIMARY>SPI_fnumber</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_fnumber(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fname</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIFNUMBER-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple description
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
char * <REPLACEABLE CLASS="PARAMETER">fname</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Field name
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIFNUMBER-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
int
</TERM>
<LISTITEM>
<PARA>
Attribute number
<SimpleList>
<Member>
Valid one-based index number of attribute
</Member>
<Member>
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> if the named attribute is not found
</Member>
</SimpleList>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIFNUMBER-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_fnumber</FUNCTION>
returns the attribute number for the attribute with name in fname.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIFNUMBER-2">
<TITLE>Usage
</TITLE>
<Para>
Attribute numbers are 1 based.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIFNUMBER-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIFNUMBER-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIFNAME-1">
<REFMETA>
<REFENTRYTITLE>SPI_fname</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Information</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_fname
</REFNAME>
<REFPURPOSE>
Finds the attribute name for the specified attribute
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIFNAME-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIFNAME-2"><PRIMARY>SPI_fname</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_fname(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fname</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIFNAME-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple description
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
char * <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Attribute number
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIFNAME-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
char *
</TERM>
<LISTITEM>
<PARA>
Attribute name
<SimpleList>
<Member>
NULL if fnumber is out of range
</Member>
<Member>
SPI_result set to
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> on error
</Member>
</SimpleList>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIFNAME-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_fname</FUNCTION>
returns the attribute name for the specified attribute.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIFNAME-2">
<TITLE>Usage
</TITLE>
<Para>
Attribute numbers are 1 based.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIFNAME-3">
<TITLE>Algorithm
</TITLE>
<PARA>
Returns a newly-allocated copy of the attribute name.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIFNAME-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIGETVALUE-1">
<REFMETA>
<REFENTRYTITLE>SPI_getvalue</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Information</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_getvalue
</REFNAME>
<REFPURPOSE>
Returns the string value of the specified attribute
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIGETVALUE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIGETVALUE-2"><PRIMARY>SPI_getvalue</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_getvalue(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIGETVALUE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be examined
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple description
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Attribute number
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIGETVALUE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
char *
</TERM>
<LISTITEM>
<PARA>
Attribute value or NULL if
<SimpleList>
<Member>
attribute is NULL
</Member>
<Member>
fnumber is out of range
(SPI_result set to
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue>)
</Member>
<Member>
no output function available
(SPI_result set to
<ReturnValue>SPI_ERROR_NOOUTFUNC</ReturnValue>)
</Member>
</SimpleList>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIGETVALUE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_getvalue</FUNCTION>
returns an external (string) representation of the value of the specified attribute.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETVALUE-2">
<TITLE>Usage
</TITLE>
<Para>
Attribute numbers are 1 based.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETVALUE-3">
<TITLE>Algorithm
</TITLE>
<PARA>
Allocates memory as required by the value.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIGETVALUE-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIGETBINVAL-1">
<REFMETA>
<REFENTRYTITLE>SPI_getbinval</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Information</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_getbinval
</REFNAME>
<REFPURPOSE>
Returns the binary value of the specified attribute
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIGETBINVAL-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIGETBINVAL-2"><PRIMARY>SPI_getbinval</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_getbinval(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">isnull</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIGETBINVAL-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be examined
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple description
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Attribute number
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIGETBINVAL-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
Datum
</TERM>
<LISTITEM>
<PARA>
Attribute binary value
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
bool * <REPLACEABLE CLASS="PARAMETER">isnull</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
flag for null value in attribute
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
SPI_result
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue>
</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIGETBINVAL-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_getbinval</FUNCTION>
returns the binary value of the specified attribute.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETBINVAL-2">
<TITLE>Usage
</TITLE>
<Para>
Attribute numbers are 1 based.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETBINVAL-3">
<TITLE>Algorithm
</TITLE>
<PARA>
Does not allocate new space for the binary value.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIGETBINVAL-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIGETTYPE-1">
<REFMETA>
<REFENTRYTITLE>SPI_gettype</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Information</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_gettype
</REFNAME>
<REFPURPOSE>
Returns the type name of the specified attribute
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIGETTYPE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIGETTYPE-2"><PRIMARY>SPI_gettype</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_gettype(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIGETTYPE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple description
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Attribute number
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIGETTYPE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
char *
</TERM>
<LISTITEM>
<PARA>
The type name for the specified attribute number
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
SPI_result
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue>
</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIGETTYPE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_gettype</FUNCTION>
returns a copy of the type name for the specified attribute.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETTYPE-2">
<TITLE>Usage
</TITLE>
<Para>
Attribute numbers are 1 based.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETTYPE-3">
<TITLE>Algorithm
</TITLE>
<PARA>
Does not allocate new space for the binary value.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIGETTYPE-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIGETTYPEID-1">
<REFMETA>
<REFENTRYTITLE>SPI_gettypeid</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Information</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_gettypeid
</REFNAME>
<REFPURPOSE>
Returns the type <Acronym>OID</Acronym> of the specified attribute
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIGETTYPEID-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIGETTYPEID-2"><PRIMARY>SPI_gettypeid</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_gettypeid(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIGETTYPEID-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple description
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Attribute number
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIGETTYPEID-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<Acronym>OID</Acronym>
</TERM>
<LISTITEM>
<PARA>
The type <Acronym>OID</Acronym> for the specified attribute number
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
SPI_result
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue>
</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIGETTYPEID-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_gettypeid</FUNCTION>
returns the type <Acronym>OID</Acronym> for the specified attribute.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETTYPEID-2">
<TITLE>Usage
</TITLE>
<Para>
Attribute numbers are 1 based.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETTYPEID-3">
<TITLE>Algorithm
</TITLE>
<PARA>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIGETTYPEID-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIGETRELNAME-1">
<REFMETA>
<REFENTRYTITLE>SPI_getrelname</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Information</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_getrelname
</REFNAME>
<REFPURPOSE>
Returns the name of the specified relation
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIGETRELNAME-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIGETRELNAME-2"><PRIMARY>SPI_getrelname</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_getrelname(<REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIGETRELNAME-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
Relation <REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input relation
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIGETRELNAME-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
char *
</TERM>
<LISTITEM>
<PARA>
The name of the specified relation
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_getrelname</FUNCTION>
returns the name of the specified relation.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-3">
<TITLE>Algorithm
</TITLE>
<PARA>
Copies the relation name into new storage.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIPALLOC-1">
<REFMETA>
<REFENTRYTITLE>SPI_palloc</REFENTRYTITLE>
<REFMISCINFO>SPI - Memory Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_palloc
</REFNAME>
<REFPURPOSE>
Allocates memory in upper Executor context
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIPALLOC-1"><PRIMARY>SPI</PRIMARY><SECONDARY>allocating space</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIPALLOC-2"><PRIMARY>SPI_palloc</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_palloc(<REPLACEABLE CLASS="PARAMETER">size</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIPALLOC-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
Size <REPLACEABLE CLASS="PARAMETER">size</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Octet size of storage to allocate
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIPALLOC-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
void *
</TERM>
<LISTITEM>
<PARA>
New storage space of specified size
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIPALLOC-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_palloc</FUNCTION>
allocates memory in upper Executor context. See section on memory management.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIPALLOC-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIPALLOC-3">
<TITLE>Algorithm
</TITLE>
<PARA>
TBD
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIPALLOC-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIREPALLOC-1">
<REFMETA>
<REFENTRYTITLE>SPI_repalloc</REFENTRYTITLE>
<REFMISCINFO>SPI - Memory Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_repalloc
</REFNAME>
<REFPURPOSE>
Re-allocates memory in upper Executor context
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIREPALLOC-1"><PRIMARY>SPI</PRIMARY><SECONDARY>allocating space</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIREPALLOC-2"><PRIMARY>SPI_repalloc</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_repalloc(<REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">size</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIREPALLOC-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
void * <REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Pointer to existing storage
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
Size <REPLACEABLE CLASS="PARAMETER">size</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Octet size of storage to allocate
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIREPALLOC-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
void *
</TERM>
<LISTITEM>
<PARA>
New storage space of specified size with contents copied from existing area
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIREPALLOC-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_repalloc</FUNCTION>
re-allocates memory in upper Executor context. See section on memory management.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIREPALLOC-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIREPALLOC-3">
<TITLE>Algorithm
</TITLE>
<PARA>
TBD
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIREPALLOC-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIPFREE-1">
<REFMETA>
<REFENTRYTITLE>SPI_pfree</REFENTRYTITLE>
<REFMISCINFO>SPI - Memory Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_pfree
</REFNAME>
<REFPURPOSE>
Frees memory from upper Executor context
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIPFREE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>allocating space</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIPFREE-2"><PRIMARY>SPI_pfree</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_pfree(<REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIPFREE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
void * <REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Pointer to existing storage
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIPFREE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
None
</TERM>
<LISTITEM>
<PARA>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIPFREE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_pfree</FUNCTION>
frees memory in upper Executor context. See section on memory management.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIPFREE-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIPFREE-3">
<TITLE>Algorithm
</TITLE>
<PARA>
TBD
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIPFREE-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
</Sect1>
<Sect1>
<Title>Memory Management</Title>
<Para>
Server allocates memory in memory contexts in such way that allocations
made in one context may be freed by context destruction without affecting
allocations made in other contexts. All allocations (via <Function>palloc</Function>, etc) are
made in the context which are chosen as current one. You'll get
unpredictable results if you'll try to free (or reallocate) memory allocated
not in current context.
</Para>
<Para>
Creation and switching between memory contexts are subject of SPI manager
memory management.
</Para>
<Para>
SPI procedures deal with two memory contexts: upper Executor memory
context and procedure memory context (if connected).
</Para>
<Para>
Before a procedure is connected to the SPI manager, current memory context
is upper Executor context so all allocation made by the procedure itself via
<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility functions before connecting to SPI are
made in this context.
</Para>
<Para>
After <Function>SPI_connect</Function> is called current context is the procedure's one. All
allocations made via <Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility functions (except
for <Function>SPI_copytuple</Function>, <Function>SPI_modifytuple</Function>,
<Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
made in this context.
</Para>
<Para>
When a procedure disconnects from the SPI manager (via <Function>SPI_finish</Function>) the
current context is restored to the upper Executor context and all allocations
made in the procedure memory context are freed and can't be used any more!
</Para>
<Para>
If you want to return something to the upper Executor then you have to
allocate memory for this in the upper context!
</Para>
<Para>
SPI has no ability to automatically free allocations in the upper Executor
context!
</Para>
<Para>
SPI automatically frees memory allocated during execution of a query when
this query is done!
</Para>
</Sect1>
<Sect1>
<Title>Visibility of Data Changes</Title>
<Para>
<ProductName>Postgres</ProductName> data changes visibility rule: during a query execution, data
changes made by the query itself (via SQL-function, SPI-function, triggers)
are invisible to the query scan. For example, in query
INSERT INTO a SELECT * FROM a
tuples inserted are invisible for SELECT' scan. In effect, this
duplicates the database table within itself (subject to unique index
rules, of course) without recursing.
</Para>
<Para>
Changes made by query Q are visible by queries which are started after
query Q, no matter whether they are started inside Q (during the execution
of Q) or after Q is done.
</Para>
</Sect1>
<Sect1>
<Title>Examples</Title>
<Para>
This example of SPI usage demonstrates the visibility rule.
There are more complex examples in in src/test/regress/regress.c and
in contrib/spi.
</Para>
<Para>
This is a very simple example of SPI usage. The procedure execq accepts
an SQL-query in its first argument and tcount in its second, executes the
query using SPI_exec and returns the number of tuples for which the query
executed:
<ProgramListing>
#include "executor/spi.h" /* this is what you need to work with SPI */
int execq(text *sql, int cnt);
int
execq(text *sql, int cnt)
{
int ret;
int proc = 0;
SPI_connect();
ret = SPI_exec(textout(sql), cnt);
proc = SPI_processed;
/*
* If this is SELECT and some tuple(s) fetched -
* returns tuples to the caller via elog (NOTICE).
*/
if ( ret == SPI_OK_SELECT && SPI_processed > 0 )
{
TupleDesc tupdesc = SPI_tuptable->tupdesc;
SPITupleTable *tuptable = SPI_tuptable;
char buf[8192];
int i;
for (ret = 0; ret < proc; ret++)
{
HeapTuple tuple = tuptable->vals[ret];
for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
sprintf(buf + strlen (buf), " %s%s",
SPI_getvalue(tuple, tupdesc, i),
(i == tupdesc->natts) ? " " : " |");
elog (NOTICE, "EXECQ: %s", buf);
}
}
SPI_finish();
return (proc);
}
</ProgramListing>
</Para>
<Para>
Now, compile and create the function:
<ProgramListing>
create function execq (text, int4) returns int4 as '...path_to_so' language 'c';
</ProgramListing>
<ProgramListing>
vac=> select execq('create table a (x int4)', 0);
execq
-----
0
(1 row)
vac=> insert into a values (execq('insert into a values (0)',0));
INSERT 167631 1
vac=> select execq('select * from a',0);
NOTICE:EXECQ: 0 <<< inserted by execq
NOTICE:EXECQ: 1 <<< value returned by execq and inserted by upper INSERT
execq
-----
2
(1 row)
vac=> select execq('insert into a select x + 2 from a',1);
execq
-----
1
(1 row)
vac=> select execq('select * from a', 10);
NOTICE:EXECQ: 0
NOTICE:EXECQ: 1
NOTICE:EXECQ: 2 <<< 0 + 2, only one tuple inserted - as specified
execq
-----
3 <<< 10 is max value only, 3 is real # of tuples
(1 row)
vac=> delete from a;
DELETE 3
vac=> insert into a values (execq('select * from a', 0) + 1);
INSERT 167712 1
vac=> select * from a;
x
-
1 <<< no tuples in a (0) + 1
(1 row)
vac=> insert into a values (execq('select * from a', 0) + 1);
NOTICE:EXECQ: 0
INSERT 167713 1
vac=> select * from a;
x
-
1
2 <<< there was single tuple in a + 1
(2 rows)
-- This demonstrates data changes visibility rule:
vac=> insert into a select execq('select * from a', 0) * x from a;
NOTICE:EXECQ: 1
NOTICE:EXECQ: 2
NOTICE:EXECQ: 1
NOTICE:EXECQ: 2
NOTICE:EXECQ: 2
INSERT 0 2
vac=> select * from a;
x
-
1
2
2 <<< 2 tuples * 1 (x in first tuple)
6 <<< 3 tuples (2 + 1 just inserted) * 2 (x in second tuple)
(4 rows) ^^^^^^^^
tuples visible to execq() in different invocations
</ProgramListing>
</Para>
</Sect1>
</Chapter>
<!--
- This file currently contains several small chapters.
- Each chapter should be split off into a separate source file...
- - thomas 1998-02-24
-->
<Chapter>
<Title>Runtime Environment</Title>
<Para>
<Figure Id="ADMIN-LAYOUT">
<Title><ProductName>Postgres</ProductName> file layout</Title>
<Graphic Align="center" FileRef="layout.gif" Format="GIF"></Graphic>
</Figure>
<XRef LinkEnd="ADMIN-LAYOUT" EndTerm="ADMIN-LAYOUT">
shows how the <ProductName>Postgres</ProductName> distribution is laid
out when installed in the default way. For simplicity,
we will assume that <ProductName>Postgres</ProductName> has been installed in the
directory <FileName>/usr/local/pgsql</FileName>. Therefore, wherever
you see the directory <FileName>/usr/local/pgsql</FileName> you should
substitute the name of the directory where <ProductName>Postgres</ProductName> is
actually installed.
All <ProductName>Postgres</ProductName> commands are installed in the directory
<FileName>/usr/local/pgsql/bin</FileName>. Therefore, you should add
this directory to your shell command path. If you use
a variant of the Berkeley C shell, such as csh or tcsh,
you would add
<ProgramListing>
set path = ( /usr/local/pgsql/bin path )
</ProgramListing>
in the .login file in your home directory. If you use
a variant of the Bourne shell, such as sh, ksh, or
bash, then you would add
<ProgramListing>
PATH=/usr/local/pgsql/bin PATH
export PATH
</ProgramListing>
to the .profile file in your home directory.
From now on, we will assume that you have added the
<ProductName>Postgres</ProductName> bin directory to your path. In addition, we
will make frequent reference to "setting a shell
variable" or "setting an environment variable" throughout
this document. If you did not fully understand the
last paragraph on modifying your search path, you
should consult the UNIX manual pages that describe your
shell before going any further.
</Para>
<Para>
If your site administrator has not set things up in the
default way, you may have some more work to do. For example, if the database server machine is a remote machine, you
will need to set the <Acronym>PGHOST</Acronym> environment variable to the name
of the database server machine. The environment variable
<Acronym>PGPORT</Acronym> may also have to be set. The bottom line is this: if
you try to start an application program and it complains
that it cannot connect to the <Application>postmaster</Application>, you should immediately consult your site administrator to make sure that your
environment is properly set up.
</Para>
<Sect1>
<Title>Locale Support</Title>
<Para>
<Note>
<Para>
Written by Oleg Bartunov.
See <ULink url="http://www.sai.msu.su/~megera/postgres/">Oleg's web page</ULink>
for additional information on locale and Russian language support.
</Para>
</Note>
While doing a project for a company in Moscow, Russia, I encountered the problem that postgresql had no
support of national alphabets. After looking for possible workarounds I decided to develop support of locale myself.
I'm not a C-programer but already had some experience with locale programming when I work with perl
(debugging) and glimpse. After several days of digging through
the <ProductName>Postgres</ProductName> source tree I made very minor corections to
src/backend/utils/adt/varlena.c and src/backend/main/main.c and got what I needed! I did support only for
LC_CTYPE and LC_COLLATE, but later LC_MONETARY was added by others. I got many
messages from people about this patch so I decided to send it to developers and (to my surprise) it was
incorporated into postgresql distribution.
<Para>
People often complain that locale doesn't work for them. There are several common mistakes:
<ItemizedList>
<ListItem>
<Para>
Didn't properly configure postgresql before compilation.
You must run configure with --enable-locale option to enable locale support.
Didn't setup environment correctly when starting postmaster.
You must define environment variables $LC_CTYPE and $LC_COLLATE before running postmaster
because backend gets information about locale from environment. I use following shell script
(runpostgres):
<ProgramListing>
#!/bin/sh
export LC_CTYPE=koi8-r
export LC_COLLATE=koi8-r
postmaster -B 1024 -S -D/usr/local/pgsql/data/ -o '-Fe'
</ProgramListing>
and run it from rc.local as
<ProgramListing>
/bin/su - postgres -c "/home/postgres/runpostgres"
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para>
Broken locale support in OS (for example, locale support in libc under Linux several times has changed
and this caused a lot of problems). Latest perl has also support of locale and if locale is broken perl -v will
complain something like:
8:17[mira]:~/WWW/postgres>setenv LC_CTYPE not_exist
8:18[mira]:~/WWW/postgres>perl -v
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LC_ALL = (unset),
LC_CTYPE = "not_exist",
LANG = (unset)
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
</Para>
</ListItem>
<ListItem>
<Para>
Wrong location of locale files!
Possible location: <FileName>/usr/lib/locale</FileName> (Linux, Solaris), <FileName>/usr/share/locale</FileName> (Linux), <FileName>/usr/lib/nls/loc</FileName> (DUX 4.0)
Check man locale for right place. Under Linux I did a symbolical link between <FileName>/usr/lib/locale</FileName> and
<FileName>/usr/share/locale</FileName> to be sure next libc will not break my locale.
</Para>
</ListItem>
</ItemizedList>
<Sect2>
<Title>What are the Benefits?</Title>
<Para>
You can use ~* and order by operators for strings contain characters from national alphabets. Non-english users
definitely need that. If you won't use locale stuff just undefine USE_LOCALE variable.
<Sect2>
<Title>What are the Drawbacks?</Title>
<Para>
There is one evident drawback of using locale - it's speed ! So, use locale only if you really need it.
</Chapter>
<Chapter>
<Title>Starting <Application>postmaster</Application></Title>
<Para>
Nothing can happen to a database unless the <Application>postmaster</Application>
process is running. As the site administrator, there
are a number of things you should remember before
starting the <Application>postmaster</Application>. These are discussed in the
section of this manual titled, "Administering Postgres."
However, if <ProductName>Postgres</ProductName> has been installed by following
the installation instructions exactly as written, the
following simple command is all you should
need to start the <Application>postmaster</Application>:
<ProgramListing>
% postmaster
</ProgramListing>
The <Application>postmaster</Application> occasionally prints out messages which
are often helpful during troubleshooting. If you wish
to view debugging messages from the <Application>postmaster</Application>, you can
start it with the -d option and redirect the output to
the log file:
<ProgramListing>
% postmaster -d >& pm.log &
</ProgramListing>
If you do not wish to see these messages, you can type
<ProgramListing>
% postmaster -S
</ProgramListing>
and the <Application>postmaster</Application> will be "S"ilent. Notice that there
is no ampersand ("&amp") at the end of the last example.
</Para>
</Chapter>
<Chapter>
<Title>Adding and Deleting Users</Title>
<Para>
<Application>createuser</Application> enables specific users to access
<ProductName>Postgres</ProductName>. <Application>destroyuser</Application> removes users and
prevents them from accessing <ProductName>Postgres</ProductName>. Note that these
commands only affect users with respect to <ProductName>Postgres</ProductName>;
they have no effect on users other privileges or status with regards
to the underlying
operating system.
</Para>
</Chapter>
<Chapter>
<Title>Disk Management</Title>
<Para>
</Para>
<Sect1>
<Title>Alternate Locations</Title>
<Para>
It is possible to create a database in a location other than the default
location for the installation. Remember that all database access actually
occurs through the database backend, so that any location specified must
be accessible by the backend.
<Para>
Either an absolute path name or an environment variable
may be specified as a location. Note that for security and integrity reasons,
all paths and environment variables so specified have some
additional path fields appended.
<Note>
<Para>
The environment variable style of specification
is to be preferred since it allows the site administrator more flexibility in
managing disk storage.
</Para>
</Note>
<Para>
Remember that database creation is actually performed by the database backend.
Therefore, any environment variable specifying an alternate location must have
been defined before the backend was started. To define an alternate location
PGDATA2 pointing to <FileName>/home/postgres/data</FileName>, type
<ProgramListing>
% setenv PGDATA2 /home/postgres/data
</ProgramListing>
<Para>
Usually, you will want to define this variable in the <ProductName>Postgres</ProductName> superuser's
<FileName>.profile</FileName>
or
<FileName>.cshrc</FileName>
initialization file to ensure that it is defined upon system startup.
<Para>
To create a data storage area in <FileName>/home/postgres/data</FileName>, ensure
that <FileName>/home/postgres</FileName> already exists and is writable.
From the command line, type
<ProgramListing>
% initlocation $PGDATA2
Creating Postgres database system directory /home/postgres/data
Creating Postgres database system directory /home/postgres/data/base
</ProgramListing>
<Para>
To test the new location, create a database <Database>test</Database> by typing
<ProgramListing>
% createdb -D PGDATA2 test
% destroydb test
</ProgramListing>
</Sect1>
</Chapter>
<Chapter>
<Title>Troubleshooting</Title>
<Para>
Assuming that your site administrator has properly
started the <Application>postmaster</Application> process and authorized you to
use the database, you (as a user) may begin to start up
applications. As previously mentioned, you should add
<FileName>/usr/local/pgsql/bin</FileName> to your shell search path.
In most cases, this is all you should have to do in
terms of preparation.
<Para>
If you get the following error message from a <ProductName>Postgres</ProductName>
command (such as <Application>psql</Application> or <Application>createdb</Application>):
<ProgramListing>
connectDB() failed: Is the postmaster running at 'localhost' on port '4322'?
</ProgramListing>
it is usually because either the <Application>postmaster</Application> is not running,
or you are attempting to connect to the wrong server host.
If you get the following error message:
<ProgramListing>
FATAL 1:Feb 17 23:19:55:process userid (2360) != database owner (268)
</ProgramListing>
it means that the site administrator started the <Application>postmaster</Application>
as the wrong user. Tell him to restart it as
the <ProductName>Postgres</ProductName> superuser.
</Para>
</Chapter>
<Chapter>
<Title>Managing a Database</Title>
<Para>
Now that <ProductName>Postgres</ProductName> is up and running we can create some
databases to experiment with. Here, we describe the
basic commands for managing a database.
</Para>
<Sect1>
<Title>Creating a Database</Title>
<Para>
Let's say you want to create a database named mydb.
You can do this with the following command:
<ProgramListing>
% createdb mydb
</ProgramListing>
<ProductName>Postgres</ProductName> allows you to create any number of databases
at a given site and you automatically become the
database administrator of the database you just created. Database names must have an alphabetic first
character and are limited to 16 characters in length.
Not every user has authorization to become a database
administrator. If <ProductName>Postgres</ProductName> refuses to create databases
for you, then the site administrator needs to grant you
permission to create databases. Consult your site
administrator if this occurs.
</Para>
</Sect1>
<Sect1>
<Title>Accessing a Database</Title>
<Para>
Once you have constructed a database, you can access it
by:
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
running the <ProductName>Postgres</ProductName> terminal monitor programs (
monitor or <Application>psql</Application>) which allows you to interactively
enter, edit, and execute <Acronym>SQL</Acronym> commands.
</Para>
</ListItem>
<ListItem>
<Para>
writing a C program using the LIBPQ subroutine
library. This allows you to submit <Acronym>SQL</Acronym> commands
from C and get answers and status messages back to
your program. This interface is discussed further
in section ??.
</Para>
</ListItem>
</ItemizedList>
You might want to start up <Application>psql</Application>, to try out the examples in this manual. It can be activated for the mydb
database by typing the command:
<ProgramListing>
% psql mydb
</ProgramListing>
You will be greeted with the following message:
<ProgramListing>
Welcome to the Postgres interactive sql monitor:
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: mydb
mydb=>
</ProgramListing>
</Para>
<Para>
This prompt indicates that the terminal monitor is listening to you and that you can type <Acronym>SQL</Acronym> queries into a
workspace maintained by the terminal monitor.
The <Application>psql</Application> program responds to escape codes that begin
with the backslash character, "\". For example, you
can get help on the syntax of various <ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> commands by typing:
<ProgramListing>
mydb=> \h
</ProgramListing>
Once you have finished entering your queries into the
workspace, you can pass the contents of the workspace
to the <ProductName>Postgres</ProductName> server by typing:
<ProgramListing>
mydb=> \g
</ProgramListing>
This tells the server to process the query. If you
terminate your query with a semicolon, the backslash-g is not
necessary. <Application>psql</Application> will automatically process semicolon terminated queries.
To read queries from a file, say myFile, instead of
entering them interactively, type:
<ProgramListing>
mydb=> \i fileName
</ProgramListing>
To get out of <Application>psql</Application> and return to UNIX, type
<ProgramListing>
mydb=> \q
</ProgramListing>
and <Application>psql</Application> will quit and return you to your command
shell. (For more escape codes, type backslash-h at the monitor
prompt.)
White space (i.e., spaces, tabs and newlines) may be
used freely in <Acronym>SQL</Acronym> queries. Single-line comments are denoted by
<Quote>--</Quote>. Everything after the dashes up to the end of the
line is ignored. Multiple-line comments, and comments within a line,
are denoted by <Quote>/* ... */</Quote>
</Para>
</Sect1>
<Sect1>
<Title>Destroying a Database</Title>
<Para>
If you are the database administrator for the database
mydb, you can destroy it using the following UNIX command:
<ProgramListing>
% destroydb mydb
</ProgramListing>
This action physically removes all of the UNIX files
associated with the database and cannot be undone, so
this should only be done with a great deal of forethought.
</Para>
</Sect1>
</Chapter>
<Chapter>
<Title>Getting Started</Title>
<Abstract>
<Para>
How to begin work with <ProductName>Postgres</ProductName> for a new user.
</Para>
</Abstract>
<Para>
Some of the steps required to use <ProductName>Postgres</ProductName>
can be performed by any Postgres user, and some must be done by
the site database administrator. This site administrator
is the person who installed the software, created
the database directories and started the <Application>postmaster</Application>
process. This person does not have to be the UNIX
superuser (<Quote>root</Quote>)
or the computer system administrator; a person can install and use
<ProductName>Postgres</ProductName> without any special accounts or privileges.
</Para>
<Para>
If you are installing <ProductName>Postgres</ProductName> yourself, then
refer to the Administrator's Guide for instructions on installation, and return
to this guide when the installation is complete.
</Para>
<Para>
Throughout this manual, any examples that begin with
the character <Quote>&percnt</Quote> are commands that should be typed
at the UNIX shell prompt. Examples that begin with the
character <Quote>*</Quote> are commands in the Postgres query
language, Postgres <Acronym>SQL</Acronym>.
</Para>
<Sect1>
<Title>Setting Up Your Environment</Title>
<Para>
This section discusses how to set up
your own environment so that you can use frontend
applications. We assume <ProductName>Postgres</ProductName> has already been
successfully installed and started; refer to the Administrator's Guide
and the installation notes
for how to install Postgres.
</Para>
<Para>
<ProductName>Postgres</ProductName> is a client/server application. As a user,
you only need access to the client portions of the installation (an example
of a client application is the interactive monitor <Application>psql</Application>).
For simplicity,
we will assume that <ProductName>Postgres</ProductName> has been installed in the
directory <FileName>/usr/local/pgsql</FileName>. Therefore, wherever
you see the directory <FileName>/usr/local/pgsql</FileName> you should
substitute the name of the directory where <ProductName>Postgres</ProductName> is
actually installed.
All <ProductName>Postgres</ProductName> commands are installed in the directory
<FileName>/usr/local/pgsql/bin</FileName>. Therefore, you should add
this directory to your shell command path. If you use
a variant of the Berkeley C shell, such as csh or tcsh,
you would add
<ProgramListing>
% set path = ( /usr/local/pgsql/bin path )
</ProgramListing>
in the <FileName>.login</FileName> file in your home directory. If you use
a variant of the Bourne shell, such as sh, ksh, or
bash, then you would add
<ProgramListing>
% PATH=/usr/local/pgsql/bin PATH
% export PATH
</ProgramListing>
to the .profile file in your home directory.
From now on, we will assume that you have added the
<ProductName>Postgres</ProductName> bin directory to your path. In addition, we
will make frequent reference to <Quote>setting a shell
variable</Quote> or <Quote>setting an environment variable</Quote> throughout
this document. If you did not fully understand the
last paragraph on modifying your search path, you
should consult the UNIX manual pages that describe your
shell before going any further.
</Para>
<Para>
If your site administrator has not set things up in the
default way, you may have some more work to do. For example, if the database
server machine is a remote machine, you
will need to set the <Acronym>PGHOST</Acronym> environment variable to the name
of the database server machine. The environment variable
<Acronym>PGPORT</Acronym> may also have to be set. The bottom line is this: if
you try to start an application program and it complains
that it cannot connect to the <Application>postmaster</Application>,
you should immediately consult your site administrator to make sure that your
environment is properly set up.
</Para>
</Sect1>
<Sect1>
<Title>Starting the Interactive Monitor (psql)</Title>
<Para>
Assuming that your site administrator has properly
started the <Application>postmaster</Application> process and authorized you to
use the database, you (as a user) may begin to start up
applications. As previously mentioned, you should add
<FileName>/usr/local/pgsql/bin</FileName> to your shell search path.
In most cases, this is all you should have to do in
terms of preparation.
</Para>
<Para>
As of <ProductName>Postgres</ProductName> v6.3, two different styles of connections
are supported. The site administrator will have chosen to allow TCP/IP network connections
or will have restricted database access to local (same-machine) socket connections only.
These choices become significant if you encounter problems in connecting to a database.
</Para>
<Para>
If you get the following error message from a <ProductName>Postgres</ProductName>
command (such as <Application>psql</Application> or <Application>createdb</Application>):
<ProgramListing>
% psql template1
Connection to database 'postgres' failed.
connectDB() failed: Is the postmaster running and accepting connections
at 'UNIX Socket' on port '5432'?
</ProgramListing>
or
<ProgramListing>
% psql -h localhost template1
Connection to database 'postgres' failed.
connectDB() failed: Is the postmaster running and accepting TCP/IP
(with -i) connections at 'localhost' on port '5432'?
</ProgramListing>
it is usually because (1) the <Application>postmaster</Application> is not running,
or (2) you are attempting to connect to the wrong server host.
If you get the following error message:
<ProgramListing>
FATAL 1:Feb 17 23:19:55:process userid (2360) != database owner (268)
</ProgramListing>
it means that the site administrator started the <Application>postmaster</Application>
as the wrong user. Tell him to restart it as
the <ProductName>Postgres</ProductName> superuser.
</Para>
</Sect1>
<Sect1>
<Title>Managing a Database</Title>
<Para>
Now that <ProductName>Postgres</ProductName> is up and running we can create some
databases to experiment with. Here, we describe the
basic commands for managing a database.
</Para>
<Para>
Most <ProductName>Postgres</ProductName>
applications assume that the database name, if not specified, is the same as the name on your computer
account.
</Para>
<Para>
If your database administrator has set up your account without database creation privileges,
then she should have told you what the name of your database is. If this is the case, then you
can skip the sections on creating and destroying databases.
</Para>
<Sect2>
<Title>Creating a Database</Title>
<Para>
Let's say you want to create a database named <Database>mydb</Database>.
You can do this with the following command:
<ProgramListing>
% createdb mydb
</ProgramListing>
</Para>
<Para>
If you do not have the privileges required to create a database, you will see
the following:
<ProgramListing>
% createdb mydb
WARN:user "your username" is not allowed to create/destroy databases
createdb: database creation failed on mydb.
</ProgramListing>
</Para>
<Para>
<ProductName>Postgres</ProductName> allows you to create any number of databases
at a given site and you automatically become the
database administrator of the database you just created. Database names must have an alphabetic first
character and are limited to 32 characters in length.
Not every user has authorization to become a database
administrator. If <ProductName>Postgres</ProductName> refuses to create databases
for you, then the site administrator needs to grant you
permission to create databases. Consult your site
administrator if this occurs.
</Para>
</Sect2>
<Sect2>
<Title>Accessing a Database</Title>
<Para>
Once you have constructed a database, you can access it
by:
<ItemizedList Mark="bullet" Spacing="compact">
<ListItem>
<Para>
running the <ProductName>Postgres</ProductName> terminal monitor programs (e.g.
<Application>psql</Application>) which allows you to interactively
enter, edit, and execute <Acronym>SQL</Acronym> commands.
</Para>
</ListItem>
<ListItem>
<Para>
writing a <Acronym>C</Acronym> program using the LIBPQ subroutine
library. This allows you to submit <Acronym>SQL</Acronym> commands
from <Acronym>C</Acronym> and get answers and status messages back to
your program. This interface is discussed further
in <XRef LinkEnd="PROGRAMMERS-GUIDE">.
</Para>
</ListItem>
</ItemizedList>
You might want to start up <Application>psql</Application>, to try out the examples in this manual.
It can be activated for the <Database>mydb</Database>
database by typing the command:
<ProgramListing>
% psql mydb
</ProgramListing>
You will be greeted with the following message:
<ProgramListing>
Welcome to the POSTGRESQL interactive sql monitor:
Please read the file COPYRIGHT for copyright terms of POSTGRESQL
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: template1
mydb=>
</ProgramListing>
</Para>
<Para>
This prompt indicates that the terminal monitor is listening
to you and that you can type <Acronym>SQL</Acronym> queries into a
workspace maintained by the terminal monitor.
The <Application>psql</Application> program responds to escape codes that begin
with the backslash character, <Quote>\</Quote> For example, you
can get help on the syntax of various
<ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> commands by typing:
<ProgramListing>
mydb=> \h
</ProgramListing>
Once you have finished entering your queries into the
workspace, you can pass the contents of the workspace
to the <ProductName>Postgres</ProductName> server by typing:
<ProgramListing>
mydb=> \g
</ProgramListing>
This tells the server to process the query. If you
terminate your query with a semicolon, the <Quote>\g</Quote> is not
necessary. <Application>psql</Application> will automatically process semicolon terminated queries.
To read queries from a file, say myFile, instead of
entering them interactively, type:
<ProgramListing>
mydb=> \i fileName
</ProgramListing>
To get out of <Application>psql</Application> and return to UNIX, type
<ProgramListing>
mydb=> \q
</ProgramListing>
and <Application>psql</Application> will quit and return you to your command
shell. (For more escape codes, type <Command>\h</Command> at the monitor
prompt.)
White space (i.e., spaces, tabs and newlines) may be
used freely in <Acronym>SQL</Acronym> queries. Single-line comments are denoted by
<Quote>--</Quote>. Everything after the dashes up to the end of the
line is ignored. Multiple-line comments, and comments within a line,
are denoted by <Quote>/* ... */</Quote>
</Para>
</Sect2>
<Sect2>
<Title>Destroying a Database</Title>
<Para>
If you are the database administrator for the database
<Database>mydb</Database>, you can destroy it using the following UNIX command:
<ProgramListing>
% destroydb mydb
</ProgramListing>
This action physically removes all of the UNIX files
associated with the database and cannot be undone, so
this should only be done with a great deal of forethought.
</Para>
</Sect2>
</Sect1>
</Chapter>
<Chapter>
<Title>Disk Storage</Title>
<Para>
This section needs to be written. Some information is in the FAQ. Volunteers?
- thomas 1998-01-11
</Para>
</Chapter>
<Chapter>
<Title>Triggers</Title>
<Para>
While the current version of <ProductName>Postgres</ProductName> has various client interfaces
such as Perl, Tcl, Python and C, it lacks an actual <FirstTerm>Procedural Language</FirstTerm>
(PL). We hope to have a proper PL one day. In the meantime it is possible
to call C functions as trigger actions. Note that STATEMENT-level trigger
events are not supported in the current version. You can currently specify
BEFORE or AFTER on INSERT, DELETE or UPDATE of a tuple as a trigger event.
</Para>
<Sect1>
<Title>Trigger Creation</Title>
<Para>
If a trigger event occurs, the trigger manager (called by the Executor)
initializes the global structure TriggerData *CurrentTriggerData (described
below) and calls the trigger function to handle the event.
</Para>
<Para>
The trigger function must be created before the trigger is created as a
function taking no arguments and returns opaque.
</Para>
<Para>
The syntax for creating triggers is as follows:
<ProgramListing>
CREATE TRIGGER &lt;trigger name&gt; &lt;BEFORE|AFTER&gt; &lt;INSERT|DELETE|UPDATE&gt;
ON &lt;relation name&gt; FOR EACH &lt;ROW|STATEMENT&gt;
EXECUTE PROCEDURE &lt;procedure name&gt; (&lt;function args&gt;);
</ProgramListing>
</Para>
<Para>
The name of the trigger is used if you ever have to delete the trigger.
It is used as an argument to the DROP TRIGGER command.
</Para>
<Para>
The next word determines whether the function is called before or after
the event.
</Para>
<Para>
The next element of the command determines on what event(s) will trigger
the function. Multiple events can be specified separated by OR.
</Para>
<Para>
The relation name determines which table the event applies to.
</Para>
<Para>
The FOR EACH statement determines whether the trigger is fired for each
affected row or before (or after) the entire statement has completed.
</Para>
<Para>
The procedure name is the C function called.
</Para>
<Para>
The args are passed to the function in the CurrentTriggerData structure.
The purpose of passing arguments to the function is to allow different
triggers with similar requirements to call the same function.
</Para>
<Para>
Also, function may be used for triggering different relations (these
functions are named as "general trigger functions").
</Para>
<Para>
As example of using both features above, there could be a general
function that takes as its arguments two field names and puts the current
user in one and the current timestamp in the other. This allows triggers to
be written on INSERT events to automatically track creation of records in a
transaction table for example. It could also be used as a "last updated"
function if used in an UPDATE event.
</Para>
<Para>
Trigger functions return HeapTuple to the calling Executor. This
is ignored for triggers fired after an INSERT, DELETE or UPDATE operation
but it allows BEFORE triggers to:
- return NULL to skip the operation for the current tuple (and so the
tuple will not be inserted/updated/deleted);
- return a pointer to another tuple (INSERT and UPDATE only) which will
be inserted (as the new version of the updated tuple if UPDATE) instead
of original tuple.
</Para>
<Para>
Note, that there is no initialization performed by the CREATE TRIGGER
handler. This will be changed in the future. Also, if more than one trigger
is defined for the same event on the same relation, the order of trigger
firing is unpredictable. This may be changed in the future.
</Para>
<Para>
If a trigger function executes SQL-queries (using SPI) then these queries
may fire triggers again. This is known as cascading triggers. There is no
explicit limitation on the number of cascade levels.
</Para>
<Para>
If a trigger is fired by INSERT and inserts a new tuple in the same
relation then this trigger will be fired again. Currently, there is nothing
provided for synchronization (etc) of these cases but this may change. At
the moment, there is function funny_dup17() in the regress tests which uses
some techniques to stop recursion (cascading) on itself...
</Para>
</Sect1>
<Sect1>
<Title>Interaction with the Trigger Manager</Title>
<Para>
As mentioned above, when function is called by the trigger manager,
structure TriggerData *CurrentTriggerData is NOT NULL and initialized. So
it is better to check CurrentTriggerData against being NULL at the start
and set it to NULL just after fetching the information to prevent calls to
a trigger function not from the trigger manager.
</Para>
<Para>
struct TriggerData is defined in src/include/commands/trigger.h:
<ProgramListing>
typedef struct TriggerData
{
TriggerEvent tg_event;
Relation tg_relation;
HeapTuple tg_trigtuple;
HeapTuple tg_newtuple;
Trigger *tg_trigger;
} TriggerData;
</ProgramListing>
<ProgramListing>
tg_event
describes event for which the function is called. You may use the
following macros to examine tg_event:
TRIGGER_FIRED_BEFORE(event) returns TRUE if trigger fired BEFORE;
TRIGGER_FIRED_AFTER(event) returns TRUE if trigger fired AFTER;
TRIGGER_FIRED_FOR_ROW(event) returns TRUE if trigger fired for
ROW-level event;
TRIGGER_FIRED_FOR_STATEMENT(event) returns TRUE if trigger fired for
STATEMENT-level event;
TRIGGER_FIRED_BY_INSERT(event) returns TRUE if trigger fired by INSERT;
TRIGGER_FIRED_BY_DELETE(event) returns TRUE if trigger fired by DELETE;
TRIGGER_FIRED_BY_UPDATE(event) returns TRUE if trigger fired by UPDATE.
tg_relation
is pointer to structure describing the triggered relation. Look at
src/include/utils/rel.h for details about this structure. The most
interest things are tg_relation->rd_att (descriptor of the relation
tuples) and tg_relation->rd_rel->relname (relation's name. This is not
char*, but NameData. Use SPI_getrelname(tg_relation) to get char* if
you need a copy of name).
tg_trigtuple
is a pointer to the tuple for which the trigger is fired. This is the tuple
being inserted (if INSERT), deleted (if DELETE) or updated (if UPDATE).
If INSERT/DELETE then this is what you are to return to Executor if
you don't want to replace tuple with another one (INSERT) or skip the
operation.
tg_newtuple
is a pointer to the new version of tuple if UPDATE and NULL if this is
for an INSERT or a DELETE. This is what you are to return to Executor if
UPDATE and you don't want to replace this tuple with another one or skip
the operation.
tg_trigger
is pointer to structure Trigger defined in src/include/utils/rel.h:
typedef struct Trigger
{
char *tgname;
Oid tgfoid;
func_ptr tgfunc;
int16 tgtype;
int16 tgnargs;
int16 tgattr[8];
char **tgargs;
} Trigger;
tgname is the trigger's name, tgnargs is number of arguments in tgargs,
tgargs is an array of pointers to the arguments specified in the CREATE
TRIGGER statement. Other members are for internal use only.
</ProgramListing>
</Para>
</Sect1>
<Sect1>
<Title>Visibility of Data Changes</Title>
<Para>
<ProductName>Postgres</ProductName> data changes visibility rule: during a query execution, data
changes made by the query itself (via SQL-function, SPI-function, triggers)
are invisible to the query scan. For example, in query
<ProgramListing>
INSERT INTO a SELECT * FROM a
</ProgramListing>
tuples inserted are invisible for SELECT' scan. In effect, this
duplicates the database table within itself (subject to unique index
rules, of course) without recursing.
</Para>
<Para>
But keep in mind this notice about visibility in the SPI documentation:
<ProgramListing>
Changes made by query Q are visible by queries which are started after
query Q, no matter whether they are started inside Q (during the
execution of Q) or after Q is done.
</ProgramListing>
</Para>
<Para>
This is true for triggers as well so, though a tuple being inserted
(tg_trigtuple) is not visible to queries in a BEFORE trigger, this tuple
(just inserted) is visible to queries in an AFTER trigger, and to queries
in BEFORE/AFTER triggers fired after this!
</Para>
</Sect1>
<Sect1>
<Title>Examples</Title>
<Para>
There are more complex examples in in src/test/regress/regress.c and
in contrib/spi.
</Para>
<Para>
Here is a very simple example of trigger usage. Function trigf reports
the number of tuples in the triggered relation ttest and skips the
operation if the query attempts to insert NULL into x (i.e - it acts as a
NOT NULL constraint but doesn't abort the transaction).
<ProgramListing>
#include "executor/spi.h" /* this is what you need to work with SPI */
#include "commands/trigger.h" /* -"- and triggers */
HeapTuple trigf(void);
HeapTuple
trigf()
{
TupleDesc tupdesc;
HeapTuple rettuple;
char *when;
bool checknull = false;
bool isnull;
int ret, i;
if (!CurrentTriggerData)
elog(WARN, "trigf: triggers are not initialized");
/* tuple to return to Executor */
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
rettuple = CurrentTriggerData->tg_newtuple;
else
rettuple = CurrentTriggerData->tg_trigtuple;
/* check for NULLs ? */
if (!TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event) &&
TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
checknull = true;
if (TRIGGER_FIRED_BEFORE(CurrentTriggerData->tg_event))
when = "before";
else
when = "after ";
tupdesc = CurrentTriggerData->tg_relation->rd_att;
CurrentTriggerData = NULL;
/* Connect to SPI manager */
if ((ret = SPI_connect()) < 0)
elog(WARN, "trigf (fired %s): SPI_connect returned %d", when, ret);
/* Get number of tuples in relation */
ret = SPI_exec("select count(*) from ttest", 0);
if (ret < 0)
elog(WARN, "trigf (fired %s): SPI_exec returned %d", when, ret);
i = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &amp;isnull);
elog (NOTICE, "trigf (fired %s): there are %d tuples in ttest", when, i);
SPI_finish();
if (checknull)
{
i = SPI_getbinval(rettuple, tupdesc, 1, &amp;isnull);
if (isnull)
rettuple = NULL;
}
return (rettuple);
}
</ProgramListing>
</Para>
<Para>
Now, compile and
create table ttest (x int4);
create function trigf () returns opaque as
'...path_to_so' language 'c';
<ProgramListing>
vac=> create trigger tbefore before insert or update or delete on ttest
for each row execute procedure trigf();
CREATE
vac=> create trigger tafter after insert or update or delete on ttest
for each row execute procedure trigf();
CREATE
vac=> insert into ttest values (null);
NOTICE:trigf (fired before): there are 0 tuples in ttest
INSERT 0 0
-- Insertion skipped and AFTER trigger is not fired
vac=> select * from ttest;
x
-
(0 rows)
vac=> insert into ttest values (1);
NOTICE:trigf (fired before): there are 0 tuples in ttest
NOTICE:trigf (fired after ): there are 1 tuples in ttest
^^^^^^^^
remember what we said about visibility.
INSERT 167793 1
vac=> select * from ttest;
x
-
1
(1 row)
vac=> insert into ttest select x * 2 from ttest;
NOTICE:trigf (fired before): there are 1 tuples in ttest
NOTICE:trigf (fired after ): there are 2 tuples in ttest
^^^^^^^^
remember what we said about visibility.
INSERT 167794 1
vac=> select * from ttest;
x
-
1
2
(2 rows)
vac=> update ttest set x = null where x = 2;
NOTICE:trigf (fired before): there are 2 tuples in ttest
UPDATE 0
vac=> update ttest set x = 4 where x = 2;
NOTICE:trigf (fired before): there are 2 tuples in ttest
NOTICE:trigf (fired after ): there are 2 tuples in ttest
UPDATE 1
vac=> select * from ttest;
x
-
1
4
(2 rows)
vac=> delete from ttest;
NOTICE:trigf (fired before): there are 2 tuples in ttest
NOTICE:trigf (fired after ): there are 1 tuples in ttest
NOTICE:trigf (fired before): there are 1 tuples in ttest
NOTICE:trigf (fired after ): there are 0 tuples in ttest
^^^^^^^^
remember what we said about visibility.
DELETE 2
vac=> select * from ttest;
x
-
(0 rows)
</ProgramListing>
</Para>
</Sect1>
</Chapter>
<!-- tutorial.sgml
-
- Postgres tutorial. Derived from postgres.sgml.
- thomas 1998-02-23
-
- -->
<!doctype book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
<!entity intro SYSTEM "intro.sgml">
<!entity arch SYSTEM "arch.sgml">
<!entity start SYSTEM "start.sgml">
<!entity query SYSTEM "query.sgml">
<!entity advanced SYSTEM "advanced.sgml">
<!entity biblio SYSTEM "biblio.sgml">
]>
<Book>
<!-- Title information -->
<Title>PostgreSQL Tutorial</Title>
<BookInfo>
<ReleaseInfo>Covering v6.3 for general release</ReleaseInfo>
<BookBiblio>
<AuthorGroup>
<CorpAuthor>The PostgreSQL Development Team</CorpAuthor>
</AuthorGroup>
<!-- editor in authorgroup is not supported
<AuthorGroup>
-->
<Editor>
<FirstName>Thomas</FirstName>
<SurName>Lockhart</SurName>
<Affiliation>
<OrgName>Caltech/JPL</OrgName>
</Affiliation>
</Editor>
<!--
</AuthorGroup>
-->
<!--
<AuthorInitials>TGL</AuthorInitials>
-->
<Date>(last updated 1998-02-23)</Date>
</BookBiblio>
<LegalNotice>
<Para>
<ProductName>PostgreSQL</ProductName> is copyright (C) 1998 by the Postgres Global Development Group.
</Para>
</LegalNotice>
</BookInfo>
<!--
<TOC> </TOC>
<LOT> </LOT>
-->
<!--
<Dedication>
<Para>
Your name here...
</Para>
</Dedication>
-->
<Preface>
<Title>Summary</Title>
<Para>
<ProductName>Postgres</ProductName>,
developed originally in the UC Berkeley Computer Science Department,
pioneered many of the object-relational concepts
now becoming available in some commercial databases.
It provides SQL92/SQL3 language support,
transaction integrity, and type extensibility.
<ProductName>PostgreSQL</ProductName> is a public-domain, open source descendant
of this original Berkeley code.
</Para>
</Preface>
&intro;
&arch;
&start;
&query;
&advanced;
&biblio;
<INDEX> </INDEX>
</Book>
<!-- user.sgml
-
- Postgres User's Manual.
- Derived from postgres.sgml.
- thomas 1998-02-24
-
- -->
<!doctype book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
<!entity intro SYSTEM "intro.sgml">
<!entity advanced SYSTEM "advanced.sgml">
<!entity environ SYSTEM "environ.sgml">
<!entity manage SYSTEM "manage.sgml">
<!entity datatype SYSTEM "datatype.sgml">
<!entity array SYSTEM "array.sgml">
<!entity inherit SYSTEM "inherit.sgml">
<!entity query-ug SYSTEM "query-ug.sgml">
<!entity storage SYSTEM "storage.sgml">
<!entity psql SYSTEM "psql.sgml">
<!entity pgaccess SYSTEM "pgaccess.sgml">
<!entity biblio SYSTEM "biblio.sgml">
]>
<!-- entity manpages SYSTEM "man/manpages.sgml" subdoc -->
<Book>
<!-- Title information -->
<Title>PostgreSQL User's Guide</Title>
<BookInfo>
<ReleaseInfo>Covering v6.3 for general release</ReleaseInfo>
<BookBiblio>
<AuthorGroup>
<CorpAuthor>The PostgreSQL Development Team</CorpAuthor>
</AuthorGroup>
<!-- editor in authorgroup is not supported
<AuthorGroup>
-->
<Editor>
<FirstName>Thomas</FirstName>
<SurName>Lockhart</SurName>
<Affiliation>
<OrgName>Caltech/JPL</OrgName>
</Affiliation>
</Editor>
<!--
</AuthorGroup>
-->
<!--
<AuthorInitials>TGL</AuthorInitials>
-->
<Date>(last updated 1998-02-23)</Date>
</BookBiblio>
<LegalNotice>
<Para>
<ProductName>PostgreSQL</ProductName> is copyright (C) 1998 by the Postgres Global Development Group.
</Para>
</LegalNotice>
</BookInfo>
<!--
<TOC> </TOC>
<LOT> </LOT>
-->
<!--
<Dedication>
<Para>
Your name here...
</Para>
</Dedication>
-->
<Preface>
<Title>Summary</Title>
<Para>
<ProductName>Postgres</ProductName>,
developed originally in the UC Berkeley Computer Science Department,
pioneered many of the object-relational concepts
now becoming available in some commercial databases.
It provides SQL92/SQL3 language support,
transaction integrity, and type extensibility.
<ProductName>PostgreSQL</ProductName> is a public-domain, open source descendant
of this original Berkeley code.
</Para>
</Preface>
&intro;
&environ;
&manage;
&datatype;
&array;
&inherit;
&query-ug;
&storage;
&psql;
&pgaccess;
<!--
&contacts;
-->
&biblio;
<INDEX> </INDEX>
</Book>
<Chapter>
<Title>Extending <Acronym>SQL</Acronym>: Aggregates</Title>
<Para>
Aggregates in <ProductName>Postgres</ProductName> are expressed in terms of state
transition functions. That is, an aggregate can be
defined in terms of state that is modified whenever an
instance is processed. Some state functions look at a
particular value in the instance when computing the new
state (<Acronym>sfunc1</Acronym> in the create aggregate syntax) while
others only keep track of their own internal state
(<Acronym>sfunc2</Acronym>).
If we define an aggregate that uses only <Acronym>sfunc1</Acronym>, we
define an aggregate that computes a running function of
the attribute values from each instance. "Sum" is an
example of this kind of aggregate. "Sum" starts at
zero and always adds the current instance's value to
its running total. We will use the <Acronym>int4pl</Acronym> that is
built into <ProductName>Postgres</ProductName> to perform this addition.
<ProgramListing>
CREATE AGGREGATE complex_sum (
sfunc1 = complex_add,
basetype = complex,
stype1 = complex,
initcond1 = '(0,0)'
);
SELECT complex_sum(a) FROM test_complex;
+------------+
|complex_sum |
+------------+
|(34,53.9) |
+------------+
</ProgramListing>
</Para>
<Para>
If we define only <Acronym>sfunc2</Acronym>, we are specifying an aggregate
that computes a running function that is independent of
the attribute values from each instance.
"Count" is the most common example of this kind of
aggregate. "Count" starts at zero and adds one to its
running total for each instance, ignoring the instance
value. Here, we use the built-in <Acronym>int4inc</Acronym> routine to do
the work for us. This routine increments (adds one to)
its argument.
<ProgramListing>
CREATE AGGREGATE my_count (sfunc2 = int4inc, -- add one
basetype = int4, stype2 = int4,
initcond2 = '0')
SELECT my_count(*) as emp_count from EMP;
+----------+
|emp_count |
+----------+
|5 |
+----------+
</ProgramListing>
</Para>
<Para>
"Average" is an example of an aggregate that requires
both a function to compute the running sum and a function
to compute the running count. When all of the
instances have been processed, the final answer for the
aggregate is the running sum divided by the running
count. We use the <Acronym>int4pl</Acronym> and <Acronym>int4inc</Acronym> routines we used
before as well as the <ProductName>Postgres</ProductName> integer division
routine, <Acronym>int4div</Acronym>, to compute the division of the sum by
the count.
<ProgramListing>
CREATE AGGREGATE my_average (sfunc1 = int4pl, -- sum
basetype = int4,
stype1 = int4,
sfunc2 = int4inc, -- count
stype2 = int4,
finalfunc = int4div, -- division
initcond1 = '0',
initcond2 = '0')
SELECT my_average(salary) as emp_average FROM EMP;
+------------+
|emp_average |
+------------+
|1640 |
+------------+
</ProgramListing>
</Para>
</Chapter>
<Chapter>
<Title>Extending <Acronym>SQL</Acronym>: Functions</Title>
<Para>
As it turns out, part of defining a new type is the
definition of functions that describe its behavior.
Consequently, while it is possible to define a new
function without defining a new type, the reverse is
not true. We therefore describe how to add new functions
to <ProductName>Postgres</ProductName> before describing how to add new
types.
<ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> provides two types of functions: query
language functions (functions written in <Acronym>SQL</Acronym> and
programming language functions (functions written in a
compiled programming language such as <Acronym>C</Acronym>.) Either kind
of function can take a base type, a composite type or
some combination as arguments (parameters). In addition,
both kinds of functions can return a base type or
a composite type. It's easier to define <Acronym>SQL</Acronym> functions,
so we'll start with those.
Examples in this section can also be found in <FileName>funcs.sql</FileName>
and <FileName>C-code/funcs.c</FileName>.
</Para>
<Sect1>
<Title>Query Language (<Acronym>SQL</Acronym>) Functions</Title>
<Sect2>
<Title><Acronym>SQL</Acronym> Functions on Base Types</Title>
<Para>
The simplest possible <Acronym>SQL</Acronym> function has no arguments and
simply returns a base type, such as <Acronym>int4</Acronym>:
<ProgramListing>
CREATE FUNCTION one() RETURNS int4
AS 'SELECT 1 as RESULT' LANGUAGE 'sql';
SELECT one() AS answer;
+-------+
|answer |
+-------+
|1 |
+-------+
</ProgramListing>
</Para>
<Para>
Notice that we defined a target list for the function
(with the name RESULT), but the target list of the
query that invoked the function overrode the function's
target list. Hence, the result is labelled answer
instead of one.
</Para>
<Para>
It's almost as easy to define <Acronym>SQL</Acronym> functions that take
base types as arguments. In the example below, notice
how we refer to the arguments within the function as $1
and $2.
<ProgramListing>
CREATE FUNCTION add_em(int4, int4) RETURNS int4
AS 'SELECT $1 + $2;' LANGUAGE 'sql';
SELECT add_em(1, 2) AS answer;
+-------+
|answer |
+-------+
|3 |
+-------+
</ProgramListing>
</Para>
<Sect2>
<Title><Acronym>SQL</Acronym> Functions on Composite Types</Title>
<Para>
When specifying functions with arguments of composite
types (such as EMP), we must not only specify which
argument we want (as we did above with $1 and $2) but
also the attributes of that argument. For example,
take the function double_salary that computes what your
salary would be if it were doubled.
<ProgramListing>
CREATE FUNCTION double_salary(EMP) RETURNS int4
AS 'SELECT $1.salary * 2 AS salary;' LANGUAGE 'sql';
SELECT name, double_salary(EMP) AS dream
FROM EMP
WHERE EMP.dept = 'toy';
+-----+-------+
|name | dream |
+-----+-------+
|Sam | 2400 |
+-----+-------+
</ProgramListing>
<Para>
Notice the use of the syntax $1.salary.
Before launching into the subject of functions that
return composite types, we must first introduce the
function notation for projecting attributes. The simple way
to explain this is that we can usually use the
notation attribute(class) and class.attribute interchangably.
<ProgramListing>
--
-- this is the same as:
-- SELECT EMP.name AS youngster FROM EMP WHERE EMP.age &lt; 30
--
SELECT name(EMP) AS youngster
FROM EMP
WHERE age(EMP) &lt; 30;
+----------+
|youngster |
+----------+
|Sam |
+----------+
</ProgramListing>
<Para>
As we shall see, however, this is not always the case.
This function notation is important when we want to use
a function that returns a single instance. We do this
by assembling the entire instance within the function,
attribute by attribute. This is an example of a function
that returns a single EMP instance:
<ProgramListing>
CREATE FUNCTION new_emp() RETURNS EMP
AS 'SELECT \'None\'::text AS name,
1000 AS salary,
25 AS age,
\'none\'::char16 AS dept;'
LANGUAGE 'sql';
</ProgramListing>
</Para>
<Para>
In this case we have specified each of the attributes
with a constant value, but any computation or expression
could have been substituted for these constants.
Defining a function like this can be tricky. Some of
the more important caveats are as follows:
<ItemizedList>
<ListItem>
<Para>
The target list order must be exactly the same as
that in which the attributes appear in the CREATE
TABLE statement (or when you execute a .* query).
</Para>
<ListItem>
<Para>
You must typecast the expressions
(using ::) very carefully or you will see the following error:
<ProgramListing>
WARN::function declared to return type EMP does not retrieve (EMP.*)
</ProgramListing>
</Para>
<ListItem>
<Para>
When calling a function that returns an instance, we
cannot retrieve the entire instance. We must either
project an attribute out of the instance or pass the
entire instance into another function.
<ProgramListing>
SELECT name(new_emp()) AS nobody;
+-------+
|nobody |
+-------+
|None |
+-------+
</ProgramListing>
</Para>
<ListItem>
<Para>
The reason why, in general, we must use the function
syntax for projecting attributes of function return
values is that the parser just doesn't understand
the other (dot) syntax for projection when combined
with function calls.
<ProgramListing>
SELECT new_emp().name AS nobody;
WARN:parser: syntax error at or near "."
</ProgramListing>
</Para>
</ItemizedList>
<Para>
Any collection of commands in the <Acronym>SQL</Acronym> query language
can be packaged together and defined as a function.
The commands can include updates (i.e., <Acronym>insert</Acronym>, <Acronym>update</Acronym>
and <Acronym>delete</Acronym>) as well as <Acronym>select</Acronym> queries. However, the
final command must be a <Acronym>select</Acronym> that returns whatever is
specified as the function's returntype.
<ProgramListing>
CREATE FUNCTION clean_EMP () RETURNS int4
AS 'DELETE FROM EMP WHERE EMP.salary &lt;= 0;
SELECT 1 AS ignore_this'
LANGUAGE 'sql';
SELECT clean_EMP();
+--+
|x |
+--+
|1 |
+--+
</ProgramListing>
</Para>
<Sect1>
<Title>Programming Language Functions</Title>
<Sect2>
<Title>Programming Language Functions on Base Types</Title>
<Para>
Internally, <ProductName>Postgres</ProductName> regards a base type as a "blob of
memory." The user-defined functions that you define
over a type in turn define the way that <ProductName>Postgres</ProductName> can
operate on it. That is, <ProductName>Postgres</ProductName> will only store and
retrieve the data from disk and use your user-defined
functions to input, process, and output the data.
Base types can have one of three internal formats:
<ItemizedList>
<ListItem><Para>pass by value, fixed-length</Para>
<ListItem><Para>pass by reference, fixed-length</Para>
<ListItem><Para>pass by reference, variable-length</Para>
</ItemizedList>
</Para>
<Para>
By-value types can only be 1, 2 or 4 bytes in length
(even if your computer supports by-value types of other
sizes). <ProductName>Postgres</ProductName> itself only passes integer types by
value. You should be careful to define your types such
that they will be the same size (in bytes) on all
architectures. For example, the <Acronym>long</Acronym> type is dangerous
because it is 4 bytes on some machines and 8 bytes on
others, whereas <Acronym>int</Acronym> type is 4 bytes on most <Acronym>UNIX</Acronym>
machines (though not on most personal computers). A
reasonable implementation of the <Acronym>int4</Acronym> type on <Acronym>UNIX</Acronym>
machines might be:
<ProgramListing>
/* 4-byte integer, passed by value */
typedef int int4;
</ProgramListing>
</Para>
<Para>
On the other hand, fixed-length types of any size may
be passed by-reference. For example, here is a sample
implementation of the <ProductName>Postgres</ProductName> char16 type:
<ProgramListing>
/* 16-byte structure, passed by reference */
typedef struct {
char data[16];
} char16;
</ProgramListing>
</Para>
<Para>
Only pointers to such types can be used when passing
them in and out of <ProductName>Postgres</ProductName> functions.
Finally, all variable-length types must also be passed
by reference. All variable-length types must begin
with a length field of exactly 4 bytes, and all data to
be stored within that type must be located in the memory
immediately following that length field. The
length field is the total length of the structure
(i.e., it includes the size of the length field
itself). We can define the text type as follows:
</Para>
<Para>
<ProgramListing>
typedef struct {
int4 length;
char data[1];
} text;
</ProgramListing>
</Para>
<Para>
Obviously, the data field is not long enough to hold
all possible strings -- it's impossible to declare such
a structure in <Acronym>C</Acronym>. When manipulating variable-length
types, we must be careful to allocate the correct
amount of memory and initialize the length field. For
example, if we wanted to store 40 bytes in a text
structure, we might use a code fragment like this:
<ProgramListing>
#include "postgres.h"
#include "utils/palloc.h"
...
char buffer[40]; /* our source data */
...
text *destination = (text *) palloc(VARHDRSZ + 40);
destination-&gt;length = VARHDRSZ + 40;
memmove(destination-&gt;data, buffer, 40);
...
</ProgramListing>
</Para>
<Para>
Now that we've gone over all of the possible structures
for base types, we can show some examples of real functions.
Suppose <FileName>funcs.c</FileName> look like:
<ProgramListing>
#include &lt;string.h&gt;
#include "postgres.h" /* for char16, etc. */
#include "utils/palloc.h" /* for palloc */
int
add_one(int arg)
{
return(arg + 1);
}
char16 *
concat16(char16 *arg1, char16 *arg2)
{
char16 *new_c16 = (char16 *) palloc(sizeof(char16));
memset((void *) new_c16, 0, sizeof(char16));
(void) strncpy(new_c16, arg1, 16);
return (char16 *)(strncat(new_c16, arg2, 16));
}
text *
copytext(text *t)
{
/*
* VARSIZE is the total size of the struct in bytes.
*/
text *new_t = (text *) palloc(VARSIZE(t));
memset(new_t, 0, VARSIZE(t));
VARSIZE(new_t) = VARSIZE(t);
/*
* VARDATA is a pointer to the data region of the struct.
*/
memcpy((void *) VARDATA(new_t), /* destination */
(void *) VARDATA(t), /* source */
VARSIZE(t)-VARHDRSZ); /* how many bytes */
return(new_t);
}
</ProgramListing>
</Para>
<Para>
On <Acronym>OSF/1</Acronym> we would type:
<ProgramListing>
CREATE FUNCTION add_one(int4) RETURNS int4
AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
CREATE FUNCTION concat16(char16, char16) RETURNS char16
AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
CREATE FUNCTION copytext(text) RETURNS text
AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
</ProgramListing>
</Para>
<Para>
On other systems, we might have to make the filename
end in .sl (to indicate that it's a shared library).
</Para>
</Sect2>
<Sect2>
<Title>Programming Language Functions on Composite Types</Title>
<Para>
Composite types do not have a fixed layout like C
structures. Instances of a composite type may contain
null fields. In addition, composite types that are
part of an inheritance hierarchy may have different
fields than other members of the same inheritance hierarchy.
Therefore, <ProductName>Postgres</ProductName> provides a procedural
interface for accessing fields of composite types from
C.
As <ProductName>Postgres</ProductName> processes a set of instances, each instance
will be passed into your function as an opaque structure of type <Acronym>TUPLE</Acronym>.
Suppose we want to write a function to answer the query
<ProgramListing>
* SELECT name, c_overpaid(EMP, 1500) AS overpaid
FROM EMP
WHERE name = 'Bill' or name = 'Sam';
</ProgramListing>
In the query above, we can define c_overpaid as:
<ProgramListing>
#include "postgres.h" /* for char16, etc. */
#include "libpq-fe.h" /* for TUPLE */
bool
c_overpaid(TUPLE t,/* the current instance of EMP */
int4 limit)
{
bool isnull = false;
int4 salary;
salary = (int4) GetAttributeByName(t, "salary", &amp;isnull);
if (isnull)
return (false);
return(salary &gt; limit);
}
</ProgramListing>
</Para>
<Para>
<Acronym>GetAttributeByName</Acronym> is the <ProductName>Postgres</ProductName> system function that
returns attributes out of the current instance. It has
three arguments: the argument of type TUPLE passed into
the function, the name of the desired attribute, and a
return parameter that describes whether the attribute
is null. <Acronym>GetAttributeByName</Acronym> will align data properly
so you can cast its return value to the desired type.
For example, if you have an attribute name which is of
the type char16, the <Acronym>GetAttributeByName</Acronym> call would look
like:
<ProgramListing>
char *str;
...
str = (char *) GetAttributeByName(t, "name", &amp;isnull)
</ProgramListing>
</Para>
<Para>
The following query lets <ProductName>Postgres</ProductName> know about the
c_overpaid function:
<ProgramListing>
* CREATE FUNCTION c_overpaid(EMP, int4) RETURNS bool
AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
</ProgramListing>
</Para>
<Para>
While there are ways to construct new instances or modify
existing instances from within a C function, these
are far too complex to discuss in this manual.
</Para>
</Sect2>
<Sect2>
<Title>Caveats</Title>
<Para>
We now turn to the more difficult task of writing
programming language functions. Be warned: this section
of the manual will not make you a programmer. You must
have a good understanding of <Acronym>C</Acronym> (including the use of
pointers and the malloc memory manager) before trying
to write <Acronym>C</Acronym> functions for use with <ProductName>Postgres</ProductName>.
While it may be possible to load functions written in
languages other than <Acronym>C</Acronym> into <ProductName>Postgres</ProductName>, this is often
difficult (when it is possible at all) because other
languages, such as <Acronym>FORTRAN</Acronym> and <Acronym>Pascal</Acronym> often do not follow
the same "calling convention" as <Acronym>C</Acronym>. That is, other
languages do not pass argument and return values
between functions in the same way. For this reason, we
will assume that your programming language functions
are written in <Acronym>C</Acronym>.
The basic rules for building <Acronym>C</Acronym> functions are as follows:
<ItemizedList>
<ListItem>
<Para>
Most of the header (include) files for <ProductName>Postgres</ProductName>
should already be installed in
<FileName>PGROOT/include</FileName> (see Figure 2).
You should always include
<ProgramListing>
-I$PGROOT/include
</ProgramListing>
on your cc command lines. Sometimes, you may
find that you require header files that are in
the server source itself (i.e., you need a file
we neglected to install in include). In those
cases you may need to add one or more of
<ProgramListing>
-I$PGROOT/src/backend
-I$PGROOT/src/backend/include
-I$PGROOT/src/backend/port/&lt;PORTNAME&gt;
-I$PGROOT/src/backend/obj
</ProgramListing>
(where &lt;PORTNAME&gt; is the name of the port, e.g.,
alpha or sparc).
</ListItem>
<ListItem>
<Para> When allocating memory, use the <ProductName>Postgres</ProductName>
routines palloc and pfree instead of the
corresponding <Acronym>C</Acronym> library routines malloc and free.
The memory allocated by palloc will be freed
automatically at the end of each transaction,
preventing memory leaks.
</Para>
<ListItem>
<Para> Always zero the bytes of your structures using
memset or bzero. Several routines (such as the
hash access method, hash join and the sort algorithm)
compute functions of the raw bits contained in
your structure. Even if you initialize all fields
of your structure, there may be
several bytes of alignment padding (holes in the
structure) that may contain garbage values.
</Para>
<ListItem>
<Para> Most of the internal <ProductName>Postgres</ProductName> types are declared
in postgres.h, so it's usually a good idea to
include that file as well.
</Para>
<ListItem>
<Para> Compiling and loading your object code so that
it can be dynamically loaded into <ProductName>Postgres</ProductName>
always requires special flags. See Appendix A
for a detailed explanation of how to do it for
your particular operating system.
</Para>
</ListItem>
</ItemizedList>
</Para>
</Sect2>
<Chapter>
<Title>Interfacing Extensions To Indices</Title>
<Para>
The procedures described thus far let you define a new
type, new functions and new operators. However, we
cannot yet define a secondary index (such as a <Acronym>B-tree</Acronym>,
<Acronym>R-tree</Acronym> or hash access method) over a new type or its
operators.
</Para>
<Para>
Look back at
<XRef LinkEnd="EXTEND-CATALOGS" EndTerm="EXTEND-CATALOGS">.
The right half shows the catalogs
that we must modify in order to tell <ProductName>Postgres</ProductName> how
to use a user-defined type and/or user-defined operators
with an index (i.e., <FileName>pg_am, pg_amop, pg_amproc</FileName> and
<FileName>pg_opclass</FileName>). Unfortunately, there is no simple command
to do this. We will demonstrate how to modify these
catalogs through a running example: a new operator
class for the <Acronym>B-tree</Acronym> access method that sorts integers
in ascending absolute value order.
</Para>
<Para>
The <FileName>pg_am</FileName> class contains one instance for every user
defined access method. Support for the heap access
method is built into <ProductName>Postgres</ProductName>, but every other access
method is described here. The schema is
<TABLE TOCENTRY="1">
<Title>Index Schema</Title>
<TitleAbbrev>Indices</TitleAbbrev>
<TGroup Cols="2">
<THead>
<Row>
<Entry>Attribute</Entry>
<Entry>Description</Entry>
</Row>
</THead>
<TBody>
<Row>
<Entry>amname</Entry>
<Entry>name of the access method</Entry>
</Row>
<Row>
<Entry>amowner</Entry>
<Entry>object id of the owner's instance in pg_user</Entry>
</Row>
<Row>
<Entry>amkind</Entry>
<Entry>not used at present, but set to 'o' as a place holder</Entry>
</Row>
<Row>
<Entry>amstrategies</Entry>
<Entry>number of strategies for this access method (see below)</Entry>
</Row>
<Row>
<Entry>amsupport</Entry>
<Entry>number of support routines for this access method (see below)</Entry>
</Row>
<Row>
<Entry>amgettuple
aminsert
...</Entry>
<Entry>procedure identifiers for interface routines to the access
method. For example, regproc ids for opening, closing, and
getting instances from the access method appear here. </Entry>
</Row>
</TBody>
</TGroup>
</TABLE>
</Para>
<Para>
The <Acronym>object ID</Acronym> of the instance in <FileName>pg_am</FileName> is used as a
foreign key in lots of other classes. You don't need
to add a new instance to this class; all you're interested in
is the <Acronym>object ID</Acronym> of the access method instance
you want to extend:
<ProgramListing>
SELECT oid FROM pg_am WHERE amname = 'btree';
+----+
|oid |
+----+
|403 |
+----+
</ProgramListing>
</Para>
<Para>
The <FileName>amstrategies</FileName> attribute exists to standardize
comparisons across data types. For example, <Acronym>B-tree</Acronym>s
impose a strict ordering on keys, lesser to greater.
Since <ProductName>Postgres</ProductName> allows the user to define operators,
<ProductName>Postgres</ProductName> cannot look at the name of an operator (eg, ">"
or "<") and tell what kind of comparison it is. In fact,
some access methods don't impose any ordering at all.
For example, <Acronym>R-tree</Acronym>s express a rectangle-containment
relationship, whereas a hashed data structure expresses
only bitwise similarity based on the value of a hash
function. <ProductName>Postgres</ProductName> needs some consistent way of taking
a qualification in your query, looking at the operator
and then deciding if a usable index exists. This
implies that <ProductName>Postgres</ProductName> needs to know, for example, that
the "<=" and ">" operators partition a <Acronym>B-tree</Acronym>. <ProductName>Postgres</ProductName>
uses strategies to express these relationships between
operators and the way they can be used to scan indices.
</Para>
<Para>
Defining a new set of strategies is beyond the scope of
this discussion, but we'll explain how <Acronym>B-tree</Acronym> strategies
work because you'll need to know that to add a new
operator class. In the <FileName>pg_am</FileName> class, the amstrategies
attribute is the number of strategies defined for this
access method. For <Acronym>B-tree</Acronym>s, this number is 5. These
strategies correspond to
<TABLE TOCENTRY="1">
<Title>B-tree Strategies</Title>
<TitleAbbrev>B-tree</TitleAbbrev>
<TGroup Cols="2">
<THead>
<Row>
<Entry>Operation</Entry>
<Entry>Index</Entry>
</Row>
</THead>
<TBody>
<Row>
<Entry>less than</Entry>
<Entry>1</Entry>
</Row>
<Row>
<Entry>less than or equal</Entry>
<Entry>2</Entry>
</Row>
<Row>
<Entry>equal</Entry>
<Entry>3</Entry>
</Row>
<Row>
<Entry>greater than or equal</Entry>
<Entry>4</Entry>
</Row>
<Row>
<Entry>greater than</Entry>
<Entry>5</Entry>
</Row>
</TBody>
</TGroup>
</TABLE>
</Para>
<Para>
The idea is that you'll need to add procedures corresponding
to the comparisons above to the <FileName>pg_amop</FileName> relation
(see below). The access method code can use these
strategy numbers, regardless of data type, to figure
out how to partition the <Acronym>B-tree</Acronym>, compute selectivity,
and so on. Don't worry about the details of adding
procedures yet; just understand that there must be a
set of these procedures for <FileName>int2, int4, oid,</FileName> and every
other data type on which a <Acronym>B-tree</Acronym> can operate.
Sometimes, strategies aren't enough information for the
system to figure out how to use an index. Some access
methods require other support routines in order to
work. For example, the <Acronym>B-tree</Acronym> access method must be
able to compare two keys and determine whether one is
greater than, equal to, or less than the other.
Similarly, the <Acronym>R-tree</Acronym> access method must be able to compute
intersections, unions, and sizes of rectangles. These
operations do not correspond to user qualifications in
SQL queries; they are administrative routines used by
the access methods, internally.
</Para>
<Para>
In order to manage diverse support routines
consistently across all <ProductName>Postgres</ProductName> access methods, <FileName>pg_am</FileName>
includes an attribute called <FileName>amsupport</FileName>. This attribute
records the number of support routines used by an
access method. For <Acronym>B-tree</Acronym>s, this number is one -- the
routine to take two keys and return -1, 0, or +1,
depending on whether the first key is less than, equal
to, or greater than the second.
<Note>
<Para>
Strictly speaking, this routine can return a negative
number (< 0), 0, or a non-zero positive number (> 0).
</Para>
</Note>
<Para>
The <FileName>amstrategies</FileName> entry in pg_am is just the number of
strategies defined for the access method in question.
The procedures for less than, less equal, and so on
don't appear in <FileName>pg_am</FileName>. Similarly, <FileName>amsupport</FileName> is just
the number of support routines required by the access
method. The actual routines are listed elsewhere.
</Para>
<Para>
The next class of interest is pg_opclass. This class
exists only to associate a name with an oid. In
pg_amop, every <Acronym>B-tree</Acronym> operator class has a set of
procedures, one through five, above. Some existing
opclasses are <FileName>int2_ops, int4_ops, and oid_ops</FileName>. You
need to add an instance with your opclass name (for
example, <FileName>complex_abs_ops</FileName>) to <FileName>pg_opclass</FileName>. The <FileName>oid</FileName> of
this instance is a foreign key in other classes.
<ProgramListing>
INSERT INTO pg_opclass (opcname) VALUES ('complex_abs_ops');
SELECT oid, opcname
FROM pg_opclass
WHERE opcname = 'complex_abs_ops';
+------+--------------+
|oid | opcname |
+------+--------------+
|17314 | int4_abs_ops |
+------+--------------+
</ProgramListing>
Note that the oid for your <FileName>pg_opclass</FileName> instance will be
different! You should substitute your value for 17314
wherever it appears in this discussion.
</Para>
<Para>
So now we have an access method and an operator class.
We still need a set of operators; the procedure for
defining operators was discussed earlier in this manual.
For the complex_abs_ops operator class on Btrees,
the operators we require are:
<ProgramListing>
absolute value less-than
absolute value less-than-or-equal
absolute value equal
absolute value greater-than-or-equal
absolute value greater-than
</ProgramListing>
</Para>
<Para>
Suppose the code that implements the functions defined
is stored in the file
<FileName>PGROOT/src/tutorial/complex.c</FileName>
</Para>
<Para>
Part of the code look like this: (note that we will
only show the equality operator for the rest of the
examples. The other four operators are very similar.
Refer to <FileName>complex.c</FileName> or <FileName>complex.sql</FileName> for the details.)
<ProgramListing>
#define Mag(c) ((c)-&gt;x*(c)-&gt;x + (c)-&gt;y*(c)-&gt;y)
bool
complex_abs_eq(Complex *a, Complex *b)
{
double amag = Mag(a), bmag = Mag(b);
return (amag==bmag);
}
</ProgramListing>
</Para>
<Para>
There are a couple of important things that are happening below.
</Para>
<Para>
First, note that operators for less-than, less-than-or
equal, equal, greater-than-or-equal, and greater-than
for <FileName>int4</FileName> are being defined. All of these operators are
already defined for <FileName>int4</FileName> under the names &lt;, &lt;=, =, &gt;=,
and &gt;. The new operators behave differently, of
course. In order to guarantee that <ProductName>Postgres</ProductName> uses these
new operators rather than the old ones, they need to be
named differently from the old ones. This is a key
point: you can overload operators in <ProductName>Postgres</ProductName>, but only
if the operator isn't already defined for the argument
types. That is, if you have &lt; defined for (int4,
int4), you can't define it again. <ProductName>Postgres</ProductName> does not
check this when you define your operator, so be careful.
To avoid this problem, odd names will be used for
the operators. If you get this wrong, the access methods
are likely to crash when you try to do scans.
</Para>
<Para>
The other important point is that all the operator
functions return Boolean values. The access methods
rely on this fact. (On the other hand, the support
function returns whatever the particular access method
expects -- in this case, a signed integer.)
The final routine in the file is the "support routine"
mentioned when we discussed the amsupport attribute of
the <FileName>pg_am</FileName> class. We will use this later on. For now,
ignore it.
</Para>
<Para>
<ProgramListing>
CREATE FUNCTION complex_abs_eq(complex, complex)
RETURNS bool
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
</ProgramListing>
</Para>
<Para>
Now define the operators that use them. As noted, the
operator names must be unique among all operators that
take two <FileName>int4</FileName> operands. In order to see if the
operator names listed below are taken, we can do a query on
<FileName>pg_operator</FileName>:
<ProgramListing>
/*
* this query uses the regular expression operator (~)
* to find three-character operator names that end in
* the character &amp;
*/
SELECT *
FROM pg_operator
WHERE oprname ~ '^..&amp;$'::text;
</ProgramListing>
</Para>
<Para>
to see if your name is taken for the types you want.
The important things here are the procedure (which are
the <Acronym>C</Acronym> functions defined above) and the restriction and
join selectivity functions. You should just use the
ones used below--note that there are different such
functions for the less-than, equal, and greater-than
cases. These must be supplied, or the access method
will crash when it tries to use the operator. You
should copy the names for restrict and join, but use
the procedure names you defined in the last step.
<ProgramListing>
CREATE OPERATOR = (
leftarg = complex, rightarg = complex,
procedure = complex_abs_eq,
restrict = eqsel, join = eqjoinsel
)
</ProgramListing>
</Para>
<Para>
Notice that five operators corresponding to less, less
equal, equal, greater, and greater equal are defined.
</Para>
<Para>
We're just about finished. the last thing we need to do
is to update the <FileName>pg_amop</FileName> relation. To do this, we need
the following attributes:
<TABLE TOCENTRY="1">
<Title><FileName>pg_amproc</FileName> Schema</Title>
<TitleAbbrev><FileName>pg_amproc</FileName></TitleAbbrev>
<TGroup Cols="2">
<THead>
<Row>
<Entry>Attribute</Entry>
<Entry>Description</Entry>
</Row>
</THead>
<TBody>
<Row>
<Entry>amopid</Entry>
<Entry>the <FileName>oid</FileName> of the <FileName>pg_am</FileName> instance
for B-tree (== 403, see above)</Entry>
</Row>
<Row>
<Entry>amopclaid</Entry>
<Entry>the <FileName>oid</FileName> of the
<FileName>pg_opclass</FileName> instance for <FileName>int4_abs_ops</FileName>
(== whatever you got instead of <FileName>17314</FileName>, see above)</Entry>
</Row>
<Row>
<Entry>amopopr</Entry>
<Entry>the <FileName>oid</FileName>s of the operators for the opclass
(which we'll get in just a minute)</Entry>
</Row>
<Row>
<Entry>amopselect, amopnpages</Entry>
<Entry>cost functions</Entry>
</Row>
</TBody>
</TGroup>
</TABLE>
The cost functions are used by the query optimizer to
decide whether or not to use a given index in a scan.
Fortunately, these already exist. The two functions
we'll use are <FileName>btreesel</FileName>, which estimates the selectivity
of the <Acronym>B-tree</Acronym>, and <FileName>btreenpage</FileName>, which estimates the
number of pages a search will touch in the tree.
</Para>
<Para>
So we need the <FileName>oid</FileName>s of the operators we just defined.
We'll look up the names of all the operators that take
two <FileName>int4</FileName>s, and pick ours out:
<ProgramListing>
SELECT o.oid AS opoid, o.oprname
INTO TABLE complex_ops_tmp
FROM pg_operator o, pg_type t
WHERE o.oprleft = t.oid and o.oprright = t.oid
and t.typname = 'complex';
+------+---------+
|oid | oprname |
+------+---------+
|17321 | &lt; |
+------+---------+
|17322 | &lt;= |
+------+---------+
|17323 | = |
+------+---------+
|17324 | &gt;= |
+------+---------+
|17325 | &gt; |
+------+---------+
</ProgramListing>
(Again, some of your <FileName>oid</FileName> numbers will almost certainly
be different.) The operators we are interested in are
those with <FileName>oid</FileName>s 17321 through 17325. The values you
get will probably be different, and you should
substitute them for the values below. We can look at the
operator names and pick out the ones we just added.
</Para>
<Para>
Now we're ready to update <FileName>pg_amop</FileName> with our new operator
class. The most important thing in this entire
discussion is that the operators are ordered, from less equal
through greater equal, in <FileName>pg_amop</FileName>. We add the
instances we need:
<ProgramListing>
INSERT INTO pg_amop (amopid, amopclaid,
amopopr, amopstrategy,
amopselect, amopnpages)
SELECT am.oid, opcl.oid, c.opoid, 3,
'btreesel'::regproc, 'btreenpage'::regproc
FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
WHERE amname = 'btree'
and opcname = 'complex_abs_ops'
and c.oprname = '=';
</ProgramListing>
Note the order: "less than" is 1, "less than or equal"
is 2, "equal" is 3, "greater than or equal" is 4, and
"greater than" is 5.
</Para>
<Para>
The last step (finally!) is registration of the
"support routine" previously described in our discussion of
<FileName>pg_am</FileName>. The <FileName>oid</FileName> of this support routine is stored in
the <FileName>pg_amproc</FileName> class, keyed by the access method <FileName>oid</FileName> and
the operator class <FileName>oid</FileName>. First, we need to register the
function in <ProductName>Postgres</ProductName> (recall that we put the <Acronym>C</Acronym> code
that implements this routine in the bottom of the file
in which we implemented the operator routines):
<ProgramListing>
CREATE FUNCTION int4_abs_cmp(int4, int4)
RETURNS int4
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
SELECT oid, proname FROM pg_proc
WHERE prname = 'int4_abs_cmp';
+------+--------------+
|oid | proname |
+------+--------------+
|17328 | int4_abs_cmp |
+------+--------------+
</ProgramListing>
(Again, your <FileName>oid</FileName> number will probably be different and
you should substitute the value you see for the value
below.) Recalling that the <Acronym>B-tree</Acronym> instance's oid is
403 and that of <FileName>int4_abs_ops</FileName> is 17314, we can add the
new instance as follows:
<ProgramListing>
INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
VALUES ('403'::oid, -- btree oid
'17314'::oid, -- pg_opclass tuple
'17328'::oid, -- new pg_proc oid
'1'::int2);
</ProgramListing>
</Para>
</Chapter>
<Chapter>
<Title>Extending <Acronym>SQL</Acronym>: Operators</Title>
<Para>
<ProductName>Postgres</ProductName> supports left unary, right unary and binary
operators. Operators can be overloaded, or re-used
with different numbers and types of arguments. If
there is an ambiguous situation and the system cannot
determine the correct operator to use, it will return
an error and you may have to typecast the left and/or
right operands to help it understand which operator you
meant to use.
To create an operator for adding two complex numbers
can be done as follows. First we need to create a
function to add the new types. Then, we can create the
operator with the function.
<ProgramListing>
CREATE FUNCTION complex_add(complex, complex)
RETURNS complex
AS '$PWD/obj/complex.so'
LANGUAGE 'c';
CREATE OPERATOR + (
leftarg = complex,
rightarg = complex,
procedure = complex_add,
commutator = +
);
</ProgramListing>
</Para>
<Para>
We've shown how to create a binary operator here. To
create unary operators, just omit one of leftarg (for
left unary) or rightarg (for right unary).
If we give the system enough type information, it can
automatically figure out which operators to use.
<ProgramListing>
SELECT (a + b) AS c FROM test_complex;
+----------------+
|c |
+----------------+
|(5.2,6.05) |
+----------------+
|(133.42,144.95) |
+----------------+
</ProgramListing>
</Para>
</Chapter>
<Chapter>
<Title>Extending <Acronym>SQL</Acronym>: Types</Title>
<Para>
As previously mentioned, there are two kinds of types
in <ProductName>Postgres</ProductName>: base types (defined in a programming language)
and composite types (instances).
Examples in this section up to interfacing indices can
be found in <FileName>complex.sql</FileName> and <FileName>complex.c</FileName>. Composite examples
are in <FileName>funcs.sql</FileName>.
</Para>
<Sect1>
<Title>User-Defined Types</Title>
<Sect2>
<Title>Functions Needed for a User-Defined Type</Title>
<Para>
A user-defined type must always have input and output
functions. These functions determine how the type
appears in strings (for input by the user and output to
the user) and how the type is organized in memory. The
input function takes a null-delimited character string
as its input and returns the internal (in memory)
representation of the type. The output function takes the
internal representation of the type and returns a null
delimited character string.
Suppose we want to define a complex type which represents
complex numbers. Naturally, we choose to represent a
complex in memory as the following <Acronym>C</Acronym> structure:
<ProgramListing>
typedef struct Complex {
double x;
double y;
} Complex;
</ProgramListing>
and a string of the form (x,y) as the external string
representation.
These functions are usually not hard to write, especially
the output function. However, there are a number of points
to remember:
<ItemizedList>
<ListItem>
<Para> When defining your external (string) representation,
remember that you must eventually write a
complete and robust parser for that representation
as your input function!
<ProgramListing>
Complex *
complex_in(char *str)
{
double x, y;
Complex *result;
if (sscanf(str, " ( &percnt;lf , &percnt;lf )", &amp;x, &amp;y) != 2) {
elog(WARN, "complex_in: error in parsing
return NULL;
}
result = (Complex *)palloc(sizeof(Complex));
result-&gt;x = x;
result-&gt;y = y;
return (result);
}
</ProgramListing>
The output function can simply be:
<ProgramListing>
char *
complex_out(Complex *complex)
{
char *result;
if (complex == NULL)
return(NULL);
result = (char *) palloc(60);
sprintf(result, "(&percnt;g,&percnt;g)", complex-&gt;x, complex-&gt;y);
return(result);
}
</ProgramListing>
</Para>
</ListItem>
<ListItem>
<Para> You should try to make the input and output
functions inverses of each other. If you do
not, you will have severe problems when you need
to dump your data into a file and then read it
back in (say, into someone else's database on
another computer). This is a particularly common
problem when floating-point numbers are
involved.
</Para>
</ListItem>
</ItemizedList>
<Para>
To define the <Acronym>complex</Acronym> type, we need to create the two
user-defined functions complex_in and complex_out
before creating the type:
<ProgramListing>
CREATE FUNCTION complex_in(opaque)
RETURNS complex
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
CREATE FUNCTION complex_out(opaque)
RETURNS opaque
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
CREATE TYPE complex (
internallength = 16,
input = complex_in,
output = complex_out
);
</ProgramListing>
</Para>
<Para>
As discussed earlier, <ProductName>Postgres</ProductName> fully supports arrays of
base types. Additionally, <ProductName>Postgres</ProductName> supports arrays of
user-defined types as well. When you define a type,
<ProductName>Postgres</ProductName> automatically provides support for arrays of
that type. For historical reasons, the array type has
the same name as the user-defined type with the
underscore character _ prepended.
Composite types do not need any function defined on
them, since the system already understands what they
look like inside.
</Para>
<Sect2>
<Title>Large Objects</Title>
<Para>
The types discussed to this point are all "small"
objects -- that is, they are smaller than 8KB in size.
<Note>
<Para>
1024 longwords == 8192 bytes. In fact, the type must be considerably smaller than 8192 bytes,
since the <ProductName>Postgres</ProductName> tuple
and page overhead must also fit into this 8KB limitation.
The actual value that fits depends on the machine architecture.
</Para>
</Note>
If you require a larger type for something like a document
retrieval system or for storing bitmaps, you will
need to use the <ProductName>Postgres</ProductName> large object interface.
</Sect2>
</Sect1>
</Chapter>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment