1515 * pq_getmessage, and then parsed and converted from that using the routines
1616 * in this module.
1717 *
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+ *
1824 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
1925 * Portions Copyright (c) 1994, Regents of the University of California
2026 *
21- *$Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.29 2003/05/08 18:16:36 tgl Exp $
27+ *$Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.30 2003/05/09 15:44:40 tgl Exp $
2228 *
2329 *-------------------------------------------------------------------------
2430 */
2834 *pq_beginmessage - initialize StringInfo buffer
2935 *pq_sendbyte- append a raw byte to a StringInfo buffer
3036 *pq_sendint- append a binary integer to a StringInfo buffer
37+ *pq_sendint64- append a binary 8-byte int to a StringInfo buffer
3138 *pq_sendbytes- append raw data to a StringInfo buffer
32- *pq_sendcountedtext - append a text string (with character set conversion)
39+ *pq_sendcountedtext - append a counted text string (with character set conversion)
40+ *pq_sendtext- append a text string (with conversion)
3341 *pq_sendstring- append a null-terminated text string (with conversion)
3442 *pq_endmessage- send the completed message to the frontend
3543 * Note: it is also possible to append data to the StringInfo buffer using
3644 * the regular StringInfo routines, but this is discouraged since required
3745 * character set conversion may not occur.
3846 *
47+ * typsend support (construct a bytea value containing external binary data):
48+ *pq_begintypsend - initialize StringInfo buffer
49+ *pq_endtypsend- return the completed string as a "bytea*"
50+ *
3951 * Special-case message output:
4052 *pq_puttextmessage - generate a character set-converted message in one step
4153 *pq_putemptymessage - convenience routine for message with empty body
4254 *
4355 * Message parsing after input:
4456 *pq_getmsgbyte- get a raw byte from a message buffer
4557 *pq_getmsgint- get a binary integer from a message buffer
58+ *pq_getmsgint64- get a binary 8-byte int from a message buffer
4659 *pq_getmsgbytes- get raw data from a message buffer
4760 *pq_copymsgbytes- copy raw data from a message buffer
61+ *pq_getmsgtext- get a counted text string (with conversion)
4862 *pq_getmsgstring- get a null-terminated text string (with conversion)
4963 *pq_getmsgend- verify message fully consumed
5064 */
@@ -101,7 +115,7 @@ pq_sendbytes(StringInfo buf, const char *data, int datalen)
101115}
102116
103117/* --------------------------------
104- *pq_sendcountedtext - append a text string (with character set conversion)
118+ *pq_sendcountedtext - append acounted text string (with character set conversion)
105119 *
106120 * The data sent to the frontend by this routine is a 4-byte count field
107121 * followed by the string. The count includes itself or not, as per the
@@ -132,6 +146,34 @@ pq_sendcountedtext(StringInfo buf, const char *str, int slen,
132146}
133147}
134148
149+ /* --------------------------------
150+ *pq_sendtext- append a text string (with conversion)
151+ *
152+ * The passed text string need not be null-terminated, and the data sent
153+ * to the frontend isn't either. Note that this is not actually useful
154+ * for direct frontend transmissions, since there'd be no way for the
155+ * frontend to determine the string length. But it is useful for binary
156+ * format conversions.
157+ * --------------------------------
158+ */
159+ void
160+ pq_sendtext (StringInfo buf ,const char * str ,int slen )
161+ {
162+ char * p ;
163+
164+ p = (char * )pg_server_to_client ((unsignedchar * )str ,slen );
165+ if (p != str )/* actual conversion has been done? */
166+ {
167+ slen = strlen (p );
168+ appendBinaryStringInfo (buf ,p ,slen );
169+ pfree (p );
170+ }
171+ else
172+ {
173+ appendBinaryStringInfo (buf ,str ,slen );
174+ }
175+ }
176+
135177/* --------------------------------
136178 *pq_sendstring- append a null-terminated text string (with conversion)
137179 *
@@ -152,9 +194,11 @@ pq_sendstring(StringInfo buf, const char *str)
152194slen = strlen (p );
153195appendBinaryStringInfo (buf ,p ,slen + 1 );
154196pfree (p );
155- return ;
156197}
157- appendBinaryStringInfo (buf ,str ,slen + 1 );
198+ else
199+ {
200+ appendBinaryStringInfo (buf ,str ,slen + 1 );
201+ }
158202}
159203
160204/* --------------------------------
@@ -188,6 +232,35 @@ pq_sendint(StringInfo buf, int i, int b)
188232}
189233}
190234
235+ /* --------------------------------
236+ *pq_sendint64- append a binary 8-byte int to a StringInfo buffer
237+ *
238+ * It is tempting to merge this with pq_sendint, but we'd have to make the
239+ * argument int64 for all data widths --- that could be a big performance
240+ * hit on machines where int64 isn't efficient.
241+ * --------------------------------
242+ */
243+ void
244+ pq_sendint64 (StringInfo buf ,int64 i )
245+ {
246+ uint32 n32 ;
247+
248+ /* High order half first, since we're doing MSB-first */
249+ #ifdef INT64_IS_BUSTED
250+ /* don't try a right shift of 32 on a 32-bit word */
251+ n32 = (i < 0 ) ?-1 :0 ;
252+ #else
253+ n32 = (uint32 ) (i >>32 );
254+ #endif
255+ n32 = htonl (n32 );
256+ appendBinaryStringInfo (buf , (char * )& n32 ,4 );
257+
258+ /* Now the low order half */
259+ n32 = (uint32 )i ;
260+ n32 = htonl (n32 );
261+ appendBinaryStringInfo (buf , (char * )& n32 ,4 );
262+ }
263+
191264/* --------------------------------
192265 *pq_endmessage- send the completed message to the frontend
193266 *
@@ -205,6 +278,44 @@ pq_endmessage(StringInfo buf)
205278buf -> data = NULL ;
206279}
207280
281+
282+ /* --------------------------------
283+ *pq_begintypsend- initialize for constructing a bytea result
284+ * --------------------------------
285+ */
286+ void
287+ pq_begintypsend (StringInfo buf )
288+ {
289+ initStringInfo (buf );
290+ /* Reserve four bytes for the bytea length word */
291+ appendStringInfoCharMacro (buf ,'\0' );
292+ appendStringInfoCharMacro (buf ,'\0' );
293+ appendStringInfoCharMacro (buf ,'\0' );
294+ appendStringInfoCharMacro (buf ,'\0' );
295+ }
296+
297+ /* --------------------------------
298+ *pq_endtypsend- finish constructing a bytea result
299+ *
300+ * The data buffer is returned as the palloc'd bytea value. (We expect
301+ * that it will be suitably aligned for this because it has been palloc'd.)
302+ * We assume the StringInfoData is just a local variable in the caller and
303+ * need not be pfree'd.
304+ * --------------------------------
305+ */
306+ bytea *
307+ pq_endtypsend (StringInfo buf )
308+ {
309+ bytea * result = (bytea * )buf -> data ;
310+
311+ /* Insert correct length into bytea length word */
312+ Assert (buf -> len >=VARHDRSZ );
313+ VARATT_SIZEP (result )= buf -> len ;
314+
315+ return result ;
316+ }
317+
318+
208319/* --------------------------------
209320 *pq_puttextmessage - generate a character set-converted message in one step
210321 *
@@ -289,6 +400,38 @@ pq_getmsgint(StringInfo msg, int b)
289400return result ;
290401}
291402
403+ /* --------------------------------
404+ *pq_getmsgint64- get a binary 8-byte int from a message buffer
405+ *
406+ * It is tempting to merge this with pq_getmsgint, but we'd have to make the
407+ * result int64 for all data widths --- that could be a big performance
408+ * hit on machines where int64 isn't efficient.
409+ * --------------------------------
410+ */
411+ int64
412+ pq_getmsgint64 (StringInfo msg )
413+ {
414+ int64 result ;
415+ uint32 h32 ;
416+ uint32 l32 ;
417+
418+ pq_copymsgbytes (msg , (char * )& h32 ,4 );
419+ pq_copymsgbytes (msg , (char * )& l32 ,4 );
420+ h32 = ntohl (h32 );
421+ l32 = ntohl (l32 );
422+
423+ #ifdef INT64_IS_BUSTED
424+ /* just lose the high half */
425+ result = l32 ;
426+ #else
427+ result = h32 ;
428+ result <<=32 ;
429+ result |=l32 ;
430+ #endif
431+
432+ return result ;
433+ }
434+
292435/* --------------------------------
293436 *pq_getmsgbytes- get raw data from a message buffer
294437 *
@@ -323,6 +466,39 @@ pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
323466msg -> cursor += datalen ;
324467}
325468
469+ /* --------------------------------
470+ *pq_getmsgtext- get a counted text string (with conversion)
471+ *
472+ *Always returns a pointer to a freshly palloc'd result.
473+ *The result has a trailing null, *and* we return its strlen in *nbytes.
474+ * --------------------------------
475+ */
476+ char *
477+ pq_getmsgtext (StringInfo msg ,int rawbytes ,int * nbytes )
478+ {
479+ char * str ;
480+ char * p ;
481+
482+ if (rawbytes < 0 || rawbytes > (msg -> len - msg -> cursor ))
483+ elog (ERROR ,"pq_getmsgtext: insufficient data left in message" );
484+ str = & msg -> data [msg -> cursor ];
485+ msg -> cursor += rawbytes ;
486+
487+ p = (char * )pg_client_to_server ((unsignedchar * )str ,rawbytes );
488+ if (p != str )/* actual conversion has been done? */
489+ {
490+ * nbytes = strlen (p );
491+ }
492+ else
493+ {
494+ p = (char * )palloc (rawbytes + 1 );
495+ memcpy (p ,str ,rawbytes );
496+ p [rawbytes ]= '\0' ;
497+ * nbytes = rawbytes ;
498+ }
499+ return p ;
500+ }
501+
326502/* --------------------------------
327503 *pq_getmsgstring- get a null-terminated text string (with conversion)
328504 *