/*------------------------------------------------------------------------- * * 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.4 1996/11/06 08:48:28 scrappy 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 * 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 /* for sprintf() */ #include #include #include #include /* where the declarations go */ #include /* ---------------------------------------------------------------- * 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) { (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 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)); }