head	1.30;
access;
symbols;
locks; strict;
comment	@# @;


1.30
date	94.03.12.11.41.30;	author aoki;	state Exp;
branches;
next	1.29;

1.29
date	94.02.12.08.57.36;	author aoki;	state Exp;
branches;
next	1.28;

1.28
date	94.02.09.18.51.55;	author aoki;	state Exp;
branches;
next	1.27;

1.27
date	94.02.01.21.18.45;	author jolly;	state Exp;
branches;
next	1.26;

1.26
date	93.09.27.06.09.25;	author aoki;	state Exp;
branches;
next	1.25;

1.25
date	93.08.13.22.28.20;	author aoki;	state Exp;
branches;
next	1.24;

1.24
date	93.07.19.18.39.13;	author jolly;	state Exp;
branches;
next	1.23;

1.23
date	93.06.14.03.43.11;	author aoki;	state Exp;
branches;
next	1.22;

1.22
date	93.05.30.07.30.36;	author aoki;	state Exp;
branches;
next	1.21;

1.21
date	93.02.22.06.24.45;	author marc;	state Exp;
branches;
next	1.20;

1.20
date	93.02.17.05.17.17;	author aoki;	state Exp;
branches;
next	1.19;

1.19
date	93.02.08.19.36.49;	author aoki;	state Exp;
branches;
next	1.18;

1.18
date	93.01.26.02.43.13;	author aoki;	state Exp;
branches;
next	1.17;

1.17
date	92.07.31.17.02.31;	author mer;	state Exp;
branches;
next	1.16;

1.16
date	92.07.22.19.26.44;	author clarsen;	state Exp;
branches;
next	1.15;

1.15
date	92.07.20.18.55.37;	author mer;	state Exp;
branches;
next	1.14;

1.14
date	92.07.15.01.57.02;	author clarsen;	state Exp;
branches;
next	1.13;

1.13
date	92.07.13.03.45.59;	author ptong;	state Exp;
branches;
next	1.12;

1.12
date	92.07.12.21.10.19;	author ptong;	state Exp;
branches;
next	1.11;

1.11
date	92.06.25.23.58.38;	author mao;	state Exp;
branches;
next	1.10;

1.10
date	92.06.17.22.24.05;	author mer;	state Exp;
branches;
next	1.9;

1.9
date	92.03.25.19.25.31;	author clarsen;	state Exp;
branches;
next	1.8;

1.8
date	92.01.30.19.39.44;	author mer;	state Exp;
branches;
next	1.7;

1.7
date	91.11.13.05.20.12;	author mer;	state Exp;
branches;
next	1.6;

1.6
date	91.11.12.06.09.09;	author mer;	state Exp;
branches;
next	1.5;

1.5
date	91.08.16.00.32.57;	author mer;	state Exp;
branches;
next	1.4;

1.4
date	91.03.09.05.27.59;	author kemnitz;	state Exp;
branches;
next	1.3;

1.3
date	91.02.25.19.17.21;	author mike;	state Exp;
branches;
next	1.2;

1.2
date	90.07.20.08.54.39;	author claire;	state Exp;
branches;
next	1.1;

1.1
date	90.07.18.16.25.41;	author mao;	state Exp;
branches;
next	;


desc
@use of libpq.a for user-level database apps that use postgres
@


1.30
log
@PQFlushI grotesqueness
@
text
@.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /usr/local/devel/postgres/src/ref/RCS/libpq.3pqsrc,v 1.29 1994/02/12 08:57:36 aoki Exp aoki $
.TH INTRODUCTION LIBPQ 03/12/94
.XA 0 "Section 5 \(em Libpq"
.BH "SECTION 5 \(em LIBPQ"
.SH DESCRIPTION
\*(LI is the programmer's interface to \*(PG.  \*(LI is a set of
library routines which allow queries to pass to the \*(PG backend and
instances to return through an IPC channel.
.PP
This version of the documentation is based on the C library.  Three
short programs are listed at the end of this section as examples of
\*(LI programming (though not necessarily of good programming).
.PP
There are several examples of \*(LI applications in the following
directories:
.(C
\&.../src/regress/demo
\&.../src/regress/regress
\&.../src/regress/video
\&.../src/bin/monitor
\&.../src/bin/fsutils
.)C
.XA 1 "Control and Initialization"
.SH "CONTROL AND INITIALIZATION"
.XA 2 "Environment Variables"
.SS "Environment Variables"
The following environment variables can be used to set up default
values for an environment and to avoid hard-coding database names into
an application program:
.TP 15n
.BR PGHOST
sets the default server name.
.TP 15n
.BR PGDATABASE
sets the default \*(PG database name.
.TP 15n
.BR PGPORT
sets the default communication port with the \*(PG backend.
.TP 15n
.BR PGTTY
sets the file or tty on which debugging messages from the backend
server are displayed.
.TP 15n
.BR PGREALM
sets the
.IR Kerberos
realm to use with \*(PG, if it is different from the local realm.  If 
.SM PGREALM
is set, \*(PG 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 
.IR Kerberos
authentication is enabled; see
.IR introduction (unix)
for additional information on 
.IR Kerberos .
.XA 2 "Internal Variables"
.SS "Internal Variables"
The following internal variables of \*(LI can be accessed by the
programmer:
.(C
char *PQhost;           /* the server on which \*(PG
                           backend is running. */

char *PQport = NULL;    /* The communication port with the
                           \*(PG backend. */

char *PQtty;            /* The tty on the PQhost backend on
                           which backend messages are
                           displayed. */

char *PQoption;         /* Optional arguements to the backend */

char *PQdatabase;       /* backend database to access */

int  PQportset = 0;     /* 1 if communication with
                           backend is established */

int  PQxactid = 0;      /* Transaction ID of the current
                           transaction */

int  PQtracep = 0;      /* 1 to print out front-end
                           debugging messages */

int  PQAsyncNotifyWaiting = 0; /* 1 if one or more asynchronous
                                  notifications have been
                                  triggered */

char PQerrormsg[];       /* null-delimited string containing the
                           error message (usually from the backend)
                           when the execution of a query or function 
                           fails */
.)C
.XA 1 "Query Execution Functions"
.SH "QUERY EXECUTION FUNCTIONS"
The following routines control the execution of queries
from a C program.
.TP 15n
.BR PQsetdb
Make the specified database the current database and reset
communication using
.IR PQreset
(see below).
.(C
void PQsetdb(dbname)
	char *dbname;
.)C
.TP 15n
.BR PQdb
Returns the name of the \*(PG database being accessed, or
.SM NULL
if no database is open.  Only one database can be accessed at a time.
The database name is a string limited to 16 characters.
.(C
char *PQdb()
.)C
.TP 15n
.BR PQreset
Reset the communication port with the backend in case of errors.  This
function will close the IPC socket connection to the backend thereby
causing the next
.IR PQexec
call to ask for a new one from the
.IR postmaster .
When the backend notices the socket was closed it will exit, and when
the
.IR postmaster
is asked for the new connection it will start a new backend.
.(C
void PQreset()
.)C
.TP 15n
.BR PQfinish
Close communication ports with the backend.  Terminates communications
and frees up the memory taken up by the \*(LI buffer.
.(C
void PQfinish()
.)C
.TP 15n
.BR PQfn
Send a function call to the \*(PG backend.  Provides access to the
\*(PG
.BR "fast path"
facility, a trapdoor into the system internals.  See the
.IR "FAST PATH"
section of the manual.
.IP
The
.IR fnid
argument is the object identifier of the function to be executed.
.IR result_len
and
.IR result_buf
specify the expected size (in bytes) of the function return value and
a buffer in which to load the return value.  The actual size of the
returned value will be loaded into the space pointed to by
.IR actual_result_len
if it is a valid pointer.
.IR result_type
should be set to 1 if the return type is an integer and 2 in all other
cases.
.IR args
and
.IR nargs
specify a pointer to a PQArgBlock structure (see
.(C
\&.../src/backend/tmp/libpq.h
.)C
for more details) and the number of arguments, respectively.
.IP
.IR PQfn
returns a string containing the character \*(lqG\*(rq when a
return-value has been loaded into 
.IR result_buf ,
or \*(lqV\*(rq if the function returned nothing.
.IR PQfn
returns a
.SM NULL
pointer and loads
.IR PQerrormsg
if any error (fatal or non-fatal) occurs.
.IP
.IR PQfn
returns an error if
.IR result_buf
is not large enough to contain the returned value.
.(C
char *PQfn(fnid, result_buf, result_len,
	   actual_result_len,
           result_type, args, nargs)
	int fnid;
	int *result_buf;
	int result_len;
	int *actual_result_len;
	int result_type;
	PQArgBlock *args;
	int nargs;
.)C
.TP 15n
.BR PQexec
Submit a query to \*(PG.  Returns a status indicator or an error
message.
.IP
If the query returns data (e.g.,
.IR fetch ),
.IR PQexec
returns a string consisting of the character \*(lqP\*(rq followed by
the name of the portal buffer.
.IP
If the query does not return any instances, as in the case with update
queries,
.IR PQexec
will return a string consisting of the character \*(lqC\*(rq followed
by the command tag (e.g., \*(lqCREPLACE\*(rq).
.IP
If a \*(lqcopy from stdin\*(rq or \*(lqcopy to stdout\*(rq query is
executed (see
.IR copy (commands)
for more details), 
.IR PQexec
will return the strings \*(lqDCOPY\*(rq and \*(lqBCOPY\*(rq,
respectively.
.IP
A string beginning with the character \*(lqI\*(rq indicates that the
server has finished sending the results of a multi-query command
(e.g., has finished processing an asynchronous portal command).
.IP
If a non-fatal error occurred during the execution of the query,
.IR PQexec
will return (for historical reasons) the character \*(lqR\*(rq and
load an error message into
.IR PQerrormsg .
If a fatal error occurred (i.e., the backend crashed),
.IR PQexec
returns the character \*(lqE\*(rq and loads an error message into 
.IR PQerrormsg .
.(C
char *PQexec(query)
	char *query;
.)C
.TP 15n
.BR PQFlushI
The frontend/backend protocol has a serious flaw in that the queries 
executed when using
.IR PQfn
and
.IR PQexec
can cause several query responses to come back to the frontend.  For
example, during the definition of a view, the server actually executes
several queries on its own to modify the system catalogs.
Unfortunately, the implementation of this was botched and these
queries return status messages to the frontend of their own.  If the
frontend application only reads one response and then goes on to
execute more queries, these extra responses sit in the message queue
and the frontend will read these leftovers instead of reading the
responses from its latest queries.
.IP
If you aren't completely positive that a call to 
.IR PQexec
won't do something more complicated than a simple 
.IR retrieve ,
you should probably wrap it in a loop that processes \*(lqP\*(rq and
\*(lqC\*(rq responses in the usual way, but also performs
.(C
result = PQexec(" "); /* dummy query */
++dummies_sent;
.)C
after receiving each good protocol result.  When the first character
of a 
.IR PQexec
result is \*(lqI\*(rq, you know you have received the last result and
have started receiving responses to your dummy queries.  To get rid of
the \*(lqI\*(rq protocol responses that are now stuffed into your
message buffer, call 
.IR PQFlushI
with the number of dummy queries you sent.
.IP
This is horrendously complicated and should be fixed.  Meanwhile, you
should look at
.(C
\&.../src/bin/monitor/monitor.c
.)C
to see an example of a program that handles this problem correctly.
.(C
int PQFlushI(i_count)
    int i_count;
.)C
.XA 1 "Portal Functions"
.SH "PORTAL FUNCTIONS"
A 
.BR portal
is a \*(PG buffer from which instances can be 
.BR fetch ed.
Each portal has a string name (currently limited to 16 bytes).
A portal is initialized by submitting a 
.IR retrieve
statement using the
.IR PQexec
function, for example:
.(C
retrieve portal foo (EMP.all)
.)C
The programmer can then move data from the portal into \*(LI by
executing a
.IR fetch
statement, e.g:
.(C
fetch 10 in foo

fetch all in foo
.)C
If no portal name is specified in a query, the default portal name is
the string \*(lqblank\*(rq, known as the
.BR "blank portal" .
All qualifying instances in a blank portal are fetched immediately,
without the need for the programmer to issue a separate 
.IR fetch
command.
.PP
Data fetched from a portal into \*(LI is moved into a 
.BR "portal buffer" .
Portal names are mapped to portal buffers through an internal table.
Each instance in a portal buffer has an index number locating its
position in the buffer.  In addition, each field in an instance has a
name (attribute name) and a field index (attribute number).
.PP
A single
.IR retrieve
command can return multiple types of instances.  This can happen if a
\*(PG function is executed in the evaluation of a query or if the
query returns multiple instance types from an inheritance hierarchy.
Consequently, the instances in a portal are set up in 
.BR groups .
Instances in the same group are guaranteed to have the same instance
format.
.PP
Portals that are associated with normal user commands are called
.BR synchronous .
In this case, the application program is expected to issue a retrieval
followed by one or more fetch commands.  The functions that follow can
now be used to manipulate data in the portal.
.TP 15n
.BR PQnportals
Return the number of open portals.  If
.IR rule_p
is not 0, then only return the number of asynchronous portals.
.(C
int PQnportals(rule_p)
	int rule_p;
.)C
.TP 15n
.BR PQpnames
Return all portal names.  If 
.IR rule_p
is not 0, then only return the names of asynchronous portals.
The caller is responsible for allocating sufficent storage for
.IR pnames.  The number of names returned can be determined with a call to 
.BR PQnportals().  Each portal name is at most PortalNameLength
characters long (see \&.../src/backend/tmp/libpq.h).
.(C
void PQpnames(pnames, rule_p)
	char **pnames;
	int rule_p;
.)C
.TP 15n
.BR PQparray
Return the portal buffer given a portal name, 
.IR pname.  
.(C
PortalBuffer *PQparray(pname)
	char *pname;
.)C
.TP 15n
.BR PQclear
Free storage claimed by portal
.IR pname .
.(C
void PQclear(pname)
	char *pname;
.)C
.TP 15n
.BR PQntuples
Return the number of instances (tuples) in a portal buffer
.IR portal .
.(C
int PQntuples(portal)
	PortalBuffer *portal;
.)C
.TP 15n
.BR PQngroups
Return the number of instance groups in a portal buffer
.IR portal .
.(C
int PQngroups(portal)
	PortalBuffer *portal
.)C
.TP 15n
.BR PQntuplesGroup
Return the number of instances in an instance group
.IR group_index 
associated with a portal buffer
.IR portal .
.(C
int PQntuplesGroup(portal, group_index)
	PortalBuffer *portal;
	int group_index;
.)C
.TP 15n
.BR PQnfieldsGroup
Return the number of fields (attributes) for the instances (tuples) in
instance group
.IR group_index
associated with portal buffer
.IR portal .
.(C
int PQnfieldsGroup(portal, group_index)
	PortalBuffer *portal;
	int group_index;
.)C
.TP 15n
.BR PQfnameGroup
Return the field (attribute) name for the instances (tuples) in
instance group 
.IR group_index
(associated with portal buffer
.IR portal )
and the field index
.IR field_number .
.(C
char *PQfnameGroup(portal, group_index, field_number)
	PortalBuffer *portal;
	int group_index;
	int field_number;
.)C
.TP 15n
.BR PQfnumberGroup
Return the field index (attribute number) given the instance group
.IR group_index
(associated with portal buffer
.IR portal )
and the field (attribute) name
.IR field_name .
.(C
int PQfnumberGroup(portal, group_index, field_name)
	PortalBuffer *portal;
	int group_index;
	char *field_name;
.)C
.TP 15n
.BR PQgetgroup
Returns the index of the instance group (associated with portal buffer
.IR portal )
that contains a particular instance
.IR tuple_index .
.(C
int PQgetgroup(portal, tuple_index)
	PortalBuffer *portal;
	int tuple_index;
.)C
.TP 15n
.BR PQnfields
Returns the number of fields (attributes) in an instance
.IR tuple_index
contained in portal buffer
.IR portal .
.(C
int PQnfields(portal, tuple_index)
	PortalBuffer *portal;
	int tuple_index;
.)C
.TP 15n
.BR PQfnumber
Returns the field index (attribute number) of a given field name
.IR field_name
within an instance
.IR tuple_index
contained in portal buffer
.IR portal .
.(C
int PQfnumber(portal, tuple_index, field_name)
	PortalBuffer *portal;
	int tuple_index;
	char *field_name;
.)C
.TP 15n
.BR PQfname
Returns the name of a field (attribute)
.IR field_number 
of instance
.IR tuple_index
contained in portal buffer
.IR portal .
.(C
char *PQfname(portal, tuple_index, field_number)
	PortalBuffer *portal;
	int tuple_index;
	int field_number;
.)C
.TP 15n
.BR PQftype
Returns the type of a field (attribute)
.IR field_number
of instance
.IR tuple_index
contained in portal buffer
.IR portal .
The type returned is an internal coding of a type.
.(C
int PQftype(portal, tuple_index, field_number)
	PortalBuffer *portal;
	int tuple_index;
	int field_number;
.)C
.TP 15n
.BR PQsametype
Returns 1 if two instances
.IR tuple_index1 
and 
.IR tuple_index2 ,
both contained in portal buffer
.IR portal ,
have the same field (attribute) types.
.(C
int PQsametype(portal, tuple_index1, tuple_index2)
	PortalBuffer *portal;
	int tuple_index1;
	int tuple_index2;
.)C
.TP 15n
.BR PQgetvalue
Returns a field (attribute) value.  
.(C
char *PQgetvalue(portal, tuple_index, field_number)
	PortalBuffer *portal;
	int tuple_index;
	int field_number;
.)C
.TP 15n
.BR PQgetlength
Return the length of a field (attribute) value in bytes.  If the field
is a
.IR "struct varlena" ,
the length returned here does 
.BR not
include the size field of the varlena, i.e., it is 4 bytes less.
.(C
char *PQgetlength(portal, tuple_index, field_number)
	PortalBuffer *portal;
	int tuple_index;
	int field_number;
.)C
.PP
If the portal is blank, or the portal was specified with the
.BR portal 
keyword, all values are returned as null-delimited strings.  It is the
programmer's responsibility to convert them to the correct type.  If
the portal is specified with the
.BR iportal
keyword, all values are returned in an architecture-dependent internal
(binary) format, namely, the format generated by the
.IR input
function specified through
.IR "define type" (commands).
Again, it is the programmer's responsibility to convert the data to
the correct type.
.XA 1 "Asynchronous Portals and Notification"
.SH "ASYNCHRONOUS PORTALS AND NOTIFICATION"
Asynchronous portals \(em query results of rules \(em are implemented
using two mechanisms: relations and notification.  The query result is
transferred through a relation.  The notification is done with special
\*(PQ commands and the frontend/backend protocol.
.PP
The first step in using asynchronous portals is to
.IR listen (commands)
on a given class name.  The fact that a process is listening on the
class is shared with all backend servers running on a database; when
one sets off the rule, it signals its peers.  The backend server
associated with the listening frontend process then sends its client
an IPC message, which the frontend process must explicitly catch by
polling the variable
.IR PQAsyncNotify .
When this variable is non-zero, the frontend process must first
issue a null (empty) query, i.e.,
.(C
PQexec(" ");
.)C
Then the frontend should check the variable, 
.IR PQAsyncNotifyWaiting .
When this variable is non-zero, the frontend can retrieve the
notification data held using 
.IR PQNotifies .
The frontend must call 
.IR PQNotifies
in order to find out which classes the data corresponds to (i.e.,
which notification events have been set off).  These events must then
be individually cleared by calling
.IR PQRemoveNotify
on each element of the list returned by
.IR PQNotifies .
.PP
Notice that the asynchronous notification process does not itself
transfer any data, but only a class name.  Hence the frontend and
backend must come to agreement on the class to be used to pass
any data prior to notification and data transfer (obviously, since 
the frontend must specify this table name in the corresponding
.IR listen
command).
.PP
The second sample program gives an example of the use of asynchronous
portals in which the frontend program retrieves the entire contents
of the result class each time it is notified.
.TP 15n
.BR PQNotifies
Return the list of relations on which notification has occurred.
.(C
PQNotifyList *PQNotifies()
.)C
.TP 15n
.BR PQRemoveNotify
Remove the notification from the list of unhandled notifications.
.(C
PQNotifyList *PQRemoveNotify(pqNotify)
	PQNotifyList *pqNotify;
.)C
.XA 1 "Miscellaneous Functions"
.XA 2 "Functions Associated with the COPY Command"
.SH "FUNCTIONS ASSOCIATED WITH THE COPY COMMAND"
The
.IR copy
command in \*(PG has options to read from or write to the network
connection used by \*(LI.  Therefore, functions are necessary to
access this network connection directly so applications may take full
advantage of this capability.
.PP
For more information about the 
.IR copy
command, see
.IR copy (commands).
.TP 15n
.BR PQgetline
Reads a newline-terminated line of characters (transmitted by the
backend server) into a buffer 
.IR string 
of size
.IR length .
Like
.IR fgets (3),
this routine copies up to 
.IR length "-1"
characters into 
.IR string .
It is like 
.IR gets (3),
however, in that it converts the terminating newline into a null
character.
.IP
.IR 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.
.IP
Notice that the application must check to see if a new line consists
of the single character \*(lq.\*(rq, which indicates that the backend
server has finished sending the results of the 
.IR copy
command.  Therefore, if the application ever expects to receive lines
that are more than
.IR length "-1"
characters long, the application must be sure to check the return
value of 
.IR PQgetline
very carefully.
.IP
The code in
.(C
\&.../src/bin/monitor/monitor.c
.)C
contains routines that correctly handle the copy protocol.
.(C
PQgetline(string, length)
	char *string;
	int length
.)C
.TP 15n
.BR PQputline
Sends a null-terminated 
.IR string
to the backend server.
.IP
The application must explicitly send the single character \*(lq.\*(rq
to indicate to the backend that it has finished sending its data.
.(C
PQputline(string)
	char *string;
.)C
.TP 15n
.BR PQendcopy
Syncs with the backend.  This function waits until the backend has
finished processing the copy.  It should either be issued when the
last string has been sent to the backend using
.IR PQputline
or when the last string has been received from the backend using
.IR PGgetline .
It must be issued or the backend may get \*(lqout of sync\*(rq with
the frontend.  Upon return from this function, the backend is ready to
receive the next query.
.IP
The return value is 0 on successful completion, nonzero otherwise.
.(C
int PQendcopy()
.)C
As an example:
.(C
PQexec("create foo (a=int4, b=char16, d=float8)");
PQexec("copy foo from stdin");
PQputline("3<TAB>hello world<TAB>4.5\en");
PQputline("4<TAB>goodbye world<TAB>7.11\en");
\&...
PQputline(".\en");
PQendcopy();
.)C
.XA 2 "LIBPQ Tracing Functions"
.SH "LIBPQ TRACING FUNCTIONS"
.TP 15n
.BR PQtrace
Enable tracing.
The routine sets the
.IR PQtracep
variable to 1 which causes debug messages to be printed.  You should
note that the messages will be printed to stdout by default.  If you
would like different behavior you must set the variable
.(C
FILE *debug_port
.)C
to the appropriate stream.
.(C
void PQtrace()
.)C
.TP 15n
.BR PQuntrace 
Disable tracing started by 
.IR PQtrace .
.(C
void PQuntrace()
.)C
.XA 2 "User Authentication Functions"
.SH "USER AUTHENTICATION FUNCTIONS"
If the user has generated the appropriate authentication credentials
(e.g., obtaining
.IR Kerberos
tickets), the frontend/backend authentication process is handled by
.IR PQexec
without any further intervention.  The following routines may be
called by \*(LI programs to tailor the behavior of the authentication
process.
.TP 15n
.BR fe_getauthname
Returns a pointer to static space containing whatever name the user
has authenticated.  Use of this routine in place of calls to
.IR getenv (3)
or 
.IR getpwuid (3)
by applications is highly recommended, as it is entirely possible that
the authenticated user name is 
.BR not
the same as value of the
.SM USER
environment variable or the user's entry in
.IR /etc/passwd .
This becomes an important issue if the user name is being used as a
value in a database interaction (e.g., using the user name as the
default database name, as is done by
.IR monitor (unix).
.(C
char *fe_getauthname()
.)C
.TP 15n
.BR fe_setauthsvc
Specifies that \*(LI should use authentication service
.IR name
rather than its compiled-in default.  This value is typically taken
from a command-line switch.
.(C
void fe_setauthsvc(name)
	char *name;
.)C
.SH BUGS
The query buffer is 8192 bytes long, and queries over that length will
be silently truncated.
.bp
.XA 1 "Sample Programs"
.SH "SAMPLE PROGRAM 1"
.(C M
/*
 * testlibpq.c \(em
 * 	Test the C version of \*(LI, the \*(PG frontend library.
 */
#include <stdio.h>
#include "tmp/libpq.h"

main ()
{
    int i, j, k, g, n, m, t;
    PortalBuffer *p;
    char pnames[MAXPORTALS][portal_name_length];

    /* Specify the database to access. */
    PQsetdb ("pic_demo");

    /* Start a transaction block for eportal */
    PQexec ("begin");

    /* Fetch instances from the EMP class. */
    PQexec ("retrieve portal eportal (EMP.all)");
    PQexec ("fetch all in eportal");

    /* Examine all the instances fetched. */
    p = PQparray ("eportal");
    g = PQngroups (p);
    t = 0;
    
    for (k = 0; k < g; k++) {
	printf ("\enA new instance group:\en");
	n = PQntuplesGroup (p, k);
	m = PQnfieldsGroup (p, k);

	/* Print out the attribute names. */
	for (i = 0; i < m; i++)
	    printf ("%-15s", PQfnameGroup (p, k, i));
	printf ("\en");
    
	/* Print out the instances. */
	for (i = 0; i < n; i++) {
	    for (j = 0; j < m; j++)
		printf("%-15s", PQgetvalue(p, t+i, j));
	    printf ("\en");
	}
	t += n;
    }

    /* Close the portal. */
    PQexec ("close eportal");

    /* End the transaction block */
    PQexec("end");

    /* Try out some other functions. */
    
    /* Print out the number of portals. */
    printf ("\enNumber of portals open: %d.\en",
            PQnportals ());

    /* If any tuples are returned by rules, print out
     * the portal name. */
    if (PQnportals (1)) {
	printf ("Tuples are returned by rules. \en");
	PQpnames (pnames, 1);
	for (i = 0; i < MAXPORTALS; i++)
	    if (pnames[i] != NULL)
		printf ("portal used by rules: %s\en", pnames[i]);
    }

    /* finish execution. */
    PQfinish ();
}
.)C
.bp
.SH "SAMPLE PROGRAM 2"
.(C M
/*
 * Testing of asynchronous notification interface.
 *
 * Do the following at the monitor:
 *
 *    * create test1 (i = int4) \eg
 *    * create test1a (i = int4) \eg
 *
 *    * define rule r1 is on append to test1 do
 *      [append test1a (i = new.i)
 *       notify test1a] \eg
 *
 *
 * Then start up this process.
 *
 *    * append test1 (i = 10) \eg
 *
 * The value i = 10 should be printed by this process.
 *
 */

#include <tmp/simplelists.h>
#include <tmp/libpq.h>
#include <tmp/postgres.h>

extern int PQAsyncNotifyWaiting;

void main() {
  PQNotifyList *l;
  PortalBuffer *portalBuf;
  char *res;
  int ngroups, tupno, grpno, ntups, nflds;

  PQsetdb(getenv("USER"));

  PQexec("listen test1a");

  while (1) {
    res = PQexec(" ");
    if (*res != 'I') {
      printf("Unexpected result from a null query --> %s", res);
      PQfinish();
      exit(1);
    }
    if (PQAsyncNotifyWaiting) {
      PQAsyncNotifyWaiting = 0;
      for (l = PQnotifies() ; l != NULL ; l = PQnotifies()) {
	PQremoveNotify(l);
	printf("Async. notification on relation %s, our backend pid is %d\en",
	       l->relname, l->be_pid);
	res = PQexec("retrieve (test1a.i)");

	if (*res != 'P') {
	  fprintf(stderr, "%s\enno portal", ++res);
	  PQfinish();
	  exit(1);
	}

	portalBuf = PQparray(++res);
	ngroups = PQngroups(portalBuf);
	for (grpno = 0 ; grpno < ngroups ; grpno++) {
	  ntups = PQntuplesGroup(portalBuf, grpno);
	  nflds = PQnfieldsGroup(portalBuf, grpno);
	  if (nflds != 1) {
	    fprintf(stderr, "expected 1 attributes, got %d\en", nflds);
	    PQfinish();
	    exit(1);
	  }
	  for (tupno = 0 ; tupno < ntups ; tupno++) {
	    printf("i = %s\en", PQgetvalue(portalBuf, tupno, 0));
	  }
	}
      }
      PQfinish();
      exit(0);
    }
  sleep(1);
  }
}
.)C
.bp
.SH "SAMPLE PROGRAM 3"
.(C M
/*
 * Test program for the binary portal interface.
 * 
 * Create a test database and do the following at the monitor:
 *
 *	* create test1 (i = int4, d = float4, p = polygon)\eg
 *	* append test1 (i = 1, d = 3.567,
 *	  p = "(3.0,4.0,1.0,2.0)"::polygon)\eg
 *	* append test1 (i = 2, d = 89.05,
 *	  p = "(4.0,3.0,2.0,1.0)"::polygon)\eg
 *
 * adding as many tuples as desired.
 *
 * Start up this program.  The contents of class "test1" should be
 * printed, e.g.:

tuple 0: got
         i=(4 bytes) 1,
         d=(4 bytes) 3.567000,
         p=(72 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.05000,
         p=(72 bytes) 2 points,
                 boundbox=(hi=4.000000,3.000000 / lo=2.000000,1.000000)

 */
#include "tmp/simplelists.h"
#include "tmp/libpq.h"
#include "utils/geo-decls.h"

void main()
{
    PortalBuffer *portalbuf;
    char *res;
    int ngroups, tupno, grpno, ntups, nflds;

    PQsetdb("test");	/* change this to your database name */
    PQexec("begin");
    res = (char *) PQexec("retrieve iportal junk (test1.all)");
    if (*res == 'E') {
	fprintf(stderr,"\enError: %s\en",++res);
	goto exit_error;
    }
    res = (char *) PQexec("fetch all in junk");
    if (*res != 'P') {
	fprintf(stderr,"\enError: no portal\en");
	goto exit_error;
    }
    /* get tuples in relation */
    portalbuf = PQparray(++res);
    ngroups = PQngroups(portalbuf);
    for (grpno = 0; grpno < ngroups; grpno++) {
	ntups = PQntuplesGroup(portalbuf, grpno);
	if ((nflds = PQnfieldsGroup(portalbuf, grpno)) != 3) {
	    fprintf(stderr, "\enError: expected 3 attributes, got %d\en", nflds);
	    goto exit_error;
	}
	for (tupno = 0; tupno < ntups; tupno++) {
	    int *ival;		/* 4 bytes */
	    float *fval;	/* 4 bytes */
	    unsigned plen;
	    POLYGON *pval;

	    ival = (int *) PQgetvalue(portalbuf, tupno, 0);
	    fval = (float *) PQgetvalue(portalbuf, tupno, 1);
	    plen = PQgetlength(portalbuf, tupno, 2);
	    if (!(pval = (POLYGON *) palloc(plen + sizeof(long)))) {
		fprintf(stderr, "\enError: palloc returned zero bytes\en");
		goto exit_error;
	    }
	    pval->size = plen + sizeof(long);
	    bcopy(PQgetvalue(portalbuf, tupno, 2), (char *) &pval->npts, plen);
	    printf ("tuple %d: got\en\e
\et i=(%d bytes) %d,\en\e
\et d=(%d bytes) %f,\en\e
\et p=(%d bytes) %d points,\en\e
\et\et boundbox=(hi=%f,%f / lo=%f,%f)\en",
		    tupno,
		    PQgetlength(portalbuf, tupno, 0),
		    *ival,
		    PQgetlength(portalbuf, tupno, 1),
		    *fval,
		    PQgetlength(portalbuf, tupno, 2),
		    pval->npts,
		    pval->boundbox.xh,
		    pval->boundbox.yh,
		    pval->boundbox.xl,
		    pval->boundbox.yl);
	}
    }
    PQexec("end");
    PQfinish();
    exit(0);
  exit_error:
    PQexec("end");
    PQfinish();
    exit(1);
}
.)C
@


1.29
log
@bit of clarification on async portals
@
text
@d3 2
a4 2
.\" $Header: /usr/local/devel/postgres/src/ref/RCS/libpq.3pqsrc,v 1.28 1994/02/09 18:51:55 aoki Exp aoki $
.TH INTRODUCTION LIBPQ 02/12/94
d15 10
d178 2
a179 1
.IR PQfn returns
a229 6
The protocol can return strings beginning with the character
\*(lqA\*(rq.  However, this indicates that the backend server thinks
that it is processing an asynchronous portal and indicates a serious
bug (since asynchronous portals are not implemented in \*(PG Version
\*(PV).
.IP
d243 47
d589 2
a590 1
Then the frontend should check the variable, PQAsyncNotifyWaiting.
a790 2
.PP
Asynchronous portals are not implemented in Version \*(PV.
@


1.28
log
@made jiang's fixes for async portals (yay!)
@
text
@d3 2
a4 2
.\" $Header: /usr/local/devel/postgres/src/ref/RCS/libpq.3pqsrc,v 1.27 1994/02/01 21:18:45 jolly Exp aoki $
.TH INTRODUCTION LIBPQ 08/13/93
d539 3
a541 1
notification data held using PQNotifies.  The frontend must call 
d550 8
d559 2
a560 1
portals.
@


1.27
log
@updated docs for PQpnames
@
text
@d3 1
a3 1
.\" $Header: /usr/local/devel/postgres/src/ref/RCS/libpq.3pqsrc,v 1.26 1993/09/27 06:09:25 aoki Exp jolly $
d531 3
a533 3
.IR PQAsyncNotifyWaiting .
When this variable is non-zero, the frontend process should execute a
null (empty) query, i.e.,
d537 3
a539 2
in order to retrieve the notification data held for it by the backend
server.  The frontend must call 
d810 2
a811 2
 * Testing of asynchronous portal interface.
 * 
d814 6
a819 2
 *	* create test1 (i = int4) \eg
 *	* create test1a (i = int4) \eg
a820 3
 *	* define rule r1 is on append to test1 do
 *	  [append test1a (i = new.i) 
 *	   notify test1a] \eg
d824 3
a826 1
 *	* append test1 (i = 10) \eg
a827 1
 * The value i=10 should be printed by this process.
d829 37
a865 2
#include "tmp/simplelists.h"
#include "tmp/libpq.h"
d867 17
a883 48
void main()
{
    extern int PQAsyncNotifyWaiting;
    PQNotifyList *l;
    PortalBuffer *portalbuf;
    char *res;
    int ngroups,tupno, grpno, ntups, nflds;
    PQsetdb(getenv("USER"));

    PQexec("listen test1a");

    while(1) {
        sleep(1);
        if (PQAsyncNotifyWaiting) {
	    PQAsyncNotifyWaiting = 0;
            PQexec(" ");
            l = PQnotifies();
            if (l != NULL) {
                printf("notification on relation %s\en",
		       l->relname);
                res = PQexec("retrieve (test1a.i)");
                if (*res == 'E') {
                    fprintf(stderr,"%s\enfailed",++res);
                    goto exit_error;
                }
                if (*res != 'P') {
                    fprintf(stderr,"%s\enno portal",++res);
                }
                /* get tuples in relation */
                portalbuf = PQparray(++res);
                ngroups = PQngroups(portalbuf);
                for (grpno = 0; grpno < ngroups; grpno++) {
                    ntups = PQntuplesGroup(portalbuf,grpno);
		    nflds = PQnfieldsGroup(portalbuf,grpno);
                    if (nflds != 1) {
                        fprintf(stderr,
			  "expected 1 attributes, got %d\en",
			  nflds);
                        goto exit_error;
                    }
                    for (tupno = 0; tupno < ntups; tupno++) {
                        printf("got i=%s\en",
			  PQgetvalue(portalbuf,tupno,0));
                    }
                }
                break;
            }
        }
d885 2
a886 5
    PQfinish();
    exit(0);
  exit_error:
    PQfinish();
    exit(1);
@


1.26
log
@updated for new PQgetline/PQputline behavior
@
text
@d3 1
a3 1
.\" $Header: /home2/aoki/master/src/ref/RCS/libpq.3pqsrc,v 1.25 1993/08/13 22:28:20 aoki Exp aoki $
d306 4
d312 1
a312 1
	char *pnames[MAXPORTALS];
d317 2
a318 2
Return the portal buffer given a portal name,
.IR pname .
@


1.25
log
@updated PQexec doc
fixed PQgetline/PQputline garbage
@
text
@d3 1
a3 1
.\" $Header: /home2/aoki/master/src/ref/RCS/libpq.3pqsrc,v 1.24 1993/07/19 18:39:13 jolly Exp aoki $
d147 4
a150 4
a buffer in which to load the return value.  (Variable-length sizes
are specified as -1.)  The actual size of the return value will be
loaded into
.IR actual_result_len .
d152 2
a153 2
should be set to 1 if the return type is a 4-byte integer and 2 in all
other cases.
d173 5
d215 9
a223 5
The current implementation can return strings beginning with the
characters \*(lqA\*(rq and \*(lqI\*(rq.  These indicate that the
backend server thinks that it is processing an asynchronous portal and
indicate a serious bug (since asynchronous portals are not implemented
in \*(PG Version \*(PV).
d590 2
a591 1
Returns EOF at EOF, 0 if the entire line has been read, and 1 if the
d604 7
a610 1
carefully.
@


1.24
log
@PQerrormsg is a char[], not a char*
(makes a difference to extern declaration for front-end apps)
@
text
@d3 2
a4 2
.\" $Header: /usr/local/devel/postgres/src/ref/RCS/libpq.3pqsrc,v 1.23 1993/06/14 03:43:11 aoki Exp jolly $
.TH INTRODUCTION LIBPQ 05/29/93
d188 3
a190 1
message.  If the query returns data (e.g.,
d194 4
a197 2
the name of the portal buffer.  When the query does not return
instances,
d200 17
a216 2
by the command tag (e.g., \*(lqCREPLACE\*(rq).  If a non-fatal error
occurred during the execution of the query,
d565 2
a566 1
Reads a null-terminated line into a buffer
d570 25
d603 5
a607 1
.IR string .
d632 2
a633 2
PQputline("3<TAB>hello world<TAB>4.5\n");
PQputline("4<TAB>goodbye world<TAB>7.11");
d707 1
a707 1
Asynchronous portals are not fully implemented in Version \*(PV.
@


1.23
log
@"new" error-handling interface for PQexec (returning "E",
which used to work and which all of *our* applications and
sample code assumes, but hasn't happened for a while).
@
text
@d3 1
a3 1
.\" $Header: /home2/aoki/master/src/ref/RCS/libpq.3pqsrc,v 1.22 1993/05/30 07:30:36 aoki Exp aoki $
d81 1
a81 1
char *PQerrormsg;       /* null-delimited string containing the
@


1.22
log
@added PQerrormsg (!)
as well as PQfn.
@
text
@d3 1
a3 1
.\" $Header: /home2/aoki/master/src/ref/RCS/libpq.3pqsrc,v 1.21 1993/02/22 06:24:45 marc Exp aoki $
d172 1
a172 1
is any error occurs.
d196 2
a197 2
by the command tag (e.g., \*(lqCREPLACE\*(rq).  If an error occurred
during the execution of the query,
d202 4
@


1.21
log
@refrence as "tmp/libpq.h"
@
text
@d3 2
a4 2
.\" $Header: /usr/local/devel/postgres/src/ref/RCS/libpq.3pqsrc,v 1.20 1993/02/17 05:17:17 aoki Exp marc $
.TH INTRODUCTION LIBPQ 01/23/93
d80 5
d139 34
d175 2
a176 1
           result_is_int, args, nargs)
d180 2
a181 1
	int result_is_int;
d196 2
a197 2
by the command tag (e.g., \*(lqCREPLACE\*(rq).  If an error occured
during the execution of the query
d199 3
a201 1
will return (for historical reasons) the character \*(lqR\*(rq.
d267 1
a267 1
	int rule_p ;
@


1.20
log
@oops.  fixed \ -> \e problem.
@
text
@d3 1
a3 1
.\" $Header: /home2/aoki/master/ref/RCS/libpq.3pqsrc,v 1.19 1993/02/08 19:36:49 aoki Exp aoki $
d621 1
a621 1
#include "libpq.h"
@


1.19
log
@somewhat ungrossified example 3
@
text
@d3 1
a3 1
.\" $Header: /home2/aoki/master/ref/RCS/libpq.3pqsrc,v 1.18 1993/01/26 02:43:13 aoki Exp aoki $
d814 1
a814 1
	fprintf(stderr,"\nError: %s\n",++res);
d819 1
a819 1
	fprintf(stderr,"\nError: no portal\n");
d828 1
a828 1
	    fprintf(stderr, "\nError: expected 3 attributes, got %d\n", nflds);
d841 1
a841 1
		fprintf(stderr, "\nError: palloc returned zero bytes\n");
d846 5
a850 5
	    printf ("tuple %d: got\n\e
\t i=(%d bytes) %d,\n\e
\t d=(%d bytes) %f,\n\e
\t p=(%d bytes) %d points,\n\e
\t\t boundbox=(hi=%f,%f / lo=%f,%f)\n",
@


1.18
log
@-man version
@
text
@d3 1
a3 1
.\" $Header: /home2/aoki/ref/RCS/libpq,v 1.17 1992/07/31 17:02:31 mer Exp aoki $
d773 1
a773 1
 * Testing of binary portal interface.
d775 1
a775 1
 * Do the following at the monitor:
d777 5
a781 3
 *	* create test1 (i = int4,d = float4,p = polygon) \eg
 *	* append test1 (i = 7, d=3.567,
 *	  p="(1.0,2.0,3.0,4.0)"::polygon) \eg
d785 14
a798 3
 * Start up this program.
 *
 * The contents of test1 should be printed.
a805 2
    extern int PQAsyncNotifyWaiting;
    PQNotifyList *l;
d808 1
a808 2
    int ngroups,tupno, grpno, ntups, nflds;
    PQsetdb(getenv("USER"));
d810 1
d812 1
a812 1
    res = (char *)PQexec("retrieve iportal junk (test1.all)");
d814 1
a814 1
	fprintf(stderr,"%s\enfailed",++res);
d817 1
a817 1
    res = (char *)PQexec("fetch all in junk");
d819 1
a819 1
	fprintf(stderr,"\enno portal");
d828 1
a828 1
	    fprintf(stderr, "expected 3 attributes, got %d\en", nflds);
d832 30
a861 18
	    int *bla1;
	    char *bla2;
	    POLYGON *bla3;
	    bla1 = (int *)PQgetvalue(portalbuf,tupno,0);
	    bla2 = PQgetvalue(portalbuf,tupno,1);
	    bla3 = PQgetvalue(portalbuf,tupno,2)-4;

	    printf ("got i=%d(%d bytes),\e
 d=(%f)(%d bytes)|%x|%x|%x|%x\en\e
 Polygon(%d bytes) %d points (%f,%f,%f,%f)\en",
		    *bla1,PQgetlength(portalbuf,tupno,0),
		    *((float *)bla2),
		    PQgetlength(portalbuf,tupno,1),
		    *bla2,*(bla2+1),*(bla2+2),*(bla2+3),
		    PQgetlength(portalbuf,tupno,2),
		    bla3->npts,
		    bla3->boundbox.xh,bla3->boundbox.yh,
		    bla3->boundbox.xl,bla3->boundbox.yl);
@


1.17
log
@clean up description of PQexec
@
text
@d1 1
d3 53
a55 45
.\" $Header: /home/postgres/mer/ref/RCS/libpq,v 1.16 1992/07/22 19:26:44 clarsen Exp mer $
.SS LIBPQ 6/14/90
.XA 0 "Section 5 \*- Libpq"
.sp 2i
.ps 14
.ce
.b "SECTION 5 \*- LIBPQ"
.sp 3
.uh NAME
.lp
libpq \*- programmer's interface to \*(PP
.uh DESCRIPTION
.lp
LIBPQ is the programmer's interface to \*(PP.  LIBPQ is a set of
library routines which allow queries to pass to the \*(PP back-end
and instances to return through an IPC channel.
.lp
This version of the documentation is based on the C library.
.uh "CONTROL AND INITIALIZATION"
.lp
.uh VARIABLES
.lp
The following five environment variables can be used to set
up default values for an environment and to avoid hard-coding
database names into an application program:
.lp
.(l
.bu
\fBPGHOST\fR sets the default server name.
.bu
\fBPGDATABASE\fR sets the default \*(PP database name.
.bu
\fBPGPORT\fR sets the default communication port with the \*(PP back-end.
.bu
\fBPGTTY\fR sets the tty on the PQhost back-end on which debugging messages are displayed.
.)l
.lp
The following internal variables of libpq can be accessed by
the programmer:
.lp
.(1
.nf
.ft C
char *PQhost;           /* the server on which \*(PP
                           back-end is running. */
d58 1
a58 1
                           \*(PP back-end. */
d60 2
a61 2
char *PQtty;            /* The tty on the PQhost back-end on
                           which back-end messages are
d64 1
a64 1
char *PQoption;         /* Optional arguements to the back-end */
d66 1
a66 1
char *PQdatabase;       /* Back-end database to access */
d69 1
a69 1
                           back-end is established */
d80 3
a82 5
.ft
.)1
.fi
.uh "QUERY EXECUTION FUNCTIONS"
.lp
d85 32
a116 30

.(1
PQsetdb \*- Make the specified database the current database, 

.nf
.ft C
void PQsetdb ( dbname )
	char	*dbname;
.ft

PQsetdb also resets communication via PQreset (see below).

PQdb \*- Return the current database being accessed.

.ft C
char * PQdb ()
.ft
.)1
.fi
.lp
Returns the name of the \*(PP database
being accessed, or NIL if no database is open.
Only one database can be accessed at a time.  The database
name is a string limited to 16 characters.
.lp
.nf
.(1
PQreset \*- Reset the communication port with the back-end in case of errors.

.ft C
d118 17
a134 25
.ft

.fi
This function will close the IPC socket connection to the backend thereby
causing the next PQexec() call to ask for a new one from the postmaster.
When the backend notices the socket was closed it will exit, and when the
postmaster is asked for the new connection it will start a new back-end.
.nf

PQfinish \*- Close communication ports with the back-end.

.ft C
void PQfinish ()
.ft
.)1
.fi
.lp
Terminates communications and frees up the memory taken up
by the libpq buffer.
.nf

.(1
PQfn \*- Send a function call to the \*(PP backend.

.ft C
d138 2
a139 2
	int *result_buf;    /* can't use void, the */
	int result_len;     /* compiler complains  */
d143 26
a168 28
.ft

.fi
PQfn provides access to the \*(PP fastpath facility, a trapdoor into
the system internals.  See \fBFASTPATH\fR.
.nf

.(1
PQexec \*- Submit a query to \*(PP.  

.ft C
char *	PQexec (query)
	char	* query;
.ft
.)1
.fi
.lp
This function returns a status indicator or an error message.  If the query
returns data (e.g. fetch), PQexec returns a string consisting of 'P' followed
by the name of the portal buffer.  
When the query does not return instances, PQexec
will return a string consisting of 'C' followed by the command tag (e.g.
"CREPLACE").  If an error occured during the execution of the query 
PQexec will return (for historical reasons) an "R".

.uh "PORTAL FUNCTIONS"
.lp
A portal is a \*(PP buffer from which instances can be fetched.
d170 96
a265 96
A portal is initialized by submitting a retrieve statement
using the PQexec function, for example:
.(l
.ft C
retrieve portal foo ( EMP.all )
.ft
.)l
.lp
The programmer can then move data from the portal into LIBPQ
by executing a \fIfetch\fR statement, e.g:
.(l
.ft C
fetch 10 in \fIfoo\fR
.ft

.ft C
fetch all in \fIfoo\fR
.ft
.)l
.lp
If no portal name is specified in a query, the default
portal name is the string "blank", known as the "blank portal."
All qualifying instances in a blank portal are fetched
immediately, without the need for the programmer to issue a
seperate fetch command.
.lp
Data fetched from a portal into LIBPQ is moved into a portal
buffer.  Portal names are mapped to portal buffers through
an internal table.  Each instance in a portal buffer has
an index number locating its position in the buffer.  In addition,
each field in an instance has a name and a field number.
.lp
A single retrieve command can return multiple types
of instances.
This can happen if a \*(PP function is executed
in the evaluation of a query or if the query
returns multiple instance types from an inheritance
hierarchy.
Consequently, the instances in a portal are set up
in groups.
Instances in the same group are guaranteed to have the
same instance format.
.lp
Portals that are associated with normal user commands
are called synchronous.
In this case, the application program is expected
to issue a retrieval followed by one or more
fetch commands.
The functions that follow can now be used to
manipulate data in the portal.
.(l
PQnportals \*- Return the number of open portals.

.ft C
int PQnportals ( rule_p )
	int	rule_p ;
.ft

If rule_p is not 0, then only return the number of asynchronous portals.

PQpnames \*- Return all portal names.

.ft C
void PQpnames  ( pnames, rule_p)
	char	*pnames [MAXPORTALS];
	int	rule_p ;
.ft

If rule_p is not 0, then only return the names of asynchronous
portals.

PQparray \*- Return the portal buffer given a portal name.

.ft C
PortalBuffer * PQparray ( pname )
	char	*pname;
.ft

PQclear \*- free storage claimed by named portal.

.ft C
void PQclear ( pname )
	char	*pname;
.ft

PQntuples \*- Return the number of instances in a portal buffer.

.ft C
int PQntuples (portal)
	PortalBuffer	*portal;
.ft

PQngroups \*- Return the number of instance groups in a portal buffer.

.ft C
int PQngroups (portal)
d267 111
a377 79
.ft

PQntuplesGroup \*- Return the number of instances in an instance group.

.ft C
int PQntuplesGroup (portal, group_index)
	PortalBuffer	*portal;
	int	group_index;
.ft

PQnfieldsGroup \*- Return the number of fields in an instance group.

.ft C
int PQnfieldsGroup ( portal, group_index)
	PortalBuffer	*portal;
	int	group_index;
.ft

PQfnameGroup \*- Return the field name given the group and field index.

.ft C
char * PQfnameGroup (portal, group_index, field_number )
	PortalBuffer	*portal;
	int	group_index;
	int	field_number;
.ft

PQfnumberGroup \*- Return the field number (index) given the group index and field name.

.ft C
int PQfnumberGroup (portal, group_index, field_name)
	PortalBuffer	*portal;
	int	group_index;
	char	*field_name;
.ft

PQgetgroup \*- Returns the index of the group that a particular instance is in.

.ft C
int PQgetgroup ( portal, tuple_index )
	PortalBuffer	*portal;
	int	tuple_index;
.ft

PQnfields \*- Return the number of fields in an instance.

.ft C
int PQnfields (portal, tuple_index )
	PortalBuffer	*portal;
	int	tuple_index;
.ft

PQfnumber \*- Return the field index of a given field name within an instance.

.ft C
int PQfnumber ( portal, tuple_index, field_name)
	PortalBuffer	*portal;
	int	tuple_index;
	char	*field_name;
.ft

PQfname \*- Return the name of a field.

.ft C
char * PQfname ( portal, tuple_index, field_number )
	PortalBuffer	*portal;
	int	tuple_index;
	int	field_number;
.ft

PQftype \*- Return the type of a field.  

.ft C
int PQftype ( portal, tuple_index, field_number )
	PortalBuffer	*portal;
	int	tuple_index;
	int	field_number;
.ft

d379 95
a473 35

PQsametype \*- Return 1 if two instances have the same attributes.

.ft C
int PQsametype ( portal, tuple_index1, tuple_index2 )
	PortalBuffer	*portal;
	int	tuple_index1, tuple_index2;
.ft

PQgetvalue \*- Return an attribute (field) value.  

.ft C
char * PQgetvalue ( portal, tuple_index, field_number )
	PortalBuffer	*portal;
	int	tuple_index;
	int	field_number;
.ft

.ft

PQgetlength \*- Return the length of an attribute (field) value in bytes.
If the field is a varlena, the length of the attribute returned here
does not include the longword size field of the varlena, e.g. it is 4
bytes less.

.ft C
char * PQgetlength ( portal, tuple_index, field_number )
	PortalBuffer	*portal;
	int	tuple_index;
	int	field_number;
.ft

PQNotifies \*- Return the list of relations on which notification has occurred.

.ft C
d475 5
a479 6
.ft

PQRemoveNotify \*- Remove the notification from the list of unhandled 
		   notifications.

.ft C
d482 4
a485 36
.ft
.)l
.lp
If the portal is blank, or specified with the
.b portal 
keyword, all
values are returned as strings.  It is the programmer's responsibility
to convert them to the correct type.  If the portal is specified with the
.b iportal
keyword, all values are returned in internal format, namely in the format 
generated by the
.i input
function specified through the 
.b definetype
command.  Again, it is the programmer's responsibility to convert the
data to the correct type.

.uh "ASYNCHRONOUS PORTALS/NOTIFICATION"
.lp
Asynchronous portals, query results of rules, are implemented using
two mechanisms: relations and notification.  The query result is
transferred through a relation.  The notification is done with special
postquel commands and frontend/backend protocol.

Referring to the second sample program, after executing "listen
relation_name" in the frontend process, periodically check
PQAsyncNotifyWaiting.  If it is non-zero, then the "notify
relation_name" command has been executed by some backend.  Immediately
clear PQAsyncNotifyWaiting, then do a NULL query, i.e.  PQexec(" "),
to retrieve the actual notification data.  Then call PQNotifies() to
get the list of relations on which notification has occurred.  After
handling the notification, do PQRemoveNotify on each element of the
list that has been handled to prevent further handling by you.

.uh "FUNCTIONS ASSOCIATED WITH THE COPY COMMAND"
.lp
d487 6
a492 6
.i copy
command in \*(PP has options to read from or write to the network
connection used by LIBPQ.  Therefore, functions are necessary to access
this network connection directly so applications may take full advantage
of this capability.
.lp
d494 10
a503 6
.i copy
command, see copy(commands).
.lp

.(1
.ft C
d505 8
a512 9
.ft
\*- Reads a null-terminated line into string.

.ft C
char *string;
int length
.ft

.ft C
d514 14
a527 20
.ft
\*- Sends a null-terminated string.

.ft C
char *string;
.ft

.ft C
int
PQendcopy()
.ft
\*- Syncs with the back-end.

This function waits until the backend has finished processing 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.

d529 5
a533 5

\fBFor Example:\fR

.nf
.ft C
d538 1
a538 1
...
d541 75
a615 34
.ft
.fi
.)1

.uh "TRACING FUNCTIONS"
.lp
.(1
PQtrace \*- Enable tracing.

.ft C
void PQtrace ()
.ft

The routine sets the PQtracep variable to 1 which causes debug messages to
be printed.  You should note that the
messages will be printed to stdout by default.  If you would like different
behavior you must set the variable FILE *debug_port to the appropriate stream.

PQuntrace \*- Disable tracing.

.ft C
void PQuntrace ()
.ft
.)1
.uh BUGS
.lp
The query buffer is only 8192 bytes long, and queries over that
length will be silently truncated.

.uh "SAMPLE PROGRAM"
.lp
.(1
.nf
.ft C
d617 2
a618 2
 * testlibpq.c \*-
 * 	Test the C version of Libpq, the \*(PP frontend library.
d688 4
a691 8
.ft
.)1

.uh "SAMPLE PROGRAM 2"
.lp
.(1
.nf
.ft C
d697 7
a703 9

 create test1 (i = int4) \eg
 create test1a (i = int4) \eg

 define rule r1 is on append to test1 do
    [append test1a (i = new.i)
    notify test1a]

 \eg
d705 3
a707 3

 append test1 (i = 10) \eg

a709 1

a761 1

a766 1

d768 4
a771 8
.ft
.)1

.uh "SAMPLE PROGRAM 3"
.lp
.(1
.nf
.ft C
d773 1
a773 1
 * Testing of new binary portal interface.
d777 6
a782 5

 create test1 (i = int4,d = float4,p = polygon) \eg
 append test1 (i = 7, d=3.567,p="(1.0,2.0,3.0,4.0)"::polygon) \eg

 -- Anything else you can think of. 
d784 2
a785 1
 * The correct contents of test1 should be printed
a786 1

d828 3
a830 3
	    printf ("got i=%d(%d bytes), d=(%f)(%d bytes)|%x|%x|%x|%x\en\e
 Polygon(%d bytes)\e
  %d points (%f,%f,%f,%f)\en",
a840 1

a847 1

d849 1
a849 2
.ft
.)1
@


1.16
log
@fix syntax error
@
text
@d2 1
a2 1
.\" $Header: /usr/local/dev/postgres/mastertree/ref/RCS/libpq,v 1.15 1992/07/20 18:55:37 mer Exp clarsen $
d159 4
a162 4
This function returns a status indicator or an error message.  If the
query submitted was a retrieve then PQexec returns a string consisting
of a 'P' followed by the portal name.  If no portal was specified the
portal name will be "blank".  When the query was not a retrieve PQexec
d165 1
a165 5
PQexec will return "R".  You might be wondering "why an 'R'?"  The answer
is that this stems from libpq's history.  It used to be the case that
when libpq received an error message from the backend it would attempt
to \fIreset\fR communications.  Thus it returned (and still returns) an 'R' 
to the application program.
@


1.15
log
@fix poor use of backslash characters.
@
text
@d2 1
a2 1
.\" $Header: /home/postgres/mer/ref/RCS/libpq,v 1.14 1992/07/15 01:57:02 clarsen Exp mer $
d372 1
a372 1
PQgetlen \*- Return the length of an attribute (field) value in bytes.
d378 1
a378 1
char * PQgetlen ( portal, tuple_index, field_number )
@


1.14
log
@add function to get length of internal data.
@
text
@d2 1
a2 1
.\" $Header: /usr/local/dev/postgres/mastertree/ref/RCS/libpq,v 1.13 1992/07/13 03:45:59 ptong Exp clarsen $
d646 1
a646 1
                printf("notification on relation %s\n",
d650 1
a650 1
                    fprintf(stderr,"%s\nfailed",++res);
d654 1
a654 1
                    fprintf(stderr,"%s\nno portal",++res);
d664 1
a664 1
			  "expected 1 attributes, got %d\n",
d669 1
a669 1
                        printf("got i=%s\n",
d699 2
a700 2
 create test1 (i = int4,d = float4,p = polygon) \g
 append test1 (i = 7, d=3.567,p="(1.0,2.0,3.0,4.0)"::polygon) \g
d723 1
a723 1
	fprintf(stderr,"%s\nfailed",++res);
d728 1
a728 1
	fprintf(stderr,"\nno portal");
d737 1
a737 1
	    fprintf(stderr, "expected 3 attributes, got %d\n", nflds);
d748 3
a750 3
	    printf ("got i=%d(%d bytes), d=(%f)(%d bytes)|%x|%x|%x|%x\n\
 Polygon(%d bytes)\
  %d points (%f,%f,%f,%f)\n",
@


1.13
log
@Fixed up formating
@
text
@d2 1
a2 1
.\" $Header: /home/postgres/mer/refs/RCS/libpq,v 1.12 1992/07/12 21:10:19 ptong Exp ptong $
d370 14
d694 1
a694 1
 * Testing of binary portal interface.
d699 2
a700 2
 create test1 (i = int4,d = float4) \eg
 append test1 (i = 7, d=3.567) \eg
d706 1
d709 1
d721 1
a721 2
    res = (char *)
	  PQexec("retrieve iportal junk (test1.all)");
d723 2
a724 2
        fprintf(stderr,"%s\nfailed",++res);
        goto exit_error;
d728 2
a729 2
        fprintf(stderr,"\nno portal");
        goto exit_error;
d735 25
a759 19
        ntups = PQntuplesGroup(portalbuf, grpno);
	nflds = PQnfieldsGroup(portalbuf, grpno);
        if (nflds != 2) {
            fprintf(stderr,
		"expected 2 attributes, got %d\n",
		nflds);
            goto exit_error;
        }
        for (tupno = 0; tupno < ntups; tupno++) {
            int *bla1;
            char *bla2;
            bla1 = (int *)PQgetvalue(portalbuf,tupno,0);
            bla2 = PQgetvalue(portalbuf,tupno,1);

            printf ("got i=%d, d=(%f)|%x|%x|%x|%x\n",
		    *bla1,*((float *)bla2),
                    *bla2,*(bla2+1),*(bla2+2),
		    *(bla2+3));
        }
@


1.12
log
@Changed references to POSTGRES to the macro \*(PP.
@
text
@d2 1
a2 1
.\" $Header: /home/postgres/mer/refs/RCS/libpq,v 1.11 1992/06/25 23:58:38 mao Exp ptong $
d44 3
a46 2
char	*PQhost ;	/* the server on which \*(PP back-end
			   is running. */
d48 2
a49 2
char	*PQport = NULL ;	/* The communication port with the
				   \*(PP back-end. */
d51 3
a53 2
char	*PQtty;		/* The tty on the PQhost back-end on which
			   back-end messages are displayed. */
d55 1
a55 1
char	*PQoption ;	/* Optional arguements to the back-end */
d57 1
a57 1
char	*PQdatabase ;	/* Back-end database to access */
d59 2
a60 1
int	PQportset = 0;	/* 1 if communication with back-end is established */
d62 2
a63 1
int	PQxactid = 0 ;	/* Transaction ID of the current transaction */
d65 2
a66 1
int	PQtracep = 0 ;	/* 1 to print out front-end debugging messages */
d68 4
a71 2
int     PQAsyncNotifyWaiting = 0; /* 1 if one or more asynchronous 
				     notifications have been triggered */
d83 1
d86 1
d92 1
d94 1
d107 1
d109 1
d120 1
d122 1
d133 3
a135 1
char *PQfn(fnid, result_buf, result_len, result_is_int, args, nargs)
d137 2
a138 2
	int *result_buf;    /* can't use void, the compiler complains */
	int result_len;
d142 1
d152 1
d155 1
d178 3
a180 1
\fBretrieve portal\fR foo ( EMP.all )
d186 7
a192 3
\fBfetch 10 in \fIfoo\fR

\fBfetch all in \fIfoo\fR
d228 1
d231 1
d237 1
d241 1
d248 1
d251 1
d255 1
d258 1
d262 1
d265 1
d269 1
d272 1
d276 1
d280 1
d284 1
d288 1
d292 1
d297 1
d301 1
d306 1
d310 1
d314 1
d318 1
d322 1
d326 1
d331 1
d335 1
d340 1
d344 1
d349 1
d355 1
d359 1
d362 2
d368 1
d372 1
d374 1
d379 1
d382 2
a383 1
.)1
d399 2
a400 1
.uh "ASYNCHRONOUS PORTALS/NOTIFICATION" 
d427 1
a427 1
command, see copy(postquel).
d431 4
a434 1
PQgetline(string, length) \*- Reads a null-terminated line into string.
d436 1
d439 1
d441 4
a444 1
PQputline(string) \*- Sends a null-terminated string.
d446 1
d448 1
d450 1
d452 3
a454 1
PQendcopy() \*- Syncs with the back-end.
d468 1
d476 1
d485 1
d487 1
d496 1
d498 1
d509 1
d551 1
a551 1
		printf ("%-15s", PQgetvalue (p, t+i, j));
d566 2
a567 1
    printf ("\enNumber of portals open: %d.\en", PQnportals ());
d569 2
a570 1
    /* If any tuples are returned by rules, print out the portal name. */
d582 1
d589 1
d632 2
a633 1
                printf("notification on relation %s\n",l->relname);
d646 6
a651 3
                    ntups = PQntuplesGroup(portalbuf, grpno);
                    if ((nflds = PQnfieldsGroup(portalbuf, grpno)) != 1) {
                        fprintf(stderr, "expected 1 attributes, got %d\n", nflds);
d655 2
a656 1
                        printf ("got i=%s\n",PQgetvalue(portalbuf,tupno,0));
d671 1
d678 1
d705 2
a706 1
    res = (char *)PQexec("retrieve iportal junk (test1.all)");
d721 5
a725 2
        if ((nflds = PQnfieldsGroup(portalbuf, grpno)) != 2) {
            fprintf(stderr, "expected 2 attributes, got %d\n", nflds);
d734 4
a737 2
            printf ("got i=%d, d=(%f)|%x|%x|%x|%x\n", *bla1,*((float *)bla2),
                    *bla2,*(bla2+1),*(bla2+2),*(bla2+3));
d750 1
a750 1

@


1.11
log
@PGOPTION no longer passed to the back end
@
text
@d2 1
a2 1
.\" $Header: /private/mao/postgres/ref/RCS/libpq,v 1.10 1992/06/17 22:24:05 mer Exp mao $
d15 2
a16 2
LIBPQ is the programmer's interface to Postgres.  LIBPQ is a set of
library routines which allow queries to pass to the Postgres back-end
d32 1
a32 1
\fBPGDATABASE\fR sets the default Postgres database name.
d34 1
a34 1
\fBPGPORT\fR sets the default communication port with the POSTGRES back-end.
d44 1
a44 1
char	*PQhost ;	/* the server on which POSTGRES back-end
d48 1
a48 1
				   POSTGRES back-end. */
d87 1
a87 1
Returns the name of the POSTGRES database
d116 1
a116 1
PQfn \*- Send a function call to the POSTGRES backend.
d127 1
a127 1
PQfn provides access to the POSTGRES fastpath facility, a trapdoor into
d132 1
a132 1
PQexec \*- Submit a query to POSTGRES.  
d153 1
a153 1
A portal is a POSTGRES buffer from which instances can be fetched.
d354 1
a354 1
command in POSTGRES has options to read from or write to the network
d426 1
a426 1
 * 	Test the C version of Libpq, the POSTGRES frontend library.
@


1.10
log
@move to groff and fix some errors that occur from the move
@
text
@d2 1
a2 1
.\" $Header: /home1/frew/s2k/postgres/ref/RCS/libpq,v 1.9 1992/03/25 19:25:31 clarsen Exp $
a36 2
.bu
\fBPGOPTION\fR contains optional arguements to the POSTGRES back-end.
@


1.9
log
@async + binary docs
@
text
@d2 2
a3 2
.\" $Header: RCS/libpq,v 1.8 92/01/30 19:39:44 mer Exp Locker: clarsen $
.SS "LIBPQ" 6/14/90
d5 5
d508 2
a509 2
 create test1 (i = int4) \g
 create test1a (i = int4) \g
d515 1
a515 1
 \g
d518 1
a518 1
 append test1 (i = 10) \g
d590 2
a591 2
 create test1 (i = int4,d = float4) \g
 append test1 (i = 7, d=3.567) \g
d650 1
a650 1
.)1@


1.8
log
@PQnames -> PQpnames
@
text
@d2 1
a2 1
.\" $Header: /users/mer/pg_grass/ref/RCS/libpq,v 1.7 1991/11/13 05:20:12 mer Exp mer $
d59 3
a222 5
PQrulep \*- Return 1 if an asynchronous portal.

int PQrulep	(portal)
	PortalBuffer	*portal;

d305 10
d317 30
a346 3
All values are returned
as string.  It is the programmer's responsibility to
convert them to the correct type.
d492 153
@


1.7
log
@better documentation for PQtrace()
@
text
@d2 1
a2 1
.\" $Header: /users/mer/postgres/ref/RCS/libpq,v 1.6 1991/11/12 06:09:09 mer Exp mer $
d201 1
a201 1
PQnames \*- Return all portal names.
d203 1
a203 1
void PQnames  ( pnames, rule_p)
@


1.6
log
@fix copy from stdin example
@
text
@d2 1
a2 1
.\" $Header: /users/mer/postgres/ref/RCS/libpq,v 1.5 1991/08/16 00:32:57 mer Exp mer $
d367 5
@


1.5
log
@version 3.0 updates..... its now a work of art.
@
text
@d2 1
a2 1
.\" $Header: RCS/libpq,v 1.4 91/03/09 05:27:59 kemnitz Exp Locker: mer $
d353 1
a353 1
PQputline("3<TAB>hello world<TAB>4.5");
@


1.4
log
@Added stuff about the copy command.
@
text
@d2 1
a2 1
.\" $Header: RCS/libpq,v 1.3 91/02/25 19:17:21 mike Exp Locker: kemnitz $
d12 1
a12 1
and instances returned through an IPC channel.
d14 2
a15 3
This version of the documentation is based on the C library.  A similar
package exists for Common Lisp.
.uh CONTROL AND INITIALIZATION
a57 2
char	*PQinitstr = NULL; 	/* Initialization string passed to back-end */

d61 1
a61 1
.uh QUERY EXECUTION FUNCTIONS
a64 2
.(l
PQsetdb \*- Make the specified database the current database.
d66 5
a70 1
PQsetdb ( dbname )
d73 2
d77 3
a79 2
	char*	PQdb ()
.)l
d85 2
d88 1
a88 1
PQreset \*- Reset the communication port with the back-end.
d90 1
a90 1
PQreset ()
d92 6
a97 1
Resets communication in case of errors.
d101 1
a101 1
PQfinish ()
d103 1
d107 2
d110 16
d128 1
a128 1
PQexec (query)
d131 1
d133 13
a145 2
This function returns a status indicator or an error message.
.uh PORTAL FUNCTIONS
d164 1
a164 1
portal name is the empty string, known as the "blank portal."
d189 1
a189 1
to issue a retrievel followed by one or more
d199 1
a199 1
If rule_p is not O, then only return the number of asynchronous portals.
d212 1
a212 1
PortalBuffer * PQparray (pname )
d215 5
d236 1
d312 1
a312 1
.uh FUNCTIONS ASSOCIATED WITH THE COPY COMMAND
d316 1
a316 1
command in \*PP has options to read from or write to the network
d337 1
a337 1
PQendcopy() \*- Syncs with the backend.
d347 12
d361 1
a361 1
.uh TRACING FUNCTIONS
a373 7
Only 3 portals can be open at a time.
.lp
IPC glitches between the front-end and the back-end may cause
a query to hang.  When this happens try killing the query with
a keyboard interrupt (^C).  If this does not work, you may have
to kill the process.
.lp
d376 2
a377 1
.uh SAMPLE PROGRAM
a381 1
/*
d395 1
a395 1
    PQsetdb ("Pic-Demo");
d397 3
d410 1
a410 1
	printf ("\nA new instance group:\en");
d431 3
d437 1
a437 1
    printf ("\nNumber of portals open: %d.\en", PQnportals ());
@


1.3
log
@objectified
@
text
@d2 1
a2 1
.\" $Header: RCS/libpq,v 1.2 90/07/20 08:54:39 claire Exp $
d266 37
@


1.2
log
@*** empty log message ***
@
text
@d2 1
a2 1
.\" $Header: RCS/libpq,v 1.1 90/07/18 16:25:41 mao Exp Locker: claire $
d12 1
a12 1
and tuples returned through an IPC channel.
d107 1
a107 1
A portal is a POSTGRES buffer from which tuples can be fetched.
d125 1
a125 1
All qualifying tuples in a blank portal are fetched
d131 1
a131 1
an internal table.  Each tuple in a portal buffer has
d133 1
a133 1
each field in a tuple has a name and a field number.
d136 1
a136 1
of tuples.
d139 1
a139 1
returns multiple record types from an inheritance
d141 1
a141 1
Consequently, the tuples in a portal are set up
d143 2
a144 2
Tuples in the same group are guaranteed to have the
same record format.
d180 1
a180 1
PQntuples \*- Return the number of tuples in a portal buffer.
d185 1
a185 1
PQngroups \*- Return the number of tuple groups in a portal buffer.
d190 1
a190 1
PQntuplesGroup \*- Return the number of tuples in a tuple group.
d195 1
a195 1
PQnfieldsGroup \*- Return the number of fields in a tuple group.
d215 1
a215 1
PQgetgroup \*- Returns the index of the group that a particular tuple is in.
d221 1
a221 1
PQnfields \*- Return the number of fields in a tuple.
d227 1
a227 1
PQfnumber \*- Return the field index of a given field name within a tuple.
d250 1
a250 1
PQsametype \*- Return 1 if two tuples have the same attributes.
d309 1
a309 1
    /* Fetch tuples from the EMP table. */
d313 1
a313 1
    /* Examine all the tuples fetched. */
d319 1
a319 1
	printf ("\nA new tuple group:\en");
d328 1
a328 1
	/* Print out the tuples. */
d342 1
a342 1
    /* Print out the nubmer of portals. */
@


1.1
log
@Initial revision
@
text
@d2 1
a2 1
.\" $Header: libpq,v 1.5 89/03/23 11:51:09 wensel Exp $
d13 1
a13 1
.sp
d16 4
a19 3
.sh 1 "CONTROL AND INITIALIZATION"
.sh 2 "VARIABLES"
.sp
d23 1
a23 1
.sp 1
d36 1
a36 1
.sp
d39 2
a40 1
.sp 1
d62 1
d64 2
a65 3
.sp 1
.sh 1  "QUERY EXECUTION FUNCTIONS"
.sp
d68 1
a68 1

d77 2
a78 1

d83 1
a83 1

d93 2
a94 1

d97 1
a97 1

d102 2
a103 1

d105 2
a106 2
.sh 1 "PORTAL FUNCTIONS"
.sp
d114 1
a114 1
.sp
d122 1
a122 1
.sp
d128 1
a128 1
.sp
d134 1
a134 1
.sp
d145 1
a145 1
.sp
d153 1
a153 2
.nf
.na
d261 2
a262 1

d266 3
a268 2
.sh 1 "TRACING FUNCTIONS"

d276 2
a277 3
.fi
.ad
.sh 1 "BUGS"
d288 3
a290 3

.sh 1 "SAMPLE PROGRAM"

d357 1
a357 1

@
