/src/postgres/src/backend/tcop/dest.c
Line | Count | Source |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * dest.c |
4 | | * support for communication destinations |
5 | | * |
6 | | * |
7 | | * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group |
8 | | * Portions Copyright (c) 1994, Regents of the University of California |
9 | | * |
10 | | * IDENTIFICATION |
11 | | * src/backend/tcop/dest.c |
12 | | * |
13 | | *------------------------------------------------------------------------- |
14 | | */ |
15 | | /* |
16 | | * INTERFACE ROUTINES |
17 | | * BeginCommand - initialize the destination at start of command |
18 | | * CreateDestReceiver - create tuple receiver object for destination |
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/printsimple.h" |
32 | | #include "access/printtup.h" |
33 | | #include "access/xact.h" |
34 | | #include "commands/copy.h" |
35 | | #include "commands/createas.h" |
36 | | #include "commands/explain_dr.h" |
37 | | #include "commands/matview.h" |
38 | | #include "executor/functions.h" |
39 | | #include "executor/tqueue.h" |
40 | | #include "executor/tstoreReceiver.h" |
41 | | #include "libpq/libpq.h" |
42 | | #include "libpq/pqformat.h" |
43 | | |
44 | | |
45 | | /* ---------------- |
46 | | * dummy DestReceiver functions |
47 | | * ---------------- |
48 | | */ |
49 | | static bool |
50 | | donothingReceive(TupleTableSlot *slot, DestReceiver *self) |
51 | 0 | { |
52 | 0 | return true; |
53 | 0 | } |
54 | | |
55 | | static void |
56 | | donothingStartup(DestReceiver *self, int operation, TupleDesc typeinfo) |
57 | 0 | { |
58 | 0 | } |
59 | | |
60 | | static void |
61 | | donothingCleanup(DestReceiver *self) |
62 | 0 | { |
63 | | /* this is used for both shutdown and destroy methods */ |
64 | 0 | } |
65 | | |
66 | | /* ---------------- |
67 | | * static DestReceiver structs for dest types needing no local state |
68 | | * ---------------- |
69 | | */ |
70 | | static const DestReceiver donothingDR = { |
71 | | donothingReceive, donothingStartup, donothingCleanup, donothingCleanup, |
72 | | DestNone |
73 | | }; |
74 | | |
75 | | static const DestReceiver debugtupDR = { |
76 | | debugtup, debugStartup, donothingCleanup, donothingCleanup, |
77 | | DestDebug |
78 | | }; |
79 | | |
80 | | static const DestReceiver printsimpleDR = { |
81 | | printsimple, printsimple_startup, donothingCleanup, donothingCleanup, |
82 | | DestRemoteSimple |
83 | | }; |
84 | | |
85 | | static const DestReceiver spi_printtupDR = { |
86 | | spi_printtup, spi_dest_startup, donothingCleanup, donothingCleanup, |
87 | | DestSPI |
88 | | }; |
89 | | |
90 | | /* |
91 | | * Globally available receiver for DestNone. |
92 | | * |
93 | | * It's ok to cast the constness away as any modification of the none receiver |
94 | | * would be a bug (which gets easier to catch this way). |
95 | | */ |
96 | | DestReceiver *None_Receiver = (DestReceiver *) &donothingDR; |
97 | | |
98 | | /* ---------------- |
99 | | * BeginCommand - initialize the destination at start of command |
100 | | * ---------------- |
101 | | */ |
102 | | void |
103 | | BeginCommand(CommandTag commandTag, CommandDest dest) |
104 | 0 | { |
105 | | /* Nothing to do at present */ |
106 | 0 | } |
107 | | |
108 | | /* ---------------- |
109 | | * CreateDestReceiver - return appropriate receiver function set for dest |
110 | | * ---------------- |
111 | | */ |
112 | | DestReceiver * |
113 | | CreateDestReceiver(CommandDest dest) |
114 | 0 | { |
115 | | /* |
116 | | * It's ok to cast the constness away as any modification of the none |
117 | | * receiver would be a bug (which gets easier to catch this way). |
118 | | */ |
119 | |
|
120 | 0 | switch (dest) |
121 | 0 | { |
122 | 0 | case DestRemote: |
123 | 0 | case DestRemoteExecute: |
124 | 0 | return printtup_create_DR(dest); |
125 | | |
126 | 0 | case DestRemoteSimple: |
127 | 0 | return unconstify(DestReceiver *, &printsimpleDR); |
128 | | |
129 | 0 | case DestNone: |
130 | 0 | return unconstify(DestReceiver *, &donothingDR); |
131 | | |
132 | 0 | case DestDebug: |
133 | 0 | return unconstify(DestReceiver *, &debugtupDR); |
134 | | |
135 | 0 | case DestSPI: |
136 | 0 | return unconstify(DestReceiver *, &spi_printtupDR); |
137 | | |
138 | 0 | case DestTuplestore: |
139 | 0 | return CreateTuplestoreDestReceiver(); |
140 | | |
141 | 0 | case DestIntoRel: |
142 | 0 | return CreateIntoRelDestReceiver(NULL); |
143 | | |
144 | 0 | case DestCopyOut: |
145 | 0 | return CreateCopyDestReceiver(); |
146 | | |
147 | 0 | case DestSQLFunction: |
148 | 0 | return CreateSQLFunctionDestReceiver(); |
149 | | |
150 | 0 | case DestTransientRel: |
151 | 0 | return CreateTransientRelDestReceiver(InvalidOid); |
152 | | |
153 | 0 | case DestTupleQueue: |
154 | 0 | return CreateTupleQueueDestReceiver(NULL); |
155 | | |
156 | 0 | case DestExplainSerialize: |
157 | 0 | return CreateExplainSerializeDestReceiver(NULL); |
158 | 0 | } |
159 | | |
160 | | /* should never get here */ |
161 | 0 | pg_unreachable(); |
162 | 0 | } |
163 | | |
164 | | /* ---------------- |
165 | | * EndCommand - clean up the destination at end of command |
166 | | * ---------------- |
167 | | */ |
168 | | |
169 | | void |
170 | | EndCommandExtended(const QueryCompletion *qc, CommandDest dest, |
171 | | bool force_undecorated_output, bool noblock) |
172 | 0 | { |
173 | 0 | char completionTag[COMPLETION_TAG_BUFSIZE]; |
174 | 0 | Size len; |
175 | |
|
176 | 0 | switch (dest) |
177 | 0 | { |
178 | 0 | case DestRemote: |
179 | 0 | case DestRemoteExecute: |
180 | 0 | case DestRemoteSimple: |
181 | |
|
182 | 0 | len = BuildQueryCompletionString(completionTag, qc, |
183 | 0 | force_undecorated_output); |
184 | 0 | if (noblock) |
185 | 0 | pq_putmessage_noblock(PqMsg_CommandComplete, completionTag, len + 1); |
186 | 0 | else |
187 | 0 | pq_putmessage(PqMsg_CommandComplete, completionTag, len + 1); |
188 | 0 | break; |
189 | | |
190 | 0 | case DestNone: |
191 | 0 | case DestDebug: |
192 | 0 | case DestSPI: |
193 | 0 | case DestTuplestore: |
194 | 0 | case DestIntoRel: |
195 | 0 | case DestCopyOut: |
196 | 0 | case DestSQLFunction: |
197 | 0 | case DestTransientRel: |
198 | 0 | case DestTupleQueue: |
199 | 0 | case DestExplainSerialize: |
200 | 0 | break; |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | | void |
205 | | EndCommand(const QueryCompletion *qc, CommandDest dest, bool force_undecorated_output) |
206 | 0 | { |
207 | 0 | EndCommandExtended(qc, dest, force_undecorated_output, false); |
208 | 0 | } |
209 | | |
210 | | /* ---------------- |
211 | | * EndReplicationCommand - stripped down version of EndCommand |
212 | | * |
213 | | * For use by replication commands. |
214 | | * ---------------- |
215 | | */ |
216 | | void |
217 | | EndReplicationCommand(const char *commandTag) |
218 | 0 | { |
219 | 0 | pq_putmessage(PqMsg_CommandComplete, commandTag, strlen(commandTag) + 1); |
220 | 0 | } |
221 | | |
222 | | /* ---------------- |
223 | | * NullCommand - tell dest that an empty query string was recognized |
224 | | * |
225 | | * This ensures that there will be a recognizable end to the response |
226 | | * to an Execute message in the extended query protocol. |
227 | | * ---------------- |
228 | | */ |
229 | | void |
230 | | NullCommand(CommandDest dest) |
231 | 0 | { |
232 | 0 | switch (dest) |
233 | 0 | { |
234 | 0 | case DestRemote: |
235 | 0 | case DestRemoteExecute: |
236 | 0 | case DestRemoteSimple: |
237 | | |
238 | | /* Tell the FE that we saw an empty query string */ |
239 | 0 | pq_putemptymessage(PqMsg_EmptyQueryResponse); |
240 | 0 | break; |
241 | | |
242 | 0 | case DestNone: |
243 | 0 | case DestDebug: |
244 | 0 | case DestSPI: |
245 | 0 | case DestTuplestore: |
246 | 0 | case DestIntoRel: |
247 | 0 | case DestCopyOut: |
248 | 0 | case DestSQLFunction: |
249 | 0 | case DestTransientRel: |
250 | 0 | case DestTupleQueue: |
251 | 0 | case DestExplainSerialize: |
252 | 0 | break; |
253 | 0 | } |
254 | 0 | } |
255 | | |
256 | | /* ---------------- |
257 | | * ReadyForQuery - tell dest that we are ready for a new query |
258 | | * |
259 | | * The ReadyForQuery message is sent so that the FE can tell when |
260 | | * we are done processing a query string. |
261 | | * In versions 3.0 and up, it also carries a transaction state indicator. |
262 | | * |
263 | | * Note that by flushing the stdio buffer here, we can avoid doing it |
264 | | * most other places and thus reduce the number of separate packets sent. |
265 | | * ---------------- |
266 | | */ |
267 | | void |
268 | | ReadyForQuery(CommandDest dest) |
269 | 0 | { |
270 | 0 | switch (dest) |
271 | 0 | { |
272 | 0 | case DestRemote: |
273 | 0 | case DestRemoteExecute: |
274 | 0 | case DestRemoteSimple: |
275 | 0 | { |
276 | 0 | StringInfoData buf; |
277 | |
|
278 | 0 | pq_beginmessage(&buf, PqMsg_ReadyForQuery); |
279 | 0 | pq_sendbyte(&buf, TransactionBlockStatusCode()); |
280 | 0 | pq_endmessage(&buf); |
281 | 0 | } |
282 | | /* Flush output at end of cycle in any case. */ |
283 | 0 | pq_flush(); |
284 | 0 | break; |
285 | | |
286 | 0 | case DestNone: |
287 | 0 | case DestDebug: |
288 | 0 | case DestSPI: |
289 | 0 | case DestTuplestore: |
290 | 0 | case DestIntoRel: |
291 | 0 | case DestCopyOut: |
292 | 0 | case DestSQLFunction: |
293 | 0 | case DestTransientRel: |
294 | 0 | case DestTupleQueue: |
295 | 0 | case DestExplainSerialize: |
296 | 0 | break; |
297 | 0 | } |
298 | 0 | } |