Quelle pqformat.c
Sprache: C
/*-------------------------------------------------------------------------
*
* pqformat . c
* Routines for formatting and parsing frontend / backend messages
*
* Outgoing messages are built up in a StringInfo buffer ( which is expansible )
* and then sent in a single call to pq_putmessage . This module provides data
* formatting / conversion routines that are needed to produce valid messages .
* Note in particular the distinction between " raw data " and " text " ; raw data
* is message protocol characters and binary values that are not subject to
* character set conversion , while text is converted by character encoding
* rules .
*
* Incoming messages are similarly read into a StringInfo buffer , via
* pq_getmessage , and then parsed and converted from that using the routines
* in this module .
*
* These same routines support reading and writing of external binary formats
* ( typsend / typreceive routines ) . The conversion routines for individual
* data types are exactly the same , only initialization and completion
* are different .
*
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
* src / backend / libpq / pqformat . c
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/*
* INTERFACE ROUTINES
* Message assembly and output :
* pq_beginmessage - initialize StringInfo buffer
* pq_sendbyte - append a raw byte to a StringInfo buffer
* pq_sendint - append a binary integer to a StringInfo buffer
* pq_sendint64 - append a binary 8 - byte int to a StringInfo buffer
* pq_sendfloat4 - append a float4 to a StringInfo buffer
* pq_sendfloat8 - append a float8 to a StringInfo buffer
* pq_sendbytes - append raw data to a StringInfo buffer
* pq_sendcountedtext - append a counted text string ( with character set conversion )
* pq_sendtext - append a text string ( with conversion )
* pq_sendstring - append a null - terminated text string ( with conversion )
* pq_send_ascii_string - append a null - terminated text string ( without conversion )
* pq_endmessage - send the completed message to the frontend
* Note : it is also possible to append data to the StringInfo buffer using
* the regular StringInfo routines , but this is discouraged since required
* character set conversion may not occur .
*
* typsend support ( construct a bytea value containing external binary data ) :
* pq_begintypsend - initialize StringInfo buffer
* pq_endtypsend - return the completed string as a " bytea * "
*
* Special - case message output :
* pq_puttextmessage - generate a character set - converted message in one step
* pq_putemptymessage - convenience routine for message with empty body
*
* Message parsing after input :
* pq_getmsgbyte - get a raw byte from a message buffer
* pq_getmsgint - get a binary integer from a message buffer
* pq_getmsgint64 - get a binary 8 - byte int from a message buffer
* pq_getmsgfloat4 - get a float4 from a message buffer
* pq_getmsgfloat8 - get a float8 from a message buffer
* pq_getmsgbytes - get raw data from a message buffer
* pq_copymsgbytes - copy raw data from a message buffer
* pq_getmsgtext - get a counted text string ( with conversion )
* pq_getmsgstring - get a null - terminated text string ( with conversion )
* pq_getmsgrawstring - get a null - terminated text string - NO conversion
* pq_getmsgend - verify message fully consumed
*/
#include "postgres.h"
#include <sys/param.h>
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "mb/pg_wchar.h"
#include "port/pg_bswap.h"
#include "varatt.h"
/* --------------------------------
* pq_beginmessage - initialize for sending a message
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_beginmessage(StringInfo buf, char msgtype)
{
initStringInfo(buf);
/*
* We stash the message type into the buffer ' s cursor field , expecting
* that the pq_sendXXX routines won ' t touch it . We could alternatively
* make it the first byte of the buffer contents , but this seems easier .
*/
buf->cursor = msgtype;
}
/* --------------------------------
* pq_beginmessage_reuse - initialize for sending a message , reuse buffer
*
* This requires the buffer to be allocated in a sufficiently long - lived
* memory context .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_beginmessage_reuse(StringInfo buf, char msgtype)
{
resetStringInfo(buf);
/*
* We stash the message type into the buffer ' s cursor field , expecting
* that the pq_sendXXX routines won ' t touch it . We could alternatively
* make it the first byte of the buffer contents , but this seems easier .
*/
buf->cursor = msgtype;
}
/* --------------------------------
* pq_sendbytes - append raw data to a StringInfo buffer
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_sendbytes(StringInfo buf, const void *data, int datalen)
{
/* use variant that maintains a trailing null-byte, out of caution */
appendBinaryStringInfo(buf, data, datalen);
}
/* --------------------------------
* pq_sendcountedtext - append a counted text string ( with character set conversion )
*
* The data sent to the frontend by this routine is a 4 - byte count field
* followed by the string . The count does not include itself , as required by
* protocol version 3 . 0 . The passed text string need not be null - terminated ,
* and the data sent to the frontend isn ' t either .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_sendcountedtext(StringInfo buf, const char *str, int slen)
{
char *p;
p = pg_server_to_client(str, slen);
if (p != str) /* actual conversion has been done? */
{
slen = strlen(p);
pq_sendint32(buf, slen);
appendBinaryStringInfoNT(buf, p, slen);
pfree(p);
}
else
{
pq_sendint32(buf, slen);
appendBinaryStringInfoNT(buf, str, slen);
}
}
/* --------------------------------
* pq_sendtext - append a text string ( with conversion )
*
* The passed text string need not be null - terminated , and the data sent
* to the frontend isn ' t either . Note that this is not actually useful
* for direct frontend transmissions , since there ' d be no way for the
* frontend to determine the string length . But it is useful for binary
* format conversions .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_sendtext(StringInfo buf, const char *str, int slen)
{
char *p;
p = pg_server_to_client(str, slen);
if (p != str) /* actual conversion has been done? */
{
slen = strlen(p);
appendBinaryStringInfo(buf, p, slen);
pfree(p);
}
else
appendBinaryStringInfo(buf, str, slen);
}
/* --------------------------------
* pq_sendstring - append a null - terminated text string ( with conversion )
*
* NB : passed text string must be null - terminated , and so is the data
* sent to the frontend .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_sendstring(StringInfo buf, const char *str)
{
int slen = strlen(str);
char *p;
p = pg_server_to_client(str, slen);
if (p != str) /* actual conversion has been done? */
{
slen = strlen(p);
appendBinaryStringInfoNT(buf, p, slen + 1 );
pfree(p);
}
else
appendBinaryStringInfoNT(buf, str, slen + 1 );
}
/* --------------------------------
* pq_send_ascii_string - append a null - terminated text string ( without conversion )
*
* This function intentionally bypasses encoding conversion , instead just
* silently replacing any non - 7 - bit - ASCII characters with question marks .
* It is used only when we are having trouble sending an error message to
* the client with normal localization and encoding conversion . The caller
* should already have taken measures to ensure the string is just ASCII ;
* the extra work here is just to make certain we don ' t send a badly encoded
* string to the client ( which might or might not be robust about that ) .
*
* NB : passed text string must be null - terminated , and so is the data
* sent to the frontend .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_send_ascii_string(StringInfo buf, const char *str)
{
while (*str)
{
char ch = *str++;
if (IS_HIGHBIT_SET(ch))
ch = '?' ;
appendStringInfoCharMacro(buf, ch);
}
appendStringInfoChar(buf, '\0' );
}
/* --------------------------------
* pq_sendfloat4 - append a float4 to a StringInfo buffer
*
* The point of this routine is to localize knowledge of the external binary
* representation of float4 , which is a component of several datatypes .
*
* We currently assume that float4 should be byte - swapped in the same way
* as int4 . This rule is not perfect but it gives us portability across
* most IEEE - float - using architectures .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_sendfloat4(StringInfo buf, float4 f)
{
union
{
float4 f;
uint32 i;
} swap;
swap.f = f;
pq_sendint32(buf, swap.i);
}
/* --------------------------------
* pq_sendfloat8 - append a float8 to a StringInfo buffer
*
* The point of this routine is to localize knowledge of the external binary
* representation of float8 , which is a component of several datatypes .
*
* We currently assume that float8 should be byte - swapped in the same way
* as int8 . This rule is not perfect but it gives us portability across
* most IEEE - float - using architectures .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_sendfloat8(StringInfo buf, float8 f)
{
union
{
float8 f;
int64 i;
} swap;
swap.f = f;
pq_sendint64(buf, swap.i);
}
/* --------------------------------
* pq_endmessage - send the completed message to the frontend
*
* The data buffer is pfree ( ) d , but if the StringInfo was allocated with
* makeStringInfo then the caller must still pfree it .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_endmessage(StringInfo buf)
{
/* msgtype was saved in cursor field */
(void ) pq_putmessage(buf->cursor, buf->data, buf->len);
/* no need to complain about any failure, since pqcomm.c already did */
pfree(buf->data);
buf->data = NULL;
}
/* --------------------------------
* pq_endmessage_reuse - send the completed message to the frontend
*
* The data buffer is * not * freed , allowing to reuse the buffer with
* pq_beginmessage_reuse .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_endmessage_reuse(StringInfo buf)
{
/* msgtype was saved in cursor field */
(void ) pq_putmessage(buf->cursor, buf->data, buf->len);
}
/* --------------------------------
* pq_begintypsend - initialize for constructing a bytea result
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_begintypsend(StringInfo buf)
{
initStringInfo(buf);
/* Reserve four bytes for the bytea length word */
appendStringInfoCharMacro(buf, '\0' );
appendStringInfoCharMacro(buf, '\0' );
appendStringInfoCharMacro(buf, '\0' );
appendStringInfoCharMacro(buf, '\0' );
}
/* --------------------------------
* pq_endtypsend - finish constructing a bytea result
*
* The data buffer is returned as the palloc ' d bytea value . ( We expect
* that it will be suitably aligned for this because it has been palloc ' d . )
* We assume the StringInfoData is just a local variable in the caller and
* need not be pfree ' d .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
bytea *
pq_endtypsend(StringInfo buf)
{
bytea *result = (bytea *) buf->data;
/* Insert correct length into bytea length word */
Assert(buf->len >= VARHDRSZ);
SET_VARSIZE(result, buf->len);
return result;
}
/* --------------------------------
* pq_puttextmessage - generate a character set - converted message in one step
*
* This is the same as the pqcomm . c routine pq_putmessage , except that
* the message body is a null - terminated string to which encoding
* conversion applies .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_puttextmessage(char msgtype, const char *str)
{
int slen = strlen(str);
char *p;
p = pg_server_to_client(str, slen);
if (p != str) /* actual conversion has been done? */
{
(void ) pq_putmessage(msgtype, p, strlen(p) + 1 );
pfree(p);
return ;
}
(void ) pq_putmessage(msgtype, str, slen + 1 );
}
/* --------------------------------
* pq_putemptymessage - convenience routine for message with empty body
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_putemptymessage(char msgtype)
{
(void ) pq_putmessage(msgtype, NULL, 0 );
}
/* --------------------------------
* pq_getmsgbyte - get a raw byte from a message buffer
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
int
pq_getmsgbyte(StringInfo msg)
{
if (msg->cursor >= msg->len)
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("no data left in message" )));
return (unsigned char ) msg->data[msg->cursor++];
}
/* --------------------------------
* pq_getmsgint - get a binary integer from a message buffer
*
* Values are treated as unsigned .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
unsigned int
pq_getmsgint(StringInfo msg, int b)
{
unsigned int result;
unsigned char n8;
uint16 n16;
uint32 n32;
switch (b)
{
case 1 :
pq_copymsgbytes(msg, &n8, 1 );
result = n8;
break ;
case 2 :
pq_copymsgbytes(msg, &n16, 2 );
result = pg_ntoh16(n16);
break ;
case 4 :
pq_copymsgbytes(msg, &n32, 4 );
result = pg_ntoh32(n32);
break ;
default :
elog(ERROR, "unsupported integer size %d" , b);
result = 0 ; /* keep compiler quiet */
break ;
}
return result;
}
/* --------------------------------
* pq_getmsgint64 - get a binary 8 - byte int from a message buffer
*
* It is tempting to merge this with pq_getmsgint , but we ' d have to make the
* result int64 for all data widths - - - that could be a big performance
* hit on machines where int64 isn ' t efficient .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
int64
pq_getmsgint64(StringInfo msg)
{
uint64 n64;
pq_copymsgbytes(msg, &n64, sizeof (n64));
return pg_ntoh64(n64);
}
/* --------------------------------
* pq_getmsgfloat4 - get a float4 from a message buffer
*
* See notes for pq_sendfloat4 .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
float4
pq_getmsgfloat4(StringInfo msg)
{
union
{
float4 f;
uint32 i;
} swap;
swap.i = pq_getmsgint(msg, 4 );
return swap.f;
}
/* --------------------------------
* pq_getmsgfloat8 - get a float8 from a message buffer
*
* See notes for pq_sendfloat8 .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
float8
pq_getmsgfloat8(StringInfo msg)
{
union
{
float8 f;
int64 i;
} swap;
swap.i = pq_getmsgint64(msg);
return swap.f;
}
/* --------------------------------
* pq_getmsgbytes - get raw data from a message buffer
*
* Returns a pointer directly into the message buffer ; note this
* may not have any particular alignment .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
const char *
pq_getmsgbytes(StringInfo msg, int datalen)
{
const char *result;
if (datalen < 0 || datalen > (msg->len - msg->cursor))
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("insufficient data left in message" )));
result = &msg->data[msg->cursor];
msg->cursor += datalen;
return result;
}
/* --------------------------------
* pq_copymsgbytes - copy raw data from a message buffer
*
* Same as above , except data is copied to caller ' s buffer .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_copymsgbytes(StringInfo msg, void *buf, int datalen)
{
if (datalen < 0 || datalen > (msg->len - msg->cursor))
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("insufficient data left in message" )));
memcpy(buf, &msg->data[msg->cursor], datalen);
msg->cursor += datalen;
}
/* --------------------------------
* pq_getmsgtext - get a counted text string ( with conversion )
*
* Always returns a pointer to a freshly palloc ' d result .
* The result has a trailing null , * and * we return its strlen in * nbytes .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
char *
pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
{
char *str;
char *p;
if (rawbytes < 0 || rawbytes > (msg->len - msg->cursor))
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("insufficient data left in message" )));
str = &msg->data[msg->cursor];
msg->cursor += rawbytes;
p = pg_client_to_server(str, rawbytes);
if (p != str) /* actual conversion has been done? */
*nbytes = strlen(p);
else
{
p = (char *) palloc(rawbytes + 1 );
memcpy(p, str, rawbytes);
p[rawbytes] = '\0' ;
*nbytes = rawbytes;
}
return p;
}
/* --------------------------------
* pq_getmsgstring - get a null - terminated text string ( with conversion )
*
* May return a pointer directly into the message buffer , or a pointer
* to a palloc ' d conversion result .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
const char *
pq_getmsgstring(StringInfo msg)
{
char *str;
int slen;
str = &msg->data[msg->cursor];
/*
* It ' s safe to use strlen ( ) here because a StringInfo is guaranteed to
* have a trailing null byte . But check we found a null inside the
* message .
*/
slen = strlen(str);
if (msg->cursor + slen >= msg->len)
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid string in message" )));
msg->cursor += slen + 1 ;
return pg_client_to_server(str, slen);
}
/* --------------------------------
* pq_getmsgrawstring - get a null - terminated text string - NO conversion
*
* Returns a pointer directly into the message buffer .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
const char *
pq_getmsgrawstring(StringInfo msg)
{
char *str;
int slen;
str = &msg->data[msg->cursor];
/*
* It ' s safe to use strlen ( ) here because a StringInfo is guaranteed to
* have a trailing null byte . But check we found a null inside the
* message .
*/
slen = strlen(str);
if (msg->cursor + slen >= msg->len)
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid string in message" )));
msg->cursor += slen + 1 ;
return str;
}
/* --------------------------------
* pq_getmsgend - verify message fully consumed
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
pq_getmsgend(StringInfo msg)
{
if (msg->cursor != msg->len)
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid message format" )));
}
Messung V0.5 in Prozent C=92 H=97 G=94
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland
2026-08-25
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=141584
#Domains=738142