1999-07-15 23:04:24 +00:00

645 lines
17 KiB
C

/*-------------------------------------------------------------------------
*
* portal.c
* generalized portal support routines
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: portal.c,v 1.24 1999/07/15 23:03:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* 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)
* PQftypeGroup - Return field type given (group index, field index)
* PQfsizeGroup - Return field size given (group index, field index)
* 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
* PQfsize - Return the size 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
*
* 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
*
*/
#include <stdio.h>
#include <string.h>
#include "postgres.h"
#include <libpq/libpq.h> /* where the declarations go */
/* ----------------------------------------------------------------
* Helper routines for PQ portal interface routines below
* ----------------------------------------------------------------
*/
static int
in_range(char *msg, int value, int min, int max)
{
if (value < min || value >= max)
{
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
"FATAL: %s, %d is not in range [%d,%d)\n", msg, value, min, max);
pqdebug("%s", PQerrormsg);
fputs(PQerrormsg, stderr);
return 0;
}
return 1;
}
static int
valid_pointer(char *msg, void *ptr)
{
if (!ptr)
{
snprintf(PQerrormsg, ERROR_MSG_LENGTH, "FATAL: %s\n", msg);
pqdebug("%s", PQerrormsg);
fputs(PQerrormsg, stderr);
return 0;
}
return 1;
}
/* ----------------------------------------------------------------
* PQ portal interface routines
* ----------------------------------------------------------------
*/
/* --------------------------------
* PQnportals - Return the number of open portals.
* If rule_p, only return asynchronous portals.
* --------------------------------
*/
int
PQnportals(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(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)
{
strncpy(pnames[cur_pname], portals[i]->name, PortalNameLength + 1);
++cur_pname;
}
}
}
}
/* --------------------------------
* PQparray - Return the portal buffer given a portal name
* --------------------------------
*/
PortalBuffer *
PQparray(char *pname)
{
int i;
if (!valid_pointer("PQparray: invalid name buffer", pname))
return NULL;
if ((i = pbuf_getIndex(pname)) < 0)
return (PortalBuffer *) NULL;
return portals[i]->portal;
}
/* --------------------------------
* PQrulep - Return 1 if an asynchronous portal
* --------------------------------
*/
int
PQrulep(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(PortalBuffer *portal)
{
if (!valid_pointer("PQntuples: invalid portal pointer", portal))
return -1;
return portal->no_tuples;
}
int
PQninstances(PortalBuffer *portal)
{
return PQntuples(portal);
}
/* --------------------------------
* PQngroups - Return the number of tuple groups in a portal buffer
* --------------------------------
*/
int
PQngroups(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(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;
gbp = pbuf_findGroup(portal, group_index);
if (gbp)
return gbp->no_tuples;
return -1;
}
int
PQninstancesGroup(PortalBuffer *portal, int group_index)
{
return PQntuplesGroup(portal, group_index);
}
/* --------------------------------
* PQnfieldsGroup - Return the number of fields in a tuple group
* --------------------------------
*/
int
PQnfieldsGroup(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;
gbp = pbuf_findGroup(portal, group_index);
if (gbp)
return gbp->no_fields;
return -1;
}
/* --------------------------------
* PQfnumberGroup - Return the field number (index) given
* the group index and the field name
* --------------------------------
*/
int
PQfnumberGroup(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;
gbp = pbuf_findGroup(portal, group_index);
if (gbp)
return pbuf_findFnumber(gbp, field_name);
return -1;
}
/* --------------------------------
* PQfnameGroup - Return the field (attribute) name given
* the group index and field index.
* --------------------------------
*/
char *
PQfnameGroup(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;
}
/* --------------------------------
* PQftypeGroup - Return the type of a field given
* the group index and field index
* --------------------------------
*/
int
PQftypeGroup(PortalBuffer *portal, int group_index, int field_number)
{
GroupBuffer *gbp;
if (!valid_pointer("PQftypeGroup: invalid portal pointer", portal) ||
!in_range("PQftypeGroup: group index",
group_index, 0, portal->no_groups))
return -1;
if ((gbp = pbuf_findGroup(portal, group_index)) &&
in_range("PQftypeGroup: field number", field_number, 0, gbp->no_fields))
return gbp->types[field_number].typid;
return -1;
}
/* --------------------------------
* PQfsizeGroup - Return the size of a field given
* the group index and field index
* --------------------------------
*/
int
PQfsizeGroup(PortalBuffer *portal, int group_index, int field_number)
{
GroupBuffer *gbp;
if (!valid_pointer("PQfsizeGroup: invalid portal pointer", portal) ||
!in_range("PQfsizeGroup: tuple index",
group_index, 0, portal->no_groups))
return -1;
if ((gbp = pbuf_findGroup(portal, group_index)) &&
in_range("PQfsizeGroup: field number", field_number, 0, gbp->no_fields))
return gbp->types[field_number].typlen;
return -1;
}
/* --------------------------------
* PQgroup - Return the tuple group that a particular tuple is in
* --------------------------------
*/
GroupBuffer *
PQgroup(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(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(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;
gbp = PQgroup(portal, tuple_index);
if (gbp)
return gbp->no_fields;
return -1;
}
/* --------------------------------
* PQfnumber - Return the field index of a given
* field name within a tuple.
* --------------------------------
*/
int
PQfnumber(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;
gbp = PQgroup(portal, tuple_index);
if (gbp)
return pbuf_findFnumber(gbp, field_name);
return -1;
}
/* --------------------------------
* PQfname - Return the name of a field
* --------------------------------
*/
char *
PQfname(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(PortalBuffer *portal, int tuple_index, int field_number)
{
GroupBuffer *gbp;
if (!valid_pointer("PQftype: 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("PQftype: field number", field_number, 0, gbp->no_fields))
return gbp->types[field_number].typid;
return -1;
}
/* --------------------------------
* PQfsize - Return the size of a field
* --------------------------------
*/
int
PQfsize(PortalBuffer *portal, int tuple_index, int field_number)
{
GroupBuffer *gbp;
if (!valid_pointer("PQfsize: invalid portal pointer", portal) ||
!in_range("PQfsize: tuple index",
tuple_index, 0, portal->no_tuples))
return -1;
if ((gbp = PQgroup(portal, tuple_index)) &&
in_range("PQfsize: field number", field_number, 0, gbp->no_fields))
return gbp->types[field_number].typlen;
return -1;
}
/* --------------------------------
* PQsametype - Return 1 if the two tuples have the same type
* (in the same group)
* --------------------------------
*/
int
PQsametype(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(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(PortalBuffer *portal,
int tuple_index,
int field_number)
{
TupleBlock *tbp;
int tuple_offset;
tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
if (tbp)
return tbp->values[tuple_offset][field_number];
return (char *) NULL;
}
/* --------------------------------
* PQgetAttr - Return an attribute (field) value
* this differs from PQgetvalue in that the value returned is
* a copy. The CALLER is responsible for free'ing the data returned.
* --------------------------------
*/
char *
PQgetAttr(PortalBuffer *portal,
int tuple_index,
int field_number)
{
TupleBlock *tbp;
int tuple_offset;
int len;
char *result = NULL;
tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
if (tbp)
{
len = tbp->lengths[tuple_offset][field_number];
result = palloc(len + 1);
memcpy(result,
tbp->values[tuple_offset][field_number],
len);
result[len] = '\0';
}
return result;
}
/* --------------------------------
* PQgetlength - Return an attribute (field) length
* --------------------------------
*/
int
PQgetlength(PortalBuffer *portal,
int tuple_index,
int field_number)
{
TupleBlock *tbp;
int tuple_offset;
tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
if (tbp)
return tbp->lengths[tuple_offset][field_number];
return -1;
}
/* ----------------
* PQclear - free storage claimed by named portal
* ----------------
*/
void
PQclear(char *pname)
{
if (!valid_pointer("PQclear: invalid portal name pointer", pname))
return;
pbuf_close(pname);
}