diff options
Diffstat (limited to 'src/backend/libpq/be-dumpdata.c')
-rw-r--r-- | src/backend/libpq/be-dumpdata.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/src/backend/libpq/be-dumpdata.c b/src/backend/libpq/be-dumpdata.c new file mode 100644 index 00000000000..fb6b90c1495 --- /dev/null +++ b/src/backend/libpq/be-dumpdata.c @@ -0,0 +1,323 @@ +/*------------------------------------------------------------------------- + * + * be-dumpdata.c-- + * support for collection of returned tuples from an internal + * PQ call into a backend buffer. + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +/* + * INTERFACE ROUTINES + * be_portalinit - initialize backend portal administration + * be_portalpush - add a portal to the top of the portal stack + * be_portalpop - remove portal on the top of the stack & return it + * be_currentportal - return the top portal on the portal stack + * be_newportal - return a new portal. + * be_portalinit - initialize backend portal expected to hold results. + * be_printtup - add a tuple to a backend portal + * + * NOTES + * Since backend user-defined operators can call queries + * which in turn call user-defined operators can call queries... + * we have to keep track of portals on a stack. BeginCommand() + * puts portals on the stack and the PQ functions remove them. + * + */ +#include "postgres.h" + +#include "lib/dllist.h" +#include "libpq/libpq-be.h" + +#include "access/heapam.h" +#include "access/htup.h" +#include "storage/buf.h" +#include "utils/memutils.h" +#include "utils/palloc.h" +#include "fmgr.h" +#include "utils/mcxt.h" +#include "utils/elog.h" +#include "utils/exc.h" + +#include "utils/syscache.h" +#include "catalog/pg_type.h" +#include "catalog/catalog.h" +#include "access/printtup.h" + +/* ---------------- + * backend portal stack for recursive PQexec calls + * ---------------- + */ +static Dllist *be_portalstack; + +/* ---------------- + * be_portalinit - initialize backend portal administration + * + * This is called once from InitPostgres() to initialize + * the portal stack. + * ---------------- + */ +void +be_portalinit() +{ + be_portalstack = DLNewList(); +} + +/* ---------------- + * be_portalpush - add a portal to the top of the portal stack + * + * used by BeginCommand() + * ---------------- + */ +void +be_portalpush(PortalEntry *entry) +{ + DLAddTail(be_portalstack, DLNewElem(entry)); +} + +/* ---------------- + * be_portalpop - remove the portal on the top of the stack & return it + * + * used by PQexec() + * ---------------- + */ +PortalEntry * +be_portalpop() +{ + PortalEntry *p; + Dlelem* elt; + elt = DLRemTail(be_portalstack); + + p = (elt ? (PortalEntry*)DLE_VAL(elt) : NULL); + DLFreeElem(elt); + return p; + + +} + +/* ---------------- + * be_currentportal - return the top portal on the portal stack + * + * used by be_printtup() + * ---------------- + */ +PortalEntry * +be_currentportal() +{ + Dlelem* elt; + elt = DLGetTail(be_portalstack); + return (elt ? (PortalEntry*)DLE_VAL(elt) : NULL); +} + +/* ---------------- + * be_newportal - return a new portal. + * + * If the user-defined function does not specify a portal name, + * we generate a unique one. Names are generated from a combination + * of a postgres oid and an integer counter which is incremented + * every time we ask for a local portal. + * + * used by BeginCommand() + * ---------------- + */ + +static Oid be_portaloid; +static u_int be_portalcnt = 0; + +PortalEntry * +be_newportal() +{ + PortalEntry *entry; + char buf[PortalNameLength]; + + /* ---------------- + * generate a new name + * ---------------- + */ + if (be_portalcnt == 0) + be_portaloid = newoid(); + be_portalcnt++; + sprintf(buf, "be_%d_%d", be_portaloid, be_portalcnt); + + /* ---------------- + * initialize the new portal entry and keep track + * of the current memory context for be_printtup(). + * This is important - otherwise whatever we allocate + * will go away and the contents of the portal after + * PQexec() returns will be meaningless. + * ---------------- + */ + entry = pbuf_setup(buf); + entry->portalcxt = (Pointer) CurrentMemoryContext; + + return entry; +} + +/* ---------------- + * be_typeinit - initialize backend portal expected to hold + * query results. + * + * used by BeginCommand() + * ---------------- + */ +void +be_typeinit(PortalEntry *entry, + TupleDesc tupDesc, + int natts) +{ + PortalBuffer *portal; + GroupBuffer *group; + int i; + AttributeTupleForm *attrs = tupDesc->attrs; + + /* ---------------- + * add a new portal group to the portal + * ---------------- + */ + portal = entry->portal; + portal->no_groups++; + portal->groups = group = pbuf_addGroup(portal); + group->no_fields = natts; + + /* ---------------- + * initialize portal group type info + * ---------------- + */ + if (natts > 0) { + group->types = pbuf_addTypes(natts); + for (i = 0; i < natts; ++i) { + strncpy(group->types[i].name, attrs[i]->attname.data, NAMEDATALEN); + group->types[i].adtid = attrs[i]->atttypid; + group->types[i].adtsize = attrs[i]->attlen; + } + } +} + +/* ---------------- + * be_printtup - add a tuple to a backend portal + * + * used indirectly by ExecRetrieve() + * + * This code is pretty much copied from printtup(), dump_type() + * and dump_data(). -cim 2/12/91 + * ---------------- + */ +void +be_printtup(HeapTuple tuple, TupleDesc typeinfo) +{ + int i; + char *attr; + bool isnull; + Oid typoutput; + + PortalEntry *entry = NULL; + PortalBuffer *portal = NULL; + GroupBuffer *group = NULL ; + TupleBlock *tuples = NULL; + char **values; + int *lengths; + + MemoryContext savecxt; + + /* ---------------- + * get the current portal and group + * ---------------- + */ + entry = be_currentportal(); + portal = entry->portal; + group = portal->groups; + + /* ---------------- + * switch to the portal's memory context so that + * the tuples we allocate are returned to the user. + * ---------------- + */ + savecxt = MemoryContextSwitchTo((MemoryContext)entry->portalcxt); + + /* ---------------- + * If no tuple block yet, allocate one. + * If the current block is full, allocate another one. + * ---------------- + */ + if (group->tuples == NULL) { + tuples = group->tuples = pbuf_addTuples(); + tuples->tuple_index = 0; + } else { + tuples = group->tuples; + /* walk to the end of the linked list of TupleBlocks */ + while (tuples->next) + tuples = tuples->next; + /* now, tuples is the last TupleBlock, check to see if it is full. + If so, allocate a new TupleBlock and add it to the end of + the chain */ + + if (tuples->tuple_index == TupleBlockSize) { + tuples->next = pbuf_addTuples(); + tuples = tuples->next; + tuples->tuple_index = 0; + } + } + + /* ---------------- + * Allocate space for a tuple. + * ---------------- + */ + tuples->values[tuples->tuple_index] = pbuf_addTuple(tuple->t_natts); + tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(tuple->t_natts); + /* ---------------- + * copy printable representations of the tuple's attributes + * to the portal. + * + * This seems silly, because the user's function which is calling + * PQexec() or PQfn() will probably just convert this back into the + * internal form anyways, but the point here is to provide a uniform + * libpq interface and this is how the fe libpq interface currently + * works. Pretty soon we'll have to add code to let the fe or be + * select the desired data representation and then deal with that. + * This should not be too hard, as there already exist typrecieve() + * and typsend() procedures for user-defined types (see pg_type.h) + * -cim 2/11/91 + * ---------------- + */ + + values = tuples->values[tuples->tuple_index]; + lengths = tuples->lengths[tuples->tuple_index]; + + for (i = 0; i < tuple->t_natts; i++) { + attr = heap_getattr(tuple, InvalidBuffer, i+1, typeinfo, &isnull); + typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid); + + lengths[i] = typeinfo->attrs[i]->attlen; + + if (lengths[i] == -1) /* variable length attribute */ + if (!isnull) + lengths[i] = VARSIZE(attr)-VARHDRSZ; + else + lengths[i] = 0; + + if (!isnull && OidIsValid(typoutput)) { + values[i] = fmgr(typoutput, attr, gettypelem(typeinfo->attrs[i]->atttypid)); + } else + values[i] = NULL; + + } + + /* ---------------- + * increment tuple group counters + * ---------------- + */ + portal->no_tuples++; + group->no_tuples++; + tuples->tuple_index++; + + /* ---------------- + * return to the original memory context + * ---------------- + */ + MemoryContextSwitchTo(savecxt); +} |