mirror of
https://github.com/postgres/postgres.git
synced 2025-07-18 17:42:25 +03:00
Remove server and libpq support for old FE/BE protocol version 2.
Protocol version 3 was introduced in PostgreSQL 7.4. There shouldn't be many clients or servers left out there without version 3 support. But as a courtesy, I kept just enough of the old protocol support that we can still send the "unsupported protocol version" error in v2 format, so that old clients can display the message properly. Likewise, libpq still understands v2 ErrorResponse messages when establishing a connection. The impetus to do this now is that I'm working on a patch to COPY FROM, to always prefetch some data. We cannot do that safely with the old protocol, because it requires parsing the input one byte at a time to detect the end-of-copy marker. Reviewed-by: Tom Lane, Alvaro Herrera, John Naylor Discussion: https://www.postgresql.org/message-id/9ec25819-0a8a-d51a-17dc-4150bb3cca3b%40iki.fi
This commit is contained in:
@ -2311,8 +2311,7 @@ NotifyMyFrontEnd(const char *channel, const char *payload, int32 srcPid)
|
||||
pq_beginmessage(&buf, 'A');
|
||||
pq_sendint32(&buf, srcPid);
|
||||
pq_sendstring(&buf, channel);
|
||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
|
||||
pq_sendstring(&buf, payload);
|
||||
pq_sendstring(&buf, payload);
|
||||
pq_endmessage(&buf);
|
||||
|
||||
/*
|
||||
|
@ -1126,13 +1126,6 @@ CopyFrom(CopyFromState cstate)
|
||||
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
/*
|
||||
* In the old protocol, tell pqcomm that we can process normal protocol
|
||||
* messages again.
|
||||
*/
|
||||
if (cstate->copy_src == COPY_OLD_FE)
|
||||
pq_endmsgread();
|
||||
|
||||
/* Execute AFTER STATEMENT insertion triggers */
|
||||
ExecASInsertTriggers(estate, target_resultRelInfo, cstate->transition_capture);
|
||||
|
||||
|
@ -124,35 +124,19 @@ static int CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
|
||||
void
|
||||
ReceiveCopyBegin(CopyFromState cstate)
|
||||
{
|
||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
|
||||
{
|
||||
/* new way */
|
||||
StringInfoData buf;
|
||||
int natts = list_length(cstate->attnumlist);
|
||||
int16 format = (cstate->opts.binary ? 1 : 0);
|
||||
int i;
|
||||
StringInfoData buf;
|
||||
int natts = list_length(cstate->attnumlist);
|
||||
int16 format = (cstate->opts.binary ? 1 : 0);
|
||||
int i;
|
||||
|
||||
pq_beginmessage(&buf, 'G');
|
||||
pq_sendbyte(&buf, format); /* overall format */
|
||||
pq_sendint16(&buf, natts);
|
||||
for (i = 0; i < natts; i++)
|
||||
pq_sendint16(&buf, format); /* per-column formats */
|
||||
pq_endmessage(&buf);
|
||||
cstate->copy_src = COPY_NEW_FE;
|
||||
cstate->fe_msgbuf = makeStringInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* old way */
|
||||
if (cstate->opts.binary)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("COPY BINARY is not supported to stdout or from stdin")));
|
||||
pq_putemptymessage('G');
|
||||
/* any error in old protocol will make us lose sync */
|
||||
pq_startmsgread();
|
||||
cstate->copy_src = COPY_OLD_FE;
|
||||
}
|
||||
pq_beginmessage(&buf, 'G');
|
||||
pq_sendbyte(&buf, format); /* overall format */
|
||||
pq_sendint16(&buf, natts);
|
||||
for (i = 0; i < natts; i++)
|
||||
pq_sendint16(&buf, format); /* per-column formats */
|
||||
pq_endmessage(&buf);
|
||||
cstate->copy_src = COPY_FRONTEND;
|
||||
cstate->fe_msgbuf = makeStringInfo();
|
||||
/* We *must* flush here to ensure FE knows it can send. */
|
||||
pq_flush();
|
||||
}
|
||||
@ -228,25 +212,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
|
||||
if (bytesread == 0)
|
||||
cstate->reached_eof = true;
|
||||
break;
|
||||
case COPY_OLD_FE:
|
||||
|
||||
/*
|
||||
* We cannot read more than minread bytes (which in practice is 1)
|
||||
* because old protocol doesn't have any clear way of separating
|
||||
* the COPY stream from following data. This is slow, but not any
|
||||
* slower than the code path was originally, and we don't care
|
||||
* much anymore about the performance of old protocol.
|
||||
*/
|
||||
if (pq_getbytes((char *) databuf, minread))
|
||||
{
|
||||
/* Only a \. terminator is legal EOF in old protocol */
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_CONNECTION_FAILURE),
|
||||
errmsg("unexpected EOF on client connection with an open transaction")));
|
||||
}
|
||||
bytesread = minread;
|
||||
break;
|
||||
case COPY_NEW_FE:
|
||||
case COPY_FRONTEND:
|
||||
while (maxread > 0 && bytesread < minread && !cstate->reached_eof)
|
||||
{
|
||||
int avail;
|
||||
@ -619,21 +585,16 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
|
||||
if (fld_count == -1)
|
||||
{
|
||||
/*
|
||||
* Received EOF marker. In a V3-protocol copy, wait for the
|
||||
* protocol-level EOF, and complain if it doesn't come
|
||||
* immediately. This ensures that we correctly handle CopyFail,
|
||||
* if client chooses to send that now.
|
||||
*
|
||||
* Note that we MUST NOT try to read more data in an old-protocol
|
||||
* copy, since there is no protocol-level EOF marker then. We
|
||||
* could go either way for copy from file, but choose to throw
|
||||
* error if there's data after the EOF marker, for consistency
|
||||
* with the new-protocol case.
|
||||
* Received EOF marker. Wait for the protocol-level EOF, and
|
||||
* complain if it doesn't come immediately. In COPY FROM STDIN,
|
||||
* this ensures that we correctly handle CopyFail, if client
|
||||
* chooses to send that now. When copying from file, we could
|
||||
* ignore the rest of the file like in text mode, but we choose to
|
||||
* be consistent with the COPY FROM STDIN case.
|
||||
*/
|
||||
char dummy;
|
||||
|
||||
if (cstate->copy_src != COPY_OLD_FE &&
|
||||
CopyReadBinaryData(cstate, &dummy, 1) > 0)
|
||||
if (CopyReadBinaryData(cstate, &dummy, 1) > 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
||||
errmsg("received copy data after EOF marker")));
|
||||
@ -712,7 +673,7 @@ CopyReadLine(CopyFromState cstate)
|
||||
* after \. up to the protocol end of copy data. (XXX maybe better
|
||||
* not to treat \. as special?)
|
||||
*/
|
||||
if (cstate->copy_src == COPY_NEW_FE)
|
||||
if (cstate->copy_src == COPY_FRONTEND)
|
||||
{
|
||||
do
|
||||
{
|
||||
|
@ -50,8 +50,7 @@
|
||||
typedef enum CopyDest
|
||||
{
|
||||
COPY_FILE, /* to file (or a piped program) */
|
||||
COPY_OLD_FE, /* to frontend (2.0 protocol) */
|
||||
COPY_NEW_FE, /* to frontend (3.0 protocol) */
|
||||
COPY_FRONTEND, /* to frontend */
|
||||
} CopyDest;
|
||||
|
||||
/*
|
||||
@ -116,7 +115,6 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
|
||||
/* non-export function prototypes */
|
||||
static void EndCopy(CopyToState cstate);
|
||||
static void ClosePipeToProgram(CopyToState cstate);
|
||||
static uint64 CopyTo(CopyToState cstate);
|
||||
static void CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot);
|
||||
static void CopyAttributeOutText(CopyToState cstate, char *string);
|
||||
static void CopyAttributeOutCSV(CopyToState cstate, char *string,
|
||||
@ -140,53 +138,27 @@ static void CopySendInt16(CopyToState cstate, int16 val);
|
||||
static void
|
||||
SendCopyBegin(CopyToState cstate)
|
||||
{
|
||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
|
||||
{
|
||||
/* new way */
|
||||
StringInfoData buf;
|
||||
int natts = list_length(cstate->attnumlist);
|
||||
int16 format = (cstate->opts.binary ? 1 : 0);
|
||||
int i;
|
||||
StringInfoData buf;
|
||||
int natts = list_length(cstate->attnumlist);
|
||||
int16 format = (cstate->opts.binary ? 1 : 0);
|
||||
int i;
|
||||
|
||||
pq_beginmessage(&buf, 'H');
|
||||
pq_sendbyte(&buf, format); /* overall format */
|
||||
pq_sendint16(&buf, natts);
|
||||
for (i = 0; i < natts; i++)
|
||||
pq_sendint16(&buf, format); /* per-column formats */
|
||||
pq_endmessage(&buf);
|
||||
cstate->copy_dest = COPY_NEW_FE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* old way */
|
||||
if (cstate->opts.binary)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("COPY BINARY is not supported to stdout or from stdin")));
|
||||
pq_putemptymessage('H');
|
||||
/* grottiness needed for old COPY OUT protocol */
|
||||
pq_startcopyout();
|
||||
cstate->copy_dest = COPY_OLD_FE;
|
||||
}
|
||||
pq_beginmessage(&buf, 'H');
|
||||
pq_sendbyte(&buf, format); /* overall format */
|
||||
pq_sendint16(&buf, natts);
|
||||
for (i = 0; i < natts; i++)
|
||||
pq_sendint16(&buf, format); /* per-column formats */
|
||||
pq_endmessage(&buf);
|
||||
cstate->copy_dest = COPY_FRONTEND;
|
||||
}
|
||||
|
||||
static void
|
||||
SendCopyEnd(CopyToState cstate)
|
||||
{
|
||||
if (cstate->copy_dest == COPY_NEW_FE)
|
||||
{
|
||||
/* Shouldn't have any unsent data */
|
||||
Assert(cstate->fe_msgbuf->len == 0);
|
||||
/* Send Copy Done message */
|
||||
pq_putemptymessage('c');
|
||||
}
|
||||
else
|
||||
{
|
||||
CopySendData(cstate, "\\.", 2);
|
||||
/* Need to flush out the trailer (this also appends a newline) */
|
||||
CopySendEndOfRow(cstate);
|
||||
pq_endcopyout(false);
|
||||
}
|
||||
/* Shouldn't have any unsent data */
|
||||
Assert(cstate->fe_msgbuf->len == 0);
|
||||
/* Send Copy Done message */
|
||||
pq_putemptymessage('c');
|
||||
}
|
||||
|
||||
/*----------
|
||||
@ -268,20 +240,7 @@ CopySendEndOfRow(CopyToState cstate)
|
||||
errmsg("could not write to COPY file: %m")));
|
||||
}
|
||||
break;
|
||||
case COPY_OLD_FE:
|
||||
/* The FE/BE protocol uses \n as newline for all platforms */
|
||||
if (!cstate->opts.binary)
|
||||
CopySendChar(cstate, '\n');
|
||||
|
||||
if (pq_putbytes(fe_msgbuf->data, fe_msgbuf->len))
|
||||
{
|
||||
/* no hope of recovering connection sync, so FATAL */
|
||||
ereport(FATAL,
|
||||
(errcode(ERRCODE_CONNECTION_FAILURE),
|
||||
errmsg("connection lost during COPY to stdout")));
|
||||
}
|
||||
break;
|
||||
case COPY_NEW_FE:
|
||||
case COPY_FRONTEND:
|
||||
/* The FE/BE protocol uses \n as newline for all platforms */
|
||||
if (!cstate->opts.binary)
|
||||
CopySendChar(cstate, '\n');
|
||||
@ -779,42 +738,6 @@ BeginCopyTo(ParseState *pstate,
|
||||
return cstate;
|
||||
}
|
||||
|
||||
/*
|
||||
* This intermediate routine exists mainly to localize the effects of setjmp
|
||||
* so we don't need to plaster a lot of variables with "volatile".
|
||||
*/
|
||||
uint64
|
||||
DoCopyTo(CopyToState cstate)
|
||||
{
|
||||
bool pipe = (cstate->filename == NULL);
|
||||
bool fe_copy = (pipe && whereToSendOutput == DestRemote);
|
||||
uint64 processed;
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
if (fe_copy)
|
||||
SendCopyBegin(cstate);
|
||||
|
||||
processed = CopyTo(cstate);
|
||||
|
||||
if (fe_copy)
|
||||
SendCopyEnd(cstate);
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
/*
|
||||
* Make sure we turn off old-style COPY OUT mode upon error. It is
|
||||
* okay to do this in all cases, since it does nothing if the mode is
|
||||
* not on.
|
||||
*/
|
||||
pq_endcopyout(true);
|
||||
PG_RE_THROW();
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up storage and release resources for COPY TO.
|
||||
*/
|
||||
@ -837,14 +760,19 @@ EndCopyTo(CopyToState cstate)
|
||||
/*
|
||||
* Copy from relation or query TO file.
|
||||
*/
|
||||
static uint64
|
||||
CopyTo(CopyToState cstate)
|
||||
uint64
|
||||
DoCopyTo(CopyToState cstate)
|
||||
{
|
||||
bool pipe = (cstate->filename == NULL);
|
||||
bool fe_copy = (pipe && whereToSendOutput == DestRemote);
|
||||
TupleDesc tupDesc;
|
||||
int num_phys_attrs;
|
||||
ListCell *cur;
|
||||
uint64 processed;
|
||||
|
||||
if (fe_copy)
|
||||
SendCopyBegin(cstate);
|
||||
|
||||
if (cstate->rel)
|
||||
tupDesc = RelationGetDescr(cstate->rel);
|
||||
else
|
||||
@ -977,11 +905,14 @@ CopyTo(CopyToState cstate)
|
||||
|
||||
MemoryContextDelete(cstate->rowcontext);
|
||||
|
||||
if (fe_copy)
|
||||
SendCopyEnd(cstate);
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit one row during CopyTo().
|
||||
* Emit one row during DoCopyTo().
|
||||
*/
|
||||
static void
|
||||
CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
|
||||
|
Reference in New Issue
Block a user