]> granicus.if.org Git - postgresql/blob - src/backend/libpq/be-dumpdata.c
From: Phil Thompson <phil@river-bank.demon.co.uk>
[postgresql] / src / backend / libpq / be-dumpdata.c
1 /*-------------------------------------------------------------------------
2  *
3  * be-dumpdata.c--
4  *        support for collection of returned tuples from an internal
5  *        PQ call into a backend buffer.
6  *
7  * Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.10 1998/01/26 01:41:05 scrappy Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
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
24  *
25  * NOTES
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.
30  *
31  */
32 #include <string.h>
33
34 #include <postgres.h>
35
36 #include <lib/dllist.h>
37 #include <libpq/libpq.h>
38 #include <access/heapam.h>
39 #include <access/htup.h>
40 #include <storage/buf.h>
41 #include <utils/memutils.h>
42 #include <fmgr.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>
49
50 /* ----------------
51  *              backend portal stack for recursive PQexec calls
52  * ----------------
53  */
54 static Dllist *be_portalstack;
55
56 /* ----------------
57  *              be_portalinit - initialize backend portal administration
58  *
59  *              This is called once from InitPostgres() to initialize
60  *              the portal stack.
61  * ----------------
62  */
63 void
64 be_portalinit(void)
65 {
66         be_portalstack = DLNewList();
67 }
68
69 /* ----------------
70  *              be_portalpush - add a portal to the top of the portal stack
71  *
72  *              used by BeginCommand()
73  * ----------------
74  */
75 void
76 be_portalpush(PortalEntry *entry)
77 {
78         DLAddTail(be_portalstack, DLNewElem(entry));
79 }
80
81 /* ----------------
82  *              be_portalpop - remove the portal on the top of the stack & return it
83  *
84  *              used by PQexec()
85  * ----------------
86  */
87 PortalEntry *
88 be_portalpop(void)
89 {
90         PortalEntry *p;
91         Dlelem     *elt;
92
93         elt = DLRemTail(be_portalstack);
94
95         p = (elt ? (PortalEntry *) DLE_VAL(elt) : NULL);
96         DLFreeElem(elt);
97         return p;
98
99
100 }
101
102 /* ----------------
103  *              be_currentportal - return the top portal on the portal stack
104  *
105  *              used by be_printtup()
106  * ----------------
107  */
108 PortalEntry *
109 be_currentportal(void)
110 {
111         Dlelem     *elt;
112
113         elt = DLGetTail(be_portalstack);
114         return (elt ? (PortalEntry *) DLE_VAL(elt) : NULL);
115 }
116
117 /* ----------------
118  *              be_newportal - return a new portal.
119  *
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.
124  *
125  *              used by BeginCommand()
126  * ----------------
127  */
128
129 static Oid      be_portaloid;
130 static u_int be_portalcnt = 0;
131
132 PortalEntry *
133 be_newportal(void)
134 {
135         PortalEntry *entry;
136         char            buf[PortalNameLength];
137
138         /* ----------------
139          *      generate a new name
140          * ----------------
141          */
142         if (be_portalcnt == 0)
143                 be_portaloid = newoid();
144         be_portalcnt++;
145         sprintf(buf, "be_%d_%d", be_portaloid, be_portalcnt);
146
147         /* ----------------
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.
153          * ----------------
154          */
155         entry = pbuf_setup(buf);
156         entry->portalcxt = (Pointer) CurrentMemoryContext;
157
158         return entry;
159 }
160
161 /* ----------------
162  *              be_typeinit - initialize backend portal expected to hold
163  *                                              query results.
164  *
165  *              used by BeginCommand()
166  * ----------------
167  */
168 void
169 be_typeinit(PortalEntry *entry,
170                         TupleDesc tupDesc,
171                         int natts)
172 {
173         PortalBuffer *portal;
174         GroupBuffer *group;
175         int                     i;
176         AttributeTupleForm *attrs = tupDesc->attrs;
177
178         /* ----------------
179          *      add a new portal group to the portal
180          * ----------------
181          */
182         portal = entry->portal;
183         portal->no_groups++;
184         portal->groups = group = pbuf_addGroup(portal);
185         group->no_fields = natts;
186
187         /* ----------------
188          *      initialize portal group type info
189          * ----------------
190          */
191         if (natts > 0)
192         {
193                 group->types = pbuf_addTypes(natts);
194                 for (i = 0; i < natts; ++i)
195                 {
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;
199                 }
200         }
201 }
202
203 /* ----------------
204  *              be_printtup - add a tuple to a backend portal
205  *
206  *              used indirectly by ExecRetrieve()
207  *
208  *              This code is pretty much copied from printtup(), dump_type()
209  *              and dump_data().  -cim 2/12/91
210  * ----------------
211  */
212 void
213 be_printtup(HeapTuple tuple, TupleDesc typeinfo)
214 {
215         int                     i;
216         Datum           attr;
217         bool            isnull;
218         Oid                     typoutput;
219
220         PortalEntry *entry = NULL;
221         PortalBuffer *portal = NULL;
222         GroupBuffer *group = NULL;
223         TupleBlock *tuples = NULL;
224         char      **values;
225         int                *lengths;
226
227         MemoryContext savecxt;
228
229         /* ----------------
230          *      get the current portal and group
231          * ----------------
232          */
233         entry = be_currentportal();
234         portal = entry->portal;
235         group = portal->groups;
236
237         /* ----------------
238          *      switch to the portal's memory context so that
239          *      the tuples we allocate are returned to the user.
240          * ----------------
241          */
242         savecxt = MemoryContextSwitchTo((MemoryContext) entry->portalcxt);
243
244         /* ----------------
245          *      If no tuple block yet, allocate one.
246          *      If the current block is full, allocate another one.
247          * ----------------
248          */
249         if (group->tuples == NULL)
250         {
251                 tuples = group->tuples = pbuf_addTuples();
252                 tuples->tuple_index = 0;
253         }
254         else
255         {
256                 tuples = group->tuples;
257                 /* walk to the end of the linked list of TupleBlocks */
258                 while (tuples->next)
259                         tuples = tuples->next;
260
261                 /*
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
264                  * chain
265                  */
266
267                 if (tuples->tuple_index == TupleBlockSize)
268                 {
269                         tuples->next = pbuf_addTuples();
270                         tuples = tuples->next;
271                         tuples->tuple_index = 0;
272                 }
273         }
274
275         /* ----------------
276          *      Allocate space for a tuple.
277          * ----------------
278          */
279         tuples->values[tuples->tuple_index] = pbuf_addTuple(tuple->t_natts);
280         tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(tuple->t_natts);
281         /* ----------------
282          *      copy printable representations of the tuple's attributes
283          *      to the portal.
284          *
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)
293          *      -cim 2/11/91
294          * ----------------
295          */
296
297         values = tuples->values[tuples->tuple_index];
298         lengths = tuples->lengths[tuples->tuple_index];
299
300         for (i = 0; i < tuple->t_natts; i++)
301         {
302                 attr = heap_getattr(tuple, InvalidBuffer, i + 1, typeinfo, &isnull);
303                 typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
304
305                 lengths[i] = typeinfo->attrs[i]->attlen;
306
307                 if (lengths[i] == -1)   /* variable length attribute */
308                         if (!isnull)
309                                 lengths[i] = VARSIZE(attr) - VARHDRSZ;
310                         else
311                                 lengths[i] = 0;
312
313                 if (!isnull && OidIsValid(typoutput))
314                 {
315                         values[i] = fmgr(typoutput, attr, gettypelem(typeinfo->attrs[i]->atttypid));
316                 }
317                 else
318                         values[i] = NULL;
319
320         }
321
322         /* ----------------
323          *      increment tuple group counters
324          * ----------------
325          */
326         portal->no_tuples++;
327         group->no_tuples++;
328         tuples->tuple_index++;
329
330         /* ----------------
331          *      return to the original memory context
332          * ----------------
333          */
334         MemoryContextSwitchTo(savecxt);
335 }