mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			513 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			513 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*-------------------------------------------------------------------------
 | 
						|
 *
 | 
						|
 * 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.3 1996/11/06 08:48:29 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 <string.h>
 | 
						|
#include <sys/types.h>
 | 
						|
 | 
						|
#include <postgres.h>
 | 
						|
 | 
						|
#include <libpq/libpq.h>		/* where the declarations go */
 | 
						|
#include <utils/exc.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;
 | 
						|
}
 | 
						|
 |