15
15
* pq_getmessage, and then parsed and converted from that using the routines
16
16
* in this module.
17
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
+ *
18
24
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
19
25
* Portions Copyright (c) 1994, Regents of the University of California
20
26
*
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 $
22
28
*
23
29
*-------------------------------------------------------------------------
24
30
*/
28
34
*pq_beginmessage - initialize StringInfo buffer
29
35
*pq_sendbyte- append a raw byte to a StringInfo buffer
30
36
*pq_sendint- append a binary integer to a StringInfo buffer
37
+ *pq_sendint64- append a binary 8-byte int to a StringInfo buffer
31
38
*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)
33
41
*pq_sendstring- append a null-terminated text string (with conversion)
34
42
*pq_endmessage- send the completed message to the frontend
35
43
* Note: it is also possible to append data to the StringInfo buffer using
36
44
* the regular StringInfo routines, but this is discouraged since required
37
45
* character set conversion may not occur.
38
46
*
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
+ *
39
51
* Special-case message output:
40
52
*pq_puttextmessage - generate a character set-converted message in one step
41
53
*pq_putemptymessage - convenience routine for message with empty body
42
54
*
43
55
* Message parsing after input:
44
56
*pq_getmsgbyte- get a raw byte from a message buffer
45
57
*pq_getmsgint- get a binary integer from a message buffer
58
+ *pq_getmsgint64- get a binary 8-byte int from a message buffer
46
59
*pq_getmsgbytes- get raw data from a message buffer
47
60
*pq_copymsgbytes- copy raw data from a message buffer
61
+ *pq_getmsgtext- get a counted text string (with conversion)
48
62
*pq_getmsgstring- get a null-terminated text string (with conversion)
49
63
*pq_getmsgend- verify message fully consumed
50
64
*/
@@ -101,7 +115,7 @@ pq_sendbytes(StringInfo buf, const char *data, int datalen)
101
115
}
102
116
103
117
/* --------------------------------
104
- *pq_sendcountedtext - append a text string (with character set conversion)
118
+ *pq_sendcountedtext - append acounted text string (with character set conversion)
105
119
*
106
120
* The data sent to the frontend by this routine is a 4-byte count field
107
121
* 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,
132
146
}
133
147
}
134
148
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
+
135
177
/* --------------------------------
136
178
*pq_sendstring- append a null-terminated text string (with conversion)
137
179
*
@@ -152,9 +194,11 @@ pq_sendstring(StringInfo buf, const char *str)
152
194
slen = strlen (p );
153
195
appendBinaryStringInfo (buf ,p ,slen + 1 );
154
196
pfree (p );
155
- return ;
156
197
}
157
- appendBinaryStringInfo (buf ,str ,slen + 1 );
198
+ else
199
+ {
200
+ appendBinaryStringInfo (buf ,str ,slen + 1 );
201
+ }
158
202
}
159
203
160
204
/* --------------------------------
@@ -188,6 +232,35 @@ pq_sendint(StringInfo buf, int i, int b)
188
232
}
189
233
}
190
234
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
+
191
264
/* --------------------------------
192
265
*pq_endmessage- send the completed message to the frontend
193
266
*
@@ -205,6 +278,44 @@ pq_endmessage(StringInfo buf)
205
278
buf -> data = NULL ;
206
279
}
207
280
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
+
208
319
/* --------------------------------
209
320
*pq_puttextmessage - generate a character set-converted message in one step
210
321
*
@@ -289,6 +400,38 @@ pq_getmsgint(StringInfo msg, int b)
289
400
return result ;
290
401
}
291
402
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
+
292
435
/* --------------------------------
293
436
*pq_getmsgbytes- get raw data from a message buffer
294
437
*
@@ -323,6 +466,39 @@ pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
323
466
msg -> cursor += datalen ;
324
467
}
325
468
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
+
326
502
/* --------------------------------
327
503
*pq_getmsgstring- get a null-terminated text string (with conversion)
328
504
*