Coverage Report

Created: 2026-08-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}