]> granicus.if.org Git - postgresql/blob - src/backend/tcop/dest.c
Implement feature of new FE/BE protocol whereby RowDescription identifies
[postgresql] / src / backend / tcop / dest.c
1 /*-------------------------------------------------------------------------
2  *
3  * dest.c
4  *        support for communication destinations
5  *
6  *
7  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.56 2003/05/06 00:20:33 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  *       INTERFACE ROUTINES
17  *              BeginCommand - initialize the destination at start of command
18  *              DestToFunction - identify per-tuple processing routines
19  *              EndCommand - clean up the destination at end of command
20  *              NullCommand - tell dest that an empty query string was recognized
21  *              ReadyForQuery - tell dest that we are ready for a new query
22  *
23  *       NOTES
24  *              These routines do the appropriate work before and after
25  *              tuples are returned by a query to keep the backend and the
26  *              "destination" portals synchronized.
27  */
28
29 #include "postgres.h"
30
31 #include "access/printtup.h"
32 #include "access/xact.h"
33 #include "executor/tstoreReceiver.h"
34 #include "libpq/libpq.h"
35 #include "libpq/pqformat.h"
36
37
38 /* ----------------
39  *              dummy DestReceiver functions
40  * ----------------
41  */
42 static void
43 donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
44 {
45 }
46
47 static void
48 donothingSetup(DestReceiver *self, int operation,
49                            const char *portalName, TupleDesc typeinfo, List *targetlist)
50 {
51 }
52
53 static void
54 donothingCleanup(DestReceiver *self)
55 {
56 }
57
58 /* ----------------
59  *              static DestReceiver structs for dest types needing no local state
60  * ----------------
61  */
62 static DestReceiver donothingDR = {
63         donothingReceive, donothingSetup, donothingCleanup
64 };
65
66 static DestReceiver debugtupDR = {
67         debugtup, debugSetup, donothingCleanup
68 };
69
70 static DestReceiver spi_printtupDR = {
71         spi_printtup, spi_dest_setup, donothingCleanup
72 };
73
74 /* ----------------
75  *              BeginCommand - initialize the destination at start of command
76  * ----------------
77  */
78 void
79 BeginCommand(const char *commandTag, CommandDest dest)
80 {
81         /* Nothing to do at present */
82 }
83
84 /* ----------------
85  *              DestToFunction - return appropriate receiver function set for dest
86  * ----------------
87  */
88 DestReceiver *
89 DestToFunction(CommandDest dest)
90 {
91         switch (dest)
92         {
93                 case Remote:
94                         return printtup_create_DR(false, true);
95
96                 case RemoteInternal:
97                         return printtup_create_DR(true, true);
98
99                 case RemoteExecute:
100                         /* like Remote, but suppress output of T message */
101                         return printtup_create_DR(false, false);
102
103                 case RemoteExecuteInternal:
104                         return printtup_create_DR(true, false);
105
106                 case None:
107                         return &donothingDR;
108
109                 case Debug:
110                         return &debugtupDR;
111
112                 case SPI:
113                         return &spi_printtupDR;
114
115                 case Tuplestore:
116                         return tstoreReceiverCreateDR();
117         }
118
119         /* should never get here */
120         return &donothingDR;
121 }
122
123 /* ----------------
124  *              EndCommand - clean up the destination at end of command
125  * ----------------
126  */
127 void
128 EndCommand(const char *commandTag, CommandDest dest)
129 {
130         switch (dest)
131         {
132                 case Remote:
133                 case RemoteInternal:
134                 case RemoteExecute:
135                 case RemoteExecuteInternal:
136                         pq_puttextmessage('C', commandTag);
137                         break;
138
139                 case None:
140                 case Debug:
141                 case SPI:
142                 case Tuplestore:
143                         break;
144         }
145 }
146
147 /* ----------------
148  *              NullCommand - tell dest that an empty query string was recognized
149  *
150  *              In FE/BE protocol version 1.0, this hack is necessary to support
151  *              libpq's crufty way of determining whether a multiple-command
152  *              query string is done.  In protocol 2.0 it's probably not really
153  *              necessary to distinguish empty queries anymore, but we still do it
154  *              for backwards compatibility with 1.0.  In protocol 3.0 it has some
155  *              use again, since it ensures that there will be a recognizable end
156  *              to the response to an Execute message.
157  * ----------------
158  */
159 void
160 NullCommand(CommandDest dest)
161 {
162         switch (dest)
163         {
164                 case Remote:
165                 case RemoteInternal:
166                 case RemoteExecute:
167                 case RemoteExecuteInternal:
168
169                         /*
170                          * tell the fe that we saw an empty query string.  In protocols
171                          * before 3.0 this has a useless empty-string message body.
172                          */
173                         if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
174                                 pq_putemptymessage('I');
175                         else
176                                 pq_puttextmessage('I', "");
177                         break;
178
179                 case None:
180                 case Debug:
181                 case SPI:
182                 case Tuplestore:
183                         break;
184         }
185 }
186
187 /* ----------------
188  *              ReadyForQuery - tell dest that we are ready for a new query
189  *
190  *              The ReadyForQuery message is sent in protocol versions 2.0 and up
191  *              so that the FE can tell when we are done processing a query string.
192  *              In versions 3.0 and up, it also carries a transaction state indicator.
193  *
194  *              Note that by flushing the stdio buffer here, we can avoid doing it
195  *              most other places and thus reduce the number of separate packets sent.
196  * ----------------
197  */
198 void
199 ReadyForQuery(CommandDest dest)
200 {
201         switch (dest)
202         {
203                 case Remote:
204                 case RemoteInternal:
205                 case RemoteExecute:
206                 case RemoteExecuteInternal:
207                         if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
208                         {
209                                 StringInfoData buf;
210
211                                 pq_beginmessage(&buf, 'Z');
212                                 pq_sendbyte(&buf, TransactionBlockStatusCode());
213                                 pq_endmessage(&buf);
214                         }
215                         else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
216                                 pq_putemptymessage('Z');
217                         /* Flush output at end of cycle in any case. */
218                         pq_flush();
219                         break;
220
221                 case None:
222                 case Debug:
223                 case SPI:
224                 case Tuplestore:
225                         break;
226         }
227 }