OSDN Git Service

Change error messages to oids come out as %u and not %d. Change has no
[pg-rex/syncrep.git] / 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  *  $Id: be-dumpdata.c,v 1.23 1999/05/10 00:45:08 momjian Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 /*
14  * INTERFACE ROUTINES
15  *              be_portalinit    - initialize backend portal administration
16  *              be_portalpush    - add a portal to the top of the portal stack
17  *              be_portalpop     - remove portal on the top of the stack & return it
18  *              be_currentportal - return the top portal on the portal stack
19  *              be_newportal     - return a new portal.
20  *              be_portalinit    - initialize backend portal expected to hold results.
21  *              be_printtup              - add a tuple to a backend portal
22  *
23  * NOTES
24  *              Since backend user-defined operators can call queries
25  *              which in turn call user-defined operators can call queries...
26  *              we have to keep track of portals on a stack.  BeginCommand()
27  *              puts portals on the stack and the PQ functions remove them.
28  *
29  */
30 #include <string.h>
31
32 #include <postgres.h>
33
34 #include <lib/dllist.h>
35 #include <libpq/libpq.h>
36 #include <access/heapam.h>
37 #include <access/htup.h>
38 #include <storage/buf.h>
39 #include <utils/memutils.h>
40 #include <fmgr.h>
41 #include <utils/mcxt.h>
42 #include <utils/exc.h>
43 #include <utils/syscache.h>
44 #include <catalog/pg_type.h>
45 #include <catalog/catalog.h>
46 #include <access/printtup.h>
47
48 /* ----------------
49  *              backend portal stack for recursive PQexec calls
50  * ----------------
51  */
52 static Dllist *be_portalstack;
53
54 /* ----------------
55  *              be_portalinit - initialize backend portal administration
56  *
57  *              This is called once from InitPostgres() to initialize
58  *              the portal stack.
59  * ----------------
60  */
61 void
62 be_portalinit(void)
63 {
64         be_portalstack = DLNewList();
65 }
66
67 /* ----------------
68  *              be_portalpush - add a portal to the top of the portal stack
69  *
70  *              used by BeginCommand()
71  * ----------------
72  */
73 void
74 be_portalpush(PortalEntry *entry)
75 {
76         DLAddTail(be_portalstack, DLNewElem(entry));
77 }
78
79 /* ----------------
80  *              be_portalpop - remove the portal on the top of the stack & return it
81  *
82  *              used by PQexec()
83  * ----------------
84  */
85 PortalEntry *
86 be_portalpop(void)
87 {
88         PortalEntry *p;
89         Dlelem     *elt;
90
91         elt = DLRemTail(be_portalstack);
92
93         p = (elt ? (PortalEntry *) DLE_VAL(elt) : NULL);
94         DLFreeElem(elt);
95         return p;
96
97
98 }
99
100 /* ----------------
101  *              be_currentportal - return the top portal on the portal stack
102  *
103  *              used by be_printtup()
104  * ----------------
105  */
106 PortalEntry *
107 be_currentportal(void)
108 {
109         Dlelem     *elt;
110
111         elt = DLGetTail(be_portalstack);
112         return elt ? (PortalEntry *) DLE_VAL(elt) : NULL;
113 }
114
115 /* ----------------
116  *              be_newportal - return a new portal.
117  *
118  *              If the user-defined function does not specify a portal name,
119  *              we generate a unique one.  Names are generated from a combination
120  *              of a postgres oid and an integer counter which is incremented
121  *              every time we ask for a local portal.
122  *
123  *              used by BeginCommand()
124  * ----------------
125  */
126
127 static Oid      be_portaloid;
128 static u_int be_portalcnt = 0;
129
130 PortalEntry *
131 be_newportal(void)
132 {
133         PortalEntry     *entry;
134         char                            buf[PortalNameLength];
135
136         /* ----------------
137          *      generate a new name
138          * ----------------
139          */
140         if (be_portalcnt == 0)
141                 be_portaloid = newoid();
142         be_portalcnt++;
143         snprintf(buf, PortalNameLength, "be_%u_%d", be_portaloid, be_portalcnt);
144
145         /* ----------------
146          *      initialize the new portal entry and keep track
147          *      of the current memory context for be_printtup().
148          *      This is important - otherwise whatever we allocate
149          *      will go away and the contents of the portal after
150          *      PQexec() returns will be meaningless.
151          * ----------------
152          */
153         entry = pbuf_setup(buf);
154         entry->portalcxt = (Pointer) CurrentMemoryContext;
155
156         return entry;
157 }
158
159 /* ----------------
160  *              be_typeinit - initialize backend portal expected to hold
161  *                                              query results.
162  *
163  *              used by BeginCommand()
164  * ----------------
165  */
166 void
167 be_typeinit(PortalEntry *entry,
168                         TupleDesc tupDesc,
169                         int natts)
170 {
171         PortalBuffer *portal;
172         GroupBuffer *group;
173         int                     i;
174         Form_pg_attribute *attrs = tupDesc->attrs;
175
176         /* ----------------
177          *      add a new portal group to the portal
178          * ----------------
179          */
180         portal = entry->portal;
181         portal->no_groups++;
182         portal->groups = group = pbuf_addGroup(portal);
183         group->no_fields = natts;
184
185         /* ----------------
186          *      initialize portal group type info
187          * ----------------
188          */
189         if (natts > 0)
190         {
191                 group->types = pbuf_addTypes(natts);
192                 for (i = 0; i < natts; ++i)
193                 {
194                         strncpy(group->types[i].name, attrs[i]->attname.data, NAMEDATALEN);
195                         group->types[i].typid = attrs[i]->atttypid;
196                         group->types[i].typlen = attrs[i]->attlen;
197                 }
198         }
199 }
200
201 /* ----------------
202  *              be_printtup - add a tuple to a backend portal
203  *
204  *              used indirectly by ExecRetrieve()
205  *
206  *              This code is pretty much copied from printtup(), dump_type()
207  *              and dump_data().  -cim 2/12/91
208  * ----------------
209  */
210 void
211 be_printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
212 {
213         int                     i;
214         Datum           attr;
215         bool            isnull;
216         Oid                     typoutput,
217                                 typelem;
218
219         PortalEntry *entry = NULL;
220         PortalBuffer *portal = NULL;
221         GroupBuffer *group = NULL;
222         TupleBlock *tuples = NULL;
223         char      **values;
224         int                *lengths;
225
226         MemoryContext savecxt;
227
228         /* ----------------
229          *      get the current portal and group
230          * ----------------
231          */
232         entry = be_currentportal();
233         portal = entry->portal;
234         group = portal->groups;
235
236         /* ----------------
237          *      switch to the portal's memory context so that
238          *      the tuples we allocate are returned to the user.
239          * ----------------
240          */
241         savecxt = MemoryContextSwitchTo((MemoryContext) entry->portalcxt);
242
243         /* ----------------
244          *      If no tuple block yet, allocate one.
245          *      If the current block is full, allocate another one.
246          * ----------------
247          */
248         if (group->tuples == NULL)
249         {
250                 tuples = group->tuples = pbuf_addTuples();
251                 tuples->tuple_index = 0;
252         }
253         else
254         {
255                 tuples = group->tuples;
256                 /* walk to the end of the linked list of TupleBlocks */
257                 while (tuples->next)
258                         tuples = tuples->next;
259
260                 /*
261                  * now, tuples is the last TupleBlock, check to see if it is full.
262                  * If so, allocate a new TupleBlock and add it to the end of the
263                  * chain
264                  */
265
266                 if (tuples->tuple_index == TupleBlockSize)
267                 {
268                         tuples->next = pbuf_addTuples();
269                         tuples = tuples->next;
270                         tuples->tuple_index = 0;
271                 }
272         }
273
274         /* ----------------
275          *      Allocate space for a tuple.
276          * ----------------
277          */
278         tuples->values[tuples->tuple_index] = pbuf_addTuple(tuple->t_data->t_natts);
279         tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(tuple->t_data->t_natts);
280         /* ----------------
281          *      copy printable representations of the tuple's attributes
282          *      to the portal.
283          *
284          *      This seems silly, because the user's function which is calling
285          *      PQexec() or PQfn() will probably just convert this back into the
286          *      internal form anyways, but the point here is to provide a uniform
287          *      libpq interface and this is how the fe libpq interface currently
288          *      works.  Pretty soon we'll have to add code to let the fe or be
289          *      select the desired data representation and then deal with that.
290          *      This should not be too hard, as there already exist typrecieve()
291          *      and typsend() procedures for user-defined types (see pg_type.h)
292          *      -cim 2/11/91
293          * ----------------
294          */
295
296         values = tuples->values[tuples->tuple_index];
297         lengths = tuples->lengths[tuples->tuple_index];
298
299         for (i = 0; i < tuple->t_data->t_natts; i++)
300         {
301                 attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
302                 getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
303                                                   &typoutput, &typelem);
304
305                 lengths[i] = typeinfo->attrs[i]->attlen;
306
307                 if (lengths[i] == -1)   /* variable length attribute */
308                 {
309                         if (!isnull)
310                                 lengths[i] = VARSIZE(attr) - VARHDRSZ;
311                         else
312                                 lengths[i] = 0;
313                 }
314
315                 if (!isnull && OidIsValid(typoutput))
316                         values[i] = fmgr(typoutput, attr, typelem,
317                                                          typeinfo->attrs[i]->atttypmod);
318                 else
319                         values[i] = NULL;
320
321         }
322
323         /* ----------------
324          *      increment tuple group counters
325          * ----------------
326          */
327         portal->no_tuples++;
328         group->no_tuples++;
329         tuples->tuple_index++;
330
331         /* ----------------
332          *      return to the original memory context
333          * ----------------
334          */
335         MemoryContextSwitchTo(savecxt);
336 }