mirror of https://github.com/postgres/postgres
can be generated in a buffer and then sent to the frontend in a single libpq call. This solves problems with NOTICE and ERROR messages generated in the middle of a data message or COPY OUT operation.REL6_5_PATCHES
parent
fc08814e00
commit
95cc41b81d
@ -1,125 +1,171 @@ |
||||
/*
|
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* stringinfo.c |
||||
* These are routines that can be used to write informations to a string, |
||||
* without having to worry about string lengths, space allocation etc. |
||||
* Ideally the interface should look like the file i/o interface, |
||||
* |
||||
* StringInfo provides an indefinitely-extensible string data type. |
||||
* It can be used to buffer either ordinary C strings (null-terminated text) |
||||
* or arbitrary binary data. All storage is allocated with palloc(). |
||||
* |
||||
* Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* $Id: stringinfo.c,v 1.14 1999/02/13 23:15:36 momjian Exp $ |
||||
* $Id: stringinfo.c,v 1.15 1999/04/25 03:19:25 tgl Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include <stdarg.h> |
||||
|
||||
#include <postgres.h> |
||||
|
||||
#include <nodes/pg_list.h> |
||||
#include <lib/stringinfo.h> |
||||
#include "postgres.h" |
||||
#include "lib/stringinfo.h" |
||||
|
||||
/*
|
||||
* makeStringInfo |
||||
* |
||||
* Create a StringInfoData & return a pointer to it. |
||||
* |
||||
* Create an empty 'StringInfoData' & return a pointer to it. |
||||
*/ |
||||
StringInfo |
||||
makeStringInfo() |
||||
makeStringInfo(void) |
||||
{ |
||||
StringInfo res; |
||||
int size; |
||||
|
||||
res = (StringInfo) palloc(sizeof(StringInfoData)); |
||||
if (res == NULL) |
||||
elog(ERROR, "makeStringInfo: Out of memory!"); |
||||
elog(ERROR, "makeStringInfo: Out of memory"); |
||||
|
||||
size = 256; /* initial default size */ |
||||
res->data = palloc(size); |
||||
if (res->data == NULL) |
||||
{ |
||||
elog(ERROR, |
||||
"makeStringInfo: Out of memory! (%d bytes requested)", size); |
||||
} |
||||
res->maxlen = size; |
||||
res->len = 0; |
||||
/* Make sure the string is empty initially. */ |
||||
res->data[0] = '\0'; |
||||
initStringInfo(res); |
||||
|
||||
return res; |
||||
} |
||||
|
||||
/*
|
||||
* appendStringInfo |
||||
* initStringInfo |
||||
* |
||||
* append to the current 'StringInfo' a new string. |
||||
* If there is not enough space in the current 'data', then reallocate |
||||
* some more... |
||||
* Initialize a StringInfoData struct (with previously undefined contents) |
||||
* to describe an empty string. |
||||
*/ |
||||
void |
||||
initStringInfo(StringInfo str) |
||||
{ |
||||
int size = 256; /* initial default buffer size */ |
||||
|
||||
str->data = palloc(size); |
||||
if (str->data == NULL) |
||||
elog(ERROR, |
||||
"initStringInfo: Out of memory (%d bytes requested)", size); |
||||
str->maxlen = size; |
||||
str->len = 0; |
||||
str->data[0] = '\0'; |
||||
} |
||||
|
||||
/*
|
||||
* enlargeStringInfo |
||||
* |
||||
* NOTE: if we reallocate space, we pfree the old one! |
||||
* Internal routine: make sure there is enough space for 'needed' more bytes |
||||
* ('needed' does not include the terminating null). |
||||
*/ |
||||
static void |
||||
enlargeStringInfo(StringInfo str, int needed) |
||||
{ |
||||
int newlen; |
||||
char *newdata; |
||||
|
||||
needed += str->len + 1; /* total space required now */ |
||||
if (needed <= str->maxlen) |
||||
return; /* got enough space already */ |
||||
|
||||
/*
|
||||
* We don't want to allocate just a little more space with each append; |
||||
* for efficiency, double the buffer size each time it overflows. |
||||
* Actually, we might need to more than double it if 'needed' is big... |
||||
*/ |
||||
newlen = 2 * str->maxlen; |
||||
while (needed > newlen) |
||||
newlen = 2 * newlen; |
||||
|
||||
newdata = palloc(newlen); |
||||
if (newdata == NULL) |
||||
elog(ERROR, |
||||
"enlargeStringInfo: Out of memory (%d bytes requested)", newlen); |
||||
|
||||
/* OK, transfer data into new buffer, and release old buffer */ |
||||
memcpy(newdata, str->data, str->len + 1); |
||||
pfree(str->data); |
||||
str->data = newdata; |
||||
str->maxlen = newlen; |
||||
} |
||||
|
||||
/*
|
||||
* appendStringInfo |
||||
* |
||||
* Format text data under the control of fmt (an sprintf-like format string) |
||||
* and append it to whatever is already in str. More space is allocated |
||||
* to str if necessary. This is sort of like a combination of sprintf and |
||||
* strcat. |
||||
* |
||||
* CAUTION: the current implementation has a 1K limit on the amount of text |
||||
* generated in a single call (not on the total string length). |
||||
*/ |
||||
void |
||||
appendStringInfo(StringInfo str, const char *fmt,...) |
||||
appendStringInfo(StringInfo str, const char *fmt, ...) |
||||
{ |
||||
int buflen, |
||||
newlen, |
||||
needed; |
||||
char *s, |
||||
buffer[512]; |
||||
va_list args; |
||||
char buffer[1024]; |
||||
int buflen; |
||||
|
||||
Assert(str != NULL); |
||||
|
||||
va_list args; |
||||
va_start(args, fmt); |
||||
buflen = vsnprintf(buffer, 512, fmt, args); |
||||
va_end(args); |
||||
buflen = vsnprintf(buffer, sizeof(buffer), fmt, args); |
||||
va_end(args); |
||||
|
||||
/* Make more room if needed */ |
||||
enlargeStringInfo(str, buflen); |
||||
|
||||
/* OK, append the data, including the trailing null */ |
||||
memcpy(str->data + str->len, buffer, buflen + 1); |
||||
str->len += buflen; |
||||
} |
||||
|
||||
/*------------------------
|
||||
* appendStringInfoChar |
||||
* Append a single byte to str. |
||||
* Like appendStringInfo(str, "%c", ch) but much faster. |
||||
*/ |
||||
void |
||||
appendStringInfoChar(StringInfo str, char ch) |
||||
{ |
||||
Assert(str != NULL); |
||||
if (buflen == 0) |
||||
strcpy(buffer, "<>"); |
||||
|
||||
/*
|
||||
* do we have enough space to append the new string? (don't forget to |
||||
* count the null string terminating char!) If no, then reallocate |
||||
* some more. |
||||
*/ |
||||
needed = str->len + buflen + 1; |
||||
if (needed > str->maxlen) |
||||
{ |
||||
|
||||
/*
|
||||
* how much more space to allocate ? Let's say double the current |
||||
* space... However we must check if this is enough! |
||||
*/ |
||||
newlen = 2 * str->maxlen; |
||||
while (needed > newlen) |
||||
newlen = 2 * newlen; |
||||
|
||||
/*
|
||||
* allocate enough space. |
||||
*/ |
||||
s = palloc(newlen); |
||||
if (s == NULL) |
||||
{ |
||||
elog(ERROR, |
||||
"appendStringInfo: Out of memory (%d bytes requested)", newlen); |
||||
} |
||||
/*
|
||||
* transfer the data. strcpy() would work, but is probably a tad |
||||
* slower than memcpy(), and since we know the string length... |
||||
*/ |
||||
memcpy(s, str->data, str->len + 1); |
||||
pfree(str->data); |
||||
str->maxlen = newlen; |
||||
str->data = s; |
||||
} |
||||
/* Make more room if needed */ |
||||
enlargeStringInfo(str, 1); |
||||
|
||||
/*
|
||||
* OK, we have enough space now, append 'buffer' at the end of the |
||||
* string & update the string length. NOTE: strcat() would work, |
||||
* but is certainly slower than just memcpy'ing the data to the right |
||||
* place. |
||||
/* OK, append the character */ |
||||
str->data[str->len] = ch; |
||||
str->len++; |
||||
str->data[str->len] = '\0'; |
||||
} |
||||
|
||||
/*
|
||||
* appendBinaryStringInfo |
||||
* |
||||
* Append arbitrary binary data to a StringInfo, allocating more space |
||||
* if necessary. |
||||
*/ |
||||
void |
||||
appendBinaryStringInfo(StringInfo str, const char *data, int datalen) |
||||
{ |
||||
Assert(str != NULL); |
||||
|
||||
/* Make more room if needed */ |
||||
enlargeStringInfo(str, datalen); |
||||
|
||||
/* OK, append the data */ |
||||
memcpy(str->data + str->len, data, datalen); |
||||
str->len += datalen; |
||||
|
||||
/* Keep a trailing null in place, even though it's probably useless
|
||||
* for binary data... |
||||
*/ |
||||
memcpy(str->data + str->len, buffer, buflen + 1); |
||||
str->len += buflen; |
||||
str->data[str->len] = '\0'; |
||||
} |
||||
|
||||
@ -1,220 +0,0 @@ |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <netinet/in.h> |
||||
|
||||
#include "postgres.h" |
||||
#include "miscadmin.h" |
||||
#include "libpq/pqcomm.h" |
||||
#include "libpq/libpq.h" |
||||
|
||||
|
||||
/*
|
||||
* The backend supports the old little endian byte order and the current |
||||
* network byte order. |
||||
*/ |
||||
|
||||
#ifndef FRONTEND |
||||
|
||||
#include "libpq/libpq-be.h" |
||||
|
||||
#ifdef HAVE_ENDIAN_H |
||||
#include <endian.h> |
||||
#endif |
||||
|
||||
#ifndef BYTE_ORDER |
||||
#error BYTE_ORDER must be defined as LITTLE_ENDIAN, BIG_ENDIAN or PDP_ENDIAN |
||||
#endif |
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN |
||||
|
||||
#define ntoh_s(n) n |
||||
#define ntoh_l(n) n |
||||
#define hton_s(n) n |
||||
#define hton_l(n) n |
||||
|
||||
#else |
||||
#if BYTE_ORDER == BIG_ENDIAN |
||||
|
||||
/*
|
||||
#define ntoh_s(n) (uint16)(((u_char *)&n)[1] << 8 \ |
||||
| ((u_char *)&n)[0]) |
||||
#define ntoh_l(n) (uint32)(((u_char *)&n)[3] << 24 \ |
||||
| ((u_char *)&n)[2] << 16 \
|
||||
| ((u_char *)&n)[1] << 8 \
|
||||
| ((u_char *)&n)[0]) |
||||
*/ |
||||
#define ntoh_s(n) (uint16)((((uint16)n & 0x00ff) << 8) | \ |
||||
(((uint16)n & 0xff00) >> 8)) |
||||
#define ntoh_l(n) (uint32)((((uint32)n & 0x000000ff) << 24) | \ |
||||
(((uint32)n & 0x0000ff00) << 8) | \
|
||||
(((uint32)n & 0x00ff0000) >> 8) | \
|
||||
(((uint32)n & 0xff000000) >> 24)) |
||||
#define hton_s(n) (ntoh_s(n)) |
||||
#define hton_l(n) (ntoh_l(n)) |
||||
|
||||
#else |
||||
#if BYTE_ORDER == PDP_ENDIAN |
||||
|
||||
#error PDP_ENDIAN macros not written yet |
||||
|
||||
#else |
||||
|
||||
#error BYTE_ORDER not defined as anything understood |
||||
|
||||
#endif |
||||
#endif |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
|
||||
/* --------------------------------------------------------------------- */ |
||||
int |
||||
pqPutShort(int integer) |
||||
{ |
||||
uint16 n; |
||||
|
||||
#ifdef FRONTEND |
||||
n = htons((uint16) integer); |
||||
#else |
||||
n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_s(integer) : htons((uint16) integer)); |
||||
#endif |
||||
|
||||
return pqPutNBytes((char *)&n, 2); /* 0 on success, EOF otherwise */ |
||||
} |
||||
|
||||
/* --------------------------------------------------------------------- */ |
||||
int |
||||
pqPutLong(int integer) |
||||
{ |
||||
uint32 n; |
||||
|
||||
#ifdef FRONTEND |
||||
n = htonl((uint32) integer); |
||||
#else |
||||
n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_l(integer) : htonl((uint32) integer)); |
||||
#endif |
||||
|
||||
return pqPutNBytes((char *)&n, 4); |
||||
} |
||||
|
||||
/* --------------------------------------------------------------------- */ |
||||
int |
||||
pqGetShort(int *result) |
||||
{ |
||||
uint16 n; |
||||
|
||||
if (pqGetNBytes((char *)&n, 2) != 0) |
||||
return EOF; |
||||
|
||||
#ifdef FRONTEND |
||||
*result = (int) ntohs(n); |
||||
#else |
||||
*result = (int) ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? ntoh_s(n) : ntohs(n)); |
||||
#endif |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* --------------------------------------------------------------------- */ |
||||
int |
||||
pqGetLong(int *result) |
||||
{ |
||||
uint32 n; |
||||
|
||||
if (pqGetNBytes((char *)&n, 4) != 0) |
||||
return EOF; |
||||
|
||||
#ifdef FRONTEND |
||||
*result = (int) ntohl(n); |
||||
#else |
||||
*result = (int) ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? ntoh_l(n) : ntohl(n)); |
||||
#endif |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* --------------------------------------------------------------------- */ |
||||
/* pqGetNBytes: Read a chunk of exactly len bytes into buffer s.
|
||||
* Return 0 if ok, EOF if trouble. |
||||
*/ |
||||
int |
||||
pqGetNBytes(char *s, size_t len) |
||||
{ |
||||
size_t amount; |
||||
|
||||
while (len > 0) |
||||
{ |
||||
while (PqRecvPointer >= PqRecvLength) |
||||
{ |
||||
if (pq_recvbuf()) /* If nothing in buffer, then recv some */ |
||||
return EOF; /* Failed to recv data */ |
||||
} |
||||
amount = PqRecvLength - PqRecvPointer; |
||||
if (amount > len) |
||||
amount = len; |
||||
memcpy(s, PqRecvBuffer + PqRecvPointer, amount); |
||||
PqRecvPointer += amount; |
||||
s += amount; |
||||
len -= amount; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/* --------------------------------------------------------------------- */ |
||||
int |
||||
pqPutNBytes(const char *s, size_t len) |
||||
{ |
||||
size_t amount; |
||||
|
||||
while (len > 0) |
||||
{ |
||||
if (PqSendPointer >= PQ_BUFFER_SIZE) |
||||
if (pq_flush()) /* If buffer is full, then flush it out */ |
||||
return EOF; |
||||
amount = PQ_BUFFER_SIZE - PqSendPointer; |
||||
if (amount > len) |
||||
amount = len; |
||||
memcpy(PqSendBuffer + PqSendPointer, s, amount); |
||||
PqSendPointer += amount; |
||||
s += amount; |
||||
len -= amount; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/* --------------------------------------------------------------------- */ |
||||
int |
||||
pqGetString(char *s, size_t len) |
||||
{ |
||||
int c; |
||||
|
||||
/*
|
||||
* Keep on reading until we get the terminating '\0', |
||||
* discarding any bytes we don't have room for. |
||||
*/ |
||||
|
||||
while ((c = pq_getchar()) != EOF && c != '\0') |
||||
if (len > 1) |
||||
{ |
||||
*s++ = c; |
||||
len--; |
||||
} |
||||
|
||||
*s = '\0'; |
||||
|
||||
if (c == EOF) |
||||
return EOF; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* --------------------------------------------------------------------- */ |
||||
int |
||||
pqPutString(const char *s) |
||||
{ |
||||
return pqPutNBytes(s,strlen(s)+1); |
||||
} |
||||
@ -0,0 +1,293 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* 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 |
||||
* MULTIBYTE conversion, while text is converted by MULTIBYTE rules. |
||||
* |
||||
* Incoming messages are read directly off the wire, as it were, but there |
||||
* are still data-conversion tasks to be performed. |
||||
* |
||||
* Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* $Id: pqformat.c,v 1.1 1999/04/25 03:19:22 tgl Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
/*
|
||||
* INTERFACE ROUTINES |
||||
* Message 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_sendbytes - append raw data to a StringInfo buffer |
||||
* pq_sendtext - append a text string (with MULTIBYTE conversion) |
||||
* pq_sendstring - append a null-terminated text string (with MULTIBYTE) |
||||
* 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 |
||||
* MULTIBYTE conversion may not occur. |
||||
* |
||||
* Message input: |
||||
* pq_getint - get an integer from connection |
||||
* pq_getstr - get a null terminated string from connection |
||||
* pq_getnchar - get n characters from connection, and null-terminate |
||||
* pq_getstr and pq_getnchar perform MULTIBYTE conversion on the collected |
||||
* string. Use the raw pqcomm.c routines pq_getstring and pq_getbytes |
||||
* to fetch data without conversion. |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "libpq/pqformat.h" |
||||
#include "libpq/libpq.h" |
||||
#ifdef MULTIBYTE |
||||
#include "mb/pg_wchar.h" |
||||
#endif |
||||
#ifdef HAVE_ENDIAN_H |
||||
#include <endian.h> |
||||
#endif |
||||
|
||||
#ifndef BYTE_ORDER |
||||
#error BYTE_ORDER must be defined as LITTLE_ENDIAN, BIG_ENDIAN or PDP_ENDIAN |
||||
#endif |
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN |
||||
|
||||
#define ntoh_s(n) n |
||||
#define ntoh_l(n) n |
||||
#define hton_s(n) n |
||||
#define hton_l(n) n |
||||
|
||||
#else |
||||
#if BYTE_ORDER == BIG_ENDIAN |
||||
|
||||
#define ntoh_s(n) (uint16)((((uint16)n & 0x00ff) << 8) | \ |
||||
(((uint16)n & 0xff00) >> 8)) |
||||
#define ntoh_l(n) (uint32)((((uint32)n & 0x000000ff) << 24) | \ |
||||
(((uint32)n & 0x0000ff00) << 8) | \
|
||||
(((uint32)n & 0x00ff0000) >> 8) | \
|
||||
(((uint32)n & 0xff000000) >> 24)) |
||||
#define hton_s(n) (ntoh_s(n)) |
||||
#define hton_l(n) (ntoh_l(n)) |
||||
|
||||
#else |
||||
#if BYTE_ORDER == PDP_ENDIAN |
||||
|
||||
#error PDP_ENDIAN macros not written yet |
||||
|
||||
#else |
||||
|
||||
#error BYTE_ORDER not defined as anything understood |
||||
|
||||
#endif |
||||
#endif |
||||
#endif |
||||
|
||||
|
||||
/* --------------------------------
|
||||
* pq_sendbyte - append a raw byte to a StringInfo buffer |
||||
* -------------------------------- |
||||
*/ |
||||
void |
||||
pq_sendbyte(StringInfo buf, int byt) |
||||
{ |
||||
appendStringInfoChar(buf, byt); |
||||
} |
||||
|
||||
/* --------------------------------
|
||||
* pq_sendbytes - append raw data to a StringInfo buffer |
||||
* -------------------------------- |
||||
*/ |
||||
void |
||||
pq_sendbytes(StringInfo buf, const char *data, int datalen) |
||||
{ |
||||
appendBinaryStringInfo(buf, data, datalen); |
||||
} |
||||
|
||||
/* --------------------------------
|
||||
* pq_sendtext - append a text string (with MULTIBYTE conversion) |
||||
* |
||||
* NB: passed text string must be null-terminated, even though we expect |
||||
* the caller to hand us the length (this is just because the caller |
||||
* usually knows the length anyway). In this routine, the data sent to |
||||
* the frontend is NOT null-terminated. |
||||
* -------------------------------- |
||||
*/ |
||||
void |
||||
pq_sendtext(StringInfo buf, const char *str, int slen) |
||||
{ |
||||
#ifdef MULTIBYTE |
||||
str = (const char *) pg_server_to_client(str, slen); |
||||
#endif |
||||
appendBinaryStringInfo(buf, str, slen); |
||||
} |
||||
|
||||
/* --------------------------------
|
||||
* pq_sendstring - append a null-terminated text string (with MULTIBYTE) |
||||
* |
||||
* NB: passed text string must be null-terminated, even though we expect |
||||
* the caller to hand us the length (this is just because the caller |
||||
* usually knows the length anyway). |
||||
* -------------------------------- |
||||
*/ |
||||
void |
||||
pq_sendstring(StringInfo buf, const char *str, int slen) |
||||
{ |
||||
#ifdef MULTIBYTE |
||||
str = (const char *) pg_server_to_client(str, slen); |
||||
#endif |
||||
appendBinaryStringInfo(buf, str, slen+1); |
||||
} |
||||
|
||||
/* --------------------------------
|
||||
* pq_sendint - append a binary integer to a StringInfo buffer |
||||
* -------------------------------- |
||||
*/ |
||||
void |
||||
pq_sendint(StringInfo buf, int i, int b) |
||||
{ |
||||
unsigned char n8; |
||||
uint16 n16; |
||||
uint32 n32; |
||||
|
||||
switch (b) |
||||
{ |
||||
case 1: |
||||
n8 = (unsigned char) i; |
||||
appendBinaryStringInfo(buf, (char *) &n8, 1); |
||||
break; |
||||
case 2: |
||||
n16 = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_s(i) : htons((uint16) i)); |
||||
appendBinaryStringInfo(buf, (char *) &n16, 2); |
||||
break; |
||||
case 4: |
||||
n32 = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_l(i) : htonl((uint32) i)); |
||||
appendBinaryStringInfo(buf, (char *) &n32, 4); |
||||
break; |
||||
default: |
||||
elog(ERROR, "pq_sendint: unsupported size %d", b); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* --------------------------------
|
||||
* 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) |
||||
{ |
||||
if (pq_putmessage('\0', buf->data, buf->len)) |
||||
{ |
||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH, |
||||
"FATAL: pq_endmessage failed: errno=%d\n", errno); |
||||
fputs(PQerrormsg, stderr); |
||||
pqdebug("%s", PQerrormsg); |
||||
} |
||||
pfree(buf->data); |
||||
buf->data = NULL; |
||||
} |
||||
|
||||
/* --------------------------------
|
||||
* pq_getint - get an integer from connection |
||||
* |
||||
* returns 0 if OK, EOF if trouble |
||||
* -------------------------------- |
||||
*/ |
||||
int |
||||
pq_getint(int *result, int b) |
||||
{ |
||||
int status; |
||||
unsigned char n8; |
||||
uint16 n16; |
||||
uint32 n32; |
||||
|
||||
switch (b) |
||||
{ |
||||
case 1: |
||||
status = pq_getbytes((char *) &n8, 1); |
||||
*result = (int) n8; |
||||
break; |
||||
case 2: |
||||
status = pq_getbytes((char *) &n16, 2); |
||||
*result = (int) ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? |
||||
ntoh_s(n16) : ntohs(n16)); |
||||
break; |
||||
case 4: |
||||
status = pq_getbytes((char *) &n32, 4); |
||||
*result = (int) ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? |
||||
ntoh_l(n32) : ntohl(n32)); |
||||
break; |
||||
default: |
||||
/* if we elog(ERROR) here, we will lose sync with the frontend,
|
||||
* so just complain to postmaster log instead... |
||||
*/ |
||||
fprintf(stderr, "pq_getint: unsupported size %d\n", b); |
||||
status = EOF; |
||||
*result = 0; |
||||
break; |
||||
} |
||||
return status; |
||||
} |
||||
|
||||
/* --------------------------------
|
||||
* pq_getstr - get a null terminated string from connection |
||||
* |
||||
* FIXME: we ought to use an expansible StringInfo buffer, |
||||
* rather than dropping data if the message is too long. |
||||
* |
||||
* returns 0 if OK, EOF if trouble |
||||
* -------------------------------- |
||||
*/ |
||||
int |
||||
pq_getstr(char *s, int maxlen) |
||||
{ |
||||
int c; |
||||
#ifdef MULTIBYTE |
||||
char *p; |
||||
#endif |
||||
|
||||
c = pq_getstring(s, maxlen); |
||||
|
||||
#ifdef MULTIBYTE |
||||
p = (char*) pg_client_to_server((unsigned char *) s, maxlen); |
||||
if (s != p) /* actual conversion has been done? */ |
||||
strcpy(s, p); |
||||
#endif |
||||
|
||||
return c; |
||||
} |
||||
|
||||
/* --------------------------------
|
||||
* pq_getnchar - get n characters from connection, and null-terminate |
||||
* |
||||
* returns 0 if OK, EOF if trouble |
||||
* -------------------------------- |
||||
*/ |
||||
int |
||||
pq_getnchar(char *s, int len) |
||||
{ |
||||
int c; |
||||
#ifdef MULTIBYTE |
||||
char *p; |
||||
#endif |
||||
|
||||
c = pq_getbytes(s, len); |
||||
s[len] = '\0'; |
||||
|
||||
#ifdef MULTIBYTE |
||||
p = (char*) pg_client_to_server((unsigned char *) s, len+1); |
||||
if (s != p) /* actual conversion has been done? */ |
||||
strcpy(s, p); |
||||
#endif |
||||
|
||||
return c; |
||||
} |
||||
@ -0,0 +1,31 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pqformat.h |
||||
* Definitions for formatting and parsing frontend/backend messages |
||||
* |
||||
* Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* $Id: pqformat.h,v 1.1 1999/04/25 03:19:14 tgl Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef PQFORMAT_H |
||||
#define PQFORMAT_H |
||||
|
||||
#include "postgres.h" |
||||
#include "lib/stringinfo.h" |
||||
|
||||
#define pq_beginmessage(buf) initStringInfo(buf) |
||||
|
||||
extern void pq_sendbyte(StringInfo buf, int byt); |
||||
extern void pq_sendbytes(StringInfo buf, const char *data, int datalen); |
||||
extern void pq_sendtext(StringInfo buf, const char *str, int slen); |
||||
extern void pq_sendstring(StringInfo buf, const char *str, int slen); |
||||
extern void pq_sendint(StringInfo buf, int i, int b); |
||||
extern void pq_endmessage(StringInfo buf); |
||||
|
||||
extern int pq_getint(int *result, int b); |
||||
extern int pq_getstr(char *s, int maxlen); |
||||
extern int pq_getnchar(char *s, int len); |
||||
|
||||
#endif /* PQFORMAT_H */ |
||||
Loading…
Reference in new issue