Revise backend libpq interfaces so that messages to the frontend
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.
This commit is contained in:
parent
fc08814e00
commit
95cc41b81d
|
@ -8,23 +8,25 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.42 1999/02/13 23:14:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.43 1999/04/25 03:19:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <postgres.h>
|
||||
|
||||
#include <fmgr.h>
|
||||
#include <access/heapam.h>
|
||||
#include <access/printtup.h>
|
||||
#include <catalog/pg_type.h>
|
||||
#include <libpq/libpq.h>
|
||||
#include <utils/syscache.h>
|
||||
#include "postgres.h"
|
||||
|
||||
#include "fmgr.h"
|
||||
#include "access/heapam.h"
|
||||
#include "access/printtup.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
#include <mb/pg_wchar.h>
|
||||
#include "mb/pg_wchar.h"
|
||||
#endif
|
||||
|
||||
static void printtup_setup(DestReceiver* self, TupleDesc typeinfo);
|
||||
|
@ -152,6 +154,7 @@ static void
|
|||
printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
||||
{
|
||||
DR_printtup *myState = (DR_printtup*) self;
|
||||
StringInfoData buf;
|
||||
int i,
|
||||
j,
|
||||
k,
|
||||
|
@ -172,7 +175,8 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
* tell the frontend to expect new tuple data (in ASCII style)
|
||||
* ----------------
|
||||
*/
|
||||
pq_putnchar("D", 1);
|
||||
pq_beginmessage(&buf);
|
||||
pq_sendbyte(&buf, 'D');
|
||||
|
||||
/* ----------------
|
||||
* send a bitmap of which attributes are not null
|
||||
|
@ -187,13 +191,13 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
k >>= 1;
|
||||
if (k == 0) /* end of byte? */
|
||||
{
|
||||
pq_putint(j, 1);
|
||||
pq_sendint(&buf, j, 1);
|
||||
j = 0;
|
||||
k = 1 << 7;
|
||||
}
|
||||
}
|
||||
if (k != (1 << 7)) /* flush last partial byte */
|
||||
pq_putint(j, 1);
|
||||
pq_sendint(&buf, j, 1);
|
||||
|
||||
/* ----------------
|
||||
* send the attributes of this tuple
|
||||
|
@ -212,12 +216,12 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
#ifdef MULTIBYTE
|
||||
p = pg_server_to_client(outputstr, strlen(outputstr));
|
||||
outputlen = strlen(p);
|
||||
pq_putint(outputlen + VARHDRSZ, VARHDRSZ);
|
||||
pq_putnchar(p, outputlen);
|
||||
pq_sendint(&buf, outputlen + VARHDRSZ, VARHDRSZ);
|
||||
pq_sendbytes(&buf, p, outputlen);
|
||||
#else
|
||||
outputlen = strlen(outputstr);
|
||||
pq_putint(outputlen + VARHDRSZ, VARHDRSZ);
|
||||
pq_putnchar(outputstr, outputlen);
|
||||
pq_sendint(&buf, outputlen + VARHDRSZ, VARHDRSZ);
|
||||
pq_sendbytes(&buf, outputstr, outputlen);
|
||||
#endif
|
||||
pfree(outputstr);
|
||||
}
|
||||
|
@ -225,10 +229,12 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
{
|
||||
outputstr = "<unprintable>";
|
||||
outputlen = strlen(outputstr);
|
||||
pq_putint(outputlen + VARHDRSZ, VARHDRSZ);
|
||||
pq_putnchar(outputstr, outputlen);
|
||||
pq_sendint(&buf, outputlen + VARHDRSZ, VARHDRSZ);
|
||||
pq_sendbytes(&buf, outputstr, outputlen);
|
||||
}
|
||||
}
|
||||
|
||||
pq_endmessage(&buf);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
@ -325,6 +331,7 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
void
|
||||
printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
||||
{
|
||||
StringInfoData buf;
|
||||
int i,
|
||||
j,
|
||||
k;
|
||||
|
@ -335,7 +342,8 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
* tell the frontend to expect new tuple data (in binary style)
|
||||
* ----------------
|
||||
*/
|
||||
pq_putnchar("B", 1);
|
||||
pq_beginmessage(&buf);
|
||||
pq_sendbyte(&buf, 'B');
|
||||
|
||||
/* ----------------
|
||||
* send a bitmap of which attributes are not null
|
||||
|
@ -350,13 +358,13 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
k >>= 1;
|
||||
if (k == 0) /* end of byte? */
|
||||
{
|
||||
pq_putint(j, 1);
|
||||
pq_sendint(&buf, j, 1);
|
||||
j = 0;
|
||||
k = 1 << 7;
|
||||
}
|
||||
}
|
||||
if (k != (1 << 7)) /* flush last partial byte */
|
||||
pq_putint(j, 1);
|
||||
pq_sendint(&buf, j, 1);
|
||||
|
||||
/* ----------------
|
||||
* send the attributes of this tuple
|
||||
|
@ -378,8 +386,8 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
/* variable length, assume a varlena structure */
|
||||
len = VARSIZE(attr) - VARHDRSZ;
|
||||
|
||||
pq_putint(len, VARHDRSZ);
|
||||
pq_putnchar(VARDATA(attr), len);
|
||||
pq_sendint(&buf, len, VARHDRSZ);
|
||||
pq_sendbytes(&buf, VARDATA(attr), len);
|
||||
|
||||
#ifdef IPORTAL_DEBUG
|
||||
{
|
||||
|
@ -399,20 +407,20 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
int16 i16;
|
||||
int32 i32;
|
||||
|
||||
pq_putint(len, sizeof(int32));
|
||||
pq_sendint(&buf, len, sizeof(int32));
|
||||
switch (len)
|
||||
{
|
||||
case sizeof(int8):
|
||||
i8 = DatumGetChar(attr);
|
||||
pq_putnchar((char *) &i8, len);
|
||||
pq_sendbytes(&buf, (char *) &i8, len);
|
||||
break;
|
||||
case sizeof(int16):
|
||||
i16 = DatumGetInt16(attr);
|
||||
pq_putnchar((char *) &i16, len);
|
||||
pq_sendbytes(&buf, (char *) &i16, len);
|
||||
break;
|
||||
case sizeof(int32):
|
||||
i32 = DatumGetInt32(attr);
|
||||
pq_putnchar((char *) &i32, len);
|
||||
pq_sendbytes(&buf, (char *) &i32, len);
|
||||
break;
|
||||
}
|
||||
#ifdef IPORTAL_DEBUG
|
||||
|
@ -421,8 +429,8 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
}
|
||||
else
|
||||
{
|
||||
pq_putint(len, sizeof(int32));
|
||||
pq_putnchar(DatumGetPointer(attr), len);
|
||||
pq_sendint(&buf, len, sizeof(int32));
|
||||
pq_sendbytes(&buf, DatumGetPointer(attr), len);
|
||||
#ifdef IPORTAL_DEBUG
|
||||
fprintf(stderr, "byref length %d data %x\n", len,
|
||||
DatumGetPointer(attr));
|
||||
|
@ -431,4 +439,6 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pq_endmessage(&buf);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.44 1999/02/13 23:15:00 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.45 1999/04/25 03:19:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -94,6 +94,7 @@
|
|||
#include "fmgr.h"
|
||||
#include "lib/dllist.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "miscadmin.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "storage/lmgr.h"
|
||||
|
@ -798,9 +799,12 @@ NotifyMyFrontEnd(char *relname, int32 listenerPID)
|
|||
{
|
||||
if (whereToSendOutput == Remote)
|
||||
{
|
||||
pq_putnchar("A", 1);
|
||||
pq_putint(listenerPID, sizeof(int32));
|
||||
pq_putstr(relname);
|
||||
StringInfoData buf;
|
||||
pq_beginmessage(&buf);
|
||||
pq_sendbyte(&buf, 'A');
|
||||
pq_sendint(&buf, listenerPID, sizeof(int32));
|
||||
pq_sendstring(&buf, relname, strlen(relname));
|
||||
pq_endmessage(&buf);
|
||||
/* NOTE: we do not do pq_flush() here. For a self-notify, it will
|
||||
* happen at the end of the transaction, and for incoming notifies
|
||||
* ProcessIncomingNotify will do it after finding all the notifies.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.73 1999/02/13 23:15:04 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.74 1999/04/25 03:19:09 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -89,12 +89,14 @@ inline void CopyDonePeek(FILE *fp, int c, int pickup);
|
|||
*
|
||||
* CopySendString does the same for null-terminated strings
|
||||
* CopySendChar does the same for single characters
|
||||
*
|
||||
* NB: no data conversion is applied by these functions
|
||||
*/
|
||||
inline void CopySendData(void *databuf, int datasize, FILE *fp) {
|
||||
if (!fp)
|
||||
pq_putnchar(databuf, datasize);
|
||||
pq_putbytes((char*) databuf, datasize);
|
||||
else
|
||||
fwrite(databuf, datasize, 1, fp);
|
||||
fwrite(databuf, datasize, 1, fp);
|
||||
}
|
||||
|
||||
inline void CopySendString(char *str, FILE *fp) {
|
||||
|
@ -112,17 +114,24 @@ inline void CopySendChar(char c, FILE *fp) {
|
|||
*
|
||||
* CopyGetChar does the same for single characters
|
||||
* CopyGetEof checks if it's EOF on the input
|
||||
*
|
||||
* NB: no data conversion is applied by these functions
|
||||
*/
|
||||
inline void CopyGetData(void *databuf, int datasize, FILE *fp) {
|
||||
if (!fp)
|
||||
pq_getnchar(databuf, 0, datasize);
|
||||
pq_getbytes((char*) databuf, datasize);
|
||||
else
|
||||
fread(databuf, datasize, 1, fp);
|
||||
}
|
||||
|
||||
inline int CopyGetChar(FILE *fp) {
|
||||
if (!fp)
|
||||
return pq_getchar();
|
||||
{
|
||||
unsigned char ch;
|
||||
if (pq_getbytes((char*) &ch, 1))
|
||||
return EOF;
|
||||
return ch;
|
||||
}
|
||||
else
|
||||
return getc(fp);
|
||||
}
|
||||
|
@ -143,7 +152,7 @@ inline int CopyGetEof(FILE *fp) {
|
|||
*/
|
||||
inline int CopyPeekChar(FILE *fp) {
|
||||
if (!fp)
|
||||
return pq_peekchar();
|
||||
return pq_peekbyte();
|
||||
else
|
||||
return getc(fp);
|
||||
}
|
||||
|
@ -153,7 +162,7 @@ inline void CopyDonePeek(FILE *fp, int c, int pickup) {
|
|||
if (pickup) {
|
||||
/* We want to pick it up - just receive again into dummy buffer */
|
||||
char c;
|
||||
pq_getnchar(&c, 0, 1);
|
||||
pq_getbytes(&c, 1);
|
||||
}
|
||||
/* If we didn't want to pick it up, just leave it where it sits */
|
||||
}
|
||||
|
@ -216,7 +225,10 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
|||
* descriptor leak. bjm 1998/08/29
|
||||
*/
|
||||
if (file_opened)
|
||||
{
|
||||
FreeFile(fp);
|
||||
file_opened = false;
|
||||
}
|
||||
|
||||
rel = heap_openr(relname);
|
||||
if (rel == NULL)
|
||||
|
@ -271,6 +283,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
|||
if (IsUnderPostmaster)
|
||||
{
|
||||
SendCopyBegin();
|
||||
pq_startcopyout();
|
||||
fp = NULL;
|
||||
}
|
||||
else
|
||||
|
@ -301,9 +314,12 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
|||
FreeFile(fp);
|
||||
file_opened = false;
|
||||
}
|
||||
else if (!from && !binary)
|
||||
else if (!from)
|
||||
{
|
||||
CopySendData("\\.\n",3,fp);
|
||||
if (!binary)
|
||||
CopySendData("\\.\n",3,fp);
|
||||
if (IsUnderPostmaster)
|
||||
pq_endcopyout(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* Copyright (c) 1994-5, Regents of the University of California
|
||||
*
|
||||
* $Id: explain.c,v 1.34 1999/04/23 21:23:48 momjian Exp $
|
||||
* $Id: explain.c,v 1.35 1999/04/25 03:19:09 tgl Exp $
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
@ -350,18 +350,13 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
|||
static char *
|
||||
Explain_PlanToString(Plan *plan, ExplainState *es)
|
||||
{
|
||||
StringInfo str;
|
||||
char *s;
|
||||
StringInfoData str;
|
||||
|
||||
if (plan == NULL)
|
||||
return "";
|
||||
Assert(plan != NULL);
|
||||
str = makeStringInfo();
|
||||
explain_outNode(str, plan, 0, es);
|
||||
s = str->data;
|
||||
pfree(str);
|
||||
|
||||
return s;
|
||||
/* see stringinfo.h for an explanation of this maneuver */
|
||||
initStringInfo(&str);
|
||||
if (plan != NULL)
|
||||
explain_outNode(&str, plan, 0, es);
|
||||
return str.data;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
*
|
||||
* append to the current 'StringInfo' a new string.
|
||||
* If there is not enough space in the current 'data', then reallocate
|
||||
* some more...
|
||||
*
|
||||
* NOTE: if we reallocate space, we pfree the old one!
|
||||
* initStringInfo
|
||||
*
|
||||
* Initialize a StringInfoData struct (with previously undefined contents)
|
||||
* to describe an empty string.
|
||||
*/
|
||||
void
|
||||
appendStringInfo(StringInfo str, const char *fmt,...)
|
||||
initStringInfo(StringInfo str)
|
||||
{
|
||||
int buflen,
|
||||
newlen,
|
||||
needed;
|
||||
char *s,
|
||||
buffer[512];
|
||||
int size = 256; /* initial default buffer size */
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
buflen = vsnprintf(buffer, 512, fmt, args);
|
||||
va_end(args);
|
||||
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
|
||||
*
|
||||
* 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, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buffer[1024];
|
||||
int buflen;
|
||||
|
||||
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)
|
||||
{
|
||||
va_start(args, fmt);
|
||||
buflen = vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
/* Make more room if needed */
|
||||
enlargeStringInfo(str, buflen);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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);
|
||||
|
||||
/* Make more room if needed */
|
||||
enlargeStringInfo(str, 1);
|
||||
|
||||
/* 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...
|
||||
*/
|
||||
str->data[str->len] = '\0';
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: portal.c,v 1.20 1999/02/13 23:15:45 momjian Exp $
|
||||
* $Id: portal.c,v 1.21 1999/04/25 03:19:20 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -37,9 +37,6 @@
|
|||
* PQgetvalue - Return an attribute (field) value
|
||||
* PQgetlength - Return an attribute (field) length
|
||||
* PQclear - free storage claimed by named portal
|
||||
* PQnotifies - Return a list of relations on which notification
|
||||
* has occurred.
|
||||
* PQremoveNotify - Remove this notification from the list.
|
||||
*
|
||||
* NOTES
|
||||
* These functions may be used by both frontend routines which
|
||||
|
@ -647,85 +644,3 @@ PQclear(char *pname)
|
|||
return;
|
||||
pbuf_close(pname);
|
||||
}
|
||||
|
||||
/*
|
||||
* async notification.
|
||||
* This is going away with pending rewrite of comm. code...
|
||||
*/
|
||||
/* static SLList pqNotifyList;*/
|
||||
static Dllist *pqNotifyList = NULL;
|
||||
|
||||
/* remove invalid notifies before returning */
|
||||
void
|
||||
PQcleanNotify()
|
||||
{
|
||||
Dlelem *e,
|
||||
*next;
|
||||
PQNotifyList *p;
|
||||
|
||||
e = DLGetHead(pqNotifyList);
|
||||
|
||||
while (e)
|
||||
{
|
||||
next = DLGetSucc(e);
|
||||
p = (PQNotifyList *) DLE_VAL(e);
|
||||
if (p->valid == 0)
|
||||
{
|
||||
DLRemove(e);
|
||||
DLFreeElem(e);
|
||||
pfree(p);
|
||||
}
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PQnotifies_init()
|
||||
{
|
||||
Dlelem *e;
|
||||
PQNotifyList *p;
|
||||
|
||||
if (pqNotifyList == NULL)
|
||||
pqNotifyList = DLNewList();
|
||||
else
|
||||
{
|
||||
/* clean all notifies */
|
||||
for (e = DLGetHead(pqNotifyList); e != NULL; e = DLGetSucc(e))
|
||||
{
|
||||
p = (PQNotifyList *) DLE_VAL(e);
|
||||
p->valid = 0;
|
||||
}
|
||||
PQcleanNotify();
|
||||
}
|
||||
}
|
||||
|
||||
PQNotifyList *
|
||||
PQnotifies()
|
||||
{
|
||||
Dlelem *e;
|
||||
|
||||
PQcleanNotify();
|
||||
e = DLGetHead(pqNotifyList);
|
||||
return e ? (PQNotifyList *) DLE_VAL(e) : NULL;
|
||||
}
|
||||
|
||||
void
|
||||
PQremoveNotify(PQNotifyList *nPtr)
|
||||
{
|
||||
nPtr->valid = 0; /* remove later */
|
||||
}
|
||||
|
||||
void
|
||||
PQappendNotify(char *relname, int pid)
|
||||
{
|
||||
PQNotifyList *p;
|
||||
|
||||
if (pqNotifyList == NULL)
|
||||
pqNotifyList = DLNewList();
|
||||
|
||||
p = (PQNotifyList *) pbuf_alloc(sizeof(PQNotifyList));
|
||||
StrNCpy(p->relname, relname, NAMEDATALEN);
|
||||
p->be_pid = pid;
|
||||
p->valid = 1;
|
||||
DLAddTail(pqNotifyList, DLNewElem(p));
|
||||
}
|
||||
|
|
|
@ -3,43 +3,60 @@
|
|||
* pqcomm.c
|
||||
* Communication functions between the Frontend and the Backend
|
||||
*
|
||||
* These routines handle the low-level details of communication between
|
||||
* frontend and backend. They just shove data across the communication
|
||||
* channel, and are ignorant of the semantics of the data --- or would be,
|
||||
* except for major brain damage in the design of the COPY OUT protocol.
|
||||
* Unfortunately, COPY OUT is designed to commandeer the communication
|
||||
* channel (it just transfers data without wrapping it into messages).
|
||||
* No other messages can be sent while COPY OUT is in progress; and if the
|
||||
* copy is aborted by an elog(ERROR), we need to close out the copy so that
|
||||
* the frontend gets back into sync. Therefore, these routines have to be
|
||||
* aware of COPY OUT state.
|
||||
*
|
||||
* NOTE: generally, it's a bad idea to emit outgoing messages directly with
|
||||
* pq_putbytes(), especially if the message would require multiple calls
|
||||
* to send. Instead, use the routines in pqformat.c to construct the message
|
||||
* in a buffer and then emit it in one call to pq_putmessage. This helps
|
||||
* ensure that the channel will not be clogged by an incomplete message
|
||||
* if execution is aborted by elog(ERROR) partway through the message.
|
||||
* The only non-libpq code that should call pq_putbytes directly is COPY OUT.
|
||||
*
|
||||
* At one time, libpq was shared between frontend and backend, but now
|
||||
* the backend's "backend/libpq" is quite separate from "interfaces/libpq".
|
||||
* All that remains is similarities of names to trap the unwary...
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pqcomm.c,v 1.67 1999/02/18 01:13:26 tgl Exp $
|
||||
* $Id: pqcomm.c,v 1.68 1999/04/25 03:19:21 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
|
||||
/*------------------------
|
||||
* INTERFACE ROUTINES
|
||||
* pq_init - initialize libpq
|
||||
* pq_getport - return the PGPORT setting
|
||||
* pq_close - close input / output connections
|
||||
* pq_flush - flush pending output
|
||||
* pq_recvbuf - load some bytes into the input buffer
|
||||
* pq_getstr - get a null terminated string from connection
|
||||
* pq_getchar - get 1 character from connection
|
||||
* pq_peekchar - peek at next character from connection
|
||||
* pq_getnchar - get n characters from connection, and null-terminate
|
||||
* pq_getint - get an integer from connection
|
||||
* pq_putchar - send 1 character to connection
|
||||
* pq_putstr - send a null terminated string to connection
|
||||
* pq_putnchar - send n characters to connection
|
||||
* pq_putint - send an integer to connection
|
||||
* pq_putncharlen - send n characters to connection
|
||||
* (also send an int header indicating
|
||||
* the length)
|
||||
* pq_getinaddr - initialize address from host and port number
|
||||
* pq_getinserv - initialize address from host and service name
|
||||
*
|
||||
* StreamDoUnlink - Shutdown UNIX socket connection
|
||||
* StreamServerPort - Open socket stream
|
||||
* setup/teardown:
|
||||
* StreamServerPort - Open postmaster's server port
|
||||
* StreamConnection - Create new connection with client
|
||||
* StreamClose - Close a client/backend connection
|
||||
*
|
||||
* NOTES
|
||||
* Frontend is now completely in interfaces/libpq, and no
|
||||
* functions from this file are used there.
|
||||
* pq_getport - return the PGPORT setting
|
||||
* pq_init - initialize libpq at backend startup
|
||||
* pq_close - shutdown libpq at backend exit
|
||||
*
|
||||
* low-level I/O:
|
||||
* pq_getbytes - get a known number of bytes from connection
|
||||
* pq_getstring - get a null terminated string from connection
|
||||
* pq_peekbyte - peek at next byte from connection
|
||||
* pq_putbytes - send bytes to connection (not flushed until pq_flush)
|
||||
* pq_flush - flush pending output
|
||||
*
|
||||
* message-level I/O (and COPY OUT cruft):
|
||||
* pq_putmessage - send a normal message (suppressed in COPY OUT mode)
|
||||
* pq_startcopyout - inform libpq that a COPY OUT transfer is beginning
|
||||
* pq_endcopyout - end a COPY OUT transfer
|
||||
*
|
||||
*------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
|
@ -62,89 +79,57 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#if defined(linux)
|
||||
#ifndef SOMAXCONN
|
||||
#define SOMAXCONN 5 /* from Linux listen(2) man page */
|
||||
#endif /* SOMAXCONN */
|
||||
#endif /* linux */
|
||||
|
||||
#include "libpq/libpq.h" /* where my declarations go */
|
||||
#include "miscadmin.h"
|
||||
#include "libpq/pqsignal.h"
|
||||
#include "libpq/auth.h"
|
||||
#include "libpq/libpq.h" /* where the declarations go */
|
||||
#include "storage/ipc.h"
|
||||
#ifdef MULTIBYTE
|
||||
#include "mb/pg_wchar.h"
|
||||
#endif
|
||||
#include "utils/trace.h"
|
||||
|
||||
#ifndef SOMAXCONN
|
||||
#define SOMAXCONN 5 /* from Linux listen(2) man page */
|
||||
#endif /* SOMAXCONN */
|
||||
|
||||
extern FILE * debug_port; /* in util.c */
|
||||
|
||||
/*
|
||||
* Buffers
|
||||
* Buffers for low-level I/O
|
||||
*/
|
||||
unsigned char PqSendBuffer[PQ_BUFFER_SIZE];
|
||||
unsigned char PqRecvBuffer[PQ_BUFFER_SIZE];
|
||||
int PqSendPointer,PqRecvPointer,PqRecvLength;
|
||||
|
||||
#define PQ_BUFFER_SIZE 8192
|
||||
|
||||
static unsigned char PqSendBuffer[PQ_BUFFER_SIZE];
|
||||
static int PqSendPointer; /* Next index to store a byte in PqSendBuffer */
|
||||
|
||||
static unsigned char PqRecvBuffer[PQ_BUFFER_SIZE];
|
||||
static int PqRecvPointer; /* Next index to read a byte from PqRecvBuffer */
|
||||
static int PqRecvLength; /* End of data available in PqRecvBuffer */
|
||||
|
||||
/*
|
||||
* Message status
|
||||
*/
|
||||
static bool DoingCopyOut;
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* pq_init - open portal file descriptors
|
||||
* pq_init - initialize libpq at backend startup
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pq_init(int fd)
|
||||
pq_init(void)
|
||||
{
|
||||
PqSendPointer = PqRecvPointer = PqRecvLength = 0;
|
||||
PQnotifies_init();
|
||||
DoingCopyOut = false;
|
||||
if (getenv("LIBPQ_DEBUG"))
|
||||
debug_port = stderr;
|
||||
}
|
||||
|
||||
/* -------------------------
|
||||
* pq_getchar()
|
||||
*
|
||||
* get a character from the input file, or EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
pq_getchar(void)
|
||||
{
|
||||
while (PqRecvPointer >= PqRecvLength)
|
||||
{
|
||||
if (pq_recvbuf()) /* If nothing in buffer, then recv some */
|
||||
return EOF; /* Failed to recv data */
|
||||
}
|
||||
return PqRecvBuffer[PqRecvPointer++];
|
||||
}
|
||||
|
||||
/* -------------------------
|
||||
* pq_peekchar()
|
||||
*
|
||||
* get a character from the connection, but leave it in the buffer
|
||||
* to be read again
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
pq_peekchar(void)
|
||||
{
|
||||
while (PqRecvPointer >= PqRecvLength)
|
||||
{
|
||||
if (pq_recvbuf()) /* If nothing in buffer, then recv some */
|
||||
return EOF; /* Failed to recv data */
|
||||
}
|
||||
/* Note we don't bump the pointer... */
|
||||
return PqRecvBuffer[PqRecvPointer];
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getport - return the PGPORT setting
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getport()
|
||||
pq_getport(void)
|
||||
{
|
||||
char *envport = getenv("PGPORT");
|
||||
|
||||
|
@ -154,327 +139,16 @@ pq_getport()
|
|||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_close - close input / output connections
|
||||
* pq_close - shutdown libpq at backend exit
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pq_close()
|
||||
pq_close(void)
|
||||
{
|
||||
close(MyProcPort->sock);
|
||||
PQnotifies_init();
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_flush - flush pending output
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_flush()
|
||||
{
|
||||
unsigned char *bufptr = PqSendBuffer;
|
||||
unsigned char *bufend = PqSendBuffer + PqSendPointer;
|
||||
|
||||
while (bufptr < bufend)
|
||||
{
|
||||
int r = send(MyProcPort->sock, bufptr, bufend - bufptr, 0);
|
||||
if (r <= 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue; /* Ok if we were interrupted */
|
||||
/* We would like to use elog() here, but cannot because elog
|
||||
* tries to write to the client, which would cause a recursive
|
||||
* flush attempt! So just write it out to the postmaster log.
|
||||
*/
|
||||
fprintf(stderr, "pq_flush: send() failed, errno %d\n", errno);
|
||||
/* We drop the buffered data anyway so that processing
|
||||
* can continue, even though we'll probably quit soon.
|
||||
*/
|
||||
PqSendPointer = 0;
|
||||
return EOF;
|
||||
}
|
||||
bufptr += r;
|
||||
}
|
||||
PqSendPointer = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_recvbuf - load some bytes into the input buffer
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
pq_recvbuf()
|
||||
{
|
||||
if (PqRecvPointer > 0)
|
||||
{
|
||||
if (PqRecvLength > PqRecvPointer)
|
||||
{
|
||||
/* still some unread data, left-justify it in the buffer */
|
||||
memmove(PqRecvBuffer, PqRecvBuffer+PqRecvPointer,
|
||||
PqRecvLength-PqRecvPointer);
|
||||
PqRecvLength -= PqRecvPointer;
|
||||
PqRecvPointer = 0;
|
||||
}
|
||||
else
|
||||
PqRecvLength = PqRecvPointer = 0;
|
||||
}
|
||||
|
||||
/* Can fill buffer from PqRecvLength and upwards */
|
||||
for (;;)
|
||||
{
|
||||
int r = recv(MyProcPort->sock, PqRecvBuffer + PqRecvLength,
|
||||
PQ_BUFFER_SIZE - PqRecvLength, 0);
|
||||
if (r < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue; /* Ok if interrupted */
|
||||
/* We would like to use elog() here, but dare not because elog
|
||||
* tries to write to the client, which will cause problems
|
||||
* if we have a hard communications failure ...
|
||||
* So just write the message to the postmaster log.
|
||||
*/
|
||||
fprintf(stderr, "pq_recvbuf: recv() failed, errno=%d\n", errno);
|
||||
return EOF;
|
||||
}
|
||||
if (r == 0)
|
||||
{
|
||||
/* as above, elog not safe */
|
||||
fprintf(stderr, "pq_recvbuf: unexpected EOF on client connection\n");
|
||||
return EOF;
|
||||
}
|
||||
/* r contains number of bytes read, so just incr length */
|
||||
PqRecvLength += r;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getstr - get a null terminated string from connection
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getstr(char *s, int maxlen)
|
||||
{
|
||||
int c;
|
||||
#ifdef MULTIBYTE
|
||||
char *p;
|
||||
#endif
|
||||
|
||||
c = pqGetString(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
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getnchar(char *s, int off, int maxlen)
|
||||
{
|
||||
int r = pqGetNBytes(s + off, maxlen);
|
||||
s[off+maxlen] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getint - get an integer from connection
|
||||
* we receive an integer a byte at a type and reconstruct it so that
|
||||
* machines with different ENDIAN representations can talk to each
|
||||
* other
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getint(int b)
|
||||
{
|
||||
int n,
|
||||
status = 1;
|
||||
|
||||
/*
|
||||
* mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
|
||||
* EOF is a valid return value for an int! XXX
|
||||
*/
|
||||
|
||||
switch (b)
|
||||
{
|
||||
case 1:
|
||||
status = ((n = pq_getchar()) == EOF);
|
||||
break;
|
||||
case 2:
|
||||
status = pqGetShort(&n);
|
||||
break;
|
||||
case 4:
|
||||
status = pqGetLong(&n);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "** Unsupported size %d\n", b);
|
||||
}
|
||||
|
||||
if (status)
|
||||
{
|
||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||
"FATAL: pq_getint failed: errno=%d\n", errno);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
n = 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_putstr - send a null terminated string to connection
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pq_putstr(char *s)
|
||||
{
|
||||
#ifdef MULTIBYTE
|
||||
unsigned char *p;
|
||||
|
||||
p = pg_server_to_client(s, strlen(s));
|
||||
if (pqPutString(p))
|
||||
#else
|
||||
if (pqPutString(s))
|
||||
#endif
|
||||
{
|
||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||
"FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_putnchar - send n characters to connection
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pq_putnchar(char *s, int n)
|
||||
{
|
||||
if (pqPutNBytes(s, n))
|
||||
{
|
||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||
"FATAL: pq_putnchar: pqPutNBytes() failed: errno=%d\n",
|
||||
errno);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_putint - send an integer to connection
|
||||
* we chop an integer into bytes and send individual bytes
|
||||
* machines with different ENDIAN representations can still talk to each
|
||||
* other
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pq_putint(int i, int b)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = 1;
|
||||
switch (b)
|
||||
{
|
||||
case 1:
|
||||
status = (pq_putchar(i) == EOF);
|
||||
break;
|
||||
case 2:
|
||||
status = pqPutShort(i);
|
||||
break;
|
||||
case 4:
|
||||
status = pqPutLong(i);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "** Unsupported size %d\n", b);
|
||||
}
|
||||
|
||||
if (status)
|
||||
{
|
||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||
"FATAL: pq_putint failed: errno=%d\n", errno);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getinaddr - initialize address from host and port number
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getinaddr(struct sockaddr_in * sin,
|
||||
char *host,
|
||||
int port)
|
||||
{
|
||||
struct hostent *hs;
|
||||
|
||||
MemSet((char *) sin, 0, sizeof(*sin));
|
||||
|
||||
if (host)
|
||||
{
|
||||
if (*host >= '0' && *host <= '9')
|
||||
sin->sin_addr.s_addr = inet_addr(host);
|
||||
else
|
||||
{
|
||||
if (!(hs = gethostbyname(host)))
|
||||
{
|
||||
perror(host);
|
||||
return 1;
|
||||
}
|
||||
if (hs->h_addrtype != AF_INET)
|
||||
{
|
||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||
"FATAL: pq_getinaddr: %s not on Internet\n",
|
||||
host);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return 1;
|
||||
}
|
||||
memmove((char *) &sin->sin_addr,
|
||||
hs->h_addr,
|
||||
hs->h_length);
|
||||
}
|
||||
}
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_port = htons(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getinserv - initialize address from host and servive name
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
|
||||
{
|
||||
struct servent *ss;
|
||||
|
||||
if (*serv >= '0' && *serv <= '9')
|
||||
return pq_getinaddr(sin, host, atoi(serv));
|
||||
if (!(ss = getservbyname(serv, NULL)))
|
||||
{
|
||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||
"FATAL: pq_getinserv: unknown service: %s\n",
|
||||
serv);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return 1;
|
||||
}
|
||||
return pq_getinaddr(sin, host, ntohs(ss->s_port));
|
||||
}
|
||||
|
||||
/*
|
||||
* Streams -- wrapper around Unix socket system calls
|
||||
|
@ -489,7 +163,7 @@ static char sock_path[MAXPGPATH + 1] = "";
|
|||
* Shutdown routine for backend connection
|
||||
* If a Unix socket is used for communication, explicitly close it.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
StreamDoUnlink()
|
||||
{
|
||||
Assert(sock_path[0]);
|
||||
|
@ -499,12 +173,7 @@ StreamDoUnlink()
|
|||
/*
|
||||
* StreamServerPort -- open a sock stream "listening" port.
|
||||
*
|
||||
* This initializes the Postmaster's connection
|
||||
* accepting port.
|
||||
*
|
||||
* ASSUME: that this doesn't need to be non-blocking because
|
||||
* the Postmaster uses select() to tell when the socket
|
||||
* is ready.
|
||||
* This initializes the Postmaster's connection-accepting port.
|
||||
*
|
||||
* RETURNS: STATUS_OK or STATUS_ERROR
|
||||
*/
|
||||
|
@ -648,7 +317,9 @@ StreamServerPort(char *hostName, short portName, int *fdP)
|
|||
* StreamConnection -- create a new connection with client using
|
||||
* server port.
|
||||
*
|
||||
* This one should be non-blocking.
|
||||
* ASSUME: that this doesn't need to be non-blocking because
|
||||
* the Postmaster uses select() to tell when the server master
|
||||
* socket is ready for accept().
|
||||
*
|
||||
* RETURNS: STATUS_OK or STATUS_ERROR
|
||||
*/
|
||||
|
@ -711,31 +382,295 @@ StreamClose(int sock)
|
|||
close(sock);
|
||||
}
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
void
|
||||
pq_putncharlen(char *s, int n)
|
||||
{
|
||||
unsigned char *p;
|
||||
int len;
|
||||
|
||||
p = pg_server_to_client(s, n);
|
||||
len = strlen(p);
|
||||
pq_putint(len, sizeof(int));
|
||||
pq_putnchar(p, len);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Act like the stdio putc() function. Write one character
|
||||
* to the stream. Return this character, or EOF on error.
|
||||
/* --------------------------------
|
||||
* Low-level I/O routines begin here.
|
||||
*
|
||||
* These routines communicate with a frontend client across a connection
|
||||
* already established by the preceding routines.
|
||||
* --------------------------------
|
||||
*/
|
||||
int pq_putchar(unsigned char c)
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* pq_recvbuf - load some bytes into the input buffer
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
static int
|
||||
pq_recvbuf(void)
|
||||
{
|
||||
if (PqSendPointer >= PQ_BUFFER_SIZE)
|
||||
if (pq_flush()) /* If buffer is full, then flush it out */
|
||||
if (PqRecvPointer > 0)
|
||||
{
|
||||
if (PqRecvLength > PqRecvPointer)
|
||||
{
|
||||
/* still some unread data, left-justify it in the buffer */
|
||||
memmove(PqRecvBuffer, PqRecvBuffer+PqRecvPointer,
|
||||
PqRecvLength-PqRecvPointer);
|
||||
PqRecvLength -= PqRecvPointer;
|
||||
PqRecvPointer = 0;
|
||||
}
|
||||
else
|
||||
PqRecvLength = PqRecvPointer = 0;
|
||||
}
|
||||
|
||||
/* Can fill buffer from PqRecvLength and upwards */
|
||||
for (;;)
|
||||
{
|
||||
int r = recv(MyProcPort->sock, PqRecvBuffer + PqRecvLength,
|
||||
PQ_BUFFER_SIZE - PqRecvLength, 0);
|
||||
if (r < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue; /* Ok if interrupted */
|
||||
/* We would like to use elog() here, but dare not because elog
|
||||
* tries to write to the client, which will cause problems
|
||||
* if we have a hard communications failure ...
|
||||
* So just write the message to the postmaster log.
|
||||
*/
|
||||
fprintf(stderr, "pq_recvbuf: recv() failed, errno=%d\n", errno);
|
||||
return EOF;
|
||||
PqSendBuffer[PqSendPointer++] = c; /* Put in buffer */
|
||||
return c;
|
||||
}
|
||||
if (r == 0)
|
||||
{
|
||||
/* as above, elog not safe */
|
||||
fprintf(stderr, "pq_recvbuf: unexpected EOF on client connection\n");
|
||||
return EOF;
|
||||
}
|
||||
/* r contains number of bytes read, so just incr length */
|
||||
PqRecvLength += r;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getbyte - get a single byte from connection, or return EOF
|
||||
* --------------------------------
|
||||
*/
|
||||
static int
|
||||
pq_getbyte(void)
|
||||
{
|
||||
while (PqRecvPointer >= PqRecvLength)
|
||||
{
|
||||
if (pq_recvbuf()) /* If nothing in buffer, then recv some */
|
||||
return EOF; /* Failed to recv data */
|
||||
}
|
||||
return PqRecvBuffer[PqRecvPointer++];
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_peekbyte - peek at next byte from connection
|
||||
*
|
||||
* Same as pq_getbyte() except we don't advance the pointer.
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_peekbyte(void)
|
||||
{
|
||||
while (PqRecvPointer >= PqRecvLength)
|
||||
{
|
||||
if (pq_recvbuf()) /* If nothing in buffer, then recv some */
|
||||
return EOF; /* Failed to recv data */
|
||||
}
|
||||
return PqRecvBuffer[PqRecvPointer];
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getbytes - get a known number of bytes from connection
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_getbytes(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;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_getstring - get a null terminated string from connection
|
||||
*
|
||||
* NOTE: this routine does not do any MULTIBYTE conversion,
|
||||
* even though it is presumably useful only for text, because
|
||||
* no code in this module should depend on MULTIBYTE mode.
|
||||
* See pq_getstr in pqformat.c for that.
|
||||
*
|
||||
* 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_getstring(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_getbyte()) != EOF && c != '\0')
|
||||
{
|
||||
if (len > 1)
|
||||
{
|
||||
*s++ = c;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
*s = '\0';
|
||||
|
||||
if (c == EOF)
|
||||
return EOF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* pq_putbytes - send bytes to connection (not flushed until pq_flush)
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_putbytes(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;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_flush - flush pending output
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_flush(void)
|
||||
{
|
||||
unsigned char *bufptr = PqSendBuffer;
|
||||
unsigned char *bufend = PqSendBuffer + PqSendPointer;
|
||||
|
||||
while (bufptr < bufend)
|
||||
{
|
||||
int r = send(MyProcPort->sock, bufptr, bufend - bufptr, 0);
|
||||
if (r <= 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue; /* Ok if we were interrupted */
|
||||
/* We would like to use elog() here, but cannot because elog
|
||||
* tries to write to the client, which would cause a recursive
|
||||
* flush attempt! So just write it out to the postmaster log.
|
||||
*/
|
||||
fprintf(stderr, "pq_flush: send() failed, errno %d\n", errno);
|
||||
/* We drop the buffered data anyway so that processing
|
||||
* can continue, even though we'll probably quit soon.
|
||||
*/
|
||||
PqSendPointer = 0;
|
||||
return EOF;
|
||||
}
|
||||
bufptr += r;
|
||||
}
|
||||
PqSendPointer = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* Message-level I/O routines begin here.
|
||||
*
|
||||
* These routines understand about COPY OUT protocol.
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* pq_putmessage - send a normal message (suppressed in COPY OUT mode)
|
||||
*
|
||||
* If msgtype is not '\0', it is a message type code to place before
|
||||
* the message body (len counts only the body size!).
|
||||
* If msgtype is '\0', then the buffer already includes the type code.
|
||||
*
|
||||
* All normal messages are suppressed while COPY OUT is in progress.
|
||||
* (In practice only NOTICE messages might get emitted then; dropping
|
||||
* them is annoying, but at least they will still appear in the
|
||||
* postmaster log.)
|
||||
*
|
||||
* returns 0 if OK, EOF if trouble
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pq_putmessage(char msgtype, const char *s, size_t len)
|
||||
{
|
||||
if (DoingCopyOut)
|
||||
return 0;
|
||||
if (msgtype)
|
||||
if (pq_putbytes(&msgtype, 1))
|
||||
return EOF;
|
||||
return pq_putbytes(s, len);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_startcopyout - inform libpq that a COPY OUT transfer is beginning
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pq_startcopyout(void)
|
||||
{
|
||||
DoingCopyOut = true;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pq_endcopyout - end a COPY OUT transfer
|
||||
*
|
||||
* If errorAbort is indicated, we are aborting a COPY OUT due to an error,
|
||||
* and must send a terminator line. Since a partial data line might have
|
||||
* been emitted, send a couple of newlines first (the first one could
|
||||
* get absorbed by a backslash...)
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pq_endcopyout(bool errorAbort)
|
||||
{
|
||||
if (! DoingCopyOut)
|
||||
return;
|
||||
if (errorAbort)
|
||||
pq_putbytes("\n\n\\.\n", 5);
|
||||
/* in non-error case, copy.c will have emitted the terminator line */
|
||||
DoingCopyOut = false;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: outfuncs.c,v 1.78 1999/03/23 16:50:53 momjian Exp $
|
||||
* $Id: outfuncs.c,v 1.79 1999/04/25 03:19:15 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||
|
@ -1658,21 +1658,15 @@ _outNode(StringInfo str, void *obj)
|
|||
|
||||
/*
|
||||
* nodeToString -
|
||||
* returns the ascii representation of the Node
|
||||
* returns the ascii representation of the Node as a palloc'd string
|
||||
*/
|
||||
char *
|
||||
nodeToString(void *obj)
|
||||
{
|
||||
StringInfo str;
|
||||
char *s;
|
||||
StringInfoData str;
|
||||
|
||||
if (obj == NULL)
|
||||
return "";
|
||||
Assert(obj != NULL);
|
||||
str = makeStringInfo();
|
||||
_outNode(str, obj);
|
||||
s = str->data;
|
||||
pfree(str);
|
||||
|
||||
return s;
|
||||
/* see stringinfo.h for an explanation of this maneuver */
|
||||
initStringInfo(&str);
|
||||
_outNode(&str, obj);
|
||||
return str.data;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.25 1999/02/13 23:18:42 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.26 1999/04/25 03:19:09 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include "access/htup.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "access/printtup.h"
|
||||
#include "utils/portal.h"
|
||||
#include "utils/palloc.h"
|
||||
|
@ -137,8 +138,7 @@ BeginCommand(char *pname,
|
|||
* send fe info on tuples we're about to send
|
||||
* ----------------
|
||||
*/
|
||||
pq_putnchar("P", 1);/* new portal.. */
|
||||
pq_putstr(pname); /* portal name */
|
||||
pq_putmessage('P', pname, strlen(pname)+1);
|
||||
|
||||
/* ----------------
|
||||
* if this is a retrieve, then we send back the tuple
|
||||
|
@ -148,17 +148,24 @@ BeginCommand(char *pname,
|
|||
*/
|
||||
if (operation == CMD_SELECT && !isIntoRel)
|
||||
{
|
||||
pq_putnchar("T", 1); /* type info to follow.. */
|
||||
pq_putint(natts, 2); /* number of attributes in tuples */
|
||||
StringInfoData buf;
|
||||
pq_beginmessage(&buf);
|
||||
pq_sendbyte(&buf, 'T'); /* tuple descriptor message type */
|
||||
pq_sendint(&buf, natts, 2); /* # of attributes in tuples */
|
||||
|
||||
for (i = 0; i < natts; ++i)
|
||||
{
|
||||
pq_putstr(attrs[i]->attname.data);
|
||||
pq_putint((int) attrs[i]->atttypid, sizeof(attrs[i]->atttypid));
|
||||
pq_putint(attrs[i]->attlen, sizeof(attrs[i]->attlen));
|
||||
pq_sendstring(&buf, attrs[i]->attname.data,
|
||||
strlen(attrs[i]->attname.data));
|
||||
pq_sendint(&buf, (int) attrs[i]->atttypid,
|
||||
sizeof(attrs[i]->atttypid));
|
||||
pq_sendint(&buf, attrs[i]->attlen,
|
||||
sizeof(attrs[i]->attlen));
|
||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
|
||||
pq_putint(attrs[i]->atttypmod, sizeof(attrs[i]->atttypmod));
|
||||
pq_sendint(&buf, attrs[i]->atttypmod,
|
||||
sizeof(attrs[i]->atttypmod));
|
||||
}
|
||||
pq_endmessage(&buf);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -265,8 +272,8 @@ EndCommand(char *commandTag, CommandDest dest)
|
|||
* tell the fe that the query is over
|
||||
* ----------------
|
||||
*/
|
||||
sprintf(buf, "C%s%s", commandTag, CommandInfo);
|
||||
pq_putstr(buf);
|
||||
sprintf(buf, "%s%s", commandTag, CommandInfo);
|
||||
pq_putmessage('C', buf, strlen(buf)+1);
|
||||
CommandInfo[0] = '\0';
|
||||
break;
|
||||
|
||||
|
@ -293,18 +300,18 @@ void
|
|||
SendCopyBegin(void)
|
||||
{
|
||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
|
||||
pq_putnchar("H", 1); /* new way */
|
||||
pq_putbytes("H", 1); /* new way */
|
||||
else
|
||||
pq_putnchar("B", 1); /* old way */
|
||||
pq_putbytes("B", 1); /* old way */
|
||||
}
|
||||
|
||||
void
|
||||
ReceiveCopyBegin(void)
|
||||
{
|
||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
|
||||
pq_putnchar("G", 1); /* new way */
|
||||
pq_putbytes("G", 1); /* new way */
|
||||
else
|
||||
pq_putnchar("D", 1); /* old way */
|
||||
pq_putbytes("D", 1); /* old way */
|
||||
/* We *must* flush here to ensure FE knows it can send. */
|
||||
pq_flush();
|
||||
}
|
||||
|
@ -330,7 +337,7 @@ NullCommand(CommandDest dest)
|
|||
* tell the fe that we saw an empty query string
|
||||
* ----------------
|
||||
*/
|
||||
pq_putstr("I");
|
||||
pq_putbytes("I", 1);
|
||||
break;
|
||||
|
||||
case Local:
|
||||
|
@ -359,7 +366,7 @@ ReadyForQuery(CommandDest dest)
|
|||
case RemoteInternal:
|
||||
case Remote:
|
||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
|
||||
pq_putnchar("Z", 1);
|
||||
pq_putbytes("Z", 1);
|
||||
/* Flush output at end of cycle in any case. */
|
||||
pq_flush();
|
||||
break;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.22 1999/02/13 23:18:44 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.23 1999/04/25 03:19:10 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This cruft is the server side of PQfn.
|
||||
|
@ -68,6 +68,7 @@
|
|||
#include "utils/builtins.h" /* for oideq */
|
||||
#include "tcop/fastpath.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/pqformat.h"
|
||||
|
||||
#include "access/xact.h" /* for TransactionId/CommandId protos */
|
||||
|
||||
|
@ -87,32 +88,36 @@ SendFunctionResult(Oid fid, /* function id */
|
|||
int retlen /* the length according to the catalogs */
|
||||
)
|
||||
{
|
||||
pq_putnchar("V", 1);
|
||||
StringInfoData buf;
|
||||
|
||||
pq_beginmessage(&buf);
|
||||
pq_sendbyte(&buf, 'V');
|
||||
|
||||
if (retlen != 0)
|
||||
{
|
||||
pq_putnchar("G", 1);
|
||||
pq_sendbyte(&buf, 'G');
|
||||
if (retbyval)
|
||||
{ /* by-value */
|
||||
pq_putint(retlen, 4);
|
||||
pq_putint((int) (Datum) retval, retlen);
|
||||
pq_sendint(&buf, retlen, 4);
|
||||
pq_sendint(&buf, (int) (Datum) retval, retlen);
|
||||
}
|
||||
else
|
||||
{ /* by-reference ... */
|
||||
if (retlen < 0)
|
||||
{ /* ... varlena */
|
||||
pq_putint(VARSIZE(retval) - VARHDRSZ, VARHDRSZ);
|
||||
pq_putnchar(VARDATA(retval), VARSIZE(retval) - VARHDRSZ);
|
||||
pq_sendint(&buf, VARSIZE(retval) - VARHDRSZ, VARHDRSZ);
|
||||
pq_sendbytes(&buf, VARDATA(retval), VARSIZE(retval) - VARHDRSZ);
|
||||
}
|
||||
else
|
||||
{ /* ... fixed */
|
||||
pq_putint(retlen, 4);
|
||||
pq_putnchar(retval, retlen);
|
||||
pq_sendint(&buf, retlen, 4);
|
||||
pq_sendbytes(&buf, retval, retlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pq_putnchar("0", 1);
|
||||
pq_sendbyte(&buf, '0');
|
||||
pq_endmessage(&buf);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -276,6 +281,7 @@ HandleFunctionRequest()
|
|||
Oid fid;
|
||||
int argsize;
|
||||
int nargs;
|
||||
int tmp;
|
||||
char *arg[8];
|
||||
char *retval;
|
||||
int i;
|
||||
|
@ -283,8 +289,9 @@ HandleFunctionRequest()
|
|||
char *p;
|
||||
struct fp_info *fip;
|
||||
|
||||
fid = (Oid) pq_getint(4); /* function oid */
|
||||
nargs = pq_getint(4); /* # of arguments */
|
||||
pq_getint(&tmp, 4); /* function oid */
|
||||
fid = (Oid) tmp;
|
||||
pq_getint(&nargs, 4); /* # of arguments */
|
||||
|
||||
/*
|
||||
* This is where the one-back caching is done. If you want to save
|
||||
|
@ -311,13 +318,14 @@ HandleFunctionRequest()
|
|||
arg[i] = (char *) NULL;
|
||||
else
|
||||
{
|
||||
argsize = pq_getint(4);
|
||||
pq_getint(&argsize, 4);
|
||||
|
||||
Assert(argsize > 0);
|
||||
if (fip->argbyval[i])
|
||||
{ /* by-value */
|
||||
Assert(argsize <= 4);
|
||||
arg[i] = (char *) pq_getint(argsize);
|
||||
pq_getint(&tmp, argsize);
|
||||
arg[i] = (char *) tmp;
|
||||
}
|
||||
else
|
||||
{ /* by-reference ... */
|
||||
|
@ -328,14 +336,14 @@ HandleFunctionRequest()
|
|||
* 98 Jan 6 */
|
||||
elog(ERROR, "HandleFunctionRequest: palloc failed");
|
||||
VARSIZE(p) = argsize + VARHDRSZ;
|
||||
pq_getnchar(VARDATA(p), 0, argsize);
|
||||
pq_getbytes(VARDATA(p), argsize);
|
||||
}
|
||||
else
|
||||
{ /* ... fixed */
|
||||
/* XXX cross our fingers and trust "argsize" */
|
||||
if (!(p = palloc(argsize + 1)))
|
||||
elog(ERROR, "HandleFunctionRequest: palloc failed");
|
||||
pq_getnchar(p, 0, argsize);
|
||||
pq_getbytes(p, argsize);
|
||||
}
|
||||
palloced |= (1 << i);
|
||||
arg[i] = p;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.107 1999/04/20 02:19:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.108 1999/04/25 03:19:10 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* this is the "main" module of the postgres backend and
|
||||
|
@ -52,6 +52,7 @@
|
|||
#include "executor/execdebug.h"
|
||||
#include "executor/executor.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "libpq/libpq-be.h"
|
||||
#include "libpq/pqsignal.h"
|
||||
#include "nodes/pg_list.h"
|
||||
|
@ -304,15 +305,15 @@ InteractiveBackend(char *inBuf)
|
|||
static char
|
||||
SocketBackend(char *inBuf)
|
||||
{
|
||||
char qtype[2];
|
||||
char qtype;
|
||||
char result = '\0';
|
||||
|
||||
/* ----------------
|
||||
* get input from the frontend
|
||||
* ----------------
|
||||
*/
|
||||
strcpy(qtype, "?");
|
||||
if (pq_getnchar(qtype, 0, 1) == EOF)
|
||||
qtype = '?';
|
||||
if (pq_getbytes(&qtype, 1) == EOF)
|
||||
{
|
||||
/* ------------
|
||||
* when front-end applications quits/dies
|
||||
|
@ -321,7 +322,7 @@ SocketBackend(char *inBuf)
|
|||
proc_exit(0);
|
||||
}
|
||||
|
||||
switch (*qtype)
|
||||
switch (qtype)
|
||||
{
|
||||
/* ----------------
|
||||
* 'Q': user entered a query
|
||||
|
@ -358,7 +359,7 @@ SocketBackend(char *inBuf)
|
|||
* ----------------
|
||||
*/
|
||||
default:
|
||||
elog(FATAL, "Socket command type %c unknown\n", *qtype);
|
||||
elog(FATAL, "Socket command type %c unknown", qtype);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
|
@ -1461,7 +1462,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
Portfd = open(NULL_DEV, O_RDWR | O_BINARY, 0666);
|
||||
#endif
|
||||
}
|
||||
pq_init(Portfd);
|
||||
pq_init(); /* reset libpq */
|
||||
whereToSendOutput = Remote;
|
||||
}
|
||||
else
|
||||
|
@ -1521,16 +1522,19 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
if (whereToSendOutput == Remote &&
|
||||
PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
|
||||
{
|
||||
pq_putnchar("K", 1);
|
||||
pq_putint((int32) MyProcPid, sizeof(int32));
|
||||
pq_putint((int32) MyCancelKey, sizeof(int32));
|
||||
StringInfoData buf;
|
||||
pq_beginmessage(&buf);
|
||||
pq_sendbyte(&buf, 'K');
|
||||
pq_sendint(&buf, (int32) MyProcPid, sizeof(int32));
|
||||
pq_sendint(&buf, (int32) MyCancelKey, sizeof(int32));
|
||||
pq_endmessage(&buf);
|
||||
/* Need not flush since ReadyForQuery will do it. */
|
||||
}
|
||||
|
||||
if (!IsUnderPostmaster)
|
||||
{
|
||||
puts("\nPOSTGRES backend interactive interface ");
|
||||
puts("$Revision: 1.107 $ $Date: 1999/04/20 02:19:53 $\n");
|
||||
puts("$Revision: 1.108 $ $Date: 1999/04/25 03:19:10 $\n");
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.41 1999/04/20 02:19:54 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.42 1999/04/25 03:19:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -188,12 +188,21 @@ elog(int lev, const char *fmt,...)
|
|||
/* Send IPC message to the front-end program */
|
||||
if (IsUnderPostmaster && lev > DEBUG)
|
||||
{
|
||||
/* notices are not exactly errors, handle it differently */
|
||||
/* notices are not errors, handle 'em differently */
|
||||
char msgtype;
|
||||
if (lev == NOTICE)
|
||||
pq_putnchar("N", 1);
|
||||
msgtype = 'N';
|
||||
else
|
||||
pq_putnchar("E", 1);
|
||||
pq_putstr(line + TIMESTAMP_SIZE); /* don't show timestamps */
|
||||
{
|
||||
/* Abort any COPY OUT in progress when an error is detected.
|
||||
* This hack is necessary because of poor design of copy protocol.
|
||||
*/
|
||||
pq_endcopyout(true);
|
||||
msgtype = 'E';
|
||||
}
|
||||
/* exclude the timestamp from msg sent to frontend */
|
||||
pq_putmessage(msgtype, line + TIMESTAMP_SIZE,
|
||||
strlen(line + TIMESTAMP_SIZE) + 1);
|
||||
/*
|
||||
* This flush is normally not necessary, since postgres.c will
|
||||
* flush out waiting data when control returns to the main loop.
|
||||
|
|
|
@ -1,52 +1,108 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* stringinfo.h
|
||||
* Declarations/definitons for "string" functions.
|
||||
* Declarations/definitions for "StringInfo" functions.
|
||||
*
|
||||
* 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.h,v 1.10 1999/02/13 23:21:32 momjian Exp $
|
||||
* $Id: stringinfo.h,v 1.11 1999/04/25 03:19:27 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef STRINGINFO_H
|
||||
#define STRINGINFO_H
|
||||
|
||||
|
||||
/*-------------------------
|
||||
* StringInfoData holds information about a string.
|
||||
* 'data' is the string.
|
||||
* 'len' is the current string length (as returned by 'strlen')
|
||||
* 'maxlen' is the size in bytes of 'data', i.e. the maximum string
|
||||
* size (including the terminating '\0' char) that we can
|
||||
* StringInfoData holds information about an extensible string.
|
||||
* data is the current buffer for the string (allocated with palloc).
|
||||
* len is the current string length. There is guaranteed to be
|
||||
* a terminating '\0' at data[len], although this is not very
|
||||
* useful when the string holds binary data rather than text.
|
||||
* maxlen is the allocated size in bytes of 'data', i.e. the maximum
|
||||
* string size (including the terminating '\0' char) that we can
|
||||
* currently store in 'data' without having to reallocate
|
||||
* more space.
|
||||
* more space. We must always have maxlen > len.
|
||||
*-------------------------
|
||||
*/
|
||||
typedef struct StringInfoData
|
||||
{
|
||||
char *data;
|
||||
int maxlen;
|
||||
int len;
|
||||
int maxlen;
|
||||
} StringInfoData;
|
||||
|
||||
typedef StringInfoData *StringInfo;
|
||||
|
||||
|
||||
/*------------------------
|
||||
* There are two ways to create a StringInfo object initially:
|
||||
*
|
||||
* StringInfo stringptr = makeStringInfo();
|
||||
* Both the StringInfoData and the data buffer are palloc'd.
|
||||
*
|
||||
* StringInfoData string;
|
||||
* initStringInfo(&string);
|
||||
* The data buffer is palloc'd but the StringInfoData is just local.
|
||||
* This is the easiest approach for a StringInfo object that will
|
||||
* only live as long as the current routine.
|
||||
*
|
||||
* To destroy a StringInfo, pfree() the data buffer, and then pfree() the
|
||||
* StringInfoData if it was palloc'd. There's no special support for this.
|
||||
*
|
||||
* NOTE: some routines build up a string using StringInfo, and then
|
||||
* release the StringInfoData but return the data string itself to their
|
||||
* caller. At that point the data string looks like a plain palloc'd
|
||||
* string.
|
||||
*-------------------------
|
||||
*/
|
||||
|
||||
/*------------------------
|
||||
* makeStringInfo
|
||||
* create a 'StringInfoData' & return a pointer to it.
|
||||
* Create an empty 'StringInfoData' & return a pointer to it.
|
||||
*/
|
||||
extern StringInfo makeStringInfo(void);
|
||||
|
||||
/*------------------------
|
||||
* appendStringInfo
|
||||
* similar to 'strcat' but reallocates more space if necessary...
|
||||
* initStringInfo
|
||||
* Initialize a StringInfoData struct (with previously undefined contents)
|
||||
* to describe an empty string.
|
||||
*/
|
||||
extern void appendStringInfo(StringInfo str, const char *fmt,...);
|
||||
extern void initStringInfo(StringInfo str);
|
||||
|
||||
/*------------------------
|
||||
* nullStringInfo
|
||||
* return the string itself or "<>" if it is NULL
|
||||
* 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).
|
||||
*/
|
||||
extern void appendStringInfo(StringInfo str, const char *fmt, ...);
|
||||
|
||||
/*------------------------
|
||||
* appendStringInfoChar
|
||||
* Append a single byte to str.
|
||||
* Like appendStringInfo(str, "%c", ch) but much faster.
|
||||
*/
|
||||
extern void appendStringInfoChar(StringInfo str, char ch);
|
||||
|
||||
/*------------------------
|
||||
* appendBinaryStringInfo
|
||||
* Append arbitrary binary data to a StringInfo, allocating more space
|
||||
* if necessary.
|
||||
*/
|
||||
extern void appendBinaryStringInfo(StringInfo str,
|
||||
const char *data, int datalen);
|
||||
|
||||
/*------------------------
|
||||
* stringStringInfo
|
||||
* Return the string itself or "<>" if it is NULL.
|
||||
* This is just a convenience macro used by many callers of appendStringInfo.
|
||||
*/
|
||||
#define stringStringInfo(s) (((s) == NULL) ? "<>" : (s))
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq.h,v 1.27 1999/02/13 23:21:35 momjian Exp $
|
||||
* $Id: libpq.h,v 1.28 1999/04/25 03:19:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -120,17 +120,6 @@ typedef struct PortalEntry
|
|||
extern PortalEntry **portals;
|
||||
extern size_t portals_array_size;
|
||||
|
||||
/*
|
||||
* Asynchronous notification
|
||||
*/
|
||||
typedef struct PQNotifyList
|
||||
{
|
||||
char relname[NAMEDATALEN]; /* listen/notify name */
|
||||
int be_pid; /* process id of backend */
|
||||
int valid; /* has this already been handled by user. */
|
||||
/* SLNode Node; */
|
||||
} PQNotifyList;
|
||||
|
||||
/*
|
||||
* Exceptions.
|
||||
*/
|
||||
|
@ -194,11 +183,6 @@ extern char *PQgetvalue(PortalBuffer *portal, int tuple_index, int field_number)
|
|||
extern char *PQgetAttr(PortalBuffer *portal, int tuple_index, int field_number);
|
||||
extern int PQgetlength(PortalBuffer *portal, int tuple_index, int field_number);
|
||||
extern void PQclear(char *pname);
|
||||
extern void PQcleanNotify(void);
|
||||
extern void PQnotifies_init(void);
|
||||
extern PQNotifyList *PQnotifies(void);
|
||||
extern void PQremoveNotify(PQNotifyList *nPtr);
|
||||
extern void PQappendNotify(char *relname, int pid);
|
||||
|
||||
/*
|
||||
* prototypes for functions in portalbuf.c
|
||||
|
@ -250,51 +234,19 @@ extern int32 pqtest(struct varlena * vlena);
|
|||
/*
|
||||
* prototypes for functions in pqcomm.c
|
||||
*/
|
||||
extern void pq_init(int fd);
|
||||
extern void pq_gettty(char *tp);
|
||||
extern int pq_getport(void);
|
||||
extern void pq_close(void);
|
||||
extern int pq_flush(void);
|
||||
extern int pq_recvbuf(void);
|
||||
extern int pq_getstr(char *s, int maxlen);
|
||||
extern int PQgetline(char *s, int maxlen);
|
||||
extern int PQputline(char *s);
|
||||
extern int pq_getchar(void);
|
||||
extern int pq_peekchar(void);
|
||||
extern int pq_getnchar(char *s, int off, int maxlen);
|
||||
extern int pq_getint(int b);
|
||||
extern int pq_putchar(unsigned char c);
|
||||
extern void pq_putstr(char *s);
|
||||
extern void pq_putnchar(char *s, int n);
|
||||
extern void pq_putint(int i, int b);
|
||||
extern int pq_getinaddr(struct sockaddr_in * sin, char *host, int port);
|
||||
extern int pq_getinserv(struct sockaddr_in * sin, char *host, char *serv);
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
extern void pq_putncharlen(char *s, int n);
|
||||
|
||||
#endif
|
||||
|
||||
extern int pq_connect(char *dbname, char *user, char *args, char *hostName,
|
||||
char *debugTty, char *execFile, short portName);
|
||||
extern int StreamOpen(char *hostName, short portName, Port *port);
|
||||
extern void StreamDoUnlink(void);
|
||||
extern int StreamServerPort(char *hostName, short portName, int *fdP);
|
||||
extern int StreamConnection(int server_fd, Port *port);
|
||||
extern void StreamClose(int sock);
|
||||
|
||||
/*
|
||||
* Internal send/receive buffers in libpq.
|
||||
* These probably shouldn't be global at all, but unless we merge
|
||||
* pqcomm.c and pqcomprim.c they have to be...
|
||||
*/
|
||||
|
||||
#define PQ_BUFFER_SIZE 8192
|
||||
|
||||
extern unsigned char PqSendBuffer[PQ_BUFFER_SIZE];
|
||||
extern int PqSendPointer; /* Next index to store a byte in PqSendBuffer */
|
||||
extern unsigned char PqRecvBuffer[PQ_BUFFER_SIZE];
|
||||
extern int PqRecvPointer; /* Next index to read a byte from PqRecvBuffer */
|
||||
extern int PqRecvLength; /* End of data available in PqRecvBuffer */
|
||||
extern void pq_init(void);
|
||||
extern int pq_getport(void);
|
||||
extern void pq_close(void);
|
||||
extern int pq_getbytes(char *s, size_t len);
|
||||
extern int pq_getstring(char *s, size_t len);
|
||||
extern int pq_peekbyte(void);
|
||||
extern int pq_putbytes(const char *s, size_t len);
|
||||
extern int pq_flush(void);
|
||||
extern int pq_putmessage(char msgtype, const char *s, size_t len);
|
||||
extern void pq_startcopyout(void);
|
||||
extern void pq_endcopyout(bool errorAbort);
|
||||
|
||||
#endif /* LIBPQ_H */
|
||||
|
|
|
@ -3,16 +3,20 @@
|
|||
* pqcomm.h
|
||||
* Definitions common to frontends and backends.
|
||||
*
|
||||
* NOTE: for historical reasons, this does not correspond to pqcomm.c.
|
||||
* pqcomm.c's routines are declared in libpq.h.
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pqcomm.h,v 1.33 1999/02/13 23:21:36 momjian Exp $
|
||||
* $Id: pqcomm.h,v 1.34 1999/04/25 03:19:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PQCOMM_H
|
||||
#define PQCOMM_H
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef WIN32
|
||||
|
@ -23,8 +27,6 @@
|
|||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
/* Define a generic socket address type. */
|
||||
|
||||
typedef union SockAddr
|
||||
|
@ -151,18 +153,4 @@ typedef struct CancelRequestPacket
|
|||
uint32 cancelAuthCode; /* secret key to authorize cancel */
|
||||
} CancelRequestPacket;
|
||||
|
||||
|
||||
/* in pqcomprim.c */
|
||||
int pqGetShort(int *);
|
||||
int pqGetLong(int *);
|
||||
int pqGetNBytes(char *, size_t);
|
||||
int pqGetString(char *, size_t);
|
||||
int pqGetByte(void);
|
||||
|
||||
int pqPutShort(int);
|
||||
int pqPutLong(int);
|
||||
int pqPutNBytes(const char *, size_t);
|
||||
int pqPutString(const char *);
|
||||
int pqPutByte(int);
|
||||
|
||||
#endif /* PQCOMM_H */
|
||||
|
|
|
@ -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