PostgreSQL Source Code: src/interfaces/libpq/fe-protocol3.c Source File

PostgreSQL Source Code git master
fe-protocol3.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * fe-protocol3.c
4 * functions that are specific to frontend/backend protocol version 3
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/interfaces/libpq/fe-protocol3.c
12 *
13 *-------------------------------------------------------------------------
14 */
15#include "postgres_fe.h"
16
17#include <ctype.h>
18#include <fcntl.h>
19
20#ifdef WIN32
21#include "win32.h"
22#else
23#include <unistd.h>
24#include <netinet/tcp.h>
25#endif
26
27#include "libpq-fe.h"
28#include "libpq-int.h"
29#include "mb/pg_wchar.h"
30#include "port/pg_bswap.h"
31
32/*
33 * This macro lists the backend message types that could be "long" (more
34 * than a couple of kilobytes).
35 */
36 #define VALID_LONG_MESSAGE_TYPE(id) \
37 ((id) == PqMsg_CopyData || \
38 (id) == PqMsg_DataRow || \
39 (id) == PqMsg_ErrorResponse || \
40 (id) == PqMsg_FunctionCallResponse || \
41 (id) == PqMsg_NoticeResponse || \
42 (id) == PqMsg_NotificationResponse || \
43 (id) == PqMsg_RowDescription)
44
45
46static void handleFatalError(PGconn *conn);
47static void handleSyncLoss(PGconn *conn, char id, int msgLength);
48static int getRowDescriptions(PGconn *conn, int msgLength);
49static int getParamDescriptions(PGconn *conn, int msgLength);
50static int getAnotherTuple(PGconn *conn, int msgLength);
51static int getParameterStatus(PGconn *conn);
52static int getBackendKeyData(PGconn *conn, int msgLength);
53static int getNotify(PGconn *conn);
54static int getCopyStart(PGconn *conn, ExecStatusType copytype);
55static int getReadyForQuery(PGconn *conn);
56static void reportErrorPosition(PQExpBuffer msg, const char *query,
57 int loc, int encoding);
58static int build_startup_packet(const PGconn *conn, char *packet,
59 const PQEnvironmentOption *options);
60
61
62/*
63 * parseInput: if appropriate, parse input data from backend
64 * until input is exhausted or a stopping state is reached.
65 * Note that this function will NOT attempt to read more data from the backend.
66 */
67void
68 pqParseInput3(PGconn *conn)
69{
70 char id;
71 int msgLength;
72 int avail;
73
74 /*
75 * Loop to parse successive complete messages available in the buffer.
76 */
77 for (;;)
78 {
79 /*
80 * Try to read a message. First get the type code and length. Return
81 * if not enough data.
82 */
83 conn->inCursor = conn->inStart;
84 if (pqGetc(&id, conn))
85 return;
86 if (pqGetInt(&msgLength, 4, conn))
87 return;
88
89 /*
90 * Try to validate message type/length here. A length less than 4 is
91 * definitely broken. Large lengths should only be believed for a few
92 * message types.
93 */
94 if (msgLength < 4)
95 {
96 handleSyncLoss(conn, id, msgLength);
97 return;
98 }
99 if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id))
100 {
101 handleSyncLoss(conn, id, msgLength);
102 return;
103 }
104
105 /*
106 * Can't process if message body isn't all here yet.
107 */
108 msgLength -= 4;
109 avail = conn->inEnd - conn->inCursor;
110 if (avail < msgLength)
111 {
112 /*
113 * Before returning, enlarge the input buffer if needed to hold
114 * the whole message. This is better than leaving it to
115 * pqReadData because we can avoid multiple cycles of realloc()
116 * when the message is large; also, we can implement a reasonable
117 * recovery strategy if we are unable to make the buffer big
118 * enough.
119 */
120 if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
121 conn))
122 {
123 /*
124 * Abandon the connection. There's not much else we can
125 * safely do; we can't just ignore the message or we could
126 * miss important changes to the connection state.
127 * pqCheckInBufferSpace() already reported the error.
128 */
129 handleFatalError(conn);
130 }
131 return;
132 }
133
134 /*
135 * NOTIFY and NOTICE messages can happen in any state; always process
136 * them right away.
137 *
138 * Most other messages should only be processed while in BUSY state.
139 * (In particular, in READY state we hold off further parsing until
140 * the application collects the current PGresult.)
141 *
142 * However, if the state is IDLE then we got trouble; we need to deal
143 * with the unexpected message somehow.
144 *
145 * ParameterStatus ('S') messages are a special case: in IDLE state we
146 * must process 'em (this case could happen if a new value was adopted
147 * from config file due to SIGHUP), but otherwise we hold off until
148 * BUSY state.
149 */
150 if (id == PqMsg_NotificationResponse)
151 {
152 if (getNotify(conn))
153 return;
154 }
155 else if (id == PqMsg_NoticeResponse)
156 {
157 if (pqGetErrorNotice3(conn, false))
158 return;
159 }
160 else if (conn->asyncStatus != PGASYNC_BUSY)
161 {
162 /* If not IDLE state, just wait ... */
163 if (conn->asyncStatus != PGASYNC_IDLE)
164 return;
165
166 /*
167 * Unexpected message in IDLE state; need to recover somehow.
168 * ERROR messages are handled using the notice processor;
169 * ParameterStatus is handled normally; anything else is just
170 * dropped on the floor after displaying a suitable warning
171 * notice. (An ERROR is very possibly the backend telling us why
172 * it is about to close the connection, so we don't want to just
173 * discard it...)
174 */
175 if (id == PqMsg_ErrorResponse)
176 {
177 if (pqGetErrorNotice3(conn, false /* treat as notice */ ))
178 return;
179 }
180 else if (id == PqMsg_ParameterStatus)
181 {
182 if (getParameterStatus(conn))
183 return;
184 }
185 else
186 {
187 /* Any other case is unexpected and we summarily skip it */
188 pqInternalNotice(&conn->noticeHooks,
189 "message type 0x%02x arrived from server while idle",
190 id);
191 /* Discard the unexpected message */
192 conn->inCursor += msgLength;
193 }
194 }
195 else
196 {
197 /*
198 * In BUSY state, we can process everything.
199 */
200 switch (id)
201 {
202 case PqMsg_CommandComplete:
203 if (pqGets(&conn->workBuffer, conn))
204 return;
205 if (!pgHavePendingResult(conn))
206 {
207 conn->result = PQmakeEmptyPGresult(conn,
208 PGRES_COMMAND_OK);
209 if (!conn->result)
210 {
211 libpq_append_conn_error(conn, "out of memory");
212 pqSaveErrorResult(conn);
213 }
214 }
215 if (conn->result)
216 strlcpy(conn->result->cmdStatus, conn->workBuffer.data,
217 CMDSTATUS_LEN);
218 conn->asyncStatus = PGASYNC_READY;
219 break;
220 case PqMsg_ErrorResponse:
221 if (pqGetErrorNotice3(conn, true))
222 return;
223 conn->asyncStatus = PGASYNC_READY;
224 break;
225 case PqMsg_ReadyForQuery:
226 if (getReadyForQuery(conn))
227 return;
228 if (conn->pipelineStatus != PQ_PIPELINE_OFF)
229 {
230 conn->result = PQmakeEmptyPGresult(conn,
231 PGRES_PIPELINE_SYNC);
232 if (!conn->result)
233 {
234 libpq_append_conn_error(conn, "out of memory");
235 pqSaveErrorResult(conn);
236 }
237 else
238 {
239 conn->pipelineStatus = PQ_PIPELINE_ON;
240 conn->asyncStatus = PGASYNC_READY;
241 }
242 }
243 else
244 {
245 /* Advance the command queue and set us idle */
246 pqCommandQueueAdvance(conn, true, false);
247 conn->asyncStatus = PGASYNC_IDLE;
248 }
249 break;
250 case PqMsg_EmptyQueryResponse:
251 if (!pgHavePendingResult(conn))
252 {
253 conn->result = PQmakeEmptyPGresult(conn,
254 PGRES_EMPTY_QUERY);
255 if (!conn->result)
256 {
257 libpq_append_conn_error(conn, "out of memory");
258 pqSaveErrorResult(conn);
259 }
260 }
261 conn->asyncStatus = PGASYNC_READY;
262 break;
263 case PqMsg_ParseComplete:
264 /* If we're doing PQprepare, we're done; else ignore */
265 if (conn->cmd_queue_head &&
266 conn->cmd_queue_head->queryclass == PGQUERY_PREPARE)
267 {
268 if (!pgHavePendingResult(conn))
269 {
270 conn->result = PQmakeEmptyPGresult(conn,
271 PGRES_COMMAND_OK);
272 if (!conn->result)
273 {
274 libpq_append_conn_error(conn, "out of memory");
275 pqSaveErrorResult(conn);
276 }
277 }
278 conn->asyncStatus = PGASYNC_READY;
279 }
280 break;
281 case PqMsg_BindComplete:
282 /* Nothing to do for this message type */
283 break;
284 case PqMsg_CloseComplete:
285 /* If we're doing PQsendClose, we're done; else ignore */
286 if (conn->cmd_queue_head &&
287 conn->cmd_queue_head->queryclass == PGQUERY_CLOSE)
288 {
289 if (!pgHavePendingResult(conn))
290 {
291 conn->result = PQmakeEmptyPGresult(conn,
292 PGRES_COMMAND_OK);
293 if (!conn->result)
294 {
295 libpq_append_conn_error(conn, "out of memory");
296 pqSaveErrorResult(conn);
297 }
298 }
299 conn->asyncStatus = PGASYNC_READY;
300 }
301 break;
302 case PqMsg_ParameterStatus:
303 if (getParameterStatus(conn))
304 return;
305 break;
306 case PqMsg_BackendKeyData:
307
308 /*
309 * This is expected only during backend startup, but it's
310 * just as easy to handle it as part of the main loop.
311 * Save the data and continue processing.
312 */
313 if (getBackendKeyData(conn, msgLength))
314 return;
315 break;
316 case PqMsg_RowDescription:
317 if (conn->error_result ||
318 (conn->result != NULL &&
319 conn->result->resultStatus == PGRES_FATAL_ERROR))
320 {
321 /*
322 * We've already choked for some reason. Just discard
323 * the data till we get to the end of the query.
324 */
325 conn->inCursor += msgLength;
326 }
327 else if (conn->result == NULL ||
328 (conn->cmd_queue_head &&
329 conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE))
330 {
331 /* First 'T' in a query sequence */
332 if (getRowDescriptions(conn, msgLength))
333 return;
334 }
335 else
336 {
337 /*
338 * A new 'T' message is treated as the start of
339 * another PGresult. (It is not clear that this is
340 * really possible with the current backend.) We stop
341 * parsing until the application accepts the current
342 * result.
343 */
344 conn->asyncStatus = PGASYNC_READY;
345 return;
346 }
347 break;
348 case PqMsg_NoData:
349
350 /*
351 * NoData indicates that we will not be seeing a
352 * RowDescription message because the statement or portal
353 * inquired about doesn't return rows.
354 *
355 * If we're doing a Describe, we have to pass something
356 * back to the client, so set up a COMMAND_OK result,
357 * instead of PGRES_TUPLES_OK. Otherwise we can just
358 * ignore this message.
359 */
360 if (conn->cmd_queue_head &&
361 conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE)
362 {
363 if (!pgHavePendingResult(conn))
364 {
365 conn->result = PQmakeEmptyPGresult(conn,
366 PGRES_COMMAND_OK);
367 if (!conn->result)
368 {
369 libpq_append_conn_error(conn, "out of memory");
370 pqSaveErrorResult(conn);
371 }
372 }
373 conn->asyncStatus = PGASYNC_READY;
374 }
375 break;
376 case PqMsg_ParameterDescription:
377 if (getParamDescriptions(conn, msgLength))
378 return;
379 break;
380 case PqMsg_DataRow:
381 if (conn->result != NULL &&
382 (conn->result->resultStatus == PGRES_TUPLES_OK ||
383 conn->result->resultStatus == PGRES_TUPLES_CHUNK))
384 {
385 /* Read another tuple of a normal query response */
386 if (getAnotherTuple(conn, msgLength))
387 return;
388 }
389 else if (conn->error_result ||
390 (conn->result != NULL &&
391 conn->result->resultStatus == PGRES_FATAL_ERROR))
392 {
393 /*
394 * We've already choked for some reason. Just discard
395 * tuples till we get to the end of the query.
396 */
397 conn->inCursor += msgLength;
398 }
399 else
400 {
401 /* Set up to report error at end of query */
402 libpq_append_conn_error(conn, "server sent data (\"D\" message) without prior row description (\"T\" message)");
403 pqSaveErrorResult(conn);
404 /* Discard the unexpected message */
405 conn->inCursor += msgLength;
406 }
407 break;
408 case PqMsg_CopyInResponse:
409 if (getCopyStart(conn, PGRES_COPY_IN))
410 return;
411 conn->asyncStatus = PGASYNC_COPY_IN;
412 break;
413 case PqMsg_CopyOutResponse:
414 if (getCopyStart(conn, PGRES_COPY_OUT))
415 return;
416 conn->asyncStatus = PGASYNC_COPY_OUT;
417 conn->copy_already_done = 0;
418 break;
419 case PqMsg_CopyBothResponse:
420 if (getCopyStart(conn, PGRES_COPY_BOTH))
421 return;
422 conn->asyncStatus = PGASYNC_COPY_BOTH;
423 conn->copy_already_done = 0;
424 break;
425 case PqMsg_CopyData:
426
427 /*
428 * If we see Copy Data, just silently drop it. This would
429 * only occur if application exits COPY OUT mode too
430 * early.
431 */
432 conn->inCursor += msgLength;
433 break;
434 case PqMsg_CopyDone:
435
436 /*
437 * If we see Copy Done, just silently drop it. This is
438 * the normal case during PQendcopy. We will keep
439 * swallowing data, expecting to see command-complete for
440 * the COPY command.
441 */
442 break;
443 default:
444 libpq_append_conn_error(conn, "unexpected response from server; first received character was \"%c\"", id);
445 /* build an error result holding the error message */
446 pqSaveErrorResult(conn);
447 /* not sure if we will see more, so go to ready state */
448 conn->asyncStatus = PGASYNC_READY;
449 /* Discard the unexpected message */
450 conn->inCursor += msgLength;
451 break;
452 } /* switch on protocol character */
453 }
454 /* Successfully consumed this message */
455 if (conn->inCursor == conn->inStart + 5 + msgLength)
456 {
457 /* Normal case: parsing agrees with specified length */
458 pqParseDone(conn, conn->inCursor);
459 }
460 else if (conn->error_result && conn->status == CONNECTION_BAD)
461 {
462 /* The connection was abandoned and we already reported it */
463 return;
464 }
465 else
466 {
467 /* Trouble --- report it */
468 libpq_append_conn_error(conn, "message contents do not agree with length in message type \"%c\"", id);
469 /* build an error result holding the error message */
470 pqSaveErrorResult(conn);
471 conn->asyncStatus = PGASYNC_READY;
472 /* trust the specified message length as what to skip */
473 conn->inStart += 5 + msgLength;
474 }
475 }
476}
477
478/*
479 * handleFatalError: clean up after a nonrecoverable error
480 *
481 * This is for errors where we need to abandon the connection. The caller has
482 * already saved the error message in conn->errorMessage.
483 */
484static void
485 handleFatalError(PGconn *conn)
486{
487 /* build an error result holding the error message */
488 pqSaveErrorResult(conn);
489 conn->asyncStatus = PGASYNC_READY; /* drop out of PQgetResult wait loop */
490 /* flush input data since we're giving up on processing it */
491 pqDropConnection(conn, true);
492 conn->status = CONNECTION_BAD; /* No more connection to backend */
493}
494
495/*
496 * handleSyncLoss: clean up after loss of message-boundary sync
497 *
498 * There isn't really a lot we can do here except abandon the connection.
499 */
500static void
501 handleSyncLoss(PGconn *conn, char id, int msgLength)
502{
503 libpq_append_conn_error(conn, "lost synchronization with server: got message type \"%c\", length %d",
504 id, msgLength);
505 handleFatalError(conn);
506}
507
508/*
509 * parseInput subroutine to read a 'T' (row descriptions) message.
510 * We'll build a new PGresult structure (unless called for a Describe
511 * command for a prepared statement) containing the attribute data.
512 * Returns: 0 if processed message successfully, EOF to suspend parsing
513 * (the latter case is not actually used currently).
514 */
515static int
516 getRowDescriptions(PGconn *conn, int msgLength)
517{
518 PGresult *result;
519 int nfields;
520 const char *errmsg;
521 int i;
522
523 /*
524 * When doing Describe for a prepared statement, there'll already be a
525 * PGresult created by getParamDescriptions, and we should fill data into
526 * that. Otherwise, create a new, empty PGresult.
527 */
528 if (!conn->cmd_queue_head ||
529 (conn->cmd_queue_head &&
530 conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE))
531 {
532 if (conn->result)
533 result = conn->result;
534 else
535 result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
536 }
537 else
538 result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
539 if (!result)
540 {
541 errmsg = NULL; /* means "out of memory", see below */
542 goto advance_and_error;
543 }
544
545 /* parseInput already read the 'T' label and message length. */
546 /* the next two bytes are the number of fields */
547 if (pqGetInt(&(result->numAttributes), 2, conn))
548 {
549 /* We should not run out of data here, so complain */
550 errmsg = libpq_gettext("insufficient data in \"T\" message");
551 goto advance_and_error;
552 }
553 nfields = result->numAttributes;
554
555 /* allocate space for the attribute descriptors */
556 if (nfields > 0)
557 {
558 result->attDescs = (PGresAttDesc *)
559 pqResultAlloc(result, nfields * sizeof(PGresAttDesc), true);
560 if (!result->attDescs)
561 {
562 errmsg = NULL; /* means "out of memory", see below */
563 goto advance_and_error;
564 }
565 MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
566 }
567
568 /* result->binary is true only if ALL columns are binary */
569 result->binary = (nfields > 0) ? 1 : 0;
570
571 /* get type info */
572 for (i = 0; i < nfields; i++)
573 {
574 int tableid;
575 int columnid;
576 int typid;
577 int typlen;
578 int atttypmod;
579 int format;
580
581 if (pqGets(&conn->workBuffer, conn) ||
582 pqGetInt(&tableid, 4, conn) ||
583 pqGetInt(&columnid, 2, conn) ||
584 pqGetInt(&typid, 4, conn) ||
585 pqGetInt(&typlen, 2, conn) ||
586 pqGetInt(&atttypmod, 4, conn) ||
587 pqGetInt(&format, 2, conn))
588 {
589 /* We should not run out of data here, so complain */
590 errmsg = libpq_gettext("insufficient data in \"T\" message");
591 goto advance_and_error;
592 }
593
594 /*
595 * Since pqGetInt treats 2-byte integers as unsigned, we need to
596 * coerce these results to signed form.
597 */
598 columnid = (int) ((int16) columnid);
599 typlen = (int) ((int16) typlen);
600 format = (int) ((int16) format);
601
602 result->attDescs[i].name = pqResultStrdup(result,
603 conn->workBuffer.data);
604 if (!result->attDescs[i].name)
605 {
606 errmsg = NULL; /* means "out of memory", see below */
607 goto advance_and_error;
608 }
609 result->attDescs[i].tableid = tableid;
610 result->attDescs[i].columnid = columnid;
611 result->attDescs[i].format = format;
612 result->attDescs[i].typid = typid;
613 result->attDescs[i].typlen = typlen;
614 result->attDescs[i].atttypmod = atttypmod;
615
616 if (format != 1)
617 result->binary = 0;
618 }
619
620 /* Success! */
621 conn->result = result;
622
623 /*
624 * If we're doing a Describe, we're done, and ready to pass the result
625 * back to the client.
626 */
627 if ((!conn->cmd_queue_head) ||
628 (conn->cmd_queue_head &&
629 conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE))
630 {
631 conn->asyncStatus = PGASYNC_READY;
632 return 0;
633 }
634
635 /*
636 * We could perform additional setup for the new result set here, but for
637 * now there's nothing else to do.
638 */
639
640 /* And we're done. */
641 return 0;
642
643advance_and_error:
644 /* Discard unsaved result, if any */
645 if (result && result != conn->result)
646 PQclear(result);
647
648 /*
649 * Replace partially constructed result with an error result. First
650 * discard the old result to try to win back some memory.
651 */
652 pqClearAsyncResult(conn);
653
654 /*
655 * If preceding code didn't provide an error message, assume "out of
656 * memory" was meant. The advantage of having this special case is that
657 * freeing the old result first greatly improves the odds that gettext()
658 * will succeed in providing a translation.
659 */
660 if (!errmsg)
661 errmsg = libpq_gettext("out of memory for query result");
662
663 appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
664 pqSaveErrorResult(conn);
665
666 /*
667 * Show the message as fully consumed, else pqParseInput3 will overwrite
668 * our error with a complaint about that.
669 */
670 conn->inCursor = conn->inStart + 5 + msgLength;
671
672 /*
673 * Return zero to allow input parsing to continue. Subsequent "D"
674 * messages will be ignored until we get to end of data, since an error
675 * result is already set up.
676 */
677 return 0;
678}
679
680/*
681 * parseInput subroutine to read a 't' (ParameterDescription) message.
682 * We'll build a new PGresult structure containing the parameter data.
683 * Returns: 0 if processed message successfully, EOF to suspend parsing
684 * (the latter case is not actually used currently).
685 */
686static int
687 getParamDescriptions(PGconn *conn, int msgLength)
688{
689 PGresult *result;
690 const char *errmsg = NULL; /* means "out of memory", see below */
691 int nparams;
692 int i;
693
694 result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
695 if (!result)
696 goto advance_and_error;
697
698 /* parseInput already read the 't' label and message length. */
699 /* the next two bytes are the number of parameters */
700 if (pqGetInt(&(result->numParameters), 2, conn))
701 goto not_enough_data;
702 nparams = result->numParameters;
703
704 /* allocate space for the parameter descriptors */
705 if (nparams > 0)
706 {
707 result->paramDescs = (PGresParamDesc *)
708 pqResultAlloc(result, nparams * sizeof(PGresParamDesc), true);
709 if (!result->paramDescs)
710 goto advance_and_error;
711 MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc));
712 }
713
714 /* get parameter info */
715 for (i = 0; i < nparams; i++)
716 {
717 int typid;
718
719 if (pqGetInt(&typid, 4, conn))
720 goto not_enough_data;
721 result->paramDescs[i].typid = typid;
722 }
723
724 /* Success! */
725 conn->result = result;
726
727 return 0;
728
729not_enough_data:
730 errmsg = libpq_gettext("insufficient data in \"t\" message");
731
732advance_and_error:
733 /* Discard unsaved result, if any */
734 if (result && result != conn->result)
735 PQclear(result);
736
737 /*
738 * Replace partially constructed result with an error result. First
739 * discard the old result to try to win back some memory.
740 */
741 pqClearAsyncResult(conn);
742
743 /*
744 * If preceding code didn't provide an error message, assume "out of
745 * memory" was meant. The advantage of having this special case is that
746 * freeing the old result first greatly improves the odds that gettext()
747 * will succeed in providing a translation.
748 */
749 if (!errmsg)
750 errmsg = libpq_gettext("out of memory");
751 appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
752 pqSaveErrorResult(conn);
753
754 /*
755 * Show the message as fully consumed, else pqParseInput3 will overwrite
756 * our error with a complaint about that.
757 */
758 conn->inCursor = conn->inStart + 5 + msgLength;
759
760 /*
761 * Return zero to allow input parsing to continue. Essentially, we've
762 * replaced the COMMAND_OK result with an error result, but since this
763 * doesn't affect the protocol state, it's fine.
764 */
765 return 0;
766}
767
768/*
769 * parseInput subroutine to read a 'D' (row data) message.
770 * We fill rowbuf with column pointers and then call the row processor.
771 * Returns: 0 if processed message successfully, EOF to suspend parsing
772 * (the latter case is not actually used currently).
773 */
774static int
775 getAnotherTuple(PGconn *conn, int msgLength)
776{
777 PGresult *result = conn->result;
778 int nfields = result->numAttributes;
779 const char *errmsg;
780 PGdataValue *rowbuf;
781 int tupnfields; /* # fields from tuple */
782 int vlen; /* length of the current field value */
783 int i;
784
785 /* Get the field count and make sure it's what we expect */
786 if (pqGetInt(&tupnfields, 2, conn))
787 {
788 /* We should not run out of data here, so complain */
789 errmsg = libpq_gettext("insufficient data in \"D\" message");
790 goto advance_and_error;
791 }
792
793 if (tupnfields != nfields)
794 {
795 errmsg = libpq_gettext("unexpected field count in \"D\" message");
796 goto advance_and_error;
797 }
798
799 /* Resize row buffer if needed */
800 rowbuf = conn->rowBuf;
801 if (nfields > conn->rowBufLen)
802 {
803 rowbuf = (PGdataValue *) realloc(rowbuf,
804 nfields * sizeof(PGdataValue));
805 if (!rowbuf)
806 {
807 errmsg = NULL; /* means "out of memory", see below */
808 goto advance_and_error;
809 }
810 conn->rowBuf = rowbuf;
811 conn->rowBufLen = nfields;
812 }
813
814 /* Scan the fields */
815 for (i = 0; i < nfields; i++)
816 {
817 /* get the value length */
818 if (pqGetInt(&vlen, 4, conn))
819 {
820 /* We should not run out of data here, so complain */
821 errmsg = libpq_gettext("insufficient data in \"D\" message");
822 goto advance_and_error;
823 }
824 rowbuf[i].len = vlen;
825
826 /*
827 * rowbuf[i].value always points to the next address in the data
828 * buffer even if the value is NULL. This allows row processors to
829 * estimate data sizes more easily.
830 */
831 rowbuf[i].value = conn->inBuffer + conn->inCursor;
832
833 /* Skip over the data value */
834 if (vlen > 0)
835 {
836 if (pqSkipnchar(vlen, conn))
837 {
838 /* We should not run out of data here, so complain */
839 errmsg = libpq_gettext("insufficient data in \"D\" message");
840 goto advance_and_error;
841 }
842 }
843 }
844
845 /* Process the collected row */
846 errmsg = NULL;
847 if (pqRowProcessor(conn, &errmsg))
848 return 0; /* normal, successful exit */
849
850 /* pqRowProcessor failed, fall through to report it */
851
852advance_and_error:
853
854 /*
855 * Replace partially constructed result with an error result. First
856 * discard the old result to try to win back some memory.
857 */
858 pqClearAsyncResult(conn);
859
860 /*
861 * If preceding code didn't provide an error message, assume "out of
862 * memory" was meant. The advantage of having this special case is that
863 * freeing the old result first greatly improves the odds that gettext()
864 * will succeed in providing a translation.
865 */
866 if (!errmsg)
867 errmsg = libpq_gettext("out of memory for query result");
868
869 appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
870 pqSaveErrorResult(conn);
871
872 /*
873 * Show the message as fully consumed, else pqParseInput3 will overwrite
874 * our error with a complaint about that.
875 */
876 conn->inCursor = conn->inStart + 5 + msgLength;
877
878 /*
879 * Return zero to allow input parsing to continue. Subsequent "D"
880 * messages will be ignored until we get to end of data, since an error
881 * result is already set up.
882 */
883 return 0;
884}
885
886
887/*
888 * Attempt to read an Error or Notice response message.
889 * This is possible in several places, so we break it out as a subroutine.
890 *
891 * Entry: 'E' or 'N' message type and length have already been consumed.
892 * Exit: returns 0 if successfully consumed message.
893 * returns EOF if not enough data.
894 */
895int
896 pqGetErrorNotice3(PGconn *conn, bool isError)
897{
898 PGresult *res = NULL;
899 bool have_position = false;
900 PQExpBufferData workBuf;
901 char id;
902
903 /* If in pipeline mode, set error indicator for it */
904 if (isError && conn->pipelineStatus != PQ_PIPELINE_OFF)
905 conn->pipelineStatus = PQ_PIPELINE_ABORTED;
906
907 /*
908 * If this is an error message, pre-emptively clear any incomplete query
909 * result we may have. We'd just throw it away below anyway, and
910 * releasing it before collecting the error might avoid out-of-memory.
911 */
912 if (isError)
913 pqClearAsyncResult(conn);
914
915 /*
916 * Since the fields might be pretty long, we create a temporary
917 * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended
918 * for stuff that is expected to be short. We shouldn't use
919 * conn->errorMessage either, since this might be only a notice.
920 */
921 initPQExpBuffer(&workBuf);
922
923 /*
924 * Make a PGresult to hold the accumulated fields. We temporarily lie
925 * about the result status, so that PQmakeEmptyPGresult doesn't uselessly
926 * copy conn->errorMessage.
927 *
928 * NB: This allocation can fail, if you run out of memory. The rest of the
929 * function handles that gracefully, and we still try to set the error
930 * message as the connection's error message.
931 */
932 res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
933 if (res)
934 res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
935
936 /*
937 * Read the fields and save into res.
938 *
939 * While at it, save the SQLSTATE in conn->last_sqlstate, and note whether
940 * we saw a PG_DIAG_STATEMENT_POSITION field.
941 */
942 for (;;)
943 {
944 if (pqGetc(&id, conn))
945 goto fail;
946 if (id == '0円')
947 break; /* terminator found */
948 if (pqGets(&workBuf, conn))
949 goto fail;
950 pqSaveMessageField(res, id, workBuf.data);
951 if (id == PG_DIAG_SQLSTATE)
952 strlcpy(conn->last_sqlstate, workBuf.data,
953 sizeof(conn->last_sqlstate));
954 else if (id == PG_DIAG_STATEMENT_POSITION)
955 have_position = true;
956 }
957
958 /*
959 * Save the active query text, if any, into res as well; but only if we
960 * might need it for an error cursor display, which is only true if there
961 * is a PG_DIAG_STATEMENT_POSITION field.
962 */
963 if (have_position && res && conn->cmd_queue_head && conn->cmd_queue_head->query)
964 res->errQuery = pqResultStrdup(res, conn->cmd_queue_head->query);
965
966 /*
967 * Now build the "overall" error message for PQresultErrorMessage.
968 */
969 resetPQExpBuffer(&workBuf);
970 pqBuildErrorMessage3(&workBuf, res, conn->verbosity, conn->show_context);
971
972 /*
973 * Either save error as current async result, or just emit the notice.
974 */
975 if (isError)
976 {
977 pqClearAsyncResult(conn); /* redundant, but be safe */
978 if (res)
979 {
980 pqSetResultError(res, &workBuf, 0);
981 conn->result = res;
982 }
983 else
984 {
985 /* Fall back to using the internal-error processing paths */
986 conn->error_result = true;
987 }
988
989 if (PQExpBufferDataBroken(workBuf))
990 libpq_append_conn_error(conn, "out of memory");
991 else
992 appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
993 }
994 else
995 {
996 /* if we couldn't allocate the result set, just discard the NOTICE */
997 if (res)
998 {
999 /*
1000 * We can cheat a little here and not copy the message. But if we
1001 * were unlucky enough to run out of memory while filling workBuf,
1002 * insert "out of memory", as in pqSetResultError.
1003 */
1004 if (PQExpBufferDataBroken(workBuf))
1005 res->errMsg = libpq_gettext("out of memory\n");
1006 else
1007 res->errMsg = workBuf.data;
1008 if (res->noticeHooks.noticeRec != NULL)
1009 res->noticeHooks.noticeRec(res->noticeHooks.noticeRecArg, res);
1010 PQclear(res);
1011 }
1012 }
1013
1014 termPQExpBuffer(&workBuf);
1015 return 0;
1016
1017fail:
1018 PQclear(res);
1019 termPQExpBuffer(&workBuf);
1020 return EOF;
1021}
1022
1023/*
1024 * Construct an error message from the fields in the given PGresult,
1025 * appending it to the contents of "msg".
1026 */
1027void
1028 pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res,
1029 PGVerbosity verbosity, PGContextVisibility show_context)
1030{
1031 const char *val;
1032 const char *querytext = NULL;
1033 int querypos = 0;
1034
1035 /* If we couldn't allocate a PGresult, just say "out of memory" */
1036 if (res == NULL)
1037 {
1038 appendPQExpBufferStr(msg, libpq_gettext("out of memory\n"));
1039 return;
1040 }
1041
1042 /*
1043 * If we don't have any broken-down fields, just return the base message.
1044 * This mainly applies if we're given a libpq-generated error result.
1045 */
1046 if (res->errFields == NULL)
1047 {
1048 if (res->errMsg && res->errMsg[0])
1049 appendPQExpBufferStr(msg, res->errMsg);
1050 else
1051 appendPQExpBufferStr(msg, libpq_gettext("no error message available\n"));
1052 return;
1053 }
1054
1055 /* Else build error message from relevant fields */
1056 val = PQresultErrorField(res, PG_DIAG_SEVERITY);
1057 if (val)
1058 appendPQExpBuffer(msg, "%s: ", val);
1059
1060 if (verbosity == PQERRORS_SQLSTATE)
1061 {
1062 /*
1063 * If we have a SQLSTATE, print that and nothing else. If not (which
1064 * shouldn't happen for server-generated errors, but might possibly
1065 * happen for libpq-generated ones), fall back to TERSE format, as
1066 * that seems better than printing nothing at all.
1067 */
1068 val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
1069 if (val)
1070 {
1071 appendPQExpBuffer(msg, "%s\n", val);
1072 return;
1073 }
1074 verbosity = PQERRORS_TERSE;
1075 }
1076
1077 if (verbosity == PQERRORS_VERBOSE)
1078 {
1079 val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
1080 if (val)
1081 appendPQExpBuffer(msg, "%s: ", val);
1082 }
1083 val = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
1084 if (val)
1085 appendPQExpBufferStr(msg, val);
1086 val = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION);
1087 if (val)
1088 {
1089 if (verbosity != PQERRORS_TERSE && res->errQuery != NULL)
1090 {
1091 /* emit position as a syntax cursor display */
1092 querytext = res->errQuery;
1093 querypos = atoi(val);
1094 }
1095 else
1096 {
1097 /* emit position as text addition to primary message */
1098 /* translator: %s represents a digit string */
1099 appendPQExpBuffer(msg, libpq_gettext(" at character %s"),
1100 val);
1101 }
1102 }
1103 else
1104 {
1105 val = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION);
1106 if (val)
1107 {
1108 querytext = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
1109 if (verbosity != PQERRORS_TERSE && querytext != NULL)
1110 {
1111 /* emit position as a syntax cursor display */
1112 querypos = atoi(val);
1113 }
1114 else
1115 {
1116 /* emit position as text addition to primary message */
1117 /* translator: %s represents a digit string */
1118 appendPQExpBuffer(msg, libpq_gettext(" at character %s"),
1119 val);
1120 }
1121 }
1122 }
1123 appendPQExpBufferChar(msg, '\n');
1124 if (verbosity != PQERRORS_TERSE)
1125 {
1126 if (querytext && querypos > 0)
1127 reportErrorPosition(msg, querytext, querypos,
1128 res->client_encoding);
1129 val = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
1130 if (val)
1131 appendPQExpBuffer(msg, libpq_gettext("DETAIL: %s\n"), val);
1132 val = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
1133 if (val)
1134 appendPQExpBuffer(msg, libpq_gettext("HINT: %s\n"), val);
1135 val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
1136 if (val)
1137 appendPQExpBuffer(msg, libpq_gettext("QUERY: %s\n"), val);
1138 if (show_context == PQSHOW_CONTEXT_ALWAYS ||
1139 (show_context == PQSHOW_CONTEXT_ERRORS &&
1140 res->resultStatus == PGRES_FATAL_ERROR))
1141 {
1142 val = PQresultErrorField(res, PG_DIAG_CONTEXT);
1143 if (val)
1144 appendPQExpBuffer(msg, libpq_gettext("CONTEXT: %s\n"),
1145 val);
1146 }
1147 }
1148 if (verbosity == PQERRORS_VERBOSE)
1149 {
1150 val = PQresultErrorField(res, PG_DIAG_SCHEMA_NAME);
1151 if (val)
1152 appendPQExpBuffer(msg,
1153 libpq_gettext("SCHEMA NAME: %s\n"), val);
1154 val = PQresultErrorField(res, PG_DIAG_TABLE_NAME);
1155 if (val)
1156 appendPQExpBuffer(msg,
1157 libpq_gettext("TABLE NAME: %s\n"), val);
1158 val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME);
1159 if (val)
1160 appendPQExpBuffer(msg,
1161 libpq_gettext("COLUMN NAME: %s\n"), val);
1162 val = PQresultErrorField(res, PG_DIAG_DATATYPE_NAME);
1163 if (val)
1164 appendPQExpBuffer(msg,
1165 libpq_gettext("DATATYPE NAME: %s\n"), val);
1166 val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_NAME);
1167 if (val)
1168 appendPQExpBuffer(msg,
1169 libpq_gettext("CONSTRAINT NAME: %s\n"), val);
1170 }
1171 if (verbosity == PQERRORS_VERBOSE)
1172 {
1173 const char *valf;
1174 const char *vall;
1175
1176 valf = PQresultErrorField(res, PG_DIAG_SOURCE_FILE);
1177 vall = PQresultErrorField(res, PG_DIAG_SOURCE_LINE);
1178 val = PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION);
1179 if (val || valf || vall)
1180 {
1181 appendPQExpBufferStr(msg, libpq_gettext("LOCATION: "));
1182 if (val)
1183 appendPQExpBuffer(msg, libpq_gettext("%s, "), val);
1184 if (valf && vall) /* unlikely we'd have just one */
1185 appendPQExpBuffer(msg, libpq_gettext("%s:%s"),
1186 valf, vall);
1187 appendPQExpBufferChar(msg, '\n');
1188 }
1189 }
1190}
1191
1192/*
1193 * Add an error-location display to the error message under construction.
1194 *
1195 * The cursor location is measured in logical characters; the query string
1196 * is presumed to be in the specified encoding.
1197 */
1198static void
1199 reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding)
1200{
1201#define DISPLAY_SIZE 60 /* screen width limit, in screen cols */
1202#define MIN_RIGHT_CUT 10 /* try to keep this far away from EOL */
1203
1204 char *wquery;
1205 int slen,
1206 cno,
1207 i,
1208 *qidx,
1209 *scridx,
1210 qoffset,
1211 scroffset,
1212 ibeg,
1213 iend,
1214 loc_line;
1215 bool mb_encoding,
1216 beg_trunc,
1217 end_trunc;
1218
1219 /* Convert loc from 1-based to 0-based; no-op if out of range */
1220 loc--;
1221 if (loc < 0)
1222 return;
1223
1224 /* Need a writable copy of the query */
1225 wquery = strdup(query);
1226 if (wquery == NULL)
1227 return; /* fail silently if out of memory */
1228
1229 /*
1230 * Each character might occupy multiple physical bytes in the string, and
1231 * in some Far Eastern character sets it might take more than one screen
1232 * column as well. We compute the starting byte offset and starting
1233 * screen column of each logical character, and store these in qidx[] and
1234 * scridx[] respectively.
1235 */
1236
1237 /* we need a safe allocation size... */
1238 slen = strlen(wquery) + 1;
1239
1240 qidx = (int *) malloc(slen * sizeof(int));
1241 if (qidx == NULL)
1242 {
1243 free(wquery);
1244 return;
1245 }
1246 scridx = (int *) malloc(slen * sizeof(int));
1247 if (scridx == NULL)
1248 {
1249 free(qidx);
1250 free(wquery);
1251 return;
1252 }
1253
1254 /* We can optimize a bit if it's a single-byte encoding */
1255 mb_encoding = (pg_encoding_max_length(encoding) != 1);
1256
1257 /*
1258 * Within the scanning loop, cno is the current character's logical
1259 * number, qoffset is its offset in wquery, and scroffset is its starting
1260 * logical screen column (all indexed from 0). "loc" is the logical
1261 * character number of the error location. We scan to determine loc_line
1262 * (the 1-based line number containing loc) and ibeg/iend (first character
1263 * number and last+1 character number of the line containing loc). Note
1264 * that qidx[] and scridx[] are filled only as far as iend.
1265 */
1266 qoffset = 0;
1267 scroffset = 0;
1268 loc_line = 1;
1269 ibeg = 0;
1270 iend = -1; /* -1 means not set yet */
1271
1272 for (cno = 0; wquery[qoffset] != '0円'; cno++)
1273 {
1274 char ch = wquery[qoffset];
1275
1276 qidx[cno] = qoffset;
1277 scridx[cno] = scroffset;
1278
1279 /*
1280 * Replace tabs with spaces in the writable copy. (Later we might
1281 * want to think about coping with their variable screen width, but
1282 * not today.)
1283 */
1284 if (ch == '\t')
1285 wquery[qoffset] = ' ';
1286
1287 /*
1288 * If end-of-line, count lines and mark positions. Each \r or \n
1289 * counts as a line except when \r \n appear together.
1290 */
1291 else if (ch == '\r' || ch == '\n')
1292 {
1293 if (cno < loc)
1294 {
1295 if (ch == '\r' ||
1296 cno == 0 ||
1297 wquery[qidx[cno - 1]] != '\r')
1298 loc_line++;
1299 /* extract beginning = last line start before loc. */
1300 ibeg = cno + 1;
1301 }
1302 else
1303 {
1304 /* set extract end. */
1305 iend = cno;
1306 /* done scanning. */
1307 break;
1308 }
1309 }
1310
1311 /* Advance */
1312 if (mb_encoding)
1313 {
1314 int w;
1315
1316 w = pg_encoding_dsplen(encoding, &wquery[qoffset]);
1317 /* treat any non-tab control chars as width 1 */
1318 if (w <= 0)
1319 w = 1;
1320 scroffset += w;
1321 qoffset += PQmblenBounded(&wquery[qoffset], encoding);
1322 }
1323 else
1324 {
1325 /* We assume wide chars only exist in multibyte encodings */
1326 scroffset++;
1327 qoffset++;
1328 }
1329 }
1330 /* Fix up if we didn't find an end-of-line after loc */
1331 if (iend < 0)
1332 {
1333 iend = cno; /* query length in chars, +1 */
1334 qidx[iend] = qoffset;
1335 scridx[iend] = scroffset;
1336 }
1337
1338 /* Print only if loc is within computed query length */
1339 if (loc <= cno)
1340 {
1341 /* If the line extracted is too long, we truncate it. */
1342 beg_trunc = false;
1343 end_trunc = false;
1344 if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
1345 {
1346 /*
1347 * We first truncate right if it is enough. This code might be
1348 * off a space or so on enforcing MIN_RIGHT_CUT if there's a wide
1349 * character right there, but that should be okay.
1350 */
1351 if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT)
1352 {
1353 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
1354 iend--;
1355 end_trunc = true;
1356 }
1357 else
1358 {
1359 /* Truncate right if not too close to loc. */
1360 while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend])
1361 {
1362 iend--;
1363 end_trunc = true;
1364 }
1365
1366 /* Truncate left if still too long. */
1367 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
1368 {
1369 ibeg++;
1370 beg_trunc = true;
1371 }
1372 }
1373 }
1374
1375 /* truncate working copy at desired endpoint */
1376 wquery[qidx[iend]] = '0円';
1377
1378 /* Begin building the finished message. */
1379 i = msg->len;
1380 appendPQExpBuffer(msg, libpq_gettext("LINE %d: "), loc_line);
1381 if (beg_trunc)
1382 appendPQExpBufferStr(msg, "...");
1383
1384 /*
1385 * While we have the prefix in the msg buffer, compute its screen
1386 * width.
1387 */
1388 scroffset = 0;
1389 for (; i < msg->len; i += PQmblenBounded(&msg->data[i], encoding))
1390 {
1391 int w = pg_encoding_dsplen(encoding, &msg->data[i]);
1392
1393 if (w <= 0)
1394 w = 1;
1395 scroffset += w;
1396 }
1397
1398 /* Finish up the LINE message line. */
1399 appendPQExpBufferStr(msg, &wquery[qidx[ibeg]]);
1400 if (end_trunc)
1401 appendPQExpBufferStr(msg, "...");
1402 appendPQExpBufferChar(msg, '\n');
1403
1404 /* Now emit the cursor marker line. */
1405 scroffset += scridx[loc] - scridx[ibeg];
1406 for (i = 0; i < scroffset; i++)
1407 appendPQExpBufferChar(msg, ' ');
1408 appendPQExpBufferChar(msg, '^');
1409 appendPQExpBufferChar(msg, '\n');
1410 }
1411
1412 /* Clean up. */
1413 free(scridx);
1414 free(qidx);
1415 free(wquery);
1416}
1417
1418
1419/*
1420 * Attempt to read a NegotiateProtocolVersion message. Sets conn->pversion
1421 * to the version that's negotiated by the server.
1422 *
1423 * Entry: 'v' message type and length have already been consumed.
1424 * Exit: returns 0 if successfully consumed message.
1425 * returns 1 on failure. The error message is filled in.
1426 */
1427int
1428 pqGetNegotiateProtocolVersion3(PGconn *conn)
1429{
1430 int their_version;
1431 int num;
1432
1433 if (pqGetInt(&their_version, 4, conn) != 0)
1434 goto eof;
1435
1436 if (pqGetInt(&num, 4, conn) != 0)
1437 goto eof;
1438
1439 /* Check the protocol version */
1440 if (their_version > conn->pversion)
1441 {
1442 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to a higher-numbered version");
1443 goto failure;
1444 }
1445
1446 if (their_version < PG_PROTOCOL(3, 0))
1447 {
1448 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to pre-3.0 protocol version");
1449 goto failure;
1450 }
1451
1452 /* 3.1 never existed, we went straight from 3.0 to 3.2 */
1453 if (their_version == PG_PROTOCOL(3, 1))
1454 {
1455 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to non-existent 3.1 protocol version");
1456 goto failure;
1457 }
1458
1459 if (num < 0)
1460 {
1461 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported negative number of unsupported parameters");
1462 goto failure;
1463 }
1464
1465 if (their_version == conn->pversion && num == 0)
1466 {
1467 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server negotiated but asks for no changes");
1468 goto failure;
1469 }
1470
1471 if (their_version < conn->min_pversion)
1472 {
1473 libpq_append_conn_error(conn, "server only supports protocol version %d.%d, but \"%s\" was set to %d.%d",
1474 PG_PROTOCOL_MAJOR(their_version),
1475 PG_PROTOCOL_MINOR(their_version),
1476 "min_protocol_version",
1477 PG_PROTOCOL_MAJOR(conn->min_pversion),
1478 PG_PROTOCOL_MINOR(conn->min_pversion));
1479
1480 goto failure;
1481 }
1482
1483 /* the version is acceptable */
1484 conn->pversion = their_version;
1485
1486 /*
1487 * We don't currently request any protocol extensions, so we don't expect
1488 * the server to reply with any either.
1489 */
1490 for (int i = 0; i < num; i++)
1491 {
1492 if (pqGets(&conn->workBuffer, conn))
1493 {
1494 goto eof;
1495 }
1496 if (strncmp(conn->workBuffer.data, "_pq_.", 5) != 0)
1497 {
1498 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported unsupported parameter name without a \"%s\" prefix (\"%s\")", "_pq_.", conn->workBuffer.data);
1499 goto failure;
1500 }
1501 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported an unsupported parameter that was not requested (\"%s\")", conn->workBuffer.data);
1502 goto failure;
1503 }
1504
1505 return 0;
1506
1507eof:
1508 libpq_append_conn_error(conn, "received invalid protocol negotiation message: message too short");
1509failure:
1510 conn->asyncStatus = PGASYNC_READY;
1511 pqSaveErrorResult(conn);
1512 return 1;
1513}
1514
1515
1516/*
1517 * Attempt to read a ParameterStatus message.
1518 * This is possible in several places, so we break it out as a subroutine.
1519 *
1520 * Entry: 'S' message type and length have already been consumed.
1521 * Exit: returns 0 if successfully consumed message.
1522 * returns EOF if not enough data.
1523 */
1524static int
1525 getParameterStatus(PGconn *conn)
1526{
1527 PQExpBufferData valueBuf;
1528
1529 /* Get the parameter name */
1530 if (pqGets(&conn->workBuffer, conn))
1531 return EOF;
1532 /* Get the parameter value (could be large) */
1533 initPQExpBuffer(&valueBuf);
1534 if (pqGets(&valueBuf, conn))
1535 {
1536 termPQExpBuffer(&valueBuf);
1537 return EOF;
1538 }
1539 /* And save it */
1540 if (!pqSaveParameterStatus(conn, conn->workBuffer.data, valueBuf.data))
1541 {
1542 libpq_append_conn_error(conn, "out of memory");
1543 handleFatalError(conn);
1544 }
1545 termPQExpBuffer(&valueBuf);
1546 return 0;
1547}
1548
1549/*
1550 * parseInput subroutine to read a BackendKeyData message.
1551 * Entry: 'v' message type and length have already been consumed.
1552 * Exit: returns 0 if successfully consumed message.
1553 * returns EOF if not enough data.
1554 */
1555static int
1556 getBackendKeyData(PGconn *conn, int msgLength)
1557{
1558 int cancel_key_len;
1559
1560 if (conn->be_cancel_key)
1561 {
1562 free(conn->be_cancel_key);
1563 conn->be_cancel_key = NULL;
1564 conn->be_cancel_key_len = 0;
1565 }
1566
1567 if (pqGetInt(&(conn->be_pid), 4, conn))
1568 return EOF;
1569
1570 cancel_key_len = 5 + msgLength - (conn->inCursor - conn->inStart);
1571
1572 if (cancel_key_len != 4 && conn->pversion == PG_PROTOCOL(3, 0))
1573 {
1574 libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d not allowed in protocol version 3.0 (must be 4 bytes)", cancel_key_len);
1575 handleFatalError(conn);
1576 return 0;
1577 }
1578
1579 if (cancel_key_len < 4)
1580 {
1581 libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d is too short (minimum 4 bytes)", cancel_key_len);
1582 handleFatalError(conn);
1583 return 0;
1584 }
1585
1586 if (cancel_key_len > 256)
1587 {
1588 libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d is too long (maximum 256 bytes)", cancel_key_len);
1589 handleFatalError(conn);
1590 return 0;
1591 }
1592
1593 conn->be_cancel_key = malloc(cancel_key_len);
1594 if (conn->be_cancel_key == NULL)
1595 {
1596 libpq_append_conn_error(conn, "out of memory");
1597 handleFatalError(conn);
1598 return 0;
1599 }
1600 if (pqGetnchar(conn->be_cancel_key, cancel_key_len, conn))
1601 {
1602 free(conn->be_cancel_key);
1603 conn->be_cancel_key = NULL;
1604 return EOF;
1605 }
1606 conn->be_cancel_key_len = cancel_key_len;
1607 return 0;
1608}
1609
1610
1611/*
1612 * Attempt to read a Notify response message.
1613 * This is possible in several places, so we break it out as a subroutine.
1614 *
1615 * Entry: 'A' message type and length have already been consumed.
1616 * Exit: returns 0 if successfully consumed Notify message.
1617 * returns EOF if not enough data.
1618 */
1619static int
1620 getNotify(PGconn *conn)
1621{
1622 int be_pid;
1623 char *svname;
1624 int nmlen;
1625 int extralen;
1626 PGnotify *newNotify;
1627
1628 if (pqGetInt(&be_pid, 4, conn))
1629 return EOF;
1630 if (pqGets(&conn->workBuffer, conn))
1631 return EOF;
1632 /* must save name while getting extra string */
1633 svname = strdup(conn->workBuffer.data);
1634 if (!svname)
1635 {
1636 /*
1637 * Notify messages can arrive at any state, so we cannot associate the
1638 * error with any particular query. There's no way to return back an
1639 * "async error", so the best we can do is drop the connection. That
1640 * seems better than silently ignoring the notification.
1641 */
1642 libpq_append_conn_error(conn, "out of memory");
1643 handleFatalError(conn);
1644 return 0;
1645 }
1646 if (pqGets(&conn->workBuffer, conn))
1647 {
1648 free(svname);
1649 return EOF;
1650 }
1651
1652 /*
1653 * Store the strings right after the PGnotify structure so it can all be
1654 * freed at once. We don't use NAMEDATALEN because we don't want to tie
1655 * this interface to a specific server name length.
1656 */
1657 nmlen = strlen(svname);
1658 extralen = strlen(conn->workBuffer.data);
1659 newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + extralen + 2);
1660 if (!newNotify)
1661 {
1662 free(svname);
1663 libpq_append_conn_error(conn, "out of memory");
1664 handleFatalError(conn);
1665 return 0;
1666 }
1667
1668 newNotify->relname = (char *) newNotify + sizeof(PGnotify);
1669 strcpy(newNotify->relname, svname);
1670 newNotify->extra = newNotify->relname + nmlen + 1;
1671 strcpy(newNotify->extra, conn->workBuffer.data);
1672 newNotify->be_pid = be_pid;
1673 newNotify->next = NULL;
1674 if (conn->notifyTail)
1675 conn->notifyTail->next = newNotify;
1676 else
1677 conn->notifyHead = newNotify;
1678 conn->notifyTail = newNotify;
1679
1680 free(svname);
1681 return 0;
1682}
1683
1684/*
1685 * getCopyStart - process CopyInResponse, CopyOutResponse or
1686 * CopyBothResponse message
1687 *
1688 * parseInput already read the message type and length.
1689 */
1690static int
1691 getCopyStart(PGconn *conn, ExecStatusType copytype)
1692{
1693 PGresult *result;
1694 int nfields;
1695 int i;
1696
1697 result = PQmakeEmptyPGresult(conn, copytype);
1698 if (!result)
1699 goto failure;
1700
1701 if (pqGetc(&conn->copy_is_binary, conn))
1702 goto failure;
1703 result->binary = conn->copy_is_binary;
1704 /* the next two bytes are the number of fields */
1705 if (pqGetInt(&(result->numAttributes), 2, conn))
1706 goto failure;
1707 nfields = result->numAttributes;
1708
1709 /* allocate space for the attribute descriptors */
1710 if (nfields > 0)
1711 {
1712 result->attDescs = (PGresAttDesc *)
1713 pqResultAlloc(result, nfields * sizeof(PGresAttDesc), true);
1714 if (!result->attDescs)
1715 goto failure;
1716 MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
1717 }
1718
1719 for (i = 0; i < nfields; i++)
1720 {
1721 int format;
1722
1723 if (pqGetInt(&format, 2, conn))
1724 goto failure;
1725
1726 /*
1727 * Since pqGetInt treats 2-byte integers as unsigned, we need to
1728 * coerce these results to signed form.
1729 */
1730 format = (int) ((int16) format);
1731 result->attDescs[i].format = format;
1732 }
1733
1734 /* Success! */
1735 conn->result = result;
1736 return 0;
1737
1738failure:
1739 PQclear(result);
1740 return EOF;
1741}
1742
1743/*
1744 * getReadyForQuery - process ReadyForQuery message
1745 */
1746static int
1747 getReadyForQuery(PGconn *conn)
1748{
1749 char xact_status;
1750
1751 if (pqGetc(&xact_status, conn))
1752 return EOF;
1753 switch (xact_status)
1754 {
1755 case 'I':
1756 conn->xactStatus = PQTRANS_IDLE;
1757 break;
1758 case 'T':
1759 conn->xactStatus = PQTRANS_INTRANS;
1760 break;
1761 case 'E':
1762 conn->xactStatus = PQTRANS_INERROR;
1763 break;
1764 default:
1765 conn->xactStatus = PQTRANS_UNKNOWN;
1766 break;
1767 }
1768
1769 return 0;
1770}
1771
1772/*
1773 * getCopyDataMessage - fetch next CopyData message, process async messages
1774 *
1775 * Returns length word of CopyData message (> 0), or 0 if no complete
1776 * message available, -1 if end of copy, -2 if error.
1777 */
1778static int
1779 getCopyDataMessage(PGconn *conn)
1780{
1781 char id;
1782 int msgLength;
1783 int avail;
1784
1785 for (;;)
1786 {
1787 /*
1788 * Do we have the next input message? To make life simpler for async
1789 * callers, we keep returning 0 until the next message is fully
1790 * available, even if it is not Copy Data.
1791 */
1792 conn->inCursor = conn->inStart;
1793 if (pqGetc(&id, conn))
1794 return 0;
1795 if (pqGetInt(&msgLength, 4, conn))
1796 return 0;
1797 if (msgLength < 4)
1798 {
1799 handleSyncLoss(conn, id, msgLength);
1800 return -2;
1801 }
1802 avail = conn->inEnd - conn->inCursor;
1803 if (avail < msgLength - 4)
1804 {
1805 /*
1806 * Before returning, enlarge the input buffer if needed to hold
1807 * the whole message. See notes in parseInput.
1808 */
1809 if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength - 4,
1810 conn))
1811 {
1812 /*
1813 * Abandon the connection. There's not much else we can
1814 * safely do; we can't just ignore the message or we could
1815 * miss important changes to the connection state.
1816 * pqCheckInBufferSpace() already reported the error.
1817 */
1818 handleFatalError(conn);
1819 return -2;
1820 }
1821 return 0;
1822 }
1823
1824 /*
1825 * If it's a legitimate async message type, process it. (NOTIFY
1826 * messages are not currently possible here, but we handle them for
1827 * completeness.) Otherwise, if it's anything except Copy Data,
1828 * report end-of-copy.
1829 */
1830 switch (id)
1831 {
1832 case PqMsg_NotificationResponse:
1833 if (getNotify(conn))
1834 return 0;
1835 break;
1836 case PqMsg_NoticeResponse:
1837 if (pqGetErrorNotice3(conn, false))
1838 return 0;
1839 break;
1840 case PqMsg_ParameterStatus:
1841 if (getParameterStatus(conn))
1842 return 0;
1843 break;
1844 case PqMsg_CopyData:
1845 return msgLength;
1846 case PqMsg_CopyDone:
1847
1848 /*
1849 * If this is a CopyDone message, exit COPY_OUT mode and let
1850 * caller read status with PQgetResult(). If we're in
1851 * COPY_BOTH mode, return to COPY_IN mode.
1852 */
1853 if (conn->asyncStatus == PGASYNC_COPY_BOTH)
1854 conn->asyncStatus = PGASYNC_COPY_IN;
1855 else
1856 conn->asyncStatus = PGASYNC_BUSY;
1857 return -1;
1858 default: /* treat as end of copy */
1859
1860 /*
1861 * Any other message terminates either COPY_IN or COPY_BOTH
1862 * mode.
1863 */
1864 conn->asyncStatus = PGASYNC_BUSY;
1865 return -1;
1866 }
1867
1868 /* Drop the processed message and loop around for another */
1869 pqParseDone(conn, conn->inCursor);
1870 }
1871}
1872
1873/*
1874 * PQgetCopyData - read a row of data from the backend during COPY OUT
1875 * or COPY BOTH
1876 *
1877 * If successful, sets *buffer to point to a malloc'd row of data, and
1878 * returns row length (always > 0) as result.
1879 * Returns 0 if no row available yet (only possible if async is true),
1880 * -1 if end of copy (consult PQgetResult), or -2 if error (consult
1881 * PQerrorMessage).
1882 */
1883int
1884 pqGetCopyData3(PGconn *conn, char **buffer, int async)
1885{
1886 int msgLength;
1887
1888 for (;;)
1889 {
1890 /*
1891 * Collect the next input message. To make life simpler for async
1892 * callers, we keep returning 0 until the next message is fully
1893 * available, even if it is not Copy Data.
1894 */
1895 msgLength = getCopyDataMessage(conn);
1896 if (msgLength < 0)
1897 return msgLength; /* end-of-copy or error */
1898 if (msgLength == 0)
1899 {
1900 /* Don't block if async read requested */
1901 if (async)
1902 return 0;
1903 /* Need to load more data */
1904 if (pqWait(true, false, conn) ||
1905 pqReadData(conn) < 0)
1906 return -2;
1907 continue;
1908 }
1909
1910 /*
1911 * Drop zero-length messages (shouldn't happen anyway). Otherwise
1912 * pass the data back to the caller.
1913 */
1914 msgLength -= 4;
1915 if (msgLength > 0)
1916 {
1917 *buffer = (char *) malloc(msgLength + 1);
1918 if (*buffer == NULL)
1919 {
1920 libpq_append_conn_error(conn, "out of memory");
1921 return -2;
1922 }
1923 memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength);
1924 (*buffer)[msgLength] = '0円'; /* Add terminating null */
1925
1926 /* Mark message consumed */
1927 pqParseDone(conn, conn->inCursor + msgLength);
1928
1929 return msgLength;
1930 }
1931
1932 /* Empty, so drop it and loop around for another */
1933 pqParseDone(conn, conn->inCursor);
1934 }
1935}
1936
1937/*
1938 * PQgetline - gets a newline-terminated string from the backend.
1939 *
1940 * See fe-exec.c for documentation.
1941 */
1942int
1943 pqGetline3(PGconn *conn, char *s, int maxlen)
1944{
1945 int status;
1946
1947 if (conn->sock == PGINVALID_SOCKET ||
1948 (conn->asyncStatus != PGASYNC_COPY_OUT &&
1949 conn->asyncStatus != PGASYNC_COPY_BOTH) ||
1950 conn->copy_is_binary)
1951 {
1952 libpq_append_conn_error(conn, "PQgetline: not doing text COPY OUT");
1953 *s = '0円';
1954 return EOF;
1955 }
1956
1957 while ((status = PQgetlineAsync(conn, s, maxlen - 1)) == 0)
1958 {
1959 /* need to load more data */
1960 if (pqWait(true, false, conn) ||
1961 pqReadData(conn) < 0)
1962 {
1963 *s = '0円';
1964 return EOF;
1965 }
1966 }
1967
1968 if (status < 0)
1969 {
1970 /* End of copy detected; gin up old-style terminator */
1971 strcpy(s, "\\.");
1972 return 0;
1973 }
1974
1975 /* Add null terminator, and strip trailing \n if present */
1976 if (s[status - 1] == '\n')
1977 {
1978 s[status - 1] = '0円';
1979 return 0;
1980 }
1981 else
1982 {
1983 s[status] = '0円';
1984 return 1;
1985 }
1986}
1987
1988/*
1989 * PQgetlineAsync - gets a COPY data row without blocking.
1990 *
1991 * See fe-exec.c for documentation.
1992 */
1993int
1994 pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize)
1995{
1996 int msgLength;
1997 int avail;
1998
1999 if (conn->asyncStatus != PGASYNC_COPY_OUT
2000 && conn->asyncStatus != PGASYNC_COPY_BOTH)
2001 return -1; /* we are not doing a copy... */
2002
2003 /*
2004 * Recognize the next input message. To make life simpler for async
2005 * callers, we keep returning 0 until the next message is fully available
2006 * even if it is not Copy Data. This should keep PQendcopy from blocking.
2007 * (Note: unlike pqGetCopyData3, we do not change asyncStatus here.)
2008 */
2009 msgLength = getCopyDataMessage(conn);
2010 if (msgLength < 0)
2011 return -1; /* end-of-copy or error */
2012 if (msgLength == 0)
2013 return 0; /* no data yet */
2014
2015 /*
2016 * Move data from libpq's buffer to the caller's. In the case where a
2017 * prior call found the caller's buffer too small, we use
2018 * conn->copy_already_done to remember how much of the row was already
2019 * returned to the caller.
2020 */
2021 conn->inCursor += conn->copy_already_done;
2022 avail = msgLength - 4 - conn->copy_already_done;
2023 if (avail <= bufsize)
2024 {
2025 /* Able to consume the whole message */
2026 memcpy(buffer, &conn->inBuffer[conn->inCursor], avail);
2027 /* Mark message consumed */
2028 conn->inStart = conn->inCursor + avail;
2029 /* Reset state for next time */
2030 conn->copy_already_done = 0;
2031 return avail;
2032 }
2033 else
2034 {
2035 /* We must return a partial message */
2036 memcpy(buffer, &conn->inBuffer[conn->inCursor], bufsize);
2037 /* The message is NOT consumed from libpq's buffer */
2038 conn->copy_already_done += bufsize;
2039 return bufsize;
2040 }
2041}
2042
2043/*
2044 * PQendcopy
2045 *
2046 * See fe-exec.c for documentation.
2047 */
2048int
2049 pqEndcopy3(PGconn *conn)
2050{
2051 PGresult *result;
2052
2053 if (conn->asyncStatus != PGASYNC_COPY_IN &&
2054 conn->asyncStatus != PGASYNC_COPY_OUT &&
2055 conn->asyncStatus != PGASYNC_COPY_BOTH)
2056 {
2057 libpq_append_conn_error(conn, "no COPY in progress");
2058 return 1;
2059 }
2060
2061 /* Send the CopyDone message if needed */
2062 if (conn->asyncStatus == PGASYNC_COPY_IN ||
2063 conn->asyncStatus == PGASYNC_COPY_BOTH)
2064 {
2065 if (pqPutMsgStart(PqMsg_CopyDone, conn) < 0 ||
2066 pqPutMsgEnd(conn) < 0)
2067 return 1;
2068
2069 /*
2070 * If we sent the COPY command in extended-query mode, we must issue a
2071 * Sync as well.
2072 */
2073 if (conn->cmd_queue_head &&
2074 conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE)
2075 {
2076 if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
2077 pqPutMsgEnd(conn) < 0)
2078 return 1;
2079 }
2080 }
2081
2082 /*
2083 * make sure no data is waiting to be sent, abort if we are non-blocking
2084 * and the flush fails
2085 */
2086 if (pqFlush(conn) && pqIsnonblocking(conn))
2087 return 1;
2088
2089 /* Return to active duty */
2090 conn->asyncStatus = PGASYNC_BUSY;
2091
2092 /*
2093 * Non blocking connections may have to abort at this point. If everyone
2094 * played the game there should be no problem, but in error scenarios the
2095 * expected messages may not have arrived yet. (We are assuming that the
2096 * backend's packetizing will ensure that CommandComplete arrives along
2097 * with the CopyDone; are there corner cases where that doesn't happen?)
2098 */
2099 if (pqIsnonblocking(conn) && PQisBusy(conn))
2100 return 1;
2101
2102 /* Wait for the completion response */
2103 result = PQgetResult(conn);
2104
2105 /* Expecting a successful result */
2106 if (result && result->resultStatus == PGRES_COMMAND_OK)
2107 {
2108 PQclear(result);
2109 return 0;
2110 }
2111
2112 /*
2113 * Trouble. For backwards-compatibility reasons, we issue the error
2114 * message as if it were a notice (would be nice to get rid of this
2115 * silliness, but too many apps probably don't handle errors from
2116 * PQendcopy reasonably). Note that the app can still obtain the error
2117 * status from the PGconn object.
2118 */
2119 if (conn->errorMessage.len > 0)
2120 {
2121 /* We have to strip the trailing newline ... pain in neck... */
2122 char svLast = conn->errorMessage.data[conn->errorMessage.len - 1];
2123
2124 if (svLast == '\n')
2125 conn->errorMessage.data[conn->errorMessage.len - 1] = '0円';
2126 pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data);
2127 conn->errorMessage.data[conn->errorMessage.len - 1] = svLast;
2128 }
2129
2130 PQclear(result);
2131
2132 return 1;
2133}
2134
2135
2136/*
2137 * PQfn - Send a function call to the POSTGRES backend.
2138 *
2139 * See fe-exec.c for documentation.
2140 */
2141PGresult *
2142 pqFunctionCall3(PGconn *conn, Oid fnid,
2143 int *result_buf, int *actual_result_len,
2144 int result_is_int,
2145 const PQArgBlock *args, int nargs)
2146{
2147 bool needInput = false;
2148 ExecStatusType status = PGRES_FATAL_ERROR;
2149 char id;
2150 int msgLength;
2151 int avail;
2152 int i;
2153
2154 /* already validated by PQfn */
2155 Assert(conn->pipelineStatus == PQ_PIPELINE_OFF);
2156
2157 /* PQfn already validated connection state */
2158
2159 if (pqPutMsgStart(PqMsg_FunctionCall, conn) < 0 ||
2160 pqPutInt(fnid, 4, conn) < 0 || /* function id */
2161 pqPutInt(1, 2, conn) < 0 || /* # of format codes */
2162 pqPutInt(1, 2, conn) < 0 || /* format code: BINARY */
2163 pqPutInt(nargs, 2, conn) < 0) /* # of args */
2164 {
2165 /* error message should be set up already */
2166 return NULL;
2167 }
2168
2169 for (i = 0; i < nargs; ++i)
2170 { /* len.int4 + contents */
2171 if (pqPutInt(args[i].len, 4, conn))
2172 return NULL;
2173 if (args[i].len == -1)
2174 continue; /* it's NULL */
2175
2176 if (args[i].isint)
2177 {
2178 if (pqPutInt(args[i].u.integer, args[i].len, conn))
2179 return NULL;
2180 }
2181 else
2182 {
2183 if (pqPutnchar(args[i].u.ptr, args[i].len, conn))
2184 return NULL;
2185 }
2186 }
2187
2188 if (pqPutInt(1, 2, conn) < 0) /* result format code: BINARY */
2189 return NULL;
2190
2191 if (pqPutMsgEnd(conn) < 0 ||
2192 pqFlush(conn))
2193 return NULL;
2194
2195 for (;;)
2196 {
2197 if (needInput)
2198 {
2199 /* Wait for some data to arrive (or for the channel to close) */
2200 if (pqWait(true, false, conn) ||
2201 pqReadData(conn) < 0)
2202 break;
2203 }
2204
2205 /*
2206 * Scan the message. If we run out of data, loop around to try again.
2207 */
2208 needInput = true;
2209
2210 conn->inCursor = conn->inStart;
2211 if (pqGetc(&id, conn))
2212 continue;
2213 if (pqGetInt(&msgLength, 4, conn))
2214 continue;
2215
2216 /*
2217 * Try to validate message type/length here. A length less than 4 is
2218 * definitely broken. Large lengths should only be believed for a few
2219 * message types.
2220 */
2221 if (msgLength < 4)
2222 {
2223 handleSyncLoss(conn, id, msgLength);
2224 break;
2225 }
2226 if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id))
2227 {
2228 handleSyncLoss(conn, id, msgLength);
2229 break;
2230 }
2231
2232 /*
2233 * Can't process if message body isn't all here yet.
2234 */
2235 msgLength -= 4;
2236 avail = conn->inEnd - conn->inCursor;
2237 if (avail < msgLength)
2238 {
2239 /*
2240 * Before looping, enlarge the input buffer if needed to hold the
2241 * whole message. See notes in parseInput.
2242 */
2243 if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
2244 conn))
2245 {
2246 /*
2247 * Abandon the connection. There's not much else we can
2248 * safely do; we can't just ignore the message or we could
2249 * miss important changes to the connection state.
2250 * pqCheckInBufferSpace() already reported the error.
2251 */
2252 handleFatalError(conn);
2253 break;
2254 }
2255 continue;
2256 }
2257
2258 /*
2259 * We should see V or E response to the command, but might get N
2260 * and/or A notices first. We also need to swallow the final Z before
2261 * returning.
2262 */
2263 switch (id)
2264 {
2265 case PqMsg_FunctionCallResponse:
2266 if (pqGetInt(actual_result_len, 4, conn))
2267 continue;
2268 if (*actual_result_len != -1)
2269 {
2270 if (result_is_int)
2271 {
2272 if (pqGetInt(result_buf, *actual_result_len, conn))
2273 continue;
2274 }
2275 else
2276 {
2277 if (pqGetnchar(result_buf,
2278 *actual_result_len,
2279 conn))
2280 continue;
2281 }
2282 }
2283 /* correctly finished function result message */
2284 status = PGRES_COMMAND_OK;
2285 break;
2286 case PqMsg_ErrorResponse:
2287 if (pqGetErrorNotice3(conn, true))
2288 continue;
2289 status = PGRES_FATAL_ERROR;
2290 break;
2291 case PqMsg_NotificationResponse:
2292 /* handle notify and go back to processing return values */
2293 if (getNotify(conn))
2294 continue;
2295 break;
2296 case PqMsg_NoticeResponse:
2297 /* handle notice and go back to processing return values */
2298 if (pqGetErrorNotice3(conn, false))
2299 continue;
2300 break;
2301 case PqMsg_ReadyForQuery:
2302 if (getReadyForQuery(conn))
2303 continue;
2304
2305 /* consume the message */
2306 pqParseDone(conn, conn->inStart + 5 + msgLength);
2307
2308 /*
2309 * If we already have a result object (probably an error), use
2310 * that. Otherwise, if we saw a function result message,
2311 * report COMMAND_OK. Otherwise, the backend violated the
2312 * protocol, so complain.
2313 */
2314 if (!pgHavePendingResult(conn))
2315 {
2316 if (status == PGRES_COMMAND_OK)
2317 {
2318 conn->result = PQmakeEmptyPGresult(conn, status);
2319 if (!conn->result)
2320 {
2321 libpq_append_conn_error(conn, "out of memory");
2322 pqSaveErrorResult(conn);
2323 }
2324 }
2325 else
2326 {
2327 libpq_append_conn_error(conn, "protocol error: no function result");
2328 pqSaveErrorResult(conn);
2329 }
2330 }
2331 /* and we're out */
2332 return pqPrepareAsyncResult(conn);
2333 case PqMsg_ParameterStatus:
2334 if (getParameterStatus(conn))
2335 continue;
2336 break;
2337 default:
2338 /* The backend violates the protocol. */
2339 libpq_append_conn_error(conn, "protocol error: id=0x%x", id);
2340 pqSaveErrorResult(conn);
2341
2342 /*
2343 * We can't call parsing done due to the protocol violation
2344 * (so message tracing wouldn't work), but trust the specified
2345 * message length as what to skip.
2346 */
2347 conn->inStart += 5 + msgLength;
2348 return pqPrepareAsyncResult(conn);
2349 }
2350
2351 /* Completed parsing this message, keep going */
2352 pqParseDone(conn, conn->inStart + 5 + msgLength);
2353 needInput = false;
2354 }
2355
2356 /*
2357 * We fall out of the loop only upon failing to read data.
2358 * conn->errorMessage has been set by pqWait or pqReadData. We want to
2359 * append it to any already-received error message.
2360 */
2361 pqSaveErrorResult(conn);
2362 return pqPrepareAsyncResult(conn);
2363}
2364
2365
2366/*
2367 * Construct startup packet
2368 *
2369 * Returns a malloc'd packet buffer, or NULL if out of memory
2370 */
2371char *
2372 pqBuildStartupPacket3(PGconn *conn, int *packetlen,
2373 const PQEnvironmentOption *options)
2374{
2375 char *startpacket;
2376
2377 *packetlen = build_startup_packet(conn, NULL, options);
2378 startpacket = (char *) malloc(*packetlen);
2379 if (!startpacket)
2380 return NULL;
2381 *packetlen = build_startup_packet(conn, startpacket, options);
2382 return startpacket;
2383}
2384
2385/*
2386 * Build a startup packet given a filled-in PGconn structure.
2387 *
2388 * We need to figure out how much space is needed, then fill it in.
2389 * To avoid duplicate logic, this routine is called twice: the first time
2390 * (with packet == NULL) just counts the space needed, the second time
2391 * (with packet == allocated space) fills it in. Return value is the number
2392 * of bytes used.
2393 */
2394static int
2395 build_startup_packet(const PGconn *conn, char *packet,
2396 const PQEnvironmentOption *options)
2397{
2398 int packet_len = 0;
2399 const PQEnvironmentOption *next_eo;
2400 const char *val;
2401
2402 /* Protocol version comes first. */
2403 if (packet)
2404 {
2405 ProtocolVersion pv = pg_hton32(conn->pversion);
2406
2407 memcpy(packet + packet_len, &pv, sizeof(ProtocolVersion));
2408 }
2409 packet_len += sizeof(ProtocolVersion);
2410
2411 /* Add user name, database name, options */
2412
2413#define ADD_STARTUP_OPTION(optname, optval) \
2414 do { \
2415 if (packet) \
2416 strcpy(packet + packet_len, optname); \
2417 packet_len += strlen(optname) + 1; \
2418 if (packet) \
2419 strcpy(packet + packet_len, optval); \
2420 packet_len += strlen(optval) + 1; \
2421 } while(0)
2422
2423 if (conn->pguser && conn->pguser[0])
2424 ADD_STARTUP_OPTION("user", conn->pguser);
2425 if (conn->dbName && conn->dbName[0])
2426 ADD_STARTUP_OPTION("database", conn->dbName);
2427 if (conn->replication && conn->replication[0])
2428 ADD_STARTUP_OPTION("replication", conn->replication);
2429 if (conn->pgoptions && conn->pgoptions[0])
2430 ADD_STARTUP_OPTION("options", conn->pgoptions);
2431 if (conn->send_appname)
2432 {
2433 /* Use appname if present, otherwise use fallback */
2434 val = conn->appname ? conn->appname : conn->fbappname;
2435 if (val && val[0])
2436 ADD_STARTUP_OPTION("application_name", val);
2437 }
2438
2439 if (conn->client_encoding_initial && conn->client_encoding_initial[0])
2440 ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial);
2441
2442 /* Add any environment-driven GUC settings needed */
2443 for (next_eo = options; next_eo->envName; next_eo++)
2444 {
2445 if ((val = getenv(next_eo->envName)) != NULL)
2446 {
2447 if (pg_strcasecmp(val, "default") != 0)
2448 ADD_STARTUP_OPTION(next_eo->pgName, val);
2449 }
2450 }
2451
2452 /* Add trailing terminator */
2453 if (packet)
2454 packet[packet_len] = '0円';
2455 packet_len++;
2456
2457 return packet_len;
2458}
int16_t int16
Definition: c.h:533
#define MemSet(start, val, len)
Definition: c.h:1019
int errmsg(const char *fmt,...)
Definition: elog.c:1071
void pqDropConnection(PGconn *conn, bool flushInput)
Definition: fe-connect.c:530
void * pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
Definition: fe-exec.c:563
void pqSaveMessageField(PGresult *res, char code, const char *value)
Definition: fe-exec.c:1060
PGresult * pqPrepareAsyncResult(PGconn *conn)
Definition: fe-exec.c:851
void pqCommandQueueAdvance(PGconn *conn, bool isReadyForQuery, bool gotSync)
Definition: fe-exec.c:3153
void pqSetResultError(PGresult *res, PQExpBuffer errorMessage, int offset)
Definition: fe-exec.c:692
void pqSaveErrorResult(PGconn *conn)
Definition: fe-exec.c:803
int pqRowProcessor(PGconn *conn, const char **errmsgp)
Definition: fe-exec.c:1217
int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)
Definition: fe-exec.c:2912
PGresult * PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
Definition: fe-exec.c:159
void pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
Definition: fe-exec.c:938
void pqClearAsyncResult(PGconn *conn)
Definition: fe-exec.c:779
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:2042
int pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
Definition: fe-exec.c:1085
char * pqResultStrdup(PGresult *res, const char *str)
Definition: fe-exec.c:675
int pqReadData(PGconn *conn)
Definition: fe-misc.c:606
int pqPutInt(int value, size_t bytes, PGconn *conn)
Definition: fe-misc.c:253
int pqFlush(PGconn *conn)
Definition: fe-misc.c:994
void pqParseDone(PGconn *conn, int newInStart)
Definition: fe-misc.c:443
int pqPutMsgStart(char msg_type, PGconn *conn)
Definition: fe-misc.c:473
int pqSkipnchar(size_t len, PGconn *conn)
Definition: fe-misc.c:187
int pqGetc(char *result, PGconn *conn)
Definition: fe-misc.c:77
int pqGetInt(int *result, size_t bytes, PGconn *conn)
Definition: fe-misc.c:216
int pqWait(int forRead, int forWrite, PGconn *conn)
Definition: fe-misc.c:1019
int pqGets(PQExpBuffer buf, PGconn *conn)
Definition: fe-misc.c:136
int pqPutnchar(const void *s, size_t len, PGconn *conn)
Definition: fe-misc.c:202
int pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
Definition: fe-misc.c:351
int pqGetnchar(void *s, size_t len, PGconn *conn)
Definition: fe-misc.c:165
int PQmblenBounded(const char *s, int encoding)
Definition: fe-misc.c:1266
int pqPutMsgEnd(PGconn *conn)
Definition: fe-misc.c:532
#define DISPLAY_SIZE
void pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res, PGVerbosity verbosity, PGContextVisibility show_context)
Definition: fe-protocol3.c:1028
void pqParseInput3(PGconn *conn)
Definition: fe-protocol3.c:68
char * pqBuildStartupPacket3(PGconn *conn, int *packetlen, const PQEnvironmentOption *options)
Definition: fe-protocol3.c:2372
static int build_startup_packet(const PGconn *conn, char *packet, const PQEnvironmentOption *options)
Definition: fe-protocol3.c:2395
int pqEndcopy3(PGconn *conn)
Definition: fe-protocol3.c:2049
static int getNotify(PGconn *conn)
Definition: fe-protocol3.c:1620
static int getAnotherTuple(PGconn *conn, int msgLength)
Definition: fe-protocol3.c:775
static int getRowDescriptions(PGconn *conn, int msgLength)
Definition: fe-protocol3.c:516
static void reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding)
Definition: fe-protocol3.c:1199
PGresult * pqFunctionCall3(PGconn *conn, Oid fnid, int *result_buf, int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs)
Definition: fe-protocol3.c:2142
#define MIN_RIGHT_CUT
int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize)
Definition: fe-protocol3.c:1994
int pqGetCopyData3(PGconn *conn, char **buffer, int async)
Definition: fe-protocol3.c:1884
int pqGetNegotiateProtocolVersion3(PGconn *conn)
Definition: fe-protocol3.c:1428
static int getParameterStatus(PGconn *conn)
Definition: fe-protocol3.c:1525
static void handleFatalError(PGconn *conn)
Definition: fe-protocol3.c:485
#define VALID_LONG_MESSAGE_TYPE(id)
Definition: fe-protocol3.c:36
static int getCopyStart(PGconn *conn, ExecStatusType copytype)
Definition: fe-protocol3.c:1691
static void handleSyncLoss(PGconn *conn, char id, int msgLength)
Definition: fe-protocol3.c:501
static int getReadyForQuery(PGconn *conn)
Definition: fe-protocol3.c:1747
#define ADD_STARTUP_OPTION(optname, optval)
static int getBackendKeyData(PGconn *conn, int msgLength)
Definition: fe-protocol3.c:1556
static int getCopyDataMessage(PGconn *conn)
Definition: fe-protocol3.c:1779
static int getParamDescriptions(PGconn *conn, int msgLength)
Definition: fe-protocol3.c:687
int pqGetline3(PGconn *conn, char *s, int maxlen)
Definition: fe-protocol3.c:1943
int pqGetErrorNotice3(PGconn *conn, bool isError)
Definition: fe-protocol3.c:896
Assert(PointerIsAligned(start, uint64))
#define realloc(a, b)
Definition: header.h:60
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
#define bufsize
Definition: indent_globs.h:36
long val
Definition: informix.c:689
i
int i
Definition: isn.c:77
#define PQgetResult
Definition: libpq-be-fe.h:246
#define PQclear
Definition: libpq-be-fe.h:245
#define PQresultErrorField
Definition: libpq-be-fe.h:249
@ CONNECTION_BAD
Definition: libpq-fe.h:85
ExecStatusType
Definition: libpq-fe.h:123
@ PGRES_COPY_IN
Definition: libpq-fe.h:132
@ PGRES_COPY_BOTH
Definition: libpq-fe.h:137
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:125
@ PGRES_TUPLES_CHUNK
Definition: libpq-fe.h:142
@ PGRES_FATAL_ERROR
Definition: libpq-fe.h:136
@ PGRES_COPY_OUT
Definition: libpq-fe.h:131
@ PGRES_EMPTY_QUERY
Definition: libpq-fe.h:124
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:139
@ PGRES_NONFATAL_ERROR
Definition: libpq-fe.h:135
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:128
PGContextVisibility
Definition: libpq-fe.h:163
@ PQSHOW_CONTEXT_ALWAYS
Definition: libpq-fe.h:166
@ PQSHOW_CONTEXT_ERRORS
Definition: libpq-fe.h:165
@ PQTRANS_INTRANS
Definition: libpq-fe.h:149
@ PQTRANS_IDLE
Definition: libpq-fe.h:147
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:151
@ PQTRANS_INERROR
Definition: libpq-fe.h:150
@ PQ_PIPELINE_OFF
Definition: libpq-fe.h:187
@ PQ_PIPELINE_ABORTED
Definition: libpq-fe.h:189
@ PQ_PIPELINE_ON
Definition: libpq-fe.h:188
PGVerbosity
Definition: libpq-fe.h:155
@ PQERRORS_VERBOSE
Definition: libpq-fe.h:158
@ PQERRORS_TERSE
Definition: libpq-fe.h:156
@ PQERRORS_SQLSTATE
Definition: libpq-fe.h:159
@ PGASYNC_COPY_OUT
Definition: libpq-int.h:223
@ PGASYNC_READY
Definition: libpq-int.h:217
@ PGASYNC_COPY_BOTH
Definition: libpq-int.h:224
@ PGASYNC_IDLE
Definition: libpq-int.h:215
@ PGASYNC_COPY_IN
Definition: libpq-int.h:222
@ PGASYNC_BUSY
Definition: libpq-int.h:216
@ PGQUERY_SIMPLE
Definition: libpq-int.h:320
@ PGQUERY_DESCRIBE
Definition: libpq-int.h:323
@ PGQUERY_CLOSE
Definition: libpq-int.h:325
@ PGQUERY_PREPARE
Definition: libpq-int.h:322
#define CMDSTATUS_LEN
Definition: libpq-int.h:83
#define pqIsnonblocking(conn)
Definition: libpq-int.h:930
#define pgHavePendingResult(conn)
Definition: libpq-int.h:923
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
Definition: oauth-utils.c:95
#define libpq_gettext(x)
Definition: oauth-utils.h:86
static char format
Definition: pg_basebackup.c:134
#define pg_hton32(x)
Definition: pg_bswap.h:121
const void size_t len
int32 encoding
Definition: pg_database.h:41
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define PGINVALID_SOCKET
Definition: port.h:31
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define PG_DIAG_INTERNAL_QUERY
Definition: postgres_ext.h:63
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:65
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:69
#define PG_DIAG_DATATYPE_NAME
Definition: postgres_ext.h:68
unsigned int Oid
Definition: postgres_ext.h:32
#define PG_DIAG_SOURCE_LINE
Definition: postgres_ext.h:71
#define PG_DIAG_STATEMENT_POSITION
Definition: postgres_ext.h:61
#define PG_DIAG_SOURCE_FILE
Definition: postgres_ext.h:70
#define PG_DIAG_MESSAGE_HINT
Definition: postgres_ext.h:60
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:66
#define PG_DIAG_MESSAGE_PRIMARY
Definition: postgres_ext.h:58
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
#define PG_DIAG_MESSAGE_DETAIL
Definition: postgres_ext.h:59
#define PG_DIAG_CONTEXT
Definition: postgres_ext.h:64
#define PG_DIAG_SEVERITY
Definition: postgres_ext.h:55
#define PG_DIAG_SOURCE_FUNCTION
Definition: postgres_ext.h:72
#define PG_DIAG_INTERNAL_POSITION
Definition: postgres_ext.h:62
#define PG_PROTOCOL_MAJOR(v)
Definition: pqcomm.h:87
uint32 ProtocolVersion
Definition: pqcomm.h:99
#define PG_PROTOCOL(m, n)
Definition: pqcomm.h:90
#define PG_PROTOCOL_MINOR(v)
Definition: pqcomm.h:88
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
#define PqMsg_CloseComplete
Definition: protocol.h:40
#define PqMsg_CopyDone
Definition: protocol.h:64
#define PqMsg_NotificationResponse
Definition: protocol.h:41
#define PqMsg_BindComplete
Definition: protocol.h:39
#define PqMsg_CopyData
Definition: protocol.h:65
#define PqMsg_ParameterDescription
Definition: protocol.h:58
#define PqMsg_FunctionCall
Definition: protocol.h:23
#define PqMsg_FunctionCallResponse
Definition: protocol.h:53
#define PqMsg_ReadyForQuery
Definition: protocol.h:55
#define PqMsg_CopyInResponse
Definition: protocol.h:45
#define PqMsg_EmptyQueryResponse
Definition: protocol.h:47
#define PqMsg_RowDescription
Definition: protocol.h:52
#define PqMsg_CopyBothResponse
Definition: protocol.h:54
#define PqMsg_ParameterStatus
Definition: protocol.h:51
#define PqMsg_NoData
Definition: protocol.h:56
#define PqMsg_Sync
Definition: protocol.h:27
#define PqMsg_BackendKeyData
Definition: protocol.h:48
#define PqMsg_CommandComplete
Definition: protocol.h:42
#define PqMsg_ErrorResponse
Definition: protocol.h:44
#define PqMsg_DataRow
Definition: protocol.h:43
#define PqMsg_NoticeResponse
Definition: protocol.h:49
#define PqMsg_CopyOutResponse
Definition: protocol.h:46
#define PqMsg_ParseComplete
Definition: protocol.h:38
PGconn * conn
Definition: streamutil.c:52
PQnoticeReceiver noticeRec
Definition: libpq-int.h:149
void * noticeRecArg
Definition: libpq-int.h:150
PGQueryClass queryclass
Definition: libpq-int.h:345
char * query
Definition: libpq-int.h:346
const char * pgName
Definition: libpq-int.h:265
const char * envName
Definition: libpq-int.h:264
char * data
Definition: pqexpbuffer.h:46
size_t len
Definition: pqexpbuffer.h:47
Definition: oid2name.c:30
int len
Definition: libpq-int.h:302
const char * value
Definition: libpq-int.h:303
struct pgNotify * next
Definition: libpq-fe.h:234
int be_pid
Definition: libpq-fe.h:231
char * relname
Definition: libpq-fe.h:230
char * extra
Definition: libpq-fe.h:232
uint8 * be_cancel_key
Definition: libpq-int.h:554
char * replication
Definition: libpq-int.h:391
PGnotify * notifyHead
Definition: libpq-int.h:476
PGdataValue * rowBuf
Definition: libpq-int.h:584
pgsocket sock
Definition: libpq-int.h:499
char * inBuffer
Definition: libpq-int.h:567
ProtocolVersion pversion
Definition: libpq-int.h:503
char * pgoptions
Definition: libpq-int.h:387
bool send_appname
Definition: libpq-int.h:543
PGTransactionStatusType xactStatus
Definition: libpq-int.h:464
int inCursor
Definition: libpq-int.h:570
int be_pid
Definition: libpq-int.h:552
ProtocolVersion min_pversion
Definition: libpq-int.h:548
char * dbName
Definition: libpq-int.h:390
int inEnd
Definition: libpq-int.h:571
char * fbappname
Definition: libpq-int.h:389
PGnotify * notifyTail
Definition: libpq-int.h:477
int copy_already_done
Definition: libpq-int.h:475
PQExpBufferData workBuffer
Definition: libpq-int.h:678
int inStart
Definition: libpq-int.h:569
char * pguser
Definition: libpq-int.h:395
PGresult * result
Definition: libpq-int.h:597
PGVerbosity verbosity
Definition: libpq-int.h:560
char * client_encoding_initial
Definition: libpq-int.h:386
char * appname
Definition: libpq-int.h:388
PQExpBufferData errorMessage
Definition: libpq-int.h:674
bool error_result
Definition: libpq-int.h:598
int rowBufLen
Definition: libpq-int.h:585
char last_sqlstate[6]
Definition: libpq-int.h:465
PGAsyncStatusType asyncStatus
Definition: libpq-int.h:463
PGpipelineStatus pipelineStatus
Definition: libpq-int.h:469
char copy_is_binary
Definition: libpq-int.h:474
PGNoticeHooks noticeHooks
Definition: libpq-int.h:454
PGcmdQueueEntry * cmd_queue_head
Definition: libpq-int.h:489
int be_cancel_key_len
Definition: libpq-int.h:553
PGContextVisibility show_context
Definition: libpq-int.h:561
ConnStatusType status
Definition: libpq-int.h:462
int binary
Definition: libpq-int.h:176
PGNoticeHooks noticeHooks
Definition: libpq-int.h:183
char * errMsg
Definition: libpq-int.h:193
int numParameters
Definition: libpq-int.h:172
PGresAttDesc * attDescs
Definition: libpq-int.h:168
int numAttributes
Definition: libpq-int.h:167
char cmdStatus[CMDSTATUS_LEN]
Definition: libpq-int.h:175
PGMessageField * errFields
Definition: libpq-int.h:194
PGresParamDesc * paramDescs
Definition: libpq-int.h:173
ExecStatusType resultStatus
Definition: libpq-int.h:174
char * errQuery
Definition: libpq-int.h:195
int client_encoding
Definition: libpq-int.h:186
char * name
Definition: libpq-fe.h:307
Oid tableid
Definition: libpq-fe.h:308
int columnid
Definition: libpq-fe.h:309
int atttypmod
Definition: libpq-fe.h:313
int format
Definition: libpq-fe.h:310
int typlen
Definition: libpq-fe.h:312
Oid typid
Definition: libpq-fe.h:311
int pg_encoding_dsplen(int encoding, const char *mbstr)
Definition: wchar.c:2176
int pg_encoding_max_length(int encoding)
Definition: wchar.c:2213

AltStyle によって変換されたページ (->オリジナル) /