1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-25 20:23:07 +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:
Heikki Linnakangas
2021-03-04 10:45:55 +02:00
parent 0a687c8f10
commit 3174d69fb9
33 changed files with 301 additions and 3112 deletions

View File

@@ -27,16 +27,9 @@
static void printtup_startup(DestReceiver *self, int operation,
TupleDesc typeinfo);
static bool printtup(TupleTableSlot *slot, DestReceiver *self);
static bool printtup_20(TupleTableSlot *slot, DestReceiver *self);
static bool printtup_internal_20(TupleTableSlot *slot, DestReceiver *self);
static void printtup_shutdown(DestReceiver *self);
static void printtup_destroy(DestReceiver *self);
static void SendRowDescriptionCols_2(StringInfo buf, TupleDesc typeinfo,
List *targetlist, int16 *formats);
static void SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo,
List *targetlist, int16 *formats);
/* ----------------------------------------------------------------
* printtup / debugtup support
* ----------------------------------------------------------------
@@ -112,19 +105,6 @@ SetRemoteDestReceiverParams(DestReceiver *self, Portal portal)
myState->pub.mydest == DestRemoteExecute);
myState->portal = portal;
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
{
/*
* In protocol 2.0 the Bind message does not exist, so there is no way
* for the columns to have different print formats; it's sufficient to
* look at the first one.
*/
if (portal->formats && portal->formats[0] != 0)
myState->pub.receiveSlot = printtup_internal_20;
else
myState->pub.receiveSlot = printtup_20;
}
}
static void
@@ -149,21 +129,6 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
"printtup",
ALLOCSET_DEFAULT_SIZES);
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
{
/*
* Send portal name to frontend (obsolete cruft, gone in proto 3.0)
*
* If portal name not specified, use "blank" portal.
*/
const char *portalName = portal->name;
if (portalName == NULL || portalName[0] == '\0')
portalName = "blank";
pq_puttextmessage('P', portalName);
}
/*
* If we are supposed to emit row descriptions, then send the tuple
* descriptor of the tuples.
@@ -202,31 +167,14 @@ SendRowDescriptionMessage(StringInfo buf, TupleDesc typeinfo,
List *targetlist, int16 *formats)
{
int natts = typeinfo->natts;
int proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
int i;
ListCell *tlist_item = list_head(targetlist);
/* tuple descriptor message type */
pq_beginmessage_reuse(buf, 'T');
/* # of attrs in tuples */
pq_sendint16(buf, natts);
if (proto >= 3)
SendRowDescriptionCols_3(buf, typeinfo, targetlist, formats);
else
SendRowDescriptionCols_2(buf, typeinfo, targetlist, formats);
pq_endmessage_reuse(buf);
}
/*
* Send description for each column when using v3+ protocol
*/
static void
SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo, List *targetlist, int16 *formats)
{
int natts = typeinfo->natts;
int i;
ListCell *tlist_item = list_head(targetlist);
/*
* Preallocate memory for the entire message to be sent. That allows to
* use the significantly faster inline pqformat.h functions and to avoid
@@ -291,33 +239,8 @@ SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo, List *targetlist, i
pq_writeint32(buf, atttypmod);
pq_writeint16(buf, format);
}
}
/*
* Send description for each column when using v2 protocol
*/
static void
SendRowDescriptionCols_2(StringInfo buf, TupleDesc typeinfo, List *targetlist, int16 *formats)
{
int natts = typeinfo->natts;
int i;
for (i = 0; i < natts; ++i)
{
Form_pg_attribute att = TupleDescAttr(typeinfo, i);
Oid atttypid = att->atttypid;
int32 atttypmod = att->atttypmod;
/* If column is a domain, send the base type and typmod instead */
atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
pq_sendstring(buf, NameStr(att->attname));
/* column ID only info appears in protocol 3.0 and up */
pq_sendint32(buf, atttypid);
pq_sendint16(buf, att->attlen);
pq_sendint32(buf, atttypmod);
/* format info only appears in protocol 3.0 and up */
}
pq_endmessage_reuse(buf);
}
/*
@@ -371,7 +294,7 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
}
/* ----------------
* printtup --- print a tuple in protocol 3.0
* printtup --- send a tuple to the client
* ----------------
*/
static bool
@@ -455,84 +378,6 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
return true;
}
/* ----------------
* printtup_20 --- print a tuple in protocol 2.0
* ----------------
*/
static bool
printtup_20(TupleTableSlot *slot, DestReceiver *self)
{
TupleDesc typeinfo = slot->tts_tupleDescriptor;
DR_printtup *myState = (DR_printtup *) self;
MemoryContext oldcontext;
StringInfo buf = &myState->buf;
int natts = typeinfo->natts;
int i,
j,
k;
/* Set or update my derived attribute info, if needed */
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
printtup_prepare_info(myState, typeinfo, natts);
/* Make sure the tuple is fully deconstructed */
slot_getallattrs(slot);
/* Switch into per-row context so we can recover memory below */
oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
/*
* tell the frontend to expect new tuple data (in ASCII style)
*/
pq_beginmessage_reuse(buf, 'D');
/*
* send a bitmap of which attributes are not null
*/
j = 0;
k = 1 << 7;
for (i = 0; i < natts; ++i)
{
if (!slot->tts_isnull[i])
j |= k; /* set bit if not null */
k >>= 1;
if (k == 0) /* end of byte? */
{
pq_sendint8(buf, j);
j = 0;
k = 1 << 7;
}
}
if (k != (1 << 7)) /* flush last partial byte */
pq_sendint8(buf, j);
/*
* send the attributes of this tuple
*/
for (i = 0; i < natts; ++i)
{
PrinttupAttrInfo *thisState = myState->myinfo + i;
Datum attr = slot->tts_values[i];
char *outputstr;
if (slot->tts_isnull[i])
continue;
Assert(thisState->format == 0);
outputstr = OutputFunctionCall(&thisState->finfo, attr);
pq_sendcountedtext(buf, outputstr, strlen(outputstr), true);
}
pq_endmessage_reuse(buf);
/* Return to caller's context, and flush row's temporary memory */
MemoryContextSwitchTo(oldcontext);
MemoryContextReset(myState->tmpcontext);
return true;
}
/* ----------------
* printtup_shutdown
* ----------------
@@ -638,88 +483,3 @@ debugtup(TupleTableSlot *slot, DestReceiver *self)
return true;
}
/* ----------------
* printtup_internal_20 --- print a binary tuple in protocol 2.0
*
* We use a different message type, i.e. 'B' instead of 'D' to
* indicate a tuple in internal (binary) form.
*
* This is largely same as printtup_20, except we use binary formatting.
* ----------------
*/
static bool
printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
{
TupleDesc typeinfo = slot->tts_tupleDescriptor;
DR_printtup *myState = (DR_printtup *) self;
MemoryContext oldcontext;
StringInfo buf = &myState->buf;
int natts = typeinfo->natts;
int i,
j,
k;
/* Set or update my derived attribute info, if needed */
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
printtup_prepare_info(myState, typeinfo, natts);
/* Make sure the tuple is fully deconstructed */
slot_getallattrs(slot);
/* Switch into per-row context so we can recover memory below */
oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
/*
* tell the frontend to expect new tuple data (in binary style)
*/
pq_beginmessage_reuse(buf, 'B');
/*
* send a bitmap of which attributes are not null
*/
j = 0;
k = 1 << 7;
for (i = 0; i < natts; ++i)
{
if (!slot->tts_isnull[i])
j |= k; /* set bit if not null */
k >>= 1;
if (k == 0) /* end of byte? */
{
pq_sendint8(buf, j);
j = 0;
k = 1 << 7;
}
}
if (k != (1 << 7)) /* flush last partial byte */
pq_sendint8(buf, j);
/*
* send the attributes of this tuple
*/
for (i = 0; i < natts; ++i)
{
PrinttupAttrInfo *thisState = myState->myinfo + i;
Datum attr = slot->tts_values[i];
bytea *outputbytes;
if (slot->tts_isnull[i])
continue;
Assert(thisState->format == 1);
outputbytes = SendFunctionCall(&thisState->finfo, attr);
pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
pq_sendbytes(buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ);
}
pq_endmessage_reuse(buf);
/* Return to caller's context, and flush row's temporary memory */
MemoryContextSwitchTo(oldcontext);
MemoryContextReset(myState->tmpcontext);
return true;
}