/*------------------------------------------------------------------------- * * portalbuf.c-- * portal buffer support routines for src/libpq/portal.c * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portalbuf.c,v 1.9 1997/12/09 03:10:45 scrappy Exp $ * *------------------------------------------------------------------------- */ /* * INTERFACE ROUTINES * pbuf_alloc - allocate memory for libpq routines * pbuf_free - free memory for libpq routines * pbuf_addPortal - Allocate a new portal buffer * pbuf_addGroup - Add a new tuple group to the portal * pbuf_addTypes - Allocate n type blocks * pbuf_addTuples - Allocate a tuple block * pbuf_addTuple - Allocate a tuple of n fields (attributes) * pbuf_addValues - Allocate n bytes for a value * pbuf_addEntry - Allocate a portal entry * pbuf_freeEntry - Free a portal entry in the portal table * pbuf_freeTypes - Free up the space used by a portal * pbuf_freeTuples - free space used by tuple block * pbuf_freeGroup - free space used by group, types and tuples * pbuf_freePortal - free space used by portal and portal's group * pbuf_getIndex - Return the index of the portal entry * pbuf_setup - Set up a portal for dumping data * pbuf_close - Close a portal, remove it from the portal table * pbuf_findGroup - Return group given the group_index * pbuf_findFnumber - Return field index of a given field within a group * pbuf_findFname - Find the field name given the field index * pbuf_checkFnumber - signal an error if field number is out of bounds * * 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 /* where the declarations go */ #include PortalEntry **portals = (PortalEntry **) NULL; size_t portals_array_size = 0; /* portals array memory is palloc'd instead of using MemoryContexts */ /* since it will be used by both front and backend programs*/ /* GlobalMemory portals_mmcxt = (GlobalMemory) NULL; */ /* ------------------------------- * portals_realloc -- * grow the size of the portals array by size * * also ensures that elements are initially NULL */ static void portals_realloc(size_t size) { size_t oldsize; int i; PortalEntry **newp; oldsize = portals_array_size; portals_array_size += size; if (portals) newp = (PortalEntry **) realloc(portals, portals_array_size * sizeof(PortalEntry *)); else newp = (PortalEntry **) palloc(portals_array_size * sizeof(PortalEntry *)); if (newp) portals = newp; else libpq_raise(&PortalError, form("Cannot alloc more memory in portals_realloc")); for (i = oldsize; i < portals_array_size; i++) portals[i] = (PortalEntry *) NULL; } /* -------------------------------- * pbuf_alloc - allocate memory for portal buffers * * remember: palloc() in the backend uses the postgres MemoryContext * library and palloc() in the frontend (fe-pqstubs.c) calls malloc(). * -------------------------------- */ caddr_t pbuf_alloc(size_t size) { caddr_t addr; if (size <= 0) libpq_raise(&MemoryError, form("Invalid argument to pbuf_alloc().")); addr = (caddr_t) palloc(size); if (addr == (caddr_t) NULL) libpq_raise(&MemoryError, form("Cannot Allocate space.")); return (addr); } /* -------------------------------- * pbuf_free - free memory for portal buffers * * remember: pfree() in the backend uses the postgres MemoryContext * library and pfree() in the frontend (fe-pqstubs.c) calls free(). * -------------------------------- */ void pbuf_free(caddr_t pointer) { if (pointer) pfree(pointer); else libpq_raise(&MemoryError, form("Tried to free NULL memory pointer")); } /* -------------------------------- * pbuf_addPortal - Allocate a new portal buffer * -------------------------------- */ PortalBuffer * pbuf_addPortal() { PortalBuffer *portal; portal = (PortalBuffer *) pbuf_alloc(sizeof(PortalBuffer)); portal->rule_p = 0; portal->no_tuples = 0; portal->no_groups = 0; portal->groups = NULL; return (portal); } /* -------------------------------- * pbuf_addGroup - Add a new tuple group to the portal * -------------------------------- */ GroupBuffer * pbuf_addGroup(PortalBuffer *portal) { GroupBuffer *group, *group1; group = (GroupBuffer *) pbuf_alloc(sizeof(GroupBuffer)); /* Initialize the new group buffer. */ group->no_tuples = 0; group->no_fields = 0; group->types = NULL; group->tuples = NULL; group->next = NULL; if ((group1 = portal->groups) == NULL) portal->groups = group; else { while (group1->next != NULL) group1 = group1->next; group1->next = group; } return (group); } /* -------------------------------- * pbuf_addTypes - Allocate n type blocks * -------------------------------- */ TypeBlock * pbuf_addTypes(int n) { TypeBlock *types; types = (TypeBlock *) pbuf_alloc(n * sizeof(TypeBlock)); return (types); } /* -------------------------------- * pbuf_addTuples - Allocate a tuple block * -------------------------------- */ TupleBlock * pbuf_addTuples() { TupleBlock *tuples; tuples = (TupleBlock *) pbuf_alloc(sizeof(TupleBlock)); tuples->next = NULL; tuples->tuple_index = 0; return (tuples); } /* -------------------------------- * pbuf_addTuple - Allocate a tuple of n fields (attributes) * -------------------------------- */ char ** pbuf_addTuple(int n) { return (char **) pbuf_alloc(n * sizeof(char *)); } /* -------------------------------- * pbuf_addTupleValueLengths - Allocate a tuple of n lengths (attributes) * -------------------------------- */ int * pbuf_addTupleValueLengths(int n) { return (int *) pbuf_alloc(n * sizeof(int)); } /* -------------------------------- * pbuf_addValues - Allocate n bytes for a value * -------------------------------- */ char * pbuf_addValues(int n) { return pbuf_alloc(n); } /* -------------------------------- * pbuf_addEntry - Allocate a portal entry * -------------------------------- */ PortalEntry * pbuf_addEntry() { return (PortalEntry *) pbuf_alloc(sizeof(PortalEntry)); } /* -------------------------------- * pbuf_freeEntry - Free a portal entry in the portal table * the portal is freed separately. * -------------------------------- */ void pbuf_freeEntry(int i) { if (portals) { pbuf_free((caddr_t) portals[i]); portals[i] = NULL; } } /* -------------------------------- * pbuf_freeTypes - Free up the space used by a portal * -------------------------------- */ void pbuf_freeTypes(TypeBlock *types) { pbuf_free((caddr_t) types); } /* -------------------------------- * pbuf_freeTuples - free space used by tuple block * -------------------------------- */ void pbuf_freeTuples(TupleBlock *tuples, int no_tuples, int no_fields) { int i, j; if (no_tuples > TupleBlockSize) { pbuf_freeTuples(tuples->next, no_tuples - TupleBlockSize, no_fields); no_tuples = TupleBlockSize; } /* For each tuple, free all its attribute values. */ for (i = 0; i < no_tuples; i++) { for (j = 0; j < no_fields; j++) if (tuples->values[i][j] != NULL) pbuf_free((caddr_t) tuples->values[i][j]); if (tuples->lengths[i]) pbuf_free((caddr_t) tuples->lengths[i]); if (tuples->values[i]) pbuf_free((caddr_t) tuples->values[i]); } pbuf_free((caddr_t) tuples); } /* -------------------------------- * pbuf_freeGroup - free space used by group, types and tuples * -------------------------------- */ void pbuf_freeGroup(GroupBuffer *group) { if (group->next != NULL) pbuf_freeGroup(group->next); if (group->types != NULL) pbuf_freeTypes(group->types); if (group->tuples != NULL) pbuf_freeTuples(group->tuples, group->no_tuples, group->no_fields); pbuf_free((caddr_t) group); } /* -------------------------------- * pbuf_freePortal - free space used by portal and portal's group * -------------------------------- */ void pbuf_freePortal(PortalBuffer *portal) { if (portal->groups != NULL) pbuf_freeGroup(portal->groups); pbuf_free((caddr_t) portal); } /* -------------------------------- * pbuf_getIndex - Return the index of the portal entry * note: portals[] maps portal names to portal buffers. * -------------------------------- */ int pbuf_getIndex(char *pname) { int i; if (portals) { for (i = 0; i < portals_array_size; i++) if (portals[i] != NULL && strncmp(portals[i]->name, pname, PortalNameLength) == 0) return i; } return (-1); } /* -------------------------------- * pbuf_setportalname - assign a user given name to a portal * -------------------------------- */ void pbuf_setportalinfo(PortalEntry *entry, char *pname) { if (entry) StrNCpy(entry->name, pname, PortalNameLength); } /* -------------------------------- * pbuf_setup - Set up a portal for dumping data * -------------------------------- */ PortalEntry * pbuf_setup(char *pname) { int i; if (!portals) /* the portals array has not been * allocated yet */ { /* allocate portals[] array here */ portals_realloc(PORTALS_INITIAL_SIZE); } /* If a portal with the same name already exists, close it. */ /* else look for an empty entry in the portal table. */ if ((i = pbuf_getIndex(pname)) != -1) pbuf_freePortal(portals[i]->portal); else { for (i = 0; i < portals_array_size; i++) if (portals[i] == NULL) break; /* If the portal table is full, enlarge it */ if (i >= portals_array_size) portals_realloc(PORTALS_GROW_BY); portals[i] = pbuf_addEntry(); strncpy(portals[i]->name, pname, PortalNameLength); } portals[i]->portal = pbuf_addPortal(); portals[i]->portalcxt = NULL; portals[i]->result = NULL; return portals[i]; } /* -------------------------------- * pbuf_close - Close a portal, remove it from the portal table * and free up the space * -------------------------------- */ void pbuf_close(char *pname) { int i; if ((i = pbuf_getIndex(pname)) == -1) libpq_raise(&PortalError, form("Portal %s does not exist.", pname)); pbuf_freePortal(portals[i]->portal); pbuf_freeEntry(i); } /* -------------------------------- * pbuf_findGroup - Return the group given the group_index * -------------------------------- */ GroupBuffer * pbuf_findGroup(PortalBuffer *portal, int group_index) { GroupBuffer *group; group = portal->groups; while (group_index > 0 && group != NULL) { group = group->next; group_index--; } if (group == NULL) libpq_raise(&PortalError, form("Group index %d out of bound.", group_index)); return (group); } /* -------------------------------- * pbuf_findFnumber - Return the field index of a given field within a group * -------------------------------- */ int pbuf_findFnumber(GroupBuffer *group, char *field_name) { TypeBlock *types; int i; types = group->types; for (i = 0; i < group->no_fields; i++) if (strncmp(types[i].name, field_name, NAMEDATALEN) == 0) return (i); libpq_raise(&PortalError, form("Field-name %s does not exist.", field_name)); /* not reached, here to make compiler happy */ return 0; } /* -------------------------------- * pbuf_checkFnumber - signal an error if field number is out of bounds * -------------------------------- */ void pbuf_checkFnumber(GroupBuffer *group, int field_number) { if (field_number < 0 || field_number >= group->no_fields) libpq_raise(&PortalError, form("Field number %d out of bound.", field_number)); } /* -------------------------------- * pbuf_findFname - Find the field name given the field index * -------------------------------- */ char * pbuf_findFname(GroupBuffer *group, int field_number) { pbuf_checkFnumber(group, field_number); return (group->types[field_number]).name; }