head	1.19;
access;
symbols
	release_4_2:1.19
	aix_ok:1.17
	Version_2_1:1.8
	C_Demo_1:1.3;
locks; strict;
comment	@ * @;


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

1.18
date	94.02.01.20.39.07;	author jolly;	state Exp;
branches;
next	1.17;

1.17
date	93.06.16.05.05.24;	author aoki;	state Exp;
branches;
next	1.16;

1.16
date	92.07.15.05.09.13;	author mao;	state Exp;
branches;
next	1.15;

1.15
date	92.04.21.13.14.16;	author clarsen;	state Exp;
branches;
next	1.14;

1.14
date	92.02.28.11.59.03;	author hong;	state Exp;
branches;
next	1.13;

1.13
date	92.02.25.15.29.50;	author clarsen;	state Exp;
branches;
next	1.12;

1.12
date	92.01.09.23.26.29;	author mer;	state Exp;
branches;
next	1.11;

1.11
date	91.11.18.22.40.48;	author hong;	state Exp;
branches;
next	1.10;

1.10
date	91.11.13.08.55.33;	author clarsen;	state Exp;
branches;
next	1.9;

1.9
date	91.11.13.05.23.06;	author mer;	state Exp;
branches;
next	1.8;

1.8
date	91.02.26.19.27.21;	author cimarron;	state Exp;
branches;
next	1.7;

1.7
date	91.02.23.23.05.36;	author cimarron;	state Exp;
branches;
next	1.6;

1.6
date	91.02.20.00.37.24;	author cimarron;	state Exp;
branches;
next	1.5;

1.5
date	91.02.10.18.29.42;	author cimarron;	state Exp;
branches;
next	1.4;

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

1.3
date	89.09.05.17.16.05;	author mao;	state C_Demo_1;
branches;
next	1.2;

1.2
date	89.08.31.09.23.50;	author ong;	state Exp;
branches;
next	1.1;

1.1
date	89.01.17.05.55.18;	author cimarron;	state Stab;
branches;
next	;


desc
@@


1.19
log
@interface for PQpname changed a bit
@
text
@/* ----------------------------------------------------------------
 *   FILE
 *	portal.c
 *	
 *   DESCRIPTION
 *	generalized portal support routines
 *
 *   UTILITY ROUTINES
 *	pqdebug		- send a string to the debugging output port
 *	pqdebug2	- send two strings to stdout
 *	PQtrace		- turn on pqdebug() tracing
 *	PQuntrace	- turn off pqdebug() tracing
 *
 *   INTERFACE ROUTINES
 *	PQnportals 	- Return the number of open portals. 
 *	PQpnames 	- Return all the portal names
 *	PQparray 	- Return the portal buffer given a portal name
 *	PQrulep 	- Return 1 if an asynchronous portal
 *	PQntuples 	- Return the number of tuples in a portal buffer
 *	PQninstances	-   same as PQntuples using object terminology
 *	PQngroups 	- Return the number of tuple groups in a portal buffer
 *	PQntuplesGroup 	- Return the number of tuples in a tuple group
 *	PQninstancesGroup  - same as PQntuplesGroup using object terminology
 *	PQnfieldsGroup 	- Return the number of fields in a tuple group
 *	PQfnumberGroup 	- Return field number given (group index, field name)
 *	PQfnameGroup 	- Return field name given (group index, field index)
 *	PQgroup 	- Return the tuple group that a particular tuple is in
 *	PQgetgroup 	- Return the index of the group that a tuple is in
 *	PQnfields 	- Return the number of fields in a tuple
 *	PQfnumber 	- Return the field index of a field name in a tuple
 *	PQfname 	- Return the name of a field
 *	PQftype 	- Return the type of a field
 *	PQsametype 	- Return 1 if the two tuples have the same type
 *	PQgetvalue 	- Return an attribute (field) value
 *	PQgetlength 	- Return an attribute (field) length
 *	PQclear		- free storage claimed by named portal
 *      PQnotifies      - Return a list of relations on which notification 
 *                        has occurred.
 *      PQremoveNotify  - Remove this notification from the list.
 *
 *   NOTES
 *	These functions may be used by both frontend routines which
 *	communicate with a backend or by user-defined functions which
 *	are compiled or dynamically loaded into a backend.
 *
 *	the portals[] array should be organized as a hash table for
 *	quick portal-by-name lookup.
 *
 *	Do not confuse "PortalEntry" (or "PortalBuffer") with "Portal"
 *	see utils/mmgr/portalmem.c for why. -cim 2/22/91
 *
 *   IDENTIFICATION
 *	$Header: /usr/local/devel/postgres/src/backend/libpq/RCS/portal.c,v 1.18 1994/02/01 20:39:07 jolly Exp aoki $
 * ----------------------------------------------------------------
 */

#include <string.h>

#include "tmp/c.h"
#include "tmp/simplelists.h"
#include "tmp/libpq.h"
#include "utils/exc.h"

RcsId("$Header: /usr/local/devel/postgres/src/backend/libpq/RCS/portal.c,v 1.18 1994/02/01 20:39:07 jolly Exp aoki $");

/* ----------------
 *	exceptions
 * ----------------
 */
Exception MemoryError = {"Memory Allocation Error"};
Exception PortalError = {"Invalid arguments to portal functions"};
Exception PostquelError = {"Postquel Error"};
Exception ProtocolError = {"Protocol Error"};
char PQerrormsg[error_msg_length];

int	PQtracep = 0;		/* 1 to print out debugging messages */
FILE    *debug_port = (FILE *) NULL;

static
in_range(msg, value, min, max)
    char *msg;
    int value, min, max;
{
    if (value < min || value >= max) {
	(void) sprintf(PQerrormsg, "FATAL: %s is not in range [%d,%d)\n",
		       msg, value, min, max);
	pqdebug("%s", PQerrormsg);
	fputs(PQerrormsg, stderr);
	return(0);
    }
    return(1);
}

static
valid_pointer(msg, ptr)
    char *msg;
    void *ptr;
{
    if (!ptr) {
	(void) sprintf(PQerrormsg, "FATAL: %s\n", msg);
	pqdebug("%s", PQerrormsg);
	fputs(PQerrormsg, stderr);
	return(0);
    }
    return(1);
}

/* ----------------------------------------------------------------
 *			PQ utility routines
 * ----------------------------------------------------------------
 */
void
pqdebug(target, msg)
    char *target, *msg;
{
    if (!target)
	return;

    if (PQtracep) {
	/*
	 * if nothing else was suggested default to stdout
	 */
	if (!debug_port)
	    debug_port = stdout;
	fprintf(debug_port, target, msg);
	fprintf(debug_port, "\n");
    }
}

void
pqdebug2(target, msg1, msg2)
    char *target, *msg1, *msg2;
{
    if (!target)
	return;

    if (PQtracep) {
	/*
	 * if nothing else was suggested default to stdout
	 */
	if (!debug_port)
	    debug_port = stdout;
	fprintf(debug_port, target, msg1, msg2);
	fprintf(debug_port, "\n");
    }
}

/* --------------------------------
 *	PQtrace() / PQuntrace()
 * --------------------------------
 */
void
PQtrace()
{
    PQtracep = 1;
}

void
PQuntrace()
{
    PQtracep = 0;
}

/* ----------------------------------------------------------------
 *		    PQ portal interface routines
 * ----------------------------------------------------------------
 */

/* --------------------------------
 *	PQnportals - Return the number of open portals. 
 * 	If rule_p, only return asynchronous portals. 
 * --------------------------------
 */
int
PQnportals(rule_p)
    int rule_p;
{
    int i, n = 0;
    
    for (i = 0; i < portals_array_size; ++i) {
	if (portals[i] && portals[i]->portal) {
	    if (!rule_p || portals[i]->portal->rule_p) {
		++n;
	    }
	}
    }
    return(n);
}

/* --------------------------------
 *	PQpnames - Return all the portal names
 * 	If rule_p, only return asynchronous portals. 
 *
 *         the caller must have allocated sufficient memory for char** pnames
 *	   (an array of PQnportals strings of length PortalNameLength).
 *
 *	   notice that this assumes that the user is calling PQnportals and
 *	   PQpnames with the same rule_p argument, and with no intervening
 *	   portal closures.  if not, you can get in heap big trouble..
 * --------------------------------
 */
void
PQpnames(pnames, rule_p)
    char **pnames;
    int rule_p;
{
    int i, cur_pname = 0;
    
    if (!valid_pointer("PQpnames: invalid name buffer", pnames))
	return;
    
    for (i = 0; i < portals_array_size; ++i) {
	if (portals[i] && portals[i]->portal) {
	    if (!rule_p || portals[i]->portal->rule_p) {
		(void) strncpy(pnames[cur_pname], portals[i]->name, PortalNameLength);
		++cur_pname;
	    }
	}
    }
}

/* --------------------------------
 *	PQparray - Return the portal buffer given a portal name
 * --------------------------------
 */
PortalBuffer *
PQparray(pname)
    char *pname;
{
    int i;

    if (!valid_pointer("PQparray: invalid name buffer", pname))
	return;
    
    if ((i = pbuf_getIndex(pname)) < 0)
	return((PortalBuffer *) NULL);
    return(portals[i]->portal);
}

/* --------------------------------
 *	PQrulep - Return 1 if an asynchronous portal
 * --------------------------------
 */
int
PQrulep(portal)
    PortalBuffer *portal;
{
    if (!valid_pointer("PQrulep: invalid portal pointer", portal))
	return(-1);

    return(portal->rule_p);
}

/* --------------------------------
 *	PQntuples - Return the number of tuples in a portal buffer
 * --------------------------------
 */
int
PQntuples(portal)
    PortalBuffer *portal;
{
    if (!valid_pointer("PQntuples: invalid portal pointer", portal))
	return(-1);

    return(portal->no_tuples);
}

int
PQninstances(portal)
    PortalBuffer *portal;
{
    return(PQntuples(portal));
}

/* --------------------------------
 *	PQngroups - Return the number of tuple groups in a portal buffer
 * --------------------------------
 */
int
PQngroups(portal)
    PortalBuffer *portal;
{
    if (!valid_pointer("PQngroups: invalid portal pointer", portal))
	return(-1);

    return(portal->no_groups);
}


/* --------------------------------
 *	PQntuplesGroup - Return the number of tuples in a tuple group
 * --------------------------------
 */
int
PQntuplesGroup(portal, group_index)
    PortalBuffer *portal;
    int 	 group_index;
{
    GroupBuffer *gbp;

    if (!valid_pointer("PQntuplesGroup: invalid portal pointer", portal) ||
	!in_range("PQntuplesGroup: group index",
		  group_index, 0, portal->no_groups))
	return(-1);
    
    if (gbp = pbuf_findGroup(portal, group_index))
	return(gbp->no_tuples);
    return(-1);
}

int
PQninstancesGroup(portal, group_index)
    PortalBuffer *portal;
    int 	 group_index;
{
    return(PQntuplesGroup(portal, group_index));
}

/* --------------------------------
 *	PQnfieldsGroup - Return the number of fields in a tuple group
 * --------------------------------
 */
int
PQnfieldsGroup(portal, group_index)
    PortalBuffer *portal;
    int		 group_index;
{
    GroupBuffer *gbp;

    if (!valid_pointer("PQnfieldsGroup: invalid portal pointer", portal) ||
	!in_range("PQnfieldsGroup: group index",
		  group_index, 0, portal->no_groups))
	return(-1);

    if (gbp = pbuf_findGroup(portal, group_index))
	return(gbp->no_fields);
    return(-1);
}

/* --------------------------------
 *	PQfnumberGroup - Return the field number (index) given
 *			 the group index and the field name
 * --------------------------------
 */
int
PQfnumberGroup(portal, group_index, field_name)
    PortalBuffer *portal;
    int		 group_index;
    char	 *field_name;
{
    GroupBuffer *gbp;

    if (!valid_pointer("PQfnumberGroup: invalid portal pointer", portal) ||
	!valid_pointer("PQfnumberGroup: invalid field name pointer",
		       field_name) ||
	!in_range("PQfnumberGroup: group index",
		  group_index, 0, portal->no_groups))
	return(-1);
    
    if (gbp = pbuf_findGroup(portal, group_index))
	return(pbuf_findFnumber(gbp, field_name));
    return(-1);
}

/* --------------------------------
 *	PQfnameGroup - Return the field (attribute) name given
 *			the group index and field index. 
 * --------------------------------
 */
char *
PQfnameGroup(portal, group_index, field_number)
    PortalBuffer *portal;
    int group_index;
    int field_number;
{
    GroupBuffer *gbp;

    if (!valid_pointer("PQfnameGroup: invalid portal pointer", portal) ||
	!in_range("PQfnameGroup: group index",
		  group_index, 0, portal->no_groups))
	return((char *) NULL);

    if ((gbp = pbuf_findGroup(portal, group_index)) &&
	in_range("PQfnameGroup: field number",
		 field_number, 0, gbp->no_fields))
	return(pbuf_findFname(gbp, field_number));
    return((char *) NULL);
}

/* --------------------------------
 *	PQgroup - Return the tuple group that a particular tuple is in
 * --------------------------------
 */
GroupBuffer *
PQgroup(portal, tuple_index)
    PortalBuffer *portal;
    int		 tuple_index;
{
    GroupBuffer *gbp;
    int tuple_count = 0;
    
    if (!valid_pointer("PQgroup: invalid portal pointer", portal) ||
	!in_range("PQgroup: tuple index",
		  tuple_index, 0, portal->no_tuples))
	return((GroupBuffer *) NULL);
    
    for (gbp = portal->groups;
	 gbp && tuple_index >= (tuple_count += gbp->no_tuples);
	 gbp = gbp->next)
	;
    if (!in_range("PQgroup: tuple not found: tuple index",
		  tuple_index, 0, tuple_count))
	return((GroupBuffer *) NULL);
    return(gbp);
}

/* --------------------------------
 *	PQgetgroup - Return the index of the group that a
 *		     particular tuple is in
 * --------------------------------
 */
int
PQgetgroup(portal, tuple_index)
    PortalBuffer *portal;
    int		 tuple_index;
{
    GroupBuffer *gbp;
    int tuple_count = 0, group_count = 0;

    if (!valid_pointer("PQgetgroup: invalid portal pointer", portal) ||
	!in_range("PQgetgroup: tuple index",
		  tuple_index, 0, portal->no_tuples))
	return(-1);
    
    for (gbp = portal->groups;
	 gbp && tuple_index >= (tuple_count += gbp->no_tuples);
	 gbp = gbp->next)
	++group_count;
    if (!gbp || !in_range("PQgetgroup: tuple not found: tuple index",
			  tuple_index, 0, tuple_count))
	return(-1);
    return(group_count);
}

/* --------------------------------
 *	PQnfields - Return the number of fields in a tuple
 * --------------------------------
 */
int
PQnfields(portal, tuple_index)
    PortalBuffer *portal;
    int		 tuple_index;
{
    GroupBuffer *gbp;
    
    if (!valid_pointer("PQnfields: invalid portal pointer", portal) ||
	!in_range("PQnfields: tuple index",
		  tuple_index, 0, portal->no_tuples))
	return(-1);

    if (gbp = PQgroup(portal, tuple_index))
	return(gbp->no_fields);
    return(-1);
}

/* --------------------------------
 *	PQfnumber - Return the field index of a given
 *		    field name within a tuple. 
 * --------------------------------
 */
int
PQfnumber(portal, tuple_index, field_name)
    PortalBuffer *portal;
    int		 tuple_index;
    char	 *field_name;
{
    GroupBuffer *gbp;

    if (!valid_pointer("PQfnumber: invalid portal pointer", portal) ||
	!valid_pointer("PQfnumber: invalid field name pointer", field_name) ||
	!in_range("PQfnumber: tuple index",
		  tuple_index, 0, portal->no_tuples))
	return(-1);

    if (gbp = PQgroup(portal, tuple_index))
	return(pbuf_findFnumber(gbp, field_name));
    return(-1);
}

/* --------------------------------
 *	PQfname - Return the name of a field
 * --------------------------------
 */
char *
PQfname(portal, tuple_index, field_number)
    PortalBuffer *portal;
    int		 tuple_index;
    int		 field_number;
{
    GroupBuffer *gbp;
        
    if (!valid_pointer("PQfname: invalid portal pointer", portal) ||
	!in_range("PQfname: tuple index",
		  tuple_index, 0, portal->no_tuples))
	return((char *) NULL);

    if ((gbp = PQgroup(portal, tuple_index)) &&
	in_range("PQfname: field number",
		 field_number, 0, gbp->no_fields))
	return(pbuf_findFname(gbp, field_number));
    return((char *) NULL);
}

/* --------------------------------
 *	PQftype - Return the type of a field
 * --------------------------------
 */
int 
PQftype(portal, tuple_index, field_number)
    PortalBuffer *portal;
    int		 tuple_index;
    int		 field_number;
{
    GroupBuffer *gbp;
    
    if (!valid_pointer("PQfname: invalid portal pointer", portal) ||
	!in_range("PQfname: tuple index",
		  tuple_index, 0, portal->no_tuples))
	return(-1);

    if ((gbp = PQgroup(portal, tuple_index)) &&
	in_range("PQfname: field number", field_number, 0, gbp->no_fields))
	return(gbp->types[field_number].adtid);
    return(-1);
}

/* --------------------------------
 *	PQsametype - Return 1 if the two tuples have the same type
 *			(in the same group)
 * --------------------------------
 */
int
PQsametype(portal, tuple_index1, tuple_index2)
    PortalBuffer *portal;
    int		 tuple_index1;
    int		 tuple_index2;
{
    GroupBuffer *gbp1, *gbp2;
    
    if (!valid_pointer("PQsametype: invalid portal pointer", portal) ||
	!in_range("PQsametype: tuple index 1",
		  tuple_index1, 0, portal->no_tuples) ||
	!in_range("PQsametype: tuple index 2",
		  tuple_index2, 0, portal->no_tuples))
	return(-1);

    gbp1 = PQgroup(portal, tuple_index1);
    gbp2 = PQgroup(portal, tuple_index2);
    if (gbp1 && gbp2)
	return(gbp1 == gbp2);
    return(-1);
}

static
TupleBlock *
PQGetTupleBlock(portal, tuple_index, tuple_offset)
    PortalBuffer *portal;
    int tuple_index;
    int *tuple_offset;
{
    GroupBuffer *gbp;
    TupleBlock  *tbp;
    int tuple_count = 0;

    if (!valid_pointer("PQGetTupleBlock: invalid portal pointer", portal) ||
	!valid_pointer("PQGetTupleBlock: invalid offset pointer",
		       tuple_offset) ||
	!in_range("PQGetTupleBlock: tuple index",
		  tuple_index, 0, portal->no_tuples))
	return((TupleBlock *) NULL);
    
    for (gbp = portal->groups;
	 gbp && tuple_index >= (tuple_count += gbp->no_tuples);
	 gbp = gbp->next)
	;
    if (!gbp ||
	!in_range("PQGetTupleBlock: tuple not found: tuple index",
		  tuple_index, 0, tuple_count))
	return((TupleBlock *) NULL);
    tuple_count -= gbp->no_tuples;
    for (tbp = gbp->tuples;
	 tbp && tuple_index >= (tuple_count += TupleBlockSize);
	 tbp = tbp->next)
	;
    if (!tbp ||
	!in_range("PQGetTupleBlock: tuple not found: tuple index",
		  tuple_index, 0, tuple_count))
	return((TupleBlock *) NULL);
    tuple_count -= TupleBlockSize;
    
    *tuple_offset = tuple_index - tuple_count;
    return(tbp);
}

/* --------------------------------
 *	PQgetvalue - Return an attribute (field) value
 * --------------------------------
 */
char *
PQgetvalue(portal, tuple_index, field_number)
    PortalBuffer *portal;
    int		 tuple_index;
    int		 field_number;
{
    TupleBlock *tbp;
    int tuple_offset;

    if (tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset))
	return(tbp->values[tuple_offset][field_number]);
    return((char *) NULL);
}

/* --------------------------------
 *	PQgetlength - Return an attribute (field) length
 * --------------------------------
 */
int
PQgetlength(portal, tuple_index, field_number)
    PortalBuffer *portal;
    int		 tuple_index;
    int		 field_number;
{
    TupleBlock *tbp;
    int tuple_offset;

    if (tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset))
	return(tbp->lengths[tuple_offset][field_number]);
    return(-1);
}

/* ----------------
 *	PQclear		- free storage claimed by named portal
 * ----------------
 */
void
PQclear(pname)
    char *pname;
{    
    if (!valid_pointer("PQclear: invalid portal name pointer", pname))
	return;
    pbuf_close(pname);
}

/*
 * async notification.
 * This is going away with pending rewrite of comm. code...
 */

SLList pqNotifyList;
static int initialized = 0;	/* statics in this module initialized? */

/* remove invalid notifies before returning */
void
PQcleanNotify()
{
    PQNotifyList *last = NULL;
    PQNotifyList *nPtr;
    for (nPtr = (PQNotifyList *)SLGetHead(&pqNotifyList);
	 nPtr != NULL;
	 nPtr = (PQNotifyList *)SLGetSucc(&nPtr->Node)) {
	if (last != NULL && last->valid == 0) {
	    SLRemove(&last->Node);
	    pbuf_free((caddr_t)last);
	}
	last = nPtr;
    }
    if (last != NULL && last->valid == 0) {
	SLRemove(&last->Node);
	pbuf_free((caddr_t)last);
    }
}


void
PQnotifies_init() {
    PQNotifyList *nPtr;
    
    if (! initialized) {
	initialized = 1;
	SLNewList(&pqNotifyList,offsetof(PQNotifyList,Node));
    } else {			/* clean all notifies */
	for (nPtr = (PQNotifyList *)SLGetHead(&pqNotifyList) ;
	     nPtr != NULL;
	     nPtr = (PQNotifyList *)SLGetSucc(&nPtr->Node)) {
	    nPtr->valid = 0;
	}
	PQcleanNotify();
    }
}

PQNotifyList *
PQnotifies()
{
    PQcleanNotify();
    return (PQNotifyList *)SLGetHead(&pqNotifyList);
}

void
PQremoveNotify(nPtr)
    PQNotifyList *nPtr;
{
    nPtr->valid = 0;		/* remove later */
}

void 
PQappendNotify(relname,pid)
    char *relname;
    int pid;
{
    PQNotifyList *nPtr;
    if (! initialized) {
	initialized = 1;
	SLNewList(&pqNotifyList,offsetof(PQNotifyList,Node));
    }
    nPtr = (PQNotifyList *)pbuf_alloc(sizeof(PQNotifyList));
    strncpy(nPtr->relname, relname, NAMEDATALEN);
    nPtr->be_pid = pid;
    nPtr->valid = 1;
    SLNewNode(&nPtr->Node);
    SLAddTail(&pqNotifyList,&nPtr->Node);

}
@


1.18
log
@changed uses of MAXPORTALS to portals_array_size
changed PQpnames() to take in char** pnames as an argument
@
text
@d53 1
a53 1
 *	$Header: /private/postgres/src/backend/libpq/RCS/portal.c,v 1.17 1993/06/16 05:05:24 aoki Exp jolly $
d64 1
a64 1
RcsId("$Header: /private/postgres/src/backend/libpq/RCS/portal.c,v 1.17 1993/06/16 05:05:24 aoki Exp jolly $");
d193 1
d195 5
d207 1
a207 1
    int i;
d215 2
a216 2
		(void) strncpy(pnames[i], portals[i]->name, PortalNameLength);
		continue;
a218 1
	pnames[i][0] = '\0';
@


1.17
log
@used to do no error checking, lots of lines like
	return(foo()->bar)
now ignores libpq_raise, returns errors with PQerrormsg set
infinite amounts of argument-checking is now done.
@
text
@d53 1
a53 1
 *	$Header: /home2/aoki/postgres/src/backend/libpq/RCS/portal.c,v 1.16 1992/07/15 05:09:13 mao Exp aoki $
d64 1
a64 1
RcsId("$Header: /home2/aoki/postgres/src/backend/libpq/RCS/portal.c,v 1.16 1992/07/15 05:09:13 mao Exp aoki $");
d180 1
a180 1
    for (i = 0; i < MAXPORTALS; ++i) {
d193 1
d198 1
a198 1
    char *pnames[MAXPORTALS];
d206 1
a206 1
    for (i = 0; i < MAXPORTALS; ++i) {
d209 1
a209 1
		(void) strcpy(pnames[i], portals[i]->name);
d213 1
a213 2
	/* XXX this looks like a memory leak to me - pma 06/13/93 */
	pnames[i] = (char *) NULL;
d721 1
a721 1
    strcpy(nPtr->relname,relname);
d726 1
@


1.16
log
@restoring changes made by case that i erroneously backed out.  case's
message was: add PQgetlength
@
text
@d18 1
a18 1
 *	PQrulep 	- Return 1 if an asynchronized portal
d53 1
a53 1
 *	$Header: /private/mao/postgres/src/lib/libpq/RCS/portal.c,v 1.16 1992/07/15 01:59:32 clarsen Exp $
d64 1
a64 1
RcsId("$Header: /private/mao/postgres/src/lib/libpq/RCS/portal.c,v 1.16 1992/07/15 01:59:32 clarsen Exp $");
d76 2
a77 2
int	PQtracep = 0;		/* 1 to print out debugging message */
FILE    *debug_port = (FILE *)NULL;
d79 29
d113 2
a114 2
pqdebug (target, msg)
char *target, *msg;
d116 3
d132 1
a132 1
char *target, *msg1, *msg2;
d134 3
d138 7
a144 2
	printf(target, msg1, msg2);
	printf("\n");
d171 1
a171 1
 * 	If rule_p, only return asynchronized portals. 
d180 8
a187 6
    for (i = 0; i < MAXPORTALS; i++) 
	if (portals[i] != NULL)
	    if (!rule_p || portals[i]->portal->rule_p)
		n++;
    
    return n;
d192 1
a192 1
 * 	If rule_p, only return asynchronized portals. 
d197 2
a198 2
     char *pnames[MAXPORTALS];
     int rule_p;
d201 10
a210 6

    for (i = 0; i < MAXPORTALS; i++)
	if (portals[i] != NULL) {
	    if (!rule_p || portals[i]->portal->rule_p) 
		strcpy(pnames[i], portals[i]->name);
	    else pnames[i] = NULL;
d212 3
a214 2
	else 
	    pnames[i] = NULL;
d226 3
a228 3
    
    if ((i = pbuf_getIndex(pname)) == -1) 
	return (PortalBuffer *) NULL;
d230 3
a232 1
    return (portals[i]->portal);
d236 1
a236 1
 *	PQrulep - Return 1 if an asynchronized portal
d243 4
a246 1
    return (portal->rule_p);
d257 4
a260 1
    return (portal->no_tuples);
d267 1
a267 1
    return PQntuples(portal);
d278 4
a281 1
    return (portal->no_groups);
d294 10
a303 2
    return
	pbuf_findGroup(portal, group_index)->no_tuples;
d311 1
a311 2
    return
	PQntuplesGroup(portal, group_index);
d323 10
a332 2
    return
	pbuf_findGroup(portal, group_index)->no_fields;
d346 12
a357 2
    return
	pbuf_findFnumber( pbuf_findGroup(portal, group_index), field_name);
d371 12
a382 2
    return
	pbuf_findFname( pbuf_findGroup(portal, group_index), field_number);
d394 2
a395 5
    GroupBuffer *group;

    if (tuple_index < 0 || tuple_index >= portal->no_tuples)
	libpq_raise(&PortalError, 
		     form((int)"tuple index %d out of bound.", tuple_index));
d397 13
a409 8
    group = portal->groups;

    while (tuple_index >= group->no_tuples) {
	tuple_index -= group->no_tuples;
	group = group->next;
    }

    return (group);
d414 1
a414 1
 *		     partibular tuple is in
d422 2
a423 14
    GroupBuffer *group;
    int n = 0;

    if (tuple_index < 0 || tuple_index >= portal->no_tuples)
	libpq_raise(&PortalError, 
		     form((int)"tuple index %d out of bound.", tuple_index));
    
    group = portal->groups;

    while (tuple_index >= group->no_tuples) {
	n++;
	tuple_index -= group->no_tuples;
	group = group->next;
    }
d425 13
a437 1
    return (n);
d449 10
a458 2
    return
	PQgroup(portal, tuple_index)->no_fields;
d472 11
a482 2
    return
	pbuf_findFnumber( PQgroup(portal, tuple_index), field_name);
d495 12
a506 2
    return
	pbuf_findFname( PQgroup(portal, tuple_index), field_number);
d519 1
a519 1
    GroupBuffer *group;
d521 9
a529 5
    group = PQgroup(portal, tuple_index);
    pbuf_checkFnumber(group, field_number);
    
    return
	(group->types + field_number)->adtid;
d543 55
a597 2
    return
	(PQgroup(portal, tuple_index1) == PQgroup(portal, tuple_index2));
d610 2
a611 20
    GroupBuffer *group;
    TupleBlock  *tuple_ptr;

    if (tuple_index < 0 || tuple_index >= portal->no_tuples)
	libpq_raise(&PortalError, 
		    form((int)"tuple index %d out of bound.", tuple_index));
    
    group = portal->groups;

    while (tuple_index >= group->no_tuples) {
	tuple_index -= group->no_tuples;
	group = group->next;
    }
    
    tuple_ptr = group->tuples;    

    while (tuple_index >= TupleBlockSize) {
	tuple_index -= TupleBlockSize;
	tuple_ptr = tuple_ptr->next;
    }
d613 3
a615 4
    pbuf_checkFnumber(group, field_number);
    
    return
	tuple_ptr->values[tuple_index][field_number];
d628 2
a629 15
    GroupBuffer *group;
    TupleBlock  *tuple_ptr;

    if (tuple_index < 0 || tuple_index >= portal->no_tuples)
	libpq_raise(&PortalError, 
		    form((int)"tuple index %d out of bound.", tuple_index));
    
    group = portal->groups;

    while (tuple_index >= group->no_tuples) {
	tuple_index -= group->no_tuples;
	group = group->next;
    }
    
    tuple_ptr = group->tuples;    
d631 3
a633 9
    while (tuple_index >= TupleBlockSize) {
	tuple_index -= TupleBlockSize;
	tuple_ptr = tuple_ptr->next;
    }

    pbuf_checkFnumber(group, field_number);
    
    return
	tuple_ptr->lengths[tuple_index][field_number];
d644 2
d682 1
a682 1

d705 1
a705 1
     PQNotifyList *nPtr;
d712 2
a713 2
     char *relname;
     int pid;
@


1.15
log
@Put error messages in PQerrormsg
@
text
@d35 1
d53 1
a53 1
 *	$Header: RCS/portal.c,v 1.14 92/02/28 11:59:03 hong Exp Locker: clarsen $
d64 1
a64 1
RcsId("$Header: RCS/portal.c,v 1.14 92/02/28 11:59:03 hong Exp Locker: clarsen $");
d456 37
@


1.14
log
@ fixed a prototype inconsistency
@
text
@d52 1
a52 1
 *	$Header: RCS/portal.c,v 1.13 92/02/25 15:29:50 clarsen Exp Locker: hong $
d63 1
a63 1
RcsId("$Header: RCS/portal.c,v 1.13 92/02/25 15:29:50 clarsen Exp Locker: hong $");
d73 1
@


1.13
log
@async portals.
@
text
@d52 1
a52 1
 *	$Header: RCS/portal.c,v 1.12 92/01/09 23:26:29 mer Exp Locker: clarsen $
d63 1
a63 1
RcsId("$Header: RCS/portal.c,v 1.12 92/01/09 23:26:29 mer Exp Locker: clarsen $");
d486 1
a486 1
	    pbuf_free(last);
d492 1
a492 1
	pbuf_free(last);
@


1.12
log
@re-do the debug_port fix that somehow got overwritten
@
text
@d36 3
d52 1
a52 1
 *	$Header: /users/mer/postgres/src/lib/libpq/RCS/portal.c,v 1.11 1991/11/18 22:40:48 hong Exp mer $
d59 1
d63 1
a63 1
RcsId("$Header: /users/mer/postgres/src/lib/libpq/RCS/portal.c,v 1.11 1991/11/18 22:40:48 hong Exp mer $");
d465 79
@


1.11
log
@incorrect parameter passing to libpq_raise(), trying to
cast a struct to a pointer.
@
text
@d49 1
a49 1
 *	$Header: RCS/portal.c,v 1.10 91/11/13 08:55:33 clarsen Exp Locker: hong $
d59 1
a59 1
RcsId("$Header: RCS/portal.c,v 1.10 91/11/13 08:55:33 clarsen Exp Locker: hong $");
d71 1
a71 1
FILE    *debug_port;
d82 5
@


1.10
log
@prototypes
@
text
@d49 1
a49 1
 *	$Header: RCS/portal.c,v 1.8 91/02/26 19:27:21 cimarron Exp Locker: clarsen $
d59 1
a59 1
RcsId("$Header: RCS/portal.c,v 1.8 91/02/26 19:27:21 cimarron Exp Locker: clarsen $");
d293 1
a293 1
	libpq_raise(PortalError, 
d320 1
a320 1
	libpq_raise(PortalError, 
d424 1
a424 1
	libpq_raise(PortalError, 
@


1.9
log
@fix core dump when user doesn't specify a stream for debug_port
@
text
@d49 1
a49 1
 *	$Header: /users/mer/postgres/src/lib/libpq/RCS/portal.c,v 1.8 1991/02/26 19:27:21 cimarron Exp mer $
d59 1
a59 1
RcsId("$Header: /users/mer/postgres/src/lib/libpq/RCS/portal.c,v 1.8 1991/02/26 19:27:21 cimarron Exp mer $");
d71 1
a71 1
FILE    *debug_port = (FILE *)NULL;
a81 5
	/*
	 * if nothing else was suggested default to stdout
	 */
	if (!debug_port)
	    debug_port = stdout;
d144 2
a145 1
    char *pnames[MAXPORTALS];
d294 1
a294 1
		     form("tuple index %d out of bound.", tuple_index));
d321 1
a321 1
		     form("tuple index %d out of bound.", tuple_index));
d425 1
a425 1
		    form("tuple index %d out of bound.", tuple_index));
@


1.8
log
@libpq changes for PQfn and renaming pg_relation to pg_class in catalogs
@
text
@d49 1
a49 1
 *	$Header: RCS/portal.c,v 1.7 91/02/23 23:05:36 cimarron Exp $
d59 1
a59 1
RcsId("$Header: RCS/portal.c,v 1.7 91/02/23 23:05:36 cimarron Exp $");
d71 1
a71 1
FILE    *debug_port;
d82 5
@


1.7
log
@PQexec() now works correctly in the backend
@
text
@d20 1
d23 1
d49 1
a49 1
 *	$Header: RCS/portal.c,v 1.6 91/02/20 00:37:24 cimarron Exp Locker: cimarron $
d59 1
a59 1
RcsId("$Header: RCS/portal.c,v 1.6 91/02/20 00:37:24 cimarron Exp Locker: cimarron $");
d196 7
d226 9
@


1.6
log
@added several new support routines and moved portal buffer
helper functions to portalbuf.c
@
text
@d43 3
d47 1
a47 1
 *	$Header: RCS/portal.c,v 1.5 91/02/10 18:29:42 cimarron Exp Locker: cimarron $
d57 1
a57 1
RcsId("$Header: RCS/portal.c,v 1.5 91/02/10 18:29:42 cimarron Exp Locker: cimarron $");
@


1.5
log
@reorganization of libpq routines to provide
PQexec and PQfn functionality from both the front
end applications and the postgres backend.
@
text
@d8 5
a12 8
 *   SUPPORT ROUTINES
 *	get_portal_index - Return the index of the portal entry
 *	portal_setup 	- Set up a portal for dumping data
 *	portal_close 	- Close a portal, remove it from the portal table
 *	findGroup 	- Return group given the group_index
 *	findFnumber 	- Return field index of a given field within a group
 *	findFname 	- Find the field name given the field index
 *	check_field_number - signal an error if field number is out of bounds
d33 1
d40 3
d44 1
a44 1
 *	$Header$
d54 1
a54 1
RcsId("$Header: RCS/portal.c,v 1.4 90/09/25 16:34:25 kemnitz Exp Locker: cimarron $");
d65 2
a66 4
/* ----------------------------------------------------------------
 *			PQ support routines
 * ----------------------------------------------------------------
 */
d68 3
a70 4
/* --------------------------------
 *	get_portal_index - Return the index of the portal entry
 * 	note: portals[] maps portal names to portal buffers.
 * --------------------------------
d72 3
a74 3
int 
get_portal_index(pname)
    char *pname;
d76 3
a78 33
    int i;

    for (i = 0; i < MAXPORTALS; i++) 
	if (portals[i] != NULL && strcmp(portals[i]->name, pname) == 0)
	    return i;
    
    return (-1);
}

/* --------------------------------
 *	portal_setup - Set up a portal for dumping data
 * --------------------------------
 */
PortalBuffer *
portal_setup(pname)
    char *pname;
{
    int i;

    /* If a portal with the same name already exists, close it. */
    if ((i = get_portal_index(pname)) != -1) 
	freePortal(portals[i]->portal);
    /* Look for an empty entry in the portal table. */
    else {
	for (i = 0; i < MAXPORTALS; i++)
	    if (portals[i] == NULL)
		break;
	/* If the portal table is full, signal an error. */
	if (i >= MAXPORTALS) 
	    libpq_raise(PortalError, form("Portal Table overflows!"));
	
	portals[i] = addPortalEntry();
	strcpy(portals[i]->name, pname);
a79 3
    portals[i]->portal = addPortal();

    return (portals[i]->portal);
a81 5
/* --------------------------------
 *	portal_close - Close a portal, remove it from the portal table
 *			and free up the space
 * --------------------------------
 */
d83 2
a84 2
portal_close(pname)
    char *pname;
d86 3
a88 24
    int i;

    if ((i = get_portal_index(pname)) == -1) 
	libpq_raise(PortalError, form("Portal %s does not exist.", pname));

    freePortal(portals[i]->portal);
    freePortalEntry(i);
}

/* --------------------------------
 *	findGroup - Return the group given the group_index
 * --------------------------------
 */
GroupBuffer *
findGroup(portal, group_index)
    PortalBuffer *portal;
    int 	 group_index;
{
    GroupBuffer *group;

    group = portal->groups;
    while (group_index > 0 && group != NULL) {
	group = group->next;
	group_index--;
a89 6

    if (group == NULL)
	libpq_raise(PortalError, 
		    form("Group index %d out of bound.", group_index));

    return (group);
d93 1
a93 1
 *	findFnumber - Return the field index of a given field within a group
a95 21
findFnumber(group, field_name)
    GroupBuffer *group;
    char	*field_name;
{	
    TypeBlock *types;
    int i;

    types = group->types;

    for (i = 0; i < group->no_fields; i++, types++) 
	if (strcmp(types->name, field_name) == 0)
	    return (i);
	
    libpq_raise(PortalError, 
		form("Field-name %s does not exist.", field_name));
}

/* --------------------------------
 *	check_field_number - signal an error if field number is out of bounds
 * --------------------------------
 */
d97 1
a97 3
check_field_number(group, field_number)
    GroupBuffer *group;
    int		 field_number;
d99 1
a99 3
    if (field_number < 0 || field_number >= group->no_fields)
	libpq_raise(PortalError, 
		    form("Field number %d out of bound.", field_number));
d102 2
a103 8
/* --------------------------------
 *	findFname - Find the field name given the field index
 * --------------------------------
 */
char *
findFname(group, field_number)
    GroupBuffer *group;
    int		field_number;
d105 1
a105 3
     check_field_number(group, field_number);
     return
	 (group->types + field_number)->name;
d163 1
a163 1
    if ((i = get_portal_index(pname)) == -1) 
d213 1
a213 1
	findGroup(portal, group_index)->no_tuples;
d226 1
a226 1
	findGroup(portal, group_index)->no_fields;
d241 1
a241 1
	findFnumber( findGroup(portal, group_index), field_name);
d256 1
a256 1
	findFname( findGroup(portal, group_index), field_number);
d337 1
a337 1
	findFnumber( PQgroup(portal, tuple_index), field_name);
d351 1
a351 1
	findFname( PQgroup(portal, tuple_index), field_number);
d367 1
a367 1
    check_field_number(group, field_number);
d419 1
a419 1
    check_field_number(group, field_number);
d425 10
@


1.4
log
@Updating from revision 1.3 to revision 1.5
@
text
@d1 44
a44 3
/*
 * portal.c --
 *	Handling portals.
d53 1
a53 1
RcsId ("$Header: RCS/portal.c,v 1.5 90/08/14 10:08:56 cimarron Exp $");
d55 3
a57 3
/* 
 * portals[] --
 *	maps portal names to portal buffers.
d59 4
d64 10
a73 1
/* Return the index of the portal entry. */
d75 2
a76 2
get_portal_index (pname)
	char *pname;
d81 3
a83 2
	if (portals[i] != NULL && strcmp (portals[i]->name, pname) == 0)
	    return (i);
d87 4
a90 1
/* Set up a portal for dumping data. */
d92 2
a93 2
portal_setup (pname)
	char *pname;
d98 2
a99 2
    if ((i = get_portal_index (pname)) != -1) 
	freePortal (portals[i]->portal);
d108 3
a110 2
	portals[i] = addPortalEntry ();
	strcpy (portals[i]->name, pname);
d112 1
a112 1
    portals[i]->portal = addPortal ();
d117 5
a121 1
/* Close a portal, remove it from the portal table and free up the space. */
d123 2
a124 2
portal_close (pname)
	char *pname;
d128 1
a128 1
    if ((i = get_portal_index (pname)) == -1) 
d131 2
a132 2
    freePortal (portals[i]->portal);
    freePortalEntry (i);
d135 3
a137 3
/* 
 * Return the number of open portals. 
 * If rule_p, only return asynchronized portals. 
d139 79
d219 2
a220 2
PQnportals (rule_p)
	int rule_p;
d228 2
a229 1
    return (n);
d232 4
a235 3
/* 
 * Return all the portal names.
 * If rule_p, only return asynchronized portals. 
d238 2
a239 2
PQpnames (pnames, rule_p)
	char *pnames[MAXPORTALS];
d246 1
a246 1
		strcpy (pnames[i], portals[i]->name);
d253 4
a256 1
/* Return the portal buffer given a portal name. */
d258 2
a259 2
PQparray (pname)
	char *pname;
d262 4
a265 2
    if ((i = get_portal_index (pname)) == -1) 
	return ((PortalBuffer *) NULL);
d269 4
a272 1
/* Return 1 if an asynchronized portal. */
d274 2
a275 2
PQrulep (portal)
	PortalBuffer *portal;
d280 4
a283 1
/* Return the number of tuples in a portal buffer. */
d285 2
a286 2
PQntuples (portal)
	PortalBuffer *portal;
d291 7
a297 3
/* Return the number of tuple groups in a portal buffer. */
int PQngroups (portal)
	PortalBuffer *portal;
a301 7
/* Return the group given the group_index. */
GroupBuffer *
findGroup (portal, group_index)
	PortalBuffer *portal;
	int group_index;
{
    GroupBuffer *group;
d303 8
a310 16
    group = portal->groups;
    while (group_index > 0 && group != NULL) {
	group = group->next;
	group_index--;
    }

    if (group == NULL)
	libpq_raise(PortalError, 
		    form("Group index %d out of bound.", group_index));
    return (group);
}

/* Return the number of tuples in a tuple group. */
PQntuplesGroup (portal, group_index)
	PortalBuffer *portal;
	int group_index;
d312 2
a313 1
    return (findGroup (portal, group_index)->no_tuples);
d316 8
a323 4
/* Return the number of fields in a tuple group. */
PQnfieldsGroup (portal, group_index)
	PortalBuffer *portal;
	int group_index;
d325 2
a326 1
    return (findGroup (portal, group_index)->no_fields);
d329 5
a333 40
/* Return the field index of a given field within a group. */
findFnumber (group, field_name)
       	GroupBuffer *group;
	char *field_name;
{
	TypeBlock *types;
	int i;

	types = group->types;

	for (i = 0; i < group->no_fields; i++, types++) 
	    if (strcmp (types->name, field_name) == 0)
		return (i);
	
	libpq_raise(PortalError, 
		    form("Field-name %s does not exist.", field_name));
}

/* If the field number if out of bound, signal an error. */
void
check_field_number (group, field_number)
	GroupBuffer *group;
	int field_number;
{
    if (field_number < 0 || field_number >= group->no_fields)
	libpq_raise(PortalError, 
		    form("Field number %d out of bound.", field_number));
}

/* Find the field name given the field index. */
char *
findFname (group, field_number)
	GroupBuffer *group;
	int field_number;
{
     check_field_number (group, field_number);
     return ((group->types + field_number)->name);
}

/* Return the field number (index) given the group index and the field name. */
d335 4
a338 4
PQfnumberGroup (portal, group_index, field_name)
	PortalBuffer *portal;
	int group_index;
	char *field_name;
d340 2
a341 1
    return (findFnumber (findGroup (portal, group_index), field_name));
d344 5
a348 1
/* Return the field (attribute) name given the group index and field index. */
d350 4
a353 4
PQfnameGroup (portal, group_index, field_number)
	PortalBuffer *portal;
	int group_index;
	int field_number;
d355 2
a356 1
    return (findFname (findGroup (portal, group_index), field_number));
d359 4
a362 1
/* Return the tuple group that a particular tuple is in. */
d364 3
a366 3
PQgroup (portal, tuple_index)
	PortalBuffer *portal;
	int tuple_index;
d373 1
d384 5
a388 1
/* Return the index of the group that a partibular tuple is in. */
d390 3
a392 3
PQgetgroup (portal, tuple_index)
	PortalBuffer *portal;
	int tuple_index;
d400 1
d412 4
a415 1
/* Return the number of fields in a tuple. */
d417 3
a419 3
PQnfields (portal, tuple_index)
	PortalBuffer *portal;
	int tuple_index;
d421 2
a422 1
    return ((PQgroup (portal, tuple_index))->no_fields);
d425 5
a429 1
/* Return the field index of a given field name within a tuple. */
d431 4
a434 4
PQfnumber (portal, tuple_index, field_name)
	PortalBuffer *portal;
	int tuple_index;
	char *field_name;
d436 2
a437 1
    return (findFnumber (PQgroup (portal, tuple_index), field_name));
d440 4
a443 1
/* Return the name of a field. */
d445 4
a448 4
PQfname (portal, tuple_index, field_number)
	PortalBuffer *portal;
	int tuple_index;
	int field_number;
d450 2
a451 1
    return (findFname (PQgroup (portal, tuple_index), field_number));
d454 4
a457 1
/* Return the type of a field. */
d459 4
a462 4
PQftype (portal, tuple_index, field_number)
	PortalBuffer *portal;
	int tuple_index;
	int field_number;
d466 2
a467 2
    group = PQgroup (portal, tuple_index);
    check_field_number (group, field_number);
d469 2
a470 1
    return ((group->types + field_number)->adtid);
d473 5
a477 1
/* Return 1 if the two tuples have the same type (in the same group). */
d479 4
a482 3
PQsametype (portal, tuple_index1, tuple_index2)
	PortalBuffer *portal;
	int tuple_index1, tuple_index2;
d484 2
a485 3
    if (PQgroup (portal, tuple_index1) == PQgroup (portal, tuple_index2))
	return (1);
    return (0);
d488 4
a491 1
/* Return an attribute (field) value. */
d493 4
a496 4
PQgetvalue (portal, tuple_index, field_number)
	PortalBuffer *portal;
	int tuple_index;
	int field_number;
d504 1
a506 1

d511 1
d519 1
a519 1
    check_field_number (group, field_number);
d521 2
a522 1
    return (tuple_ptr->values[tuple_index][field_number]);
@


1.3
log
@Working version of C-only demo
@
text
@a0 1

a1 26
 * 
 * POSTGRES Data Base Management System
 * 
 * Copyright (c) 1988 Regents of the University of California
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for educational, research, and non-profit purposes and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of the University of California not be used in advertising
 * or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Permission to incorporate this
 * software into commercial products can be obtained from the Campus
 * Software Office, 295 Evans Hall, University of California, Berkeley,
 * Ca., 94720 provided only that the the requestor give the University
 * of California a free licence to any derived software for educational
 * and research purposes.  The University of California makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 * 
 */



/*
d6 1
a6 1
#include "c.h"
d8 3
a10 3
#include "string.h"
#include "libpq.h"
#include "exc.h"
d12 1
a12 1
RcsId ("$Header: RCS/portal.c,v 1.2 89/08/31 09:23:50 ong Exp Locker: ong $");
@


1.2
log
@changed exception.h to exc.h
@
text
@d39 1
a39 1
RcsId ("$Header: /n/postgres/a/postgres/ong/postgres/src/lib/libpq/RCS/portal.c,v 1.1 89/01/17 05:55:18 cimarron Stab $");
@


1.1
log
@Initial revision
@
text
@d37 1
a37 1
#include "exception.h"
d39 1
a39 1
RcsId ("$Header: portal.c,v 1.1 88/11/11 16:37:51 postgres Exp $");
@
