diff options
Diffstat (limited to 'src/backend/libpq/portalbuf.c')
-rw-r--r-- | src/backend/libpq/portalbuf.c | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/src/backend/libpq/portalbuf.c b/src/backend/libpq/portalbuf.c new file mode 100644 index 00000000000..f927e268edf --- /dev/null +++ b/src/backend/libpq/portalbuf.c @@ -0,0 +1,511 @@ +/*------------------------------------------------------------------------- + * + * 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.1.1.1 1996/07/09 06:21:30 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 <sys/types.h> +#include "c.h" + +#include "libpq/libpq.h" /* where the declarations go */ +#include "utils/exc.h" +#include "utils/palloc.h" + +PortalEntry** portals = (PortalEntry**) NULL; +size_t portals_array_size = 0; + +/* portals array memory is malloc'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**)malloc(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-1); + entry->name[PortalNameLength-1] = '\0'; +} + +/* -------------------------------- + * 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; +} + |