/*------------------------------------------------------------------------- * * portal.c * generalized portal support routines * * Copyright (c) 1994, Regents of the University of California * * $Id: portal.c,v 1.21 1999/04/25 03:19:20 tgl 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 #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) { 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); }