/*------------------------------------------------------------------------- * * pqformat.h * Definitions for formatting and parsing frontend/backend messages * * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/libpq/pqformat.h * *------------------------------------------------------------------------- */ #ifndef PQFORMAT_H #define PQFORMAT_H #include "lib/stringinfo.h" #include "mb/pg_wchar.h" #include "port/pg_bswap.h" extern void pq_beginmessage(StringInfo buf, char msgtype); extern void pq_beginmessage_reuse(StringInfo buf, char msgtype); extern void pq_endmessage(StringInfo buf); extern void pq_endmessage_reuse(StringInfo buf); extern void pq_sendbytes(StringInfo buf, const char *data, int datalen); extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen, bool countincludesself); extern void pq_sendtext(StringInfo buf, const char *str, int slen); extern void pq_sendstring(StringInfo buf, const char *str); extern void pq_send_ascii_string(StringInfo buf, const char *str); extern void pq_sendfloat4(StringInfo buf, float4 f); extern void pq_sendfloat8(StringInfo buf, float8 f); /* * Append a [u]int8 to a StringInfo buffer, which already has enough space * preallocated. * * The use of pg_restrict allows the compiler to optimize the code based on * the assumption that buf, buf->len, buf->data and *buf->data don't * overlap. Without the annotation buf->len etc cannot be kept in a register * over subsequent pq_writeintN calls. * * The use of StringInfoData * rather than StringInfo is due to MSVC being * overly picky and demanding a * before a restrict. */ static inline void pq_writeint8(StringInfoData *pg_restrict buf, uint8 i) { uint8 ni = i; Assert(buf->len + (int) sizeof(uint8) <= buf->maxlen); memcpy((char *pg_restrict) (buf->data + buf->len), &ni, sizeof(uint8)); buf->len += sizeof(uint8); } /* * Append a [u]int16 to a StringInfo buffer, which already has enough space * preallocated. */ static inline void pq_writeint16(StringInfoData *pg_restrict buf, uint16 i) { uint16 ni = pg_hton16(i); Assert(buf->len + (int) sizeof(uint16) <= buf->maxlen); memcpy((char *pg_restrict) (buf->data + buf->len), &ni, sizeof(uint16)); buf->len += sizeof(uint16); } /* * Append a [u]int32 to a StringInfo buffer, which already has enough space * preallocated. */ static inline void pq_writeint32(StringInfoData *pg_restrict buf, uint32 i) { uint32 ni = pg_hton32(i); Assert(buf->len + (int) sizeof(uint32) <= buf->maxlen); memcpy((char *pg_restrict) (buf->data + buf->len), &ni, sizeof(uint32)); buf->len += sizeof(uint32); } /* * Append a [u]int64 to a StringInfo buffer, which already has enough space * preallocated. */ static inline void pq_writeint64(StringInfoData *pg_restrict buf, uint64 i) { uint64 ni = pg_hton64(i); Assert(buf->len + (int) sizeof(uint64) <= buf->maxlen); memcpy((char *pg_restrict) (buf->data + buf->len), &ni, sizeof(uint64)); buf->len += sizeof(uint64); } /* * Append a null-terminated text string (with conversion) to a buffer with * preallocated space. * * NB: The pre-allocated space needs to be sufficient for the string after * converting to client encoding. * * NB: passed text string must be null-terminated, and so is the data * sent to the frontend. */ static inline void pq_writestring(StringInfoData *pg_restrict buf, const char *pg_restrict 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); Assert(buf->len + slen + 1 <= buf->maxlen); memcpy(((char *pg_restrict) buf->data + buf->len), p, slen + 1); buf->len += slen + 1; if (p != str) pfree(p); } /* append a binary [u]int8 to a StringInfo buffer */ static inline void pq_sendint8(StringInfo buf, uint8 i) { enlargeStringInfo(buf, sizeof(uint8)); pq_writeint8(buf, i); } /* append a binary [u]int16 to a StringInfo buffer */ static inline void pq_sendint16(StringInfo buf, uint16 i) { enlargeStringInfo(buf, sizeof(uint16)); pq_writeint16(buf, i); } /* append a binary [u]int32 to a StringInfo buffer */ static inline void pq_sendint32(StringInfo buf, uint32 i) { enlargeStringInfo(buf, sizeof(uint32)); pq_writeint32(buf, i); } /* append a binary [u]int64 to a StringInfo buffer */ static inline void pq_sendint64(StringInfo buf, uint64 i) { enlargeStringInfo(buf, sizeof(uint64)); pq_writeint64(buf, i); } /* append a binary byte to a StringInfo buffer */ static inline void pq_sendbyte(StringInfo buf, uint8 byt) { pq_sendint8(buf, byt); } /* * Append a binary integer to a StringInfo buffer * * This function is deprecated; prefer use of the functions above. */ static inline void pq_sendint(StringInfo buf, uint32 i, int b) { switch (b) { case 1: pq_sendint8(buf, (uint8) i); break; case 2: pq_sendint16(buf, (uint16) i); break; case 4: pq_sendint32(buf, (uint32) i); break; default: elog(ERROR, "unsupported integer size %d", b); break; } } extern void pq_begintypsend(StringInfo buf); extern bytea *pq_endtypsend(StringInfo buf); extern void pq_puttextmessage(char msgtype, const char *str); extern void pq_putemptymessage(char msgtype); extern int pq_getmsgbyte(StringInfo msg); extern unsigned int pq_getmsgint(StringInfo msg, int b); extern int64 pq_getmsgint64(StringInfo msg); extern float4 pq_getmsgfloat4(StringInfo msg); extern float8 pq_getmsgfloat8(StringInfo msg); extern const char *pq_getmsgbytes(StringInfo msg, int datalen); extern void pq_copymsgbytes(StringInfo msg, char *buf, int datalen); extern char *pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes); extern const char *pq_getmsgstring(StringInfo msg); extern const char *pq_getmsgrawstring(StringInfo msg); extern void pq_getmsgend(StringInfo msg); #endif /* PQFORMAT_H */