]> granicus.if.org Git - postgresql/blob - src/backend/tcop/dest.c
Pass atttypmod to the frontend.
[postgresql] / src / backend / tcop / dest.c
1 /*-------------------------------------------------------------------------
2  *
3  * dest.c--
4  *        support for various communication destinations - see lib/H/tcop/dest.h
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.19 1998/05/14 17:18:13 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  *       INTERFACE ROUTINES
16  *              BeginCommand - prepare destination for tuples of the given type
17  *              EndCommand - tell destination that no more tuples will arrive
18  *              NullCommand - tell dest that an empty query string was recognized
19  *              ReadyForQuery - tell dest that we are ready for a new query
20  *
21  *       NOTES
22  *              These routines do the appropriate work before and after
23  *              tuples are returned by a query to keep the backend and the
24  *              "destination" portals synchronized.
25  *
26  */
27 #include <stdio.h>                              /* for sprintf() */
28 #include <string.h>
29
30 #include "postgres.h"
31
32 #include "access/htup.h"
33 #include "libpq/libpq.h"
34 #include "access/printtup.h"
35 #include "utils/portal.h"
36 #include "utils/palloc.h"
37
38 #include "executor/executor.h"
39
40 #include "tcop/dest.h"
41
42 #include "catalog/pg_type.h"
43 #include "utils/mcxt.h"
44
45 #include "commands/async.h"
46
47 static char CommandInfo[32] = {0};
48
49 /* ----------------
50  *              output functions
51  * ----------------
52  */
53 static void
54 donothing(HeapTuple tuple, TupleDesc attrdesc)
55 {
56 }
57
58 extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
59
60 void            (*
61                          DestToFunction(CommandDest dest)) (HeapTuple, TupleDesc)
62 {
63         switch (dest)
64         {
65                         case RemoteInternal:
66                         return printtup_internal;
67                         break;
68
69                 case Remote:
70                         return printtup;
71                         break;
72
73                 case Local:
74                         return be_printtup;
75                         break;
76
77                 case Debug:
78                         return debugtup;
79                         break;
80
81                 case SPI:
82                         return spi_printtup;
83                         break;
84
85                 case None:
86                 default:
87                         return donothing;
88                         break;
89         }
90
91         /*
92          * never gets here, but DECstation lint appears to be stupid...
93          */
94
95         return donothing;
96 }
97
98 /* ----------------
99  *              EndCommand - tell destination that no more tuples will arrive
100  * ----------------
101  */
102 void
103 EndCommand(char *commandTag, CommandDest dest)
104 {
105         char            buf[64];
106
107         switch (dest)
108         {
109                 case RemoteInternal:
110                 case Remote:
111                         /* ----------------
112                          *              tell the fe that the query is over
113                          * ----------------
114                          */
115                         pq_putnchar("C", 1);
116                         sprintf(buf, "%s%s", commandTag, CommandInfo);
117                         CommandInfo[0] = 0;
118                         pq_putstr(buf);
119                         break;
120
121                 case Local:
122                 case Debug:
123                 case None:
124                 default:
125                         break;
126         }
127 }
128
129 /*
130  * These are necessary to sync communications between fe/be processes doing
131  * COPY rel TO stdout
132  *
133  * or
134  *
135  * COPY rel FROM stdin
136  *
137  * NOTE: the message code letters are changed at protocol version 2.0
138  * to eliminate possible confusion with data tuple messages.
139  */
140 void
141 SendCopyBegin(void)
142 {
143         if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
144                 pq_putnchar("H", 1);    /* new way */
145         else
146                 pq_putnchar("B", 1);    /* old way */
147 }
148
149 void
150 ReceiveCopyBegin(void)
151 {
152         if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
153                 pq_putnchar("G", 1);    /* new way */
154         else
155                 pq_putnchar("D", 1);    /* old way */
156         /* We *must* flush here to ensure FE knows it can send. */
157         pq_flush();
158 }
159
160 /* ----------------
161  *              NullCommand - tell dest that an empty query string was recognized
162  *
163  *              In FE/BE protocol version 1.0, this hack is necessary to support
164  *              libpq's crufty way of determining whether a multiple-command
165  *              query string is done.  In protocol 2.0 it's probably not really
166  *              necessary to distinguish empty queries anymore, but we still do it
167  *              for backwards compatibility with 1.0.
168  * ----------------
169  */
170 void
171 NullCommand(CommandDest dest)
172 {
173         switch (dest)
174         {
175                 case RemoteInternal:
176                 case Remote:
177                         {
178                                 /* ----------------
179                                  *              tell the fe that we saw an empty query string
180                                  * ----------------
181                                  */
182                                 pq_putstr("I");
183                         }
184                         break;
185
186                 case Local:
187                 case Debug:
188                 case None:
189                 default:
190                         break;
191         }
192 }
193
194 /* ----------------
195  *              ReadyForQuery - tell dest that we are ready for a new query
196  *
197  *              The ReadyForQuery message is sent in protocol versions 2.0 and up
198  *              so that the FE can tell when we are done processing a query string.
199  *
200  *              Note that by flushing the stdio buffer here, we can avoid doing it
201  *              most other places and thus reduce the number of separate packets sent.
202  * ----------------
203  */
204 void
205 ReadyForQuery(CommandDest dest)
206 {
207         switch (dest)
208         {
209                 case RemoteInternal:
210                 case Remote:
211                         {
212                                 if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
213                                         pq_putnchar("Z", 1);
214                                 /* Flush output at end of cycle in any case. */
215                                 pq_flush();
216                         }
217                         break;
218
219                 case Local:
220                 case Debug:
221                 case None:
222                 default:
223                         break;
224         }
225 }
226
227 /* ----------------
228  *              BeginCommand - prepare destination for tuples of the given type
229  * ----------------
230  */
231 void
232 BeginCommand(char *pname,
233                          int operation,
234                          TupleDesc tupdesc,
235                          bool isIntoRel,
236                          bool isIntoPortal,
237                          char *tag,
238                          CommandDest dest)
239 {
240         PortalEntry *entry;
241         AttributeTupleForm *attrs = tupdesc->attrs;
242         int                     natts = tupdesc->natts;
243         int                     i;
244         char       *p;
245
246         switch (dest)
247         {
248                 case RemoteInternal:
249                 case Remote:
250                         /* ----------------
251                          *              if this is a "retrieve portal" query, just return
252                          *              because nothing needs to be sent to the fe.
253                          * ----------------
254                          */
255                         CommandInfo[0] = 0;
256                         if (isIntoPortal)
257                                 return;
258
259                         /* ----------------
260                          *              if portal name not specified for remote query,
261                          *              use the "blank" portal.
262                          * ----------------
263                          */
264                         if (pname == NULL)
265                                 pname = "blank";
266
267                         /* ----------------
268                          *              send fe info on tuples we're about to send
269                          * ----------------
270                          */
271                         pq_putnchar("P", 1);/* new portal.. */
272                         pq_putstr(pname);       /* portal name */
273
274                         /* ----------------
275                          *              if this is a retrieve, then we send back the tuple
276                          *              descriptor of the tuples.  "retrieve into" is an
277                          *              exception because no tuples are returned in that case.
278                          * ----------------
279                          */
280                         if (operation == CMD_SELECT && !isIntoRel)
281                         {
282                                 pq_putnchar("T", 1);    /* type info to follow.. */
283                                 pq_putint(natts, 2);    /* number of attributes in tuples */
284
285                                 for (i = 0; i < natts; ++i)
286                                 {
287                                         pq_putstr(attrs[i]->attname.data);      /* if 16 char name
288                                                                                                                  * oops.. */
289                                         pq_putint((int) attrs[i]->atttypid, sizeof(attrs[i]->atttypid));
290                                         pq_putint(attrs[i]->attlen, sizeof(attrs[i]->attlen));
291                                         pq_putint(attrs[i]->atttypmod, sizeof(attrs[i]->atttypmod));
292                                 }
293                         }
294                         break;
295
296                 case Local:
297                         /* ----------------
298                          *              prepare local portal buffer for query results
299                          *              and setup result for PQexec()
300                          * ----------------
301                          */
302                         entry = be_currentportal();
303                         if (pname != NULL)
304                                 pbuf_setportalinfo(entry, pname);
305
306                         if (operation == CMD_SELECT && !isIntoRel)
307                         {
308                                 be_typeinit(entry, tupdesc, natts);
309                                 p = (char *) palloc(strlen(entry->name) + 2);
310                                 p[0] = 'P';
311                                 strcpy(p + 1, entry->name);
312                         }
313                         else
314                         {
315                                 p = (char *) palloc(strlen(tag) + 2);
316                                 p[0] = 'C';
317                                 strcpy(p + 1, tag);
318                         }
319                         entry->result = p;
320                         break;
321
322                 case Debug:
323                         /* ----------------
324                          *              show the return type of the tuples
325                          * ----------------
326                          */
327                         if (pname == NULL)
328                                 pname = "blank";
329
330                         showatts(pname, tupdesc);
331                         break;
332
333                 case None:
334                 default:
335                         break;
336         }
337 }
338
339 void
340 UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples)
341 {
342         switch (operation)
343         {
344                         case CMD_INSERT:
345                         if (tuples > 1)
346                                 lastoid = InvalidOid;
347                         sprintf(CommandInfo, " %u %u", lastoid, tuples);
348                         break;
349                 case CMD_DELETE:
350                 case CMD_UPDATE:
351                         sprintf(CommandInfo, " %u", tuples);
352                         break;
353                 default:
354                         CommandInfo[0] = 0;
355         }
356         return;
357 }