1 /*-------------------------------------------------------------------------
4 * support for collection of returned tuples from an internal
5 * PQ call into a backend buffer.
7 * Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.9 1997/09/12 04:07:50 momjian Exp $
13 *-------------------------------------------------------------------------
17 * be_portalinit - initialize backend portal administration
18 * be_portalpush - add a portal to the top of the portal stack
19 * be_portalpop - remove portal on the top of the stack & return it
20 * be_currentportal - return the top portal on the portal stack
21 * be_newportal - return a new portal.
22 * be_portalinit - initialize backend portal expected to hold results.
23 * be_printtup - add a tuple to a backend portal
26 * Since backend user-defined operators can call queries
27 * which in turn call user-defined operators can call queries...
28 * we have to keep track of portals on a stack. BeginCommand()
29 * puts portals on the stack and the PQ functions remove them.
36 #include <lib/dllist.h>
37 #include <libpq/libpq-be.h>
38 #include <access/heapam.h>
39 #include <access/htup.h>
40 #include <storage/buf.h>
41 #include <utils/memutils.h>
43 #include <utils/mcxt.h>
44 #include <utils/exc.h>
45 #include <utils/syscache.h>
46 #include <catalog/pg_type.h>
47 #include <catalog/catalog.h>
48 #include <access/printtup.h>
51 * backend portal stack for recursive PQexec calls
54 static Dllist *be_portalstack;
57 * be_portalinit - initialize backend portal administration
59 * This is called once from InitPostgres() to initialize
66 be_portalstack = DLNewList();
70 * be_portalpush - add a portal to the top of the portal stack
72 * used by BeginCommand()
76 be_portalpush(PortalEntry *entry)
78 DLAddTail(be_portalstack, DLNewElem(entry));
82 * be_portalpop - remove the portal on the top of the stack & return it
93 elt = DLRemTail(be_portalstack);
95 p = (elt ? (PortalEntry *) DLE_VAL(elt) : NULL);
103 * be_currentportal - return the top portal on the portal stack
105 * used by be_printtup()
109 be_currentportal(void)
113 elt = DLGetTail(be_portalstack);
114 return (elt ? (PortalEntry *) DLE_VAL(elt) : NULL);
118 * be_newportal - return a new portal.
120 * If the user-defined function does not specify a portal name,
121 * we generate a unique one. Names are generated from a combination
122 * of a postgres oid and an integer counter which is incremented
123 * every time we ask for a local portal.
125 * used by BeginCommand()
129 static Oid be_portaloid;
130 static u_int be_portalcnt = 0;
136 char buf[PortalNameLength];
139 * generate a new name
142 if (be_portalcnt == 0)
143 be_portaloid = newoid();
145 sprintf(buf, "be_%d_%d", be_portaloid, be_portalcnt);
148 * initialize the new portal entry and keep track
149 * of the current memory context for be_printtup().
150 * This is important - otherwise whatever we allocate
151 * will go away and the contents of the portal after
152 * PQexec() returns will be meaningless.
155 entry = pbuf_setup(buf);
156 entry->portalcxt = (Pointer) CurrentMemoryContext;
162 * be_typeinit - initialize backend portal expected to hold
165 * used by BeginCommand()
169 be_typeinit(PortalEntry *entry,
173 PortalBuffer *portal;
176 AttributeTupleForm *attrs = tupDesc->attrs;
179 * add a new portal group to the portal
182 portal = entry->portal;
184 portal->groups = group = pbuf_addGroup(portal);
185 group->no_fields = natts;
188 * initialize portal group type info
193 group->types = pbuf_addTypes(natts);
194 for (i = 0; i < natts; ++i)
196 strncpy(group->types[i].name, attrs[i]->attname.data, NAMEDATALEN);
197 group->types[i].adtid = attrs[i]->atttypid;
198 group->types[i].adtsize = attrs[i]->attlen;
204 * be_printtup - add a tuple to a backend portal
206 * used indirectly by ExecRetrieve()
208 * This code is pretty much copied from printtup(), dump_type()
209 * and dump_data(). -cim 2/12/91
213 be_printtup(HeapTuple tuple, TupleDesc typeinfo)
220 PortalEntry *entry = NULL;
221 PortalBuffer *portal = NULL;
222 GroupBuffer *group = NULL;
223 TupleBlock *tuples = NULL;
227 MemoryContext savecxt;
230 * get the current portal and group
233 entry = be_currentportal();
234 portal = entry->portal;
235 group = portal->groups;
238 * switch to the portal's memory context so that
239 * the tuples we allocate are returned to the user.
242 savecxt = MemoryContextSwitchTo((MemoryContext) entry->portalcxt);
245 * If no tuple block yet, allocate one.
246 * If the current block is full, allocate another one.
249 if (group->tuples == NULL)
251 tuples = group->tuples = pbuf_addTuples();
252 tuples->tuple_index = 0;
256 tuples = group->tuples;
257 /* walk to the end of the linked list of TupleBlocks */
259 tuples = tuples->next;
262 * now, tuples is the last TupleBlock, check to see if it is full.
263 * If so, allocate a new TupleBlock and add it to the end of the
267 if (tuples->tuple_index == TupleBlockSize)
269 tuples->next = pbuf_addTuples();
270 tuples = tuples->next;
271 tuples->tuple_index = 0;
276 * Allocate space for a tuple.
279 tuples->values[tuples->tuple_index] = pbuf_addTuple(tuple->t_natts);
280 tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(tuple->t_natts);
282 * copy printable representations of the tuple's attributes
285 * This seems silly, because the user's function which is calling
286 * PQexec() or PQfn() will probably just convert this back into the
287 * internal form anyways, but the point here is to provide a uniform
288 * libpq interface and this is how the fe libpq interface currently
289 * works. Pretty soon we'll have to add code to let the fe or be
290 * select the desired data representation and then deal with that.
291 * This should not be too hard, as there already exist typrecieve()
292 * and typsend() procedures for user-defined types (see pg_type.h)
297 values = tuples->values[tuples->tuple_index];
298 lengths = tuples->lengths[tuples->tuple_index];
300 for (i = 0; i < tuple->t_natts; i++)
302 attr = heap_getattr(tuple, InvalidBuffer, i + 1, typeinfo, &isnull);
303 typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
305 lengths[i] = typeinfo->attrs[i]->attlen;
307 if (lengths[i] == -1) /* variable length attribute */
309 lengths[i] = VARSIZE(attr) - VARHDRSZ;
313 if (!isnull && OidIsValid(typoutput))
315 values[i] = fmgr(typoutput, attr, gettypelem(typeinfo->attrs[i]->atttypid));
323 * increment tuple group counters
328 tuples->tuple_index++;
331 * return to the original memory context
334 MemoryContextSwitchTo(savecxt);