1 /*-------------------------------------------------------------------------
2  *
3  * pqformat.c
4  *		Routines for formatting and parsing frontend/backend messages
5  *
6  * Outgoing messages are built up in a StringInfo buffer (which is expansible)
7  * and then sent in a single call to pq_putmessage.  This module provides data
8  * formatting/conversion routines that are needed to produce valid messages.
9  * Note in particular the distinction between "raw data" and "text"; raw data
10  * is message protocol characters and binary values that are not subject to
11  * character set conversion, while text is converted by character encoding
12  * rules.
13  *
14  * Incoming messages are similarly read into a StringInfo buffer, via
15  * pq_getmessage, and then parsed and converted from that using the routines
16  * in this module.
17  *
18  * These same routines support reading and writing of external binary formats
19  * (typsend/typreceive routines).  The conversion routines for individual
20  * data types are exactly the same, only initialization and completion
21  * are different.
22  *
23  *
24  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
25  * Portions Copyright (c) 1994, Regents of the University of California
26  *
27  *	src/backend/libpq/pqformat.c
28  *
29  *-------------------------------------------------------------------------
30  */
31 /*
32  * INTERFACE ROUTINES
33  * Message assembly and output:
34  *		pq_beginmessage - initialize StringInfo buffer
35  *		pq_sendbyte		- append a raw byte to a StringInfo buffer
36  *		pq_sendint		- append a binary integer to a StringInfo buffer
37  *		pq_sendint64	- append a binary 8-byte int to a StringInfo buffer
38  *		pq_sendfloat4	- append a float4 to a StringInfo buffer
39  *		pq_sendfloat8	- append a float8 to a StringInfo buffer
40  *		pq_sendbytes	- append raw data to a StringInfo buffer
41  *		pq_sendcountedtext - append a counted text string (with character set conversion)
42  *		pq_sendtext		- append a text string (with conversion)
43  *		pq_sendstring	- append a null-terminated text string (with conversion)
44  *		pq_send_ascii_string - append a null-terminated text string (without conversion)
45  *		pq_endmessage	- send the completed message to the frontend
46  * Note: it is also possible to append data to the StringInfo buffer using
47  * the regular StringInfo routines, but this is discouraged since required
48  * character set conversion may not occur.
49  *
50  * typsend support (construct a bytea value containing external binary data):
51  *		pq_begintypsend - initialize StringInfo buffer
52  *		pq_endtypsend	- return the completed string as a "bytea*"
53  *
54  * Special-case message output:
55  *		pq_puttextmessage - generate a character set-converted message in one step
56  *		pq_putemptymessage - convenience routine for message with empty body
57  *
58  * Message parsing after input:
59  *		pq_getmsgbyte	- get a raw byte from a message buffer
60  *		pq_getmsgint	- get a binary integer from a message buffer
61  *		pq_getmsgint64	- get a binary 8-byte int from a message buffer
62  *		pq_getmsgfloat4 - get a float4 from a message buffer
63  *		pq_getmsgfloat8 - get a float8 from a message buffer
64  *		pq_getmsgbytes	- get raw data from a message buffer
65  *		pq_copymsgbytes - copy raw data from a message buffer
66  *		pq_getmsgtext	- get a counted text string (with conversion)
67  *		pq_getmsgstring - get a null-terminated text string (with conversion)
68  *		pq_getmsgrawstring - get a null-terminated text string - NO conversion
69  *		pq_getmsgend	- verify message fully consumed
70  */
71 
72 #include "postgres.h"
73 
74 #include <sys/param.h>
75 
76 #include "libpq/libpq.h"
77 #include "libpq/pqformat.h"
78 #include "mb/pg_wchar.h"
79 #include "port/pg_bswap.h"
80 
81 
82 /* --------------------------------
83  *		pq_beginmessage		- initialize for sending a message
84  * --------------------------------
85  */
86 void
pq_beginmessage(StringInfo buf,char msgtype)87 pq_beginmessage(StringInfo buf, char msgtype)
88 {
89 	initStringInfo(buf);
90 
91 	/*
92 	 * We stash the message type into the buffer's cursor field, expecting
93 	 * that the pq_sendXXX routines won't touch it.  We could alternatively
94 	 * make it the first byte of the buffer contents, but this seems easier.
95 	 */
96 	buf->cursor = msgtype;
97 }
98 
99 /* --------------------------------
100 
101  *		pq_beginmessage_reuse - initialize for sending a message, reuse buffer
102  *
103  * This requires the buffer to be allocated in a sufficiently long-lived
104  * memory context.
105  * --------------------------------
106  */
107 void
pq_beginmessage_reuse(StringInfo buf,char msgtype)108 pq_beginmessage_reuse(StringInfo buf, char msgtype)
109 {
110 	resetStringInfo(buf);
111 
112 	/*
113 	 * We stash the message type into the buffer's cursor field, expecting
114 	 * that the pq_sendXXX routines won't touch it.  We could alternatively
115 	 * make it the first byte of the buffer contents, but this seems easier.
116 	 */
117 	buf->cursor = msgtype;
118 }
119 
120 /* --------------------------------
121  *		pq_sendbytes	- append raw data to a StringInfo buffer
122  * --------------------------------
123  */
124 void
pq_sendbytes(StringInfo buf,const char * data,int datalen)125 pq_sendbytes(StringInfo buf, const char *data, int datalen)
126 {
127 	/* use variant that maintains a trailing null-byte, out of caution */
128 	appendBinaryStringInfo(buf, data, datalen);
129 }
130 
131 /* --------------------------------
132  *		pq_sendcountedtext - append a counted text string (with character set conversion)
133  *
134  * The data sent to the frontend by this routine is a 4-byte count field
135  * followed by the string.  The count includes itself or not, as per the
136  * countincludesself flag (pre-3.0 protocol requires it to include itself).
137  * The passed text string need not be null-terminated, and the data sent
138  * to the frontend isn't either.
139  * --------------------------------
140  */
141 void
pq_sendcountedtext(StringInfo buf,const char * str,int slen,bool countincludesself)142 pq_sendcountedtext(StringInfo buf, const char *str, int slen,
143 				   bool countincludesself)
144 {
145 	int			extra = countincludesself ? 4 : 0;
146 	char	   *p;
147 
148 	p = pg_server_to_client(str, slen);
149 	if (p != str)				/* actual conversion has been done? */
150 	{
151 		slen = strlen(p);
152 		pq_sendint32(buf, slen + extra);
153 		appendBinaryStringInfoNT(buf, p, slen);
154 		pfree(p);
155 	}
156 	else
157 	{
158 		pq_sendint32(buf, slen + extra);
159 		appendBinaryStringInfoNT(buf, str, slen);
160 	}
161 }
162 
163 /* --------------------------------
164  *		pq_sendtext		- append a text string (with conversion)
165  *
166  * The passed text string need not be null-terminated, and the data sent
167  * to the frontend isn't either.  Note that this is not actually useful
168  * for direct frontend transmissions, since there'd be no way for the
169  * frontend to determine the string length.  But it is useful for binary
170  * format conversions.
171  * --------------------------------
172  */
173 void
pq_sendtext(StringInfo buf,const char * str,int slen)174 pq_sendtext(StringInfo buf, const char *str, int slen)
175 {
176 	char	   *p;
177 
178 	p = pg_server_to_client(str, slen);
179 	if (p != str)				/* actual conversion has been done? */
180 	{
181 		slen = strlen(p);
182 		appendBinaryStringInfo(buf, p, slen);
183 		pfree(p);
184 	}
185 	else
186 		appendBinaryStringInfo(buf, str, slen);
187 }
188 
189 /* --------------------------------
190  *		pq_sendstring	- append a null-terminated text string (with conversion)
191  *
192  * NB: passed text string must be null-terminated, and so is the data
193  * sent to the frontend.
194  * --------------------------------
195  */
196 void
pq_sendstring(StringInfo buf,const char * str)197 pq_sendstring(StringInfo buf, const char *str)
198 {
199 	int			slen = strlen(str);
200 	char	   *p;
201 
202 	p = pg_server_to_client(str, slen);
203 	if (p != str)				/* actual conversion has been done? */
204 	{
205 		slen = strlen(p);
206 		appendBinaryStringInfoNT(buf, p, slen + 1);
207 		pfree(p);
208 	}
209 	else
210 		appendBinaryStringInfoNT(buf, str, slen + 1);
211 }
212 
213 /* --------------------------------
214  *		pq_send_ascii_string	- append a null-terminated text string (without conversion)
215  *
216  * This function intentionally bypasses encoding conversion, instead just
217  * silently replacing any non-7-bit-ASCII characters with question marks.
218  * It is used only when we are having trouble sending an error message to
219  * the client with normal localization and encoding conversion.  The caller
220  * should already have taken measures to ensure the string is just ASCII;
221  * the extra work here is just to make certain we don't send a badly encoded
222  * string to the client (which might or might not be robust about that).
223  *
224  * NB: passed text string must be null-terminated, and so is the data
225  * sent to the frontend.
226  * --------------------------------
227  */
228 void
pq_send_ascii_string(StringInfo buf,const char * str)229 pq_send_ascii_string(StringInfo buf, const char *str)
230 {
231 	while (*str)
232 	{
233 		char		ch = *str++;
234 
235 		if (IS_HIGHBIT_SET(ch))
236 			ch = '?';
237 		appendStringInfoCharMacro(buf, ch);
238 	}
239 	appendStringInfoChar(buf, '\0');
240 }
241 
242 /* --------------------------------
243  *		pq_sendfloat4	- append a float4 to a StringInfo buffer
244  *
245  * The point of this routine is to localize knowledge of the external binary
246  * representation of float4, which is a component of several datatypes.
247  *
248  * We currently assume that float4 should be byte-swapped in the same way
249  * as int4.  This rule is not perfect but it gives us portability across
250  * most IEEE-float-using architectures.
251  * --------------------------------
252  */
253 void
pq_sendfloat4(StringInfo buf,float4 f)254 pq_sendfloat4(StringInfo buf, float4 f)
255 {
256 	union
257 	{
258 		float4		f;
259 		uint32		i;
260 	}			swap;
261 
262 	swap.f = f;
263 	pq_sendint32(buf, swap.i);
264 }
265 
266 /* --------------------------------
267  *		pq_sendfloat8	- append a float8 to a StringInfo buffer
268  *
269  * The point of this routine is to localize knowledge of the external binary
270  * representation of float8, which is a component of several datatypes.
271  *
272  * We currently assume that float8 should be byte-swapped in the same way
273  * as int8.  This rule is not perfect but it gives us portability across
274  * most IEEE-float-using architectures.
275  * --------------------------------
276  */
277 void
pq_sendfloat8(StringInfo buf,float8 f)278 pq_sendfloat8(StringInfo buf, float8 f)
279 {
280 	union
281 	{
282 		float8		f;
283 		int64		i;
284 	}			swap;
285 
286 	swap.f = f;
287 	pq_sendint64(buf, swap.i);
288 }
289 
290 /* --------------------------------
291  *		pq_endmessage	- send the completed message to the frontend
292  *
293  * The data buffer is pfree()d, but if the StringInfo was allocated with
294  * makeStringInfo then the caller must still pfree it.
295  * --------------------------------
296  */
297 void
pq_endmessage(StringInfo buf)298 pq_endmessage(StringInfo buf)
299 {
300 	/* msgtype was saved in cursor field */
301 	(void) pq_putmessage(buf->cursor, buf->data, buf->len);
302 	/* no need to complain about any failure, since pqcomm.c already did */
303 	pfree(buf->data);
304 	buf->data = NULL;
305 }
306 
307 /* --------------------------------
308  *		pq_endmessage_reuse	- send the completed message to the frontend
309  *
310  * The data buffer is *not* freed, allowing to reuse the buffer with
311  * pq_beginmessage_reuse.
312  --------------------------------
313  */
314 
315 void
pq_endmessage_reuse(StringInfo buf)316 pq_endmessage_reuse(StringInfo buf)
317 {
318 	/* msgtype was saved in cursor field */
319 	(void) pq_putmessage(buf->cursor, buf->data, buf->len);
320 }
321 
322 
323 /* --------------------------------
324  *		pq_begintypsend		- initialize for constructing a bytea result
325  * --------------------------------
326  */
327 void
pq_begintypsend(StringInfo buf)328 pq_begintypsend(StringInfo buf)
329 {
330 	initStringInfo(buf);
331 	/* Reserve four bytes for the bytea length word */
332 	appendStringInfoCharMacro(buf, '\0');
333 	appendStringInfoCharMacro(buf, '\0');
334 	appendStringInfoCharMacro(buf, '\0');
335 	appendStringInfoCharMacro(buf, '\0');
336 }
337 
338 /* --------------------------------
339  *		pq_endtypsend	- finish constructing a bytea result
340  *
341  * The data buffer is returned as the palloc'd bytea value.  (We expect
342  * that it will be suitably aligned for this because it has been palloc'd.)
343  * We assume the StringInfoData is just a local variable in the caller and
344  * need not be pfree'd.
345  * --------------------------------
346  */
347 bytea *
pq_endtypsend(StringInfo buf)348 pq_endtypsend(StringInfo buf)
349 {
350 	bytea	   *result = (bytea *) buf->data;
351 
352 	/* Insert correct length into bytea length word */
353 	Assert(buf->len >= VARHDRSZ);
354 	SET_VARSIZE(result, buf->len);
355 
356 	return result;
357 }
358 
359 
360 /* --------------------------------
361  *		pq_puttextmessage - generate a character set-converted message in one step
362  *
363  *		This is the same as the pqcomm.c routine pq_putmessage, except that
364  *		the message body is a null-terminated string to which encoding
365  *		conversion applies.
366  * --------------------------------
367  */
368 void
pq_puttextmessage(char msgtype,const char * str)369 pq_puttextmessage(char msgtype, const char *str)
370 {
371 	int			slen = strlen(str);
372 	char	   *p;
373 
374 	p = pg_server_to_client(str, slen);
375 	if (p != str)				/* actual conversion has been done? */
376 	{
377 		(void) pq_putmessage(msgtype, p, strlen(p) + 1);
378 		pfree(p);
379 		return;
380 	}
381 	(void) pq_putmessage(msgtype, str, slen + 1);
382 }
383 
384 
385 /* --------------------------------
386  *		pq_putemptymessage - convenience routine for message with empty body
387  * --------------------------------
388  */
389 void
pq_putemptymessage(char msgtype)390 pq_putemptymessage(char msgtype)
391 {
392 	(void) pq_putmessage(msgtype, NULL, 0);
393 }
394 
395 
396 /* --------------------------------
397  *		pq_getmsgbyte	- get a raw byte from a message buffer
398  * --------------------------------
399  */
400 int
pq_getmsgbyte(StringInfo msg)401 pq_getmsgbyte(StringInfo msg)
402 {
403 	if (msg->cursor >= msg->len)
404 		ereport(ERROR,
405 				(errcode(ERRCODE_PROTOCOL_VIOLATION),
406 				 errmsg("no data left in message")));
407 	return (unsigned char) msg->data[msg->cursor++];
408 }
409 
410 /* --------------------------------
411  *		pq_getmsgint	- get a binary integer from a message buffer
412  *
413  *		Values are treated as unsigned.
414  * --------------------------------
415  */
416 unsigned int
pq_getmsgint(StringInfo msg,int b)417 pq_getmsgint(StringInfo msg, int b)
418 {
419 	unsigned int result;
420 	unsigned char n8;
421 	uint16		n16;
422 	uint32		n32;
423 
424 	switch (b)
425 	{
426 		case 1:
427 			pq_copymsgbytes(msg, (char *) &n8, 1);
428 			result = n8;
429 			break;
430 		case 2:
431 			pq_copymsgbytes(msg, (char *) &n16, 2);
432 			result = pg_ntoh16(n16);
433 			break;
434 		case 4:
435 			pq_copymsgbytes(msg, (char *) &n32, 4);
436 			result = pg_ntoh32(n32);
437 			break;
438 		default:
439 			elog(ERROR, "unsupported integer size %d", b);
440 			result = 0;			/* keep compiler quiet */
441 			break;
442 	}
443 	return result;
444 }
445 
446 /* --------------------------------
447  *		pq_getmsgint64	- get a binary 8-byte int from a message buffer
448  *
449  * It is tempting to merge this with pq_getmsgint, but we'd have to make the
450  * result int64 for all data widths --- that could be a big performance
451  * hit on machines where int64 isn't efficient.
452  * --------------------------------
453  */
454 int64
pq_getmsgint64(StringInfo msg)455 pq_getmsgint64(StringInfo msg)
456 {
457 	uint64		n64;
458 
459 	pq_copymsgbytes(msg, (char *) &n64, sizeof(n64));
460 
461 	return pg_ntoh64(n64);
462 }
463 
464 /* --------------------------------
465  *		pq_getmsgfloat4 - get a float4 from a message buffer
466  *
467  * See notes for pq_sendfloat4.
468  * --------------------------------
469  */
470 float4
pq_getmsgfloat4(StringInfo msg)471 pq_getmsgfloat4(StringInfo msg)
472 {
473 	union
474 	{
475 		float4		f;
476 		uint32		i;
477 	}			swap;
478 
479 	swap.i = pq_getmsgint(msg, 4);
480 	return swap.f;
481 }
482 
483 /* --------------------------------
484  *		pq_getmsgfloat8 - get a float8 from a message buffer
485  *
486  * See notes for pq_sendfloat8.
487  * --------------------------------
488  */
489 float8
pq_getmsgfloat8(StringInfo msg)490 pq_getmsgfloat8(StringInfo msg)
491 {
492 	union
493 	{
494 		float8		f;
495 		int64		i;
496 	}			swap;
497 
498 	swap.i = pq_getmsgint64(msg);
499 	return swap.f;
500 }
501 
502 /* --------------------------------
503  *		pq_getmsgbytes	- get raw data from a message buffer
504  *
505  *		Returns a pointer directly into the message buffer; note this
506  *		may not have any particular alignment.
507  * --------------------------------
508  */
509 const char *
pq_getmsgbytes(StringInfo msg,int datalen)510 pq_getmsgbytes(StringInfo msg, int datalen)
511 {
512 	const char *result;
513 
514 	if (datalen < 0 || datalen > (msg->len - msg->cursor))
515 		ereport(ERROR,
516 				(errcode(ERRCODE_PROTOCOL_VIOLATION),
517 				 errmsg("insufficient data left in message")));
518 	result = &msg->data[msg->cursor];
519 	msg->cursor += datalen;
520 	return result;
521 }
522 
523 /* --------------------------------
524  *		pq_copymsgbytes - copy raw data from a message buffer
525  *
526  *		Same as above, except data is copied to caller's buffer.
527  * --------------------------------
528  */
529 void
pq_copymsgbytes(StringInfo msg,char * buf,int datalen)530 pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
531 {
532 	if (datalen < 0 || datalen > (msg->len - msg->cursor))
533 		ereport(ERROR,
534 				(errcode(ERRCODE_PROTOCOL_VIOLATION),
535 				 errmsg("insufficient data left in message")));
536 	memcpy(buf, &msg->data[msg->cursor], datalen);
537 	msg->cursor += datalen;
538 }
539 
540 /* --------------------------------
541  *		pq_getmsgtext	- get a counted text string (with conversion)
542  *
543  *		Always returns a pointer to a freshly palloc'd result.
544  *		The result has a trailing null, *and* we return its strlen in *nbytes.
545  * --------------------------------
546  */
547 char *
pq_getmsgtext(StringInfo msg,int rawbytes,int * nbytes)548 pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
549 {
550 	char	   *str;
551 	char	   *p;
552 
553 	if (rawbytes < 0 || rawbytes > (msg->len - msg->cursor))
554 		ereport(ERROR,
555 				(errcode(ERRCODE_PROTOCOL_VIOLATION),
556 				 errmsg("insufficient data left in message")));
557 	str = &msg->data[msg->cursor];
558 	msg->cursor += rawbytes;
559 
560 	p = pg_client_to_server(str, rawbytes);
561 	if (p != str)				/* actual conversion has been done? */
562 		*nbytes = strlen(p);
563 	else
564 	{
565 		p = (char *) palloc(rawbytes + 1);
566 		memcpy(p, str, rawbytes);
567 		p[rawbytes] = '\0';
568 		*nbytes = rawbytes;
569 	}
570 	return p;
571 }
572 
573 /* --------------------------------
574  *		pq_getmsgstring - get a null-terminated text string (with conversion)
575  *
576  *		May return a pointer directly into the message buffer, or a pointer
577  *		to a palloc'd conversion result.
578  * --------------------------------
579  */
580 const char *
pq_getmsgstring(StringInfo msg)581 pq_getmsgstring(StringInfo msg)
582 {
583 	char	   *str;
584 	int			slen;
585 
586 	str = &msg->data[msg->cursor];
587 
588 	/*
589 	 * It's safe to use strlen() here because a StringInfo is guaranteed to
590 	 * have a trailing null byte.  But check we found a null inside the
591 	 * message.
592 	 */
593 	slen = strlen(str);
594 	if (msg->cursor + slen >= msg->len)
595 		ereport(ERROR,
596 				(errcode(ERRCODE_PROTOCOL_VIOLATION),
597 				 errmsg("invalid string in message")));
598 	msg->cursor += slen + 1;
599 
600 	return pg_client_to_server(str, slen);
601 }
602 
603 /* --------------------------------
604  *		pq_getmsgrawstring - get a null-terminated text string - NO conversion
605  *
606  *		Returns a pointer directly into the message buffer.
607  * --------------------------------
608  */
609 const char *
pq_getmsgrawstring(StringInfo msg)610 pq_getmsgrawstring(StringInfo msg)
611 {
612 	char	   *str;
613 	int			slen;
614 
615 	str = &msg->data[msg->cursor];
616 
617 	/*
618 	 * It's safe to use strlen() here because a StringInfo is guaranteed to
619 	 * have a trailing null byte.  But check we found a null inside the
620 	 * message.
621 	 */
622 	slen = strlen(str);
623 	if (msg->cursor + slen >= msg->len)
624 		ereport(ERROR,
625 				(errcode(ERRCODE_PROTOCOL_VIOLATION),
626 				 errmsg("invalid string in message")));
627 	msg->cursor += slen + 1;
628 
629 	return str;
630 }
631 
632 /* --------------------------------
633  *		pq_getmsgend	- verify message fully consumed
634  * --------------------------------
635  */
636 void
pq_getmsgend(StringInfo msg)637 pq_getmsgend(StringInfo msg)
638 {
639 	if (msg->cursor != msg->len)
640 		ereport(ERROR,
641 				(errcode(ERRCODE_PROTOCOL_VIOLATION),
642 				 errmsg("invalid message format")));
643 }
644