diff options
Diffstat (limited to 'src/backend/libpq/portal.c')
-rw-r--r-- | src/backend/libpq/portal.c | 783 |
1 files changed, 783 insertions, 0 deletions
diff --git a/src/backend/libpq/portal.c b/src/backend/libpq/portal.c new file mode 100644 index 00000000000..ca27fd83089 --- /dev/null +++ b/src/backend/libpq/portal.c @@ -0,0 +1,783 @@ +/*------------------------------------------------------------------------- + * + * portal.c-- + * generalized portal support routines + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portal.c,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +/* + * 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) + * 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 + * 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 + * + */ +#include <stdio.h> /* for sprintf() */ +#include <string.h> + +#include "c.h" +#include "lib/dllist.h" +#include "libpq/libpq.h" /* where the declarations go */ +#include "utils/exc.h" +#include "utils/palloc.h" + +/* ---------------- + * exceptions + * ---------------- + */ +Exception MemoryError = {"Memory Allocation Error"}; +Exception PortalError = {"Invalid arguments to portal functions"}; +Exception PostquelError = {"Sql 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 int +in_range(char *msg, int value, int min, int max) +{ + if (value < min || value >= max) { + (void) sprintf(PQerrormsg, "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) { + (void) sprintf(PQerrormsg, "FATAL: %s\n", msg); + pqdebug("%s", PQerrormsg); + fputs(PQerrormsg, stderr); + return(0); + } + return(1); +} + +/* ---------------------------------------------------------------- + * PQ utility routines + * ---------------------------------------------------------------- + */ +void +pqdebug(char *target, char *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(char *target, char *msg1, char *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(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) { + (void) strncpy(pnames[cur_pname], portals[i]->name, PortalNameLength); + ++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].adtid); + 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].adtsize); + 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].adtid); + 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].adtsize); + 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 = malloc(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); +} + +/* + * async notification. + * This is going away with pending rewrite of comm. code... + */ +/* static SLList pqNotifyList;*/ +static Dllist *pqNotifyList = NULL; + +/* remove invalid notifies before returning */ +void +PQcleanNotify() +{ + Dlelem *e, *next; + PQNotifyList *p; + + e = DLGetHead(pqNotifyList); + + while (e) { + next = DLGetSucc(e); + p = (PQNotifyList*)DLE_VAL(e); + if (p->valid == 0) { + DLRemove(e); + DLFreeElem(e); + pfree(p); + } + e = next; + } +} + +void +PQnotifies_init() +{ + Dlelem *e; + PQNotifyList *p; + + if (pqNotifyList == NULL) { + pqNotifyList = DLNewList(); + } + else { + /* clean all notifies */ + for (e = DLGetHead(pqNotifyList); e != NULL; e = DLGetSucc(e)) { + p = (PQNotifyList*)DLE_VAL(e); + p->valid = 0; + } + PQcleanNotify(); + } +} + +PQNotifyList * +PQnotifies() +{ + Dlelem *e; + PQcleanNotify(); + e = DLGetHead(pqNotifyList); + return (e ? (PQNotifyList*)DLE_VAL(e) : NULL); +} + +void +PQremoveNotify(PQNotifyList *nPtr) +{ + nPtr->valid = 0; /* remove later */ +} + +void +PQappendNotify(char *relname, int pid) +{ + PQNotifyList *p; + + if (pqNotifyList == NULL) + pqNotifyList = DLNewList(); + + p = (PQNotifyList*)pbuf_alloc(sizeof(PQNotifyList)); + strncpy(p->relname, relname, NAMEDATALEN); + p->be_pid = pid; + p->valid = 1; + DLAddTail(pqNotifyList, DLNewElem(p)); +} |