645 lines
17 KiB
C
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);
|
|
}
|