Commit 3174d69f authored by Heikki Linnakangas's avatar Heikki Linnakangas

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
parent 0a687c8f
......@@ -2274,20 +2274,6 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName);
cannot change after startup.
</para>
<para>
Pre-3.0-protocol servers do not report parameter settings, but
<application>libpq</application> includes logic to obtain values for
<varname>server_version</varname> and <varname>client_encoding</varname> anyway.
Applications are encouraged to use <xref linkend="libpq-PQparameterStatus"/>
rather than <foreignphrase>ad hoc</foreignphrase> code to determine these values.
(Beware however that on a pre-3.0 connection, changing
<varname>client_encoding</varname> via <command>SET</command> after connection
startup will not be reflected by <xref linkend="libpq-PQparameterStatus"/>.)
For <varname>server_version</varname>, see also
<xref linkend="libpq-PQserverVersion"/>, which returns the information in a
numeric form that is much easier to compare against.
</para>
<para>
If no value for <varname>standard_conforming_strings</varname> is reported,
applications can assume it is <literal>off</literal>, that is, backslashes
......@@ -2314,15 +2300,12 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName);
int PQprotocolVersion(const PGconn *conn);
</synopsis>
Applications might wish to use this function to determine whether certain
features are supported. Currently, the possible values are 2 (2.0
protocol), 3 (3.0 protocol), or zero (connection bad). The
protocol version will
features are supported. Currently, the possible values are 3
(3.0 protocol), or zero (connection bad). The protocol version will
not change after connection startup is complete, but it could
theoretically change during a connection reset. The 3.0 protocol
will normally be used when communicating with
<productname>PostgreSQL</productname> 7.4 or later servers; pre-7.4 servers
support only protocol 2.0. (Protocol 1.0 is obsolete and not
supported by <application>libpq</application>.)
theoretically change during a connection reset. The 3.0 protocol is
supported by <productname>PostgreSQL</productname> server versions 7.4
and above.
</para>
</listitem>
</varlistentry>
......@@ -2739,8 +2722,7 @@ PGresult *PQexecParams(PGconn *conn,
<xref linkend="libpq-PQexecParams"/> is like <xref linkend="libpq-PQexec"/>, but offers additional
functionality: parameter values can be specified separately from the command
string proper, and query results can be requested in either text or binary
format. <xref linkend="libpq-PQexecParams"/> is supported only in protocol 3.0 and later
connections; it will fail when using protocol 2.0.
format.
</para>
<para>
......@@ -2917,8 +2899,6 @@ PGresult *PQprepare(PGconn *conn,
execution with <xref linkend="libpq-PQexecPrepared"/>. This feature allows
commands to be executed repeatedly without being parsed and
planned each time; see <xref linkend="sql-prepare"/> for details.
<xref linkend="libpq-PQprepare"/> is supported only in protocol 3.0 and later
connections; it will fail when using protocol 2.0.
</para>
<para>
......@@ -2992,9 +2972,7 @@ PGresult *PQexecPrepared(PGconn *conn,
This feature allows commands that will be used repeatedly to be
parsed and planned just once, rather than each time they are
executed. The statement must have been prepared previously in
the current session. <xref linkend="libpq-PQexecPrepared"/> is supported
only in protocol 3.0 and later connections; it will fail when
using protocol 2.0.
the current session.
</para>
<para>
......@@ -3021,8 +2999,6 @@ PGresult *PQdescribePrepared(PGconn *conn, const char *stmtName);
<para>
<xref linkend="libpq-PQdescribePrepared"/> allows an application to obtain
information about a previously prepared statement.
<xref linkend="libpq-PQdescribePrepared"/> is supported only in protocol 3.0
and later connections; it will fail when using protocol 2.0.
</para>
<para>
......@@ -3059,8 +3035,6 @@ PGresult *PQdescribePortal(PGconn *conn, const char *portalName);
(<application>libpq</application> does not provide any direct access to
portals, but you can use this function to inspect the properties
of a cursor created with a <command>DECLARE CURSOR</command> SQL command.)
<xref linkend="libpq-PQdescribePortal"/> is supported only in protocol 3.0
and later connections; it will fail when using protocol 2.0.
</para>
<para>
......@@ -3566,8 +3540,6 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
<para>
Errors generated internally by <application>libpq</application> will
have severity and primary message, but typically no other fields.
Errors returned by a pre-3.0-protocol server will include severity and
primary message, and sometimes a detail message, but no other fields.
</para>
<para>
......@@ -3728,8 +3700,7 @@ Oid PQftable(const PGresult *res,
<para>
<literal>InvalidOid</literal> is returned if the column number is out of range,
or if the specified column is not a simple reference to a table column,
or when using pre-3.0 protocol.
or if the specified column is not a simple reference to a table column.
You can query the system table <literal>pg_class</literal> to determine
exactly which table is referenced.
</para>
......@@ -3759,8 +3730,7 @@ int PQftablecol(const PGresult *res,
<para>
Zero is returned if the column number is out of range, or if the
specified column is not a simple reference to a table column, or
when using pre-3.0 protocol.
specified column is not a simple reference to a table column.
</para>
</listitem>
</varlistentry>
......@@ -4593,8 +4563,8 @@ int PQsendQueryParams(PGconn *conn,
query parameters can be specified separately from the query string.
The function's parameters are handled identically to
<xref linkend="libpq-PQexecParams"/>. Like
<xref linkend="libpq-PQexecParams"/>, it will not work on 2.0-protocol
connections, and it allows only one command in the query string.
<xref linkend="libpq-PQexecParams"/>, it allows only one command in the
query string.
</para>
</listitem>
</varlistentry>
......@@ -4619,9 +4589,7 @@ int PQsendPrepare(PGconn *conn,
After a successful call, call <xref linkend="libpq-PQgetResult"/> to
determine whether the server successfully created the prepared
statement. The function's parameters are handled identically to
<xref linkend="libpq-PQprepare"/>. Like
<xref linkend="libpq-PQprepare"/>, it will not work on 2.0-protocol
connections.
<xref linkend="libpq-PQprepare"/>.
</para>
</listitem>
</varlistentry>
......@@ -4647,9 +4615,7 @@ int PQsendQueryPrepared(PGconn *conn,
the command to be executed is specified by naming a
previously-prepared statement, instead of giving a query string.
The function's parameters are handled identically to
<xref linkend="libpq-PQexecPrepared"/>. Like
<xref linkend="libpq-PQexecPrepared"/>, it will not work on
2.0-protocol connections.
<xref linkend="libpq-PQexecPrepared"/>.
</para>
</listitem>
</varlistentry>
......@@ -4669,9 +4635,7 @@ int PQsendDescribePrepared(PGconn *conn, const char *stmtName);
it returns 1 if it was able to dispatch the request, and 0 if not.
After a successful call, call <xref linkend="libpq-PQgetResult"/> to
obtain the results. The function's parameters are handled
identically to <xref linkend="libpq-PQdescribePrepared"/>. Like
<xref linkend="libpq-PQdescribePrepared"/>, it will not work on
2.0-protocol connections.
identically to <xref linkend="libpq-PQdescribePrepared"/>.
</para>
</listitem>
</varlistentry>
......@@ -4691,9 +4655,7 @@ int PQsendDescribePortal(PGconn *conn, const char *portalName);
it returns 1 if it was able to dispatch the request, and 0 if not.
After a successful call, call <xref linkend="libpq-PQgetResult"/> to
obtain the results. The function's parameters are handled
identically to <xref linkend="libpq-PQdescribePortal"/>. Like
<xref linkend="libpq-PQdescribePortal"/>, it will not work on
2.0-protocol connections.
identically to <xref linkend="libpq-PQdescribePortal"/>.
</para>
</listitem>
</varlistentry>
......@@ -5460,13 +5422,6 @@ typedef struct pgNotify
</variablelist>
</para>
<note>
<para>
These additional data values are only available when using protocol
3.0. When using protocol 2.0, all these functions will return 0.
</para>
</note>
<sect2 id="libpq-copy-send">
<title>Functions for Sending <command>COPY</command> Data</title>
......@@ -5531,9 +5486,7 @@ int PQputCopyEnd(PGconn *conn,
<parameter>errormsg</parameter> used as the error message. (One should not
assume that this exact error message will come back from the server,
however, as the server might have already failed the
<command>COPY</command> for its own reasons. Also note that the option
to force failure does not work when using pre-3.0-protocol
connections.)
<command>COPY</command> for its own reasons.)
</para>
<para>
......
......@@ -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;
}
......@@ -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;
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;
}
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_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;
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;
}
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_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)
......
......@@ -653,35 +653,26 @@ static char *
recv_password_packet(Port *port)
{
StringInfoData buf;
int mtype;
pq_startmsgread();
if (PG_PROTOCOL_MAJOR(port->proto) >= 3)
{
/* Expect 'p' message type */
int mtype;
mtype = pq_getbyte();
if (mtype != 'p')
{
/*
* If the client just disconnects without offering a password,
* don't make a log entry. This is legal per protocol spec and in
* fact commonly done by psql, so complaining just clutters the
* log.
*/
if (mtype != EOF)
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("expected password response, got message type %d",
mtype)));
return NULL; /* EOF or bad message type */
}
}
else
/* Expect 'p' message type */
mtype = pq_getbyte();
if (mtype != 'p')
{
/* For pre-3.0 clients, avoid log entry if they just disconnect */
if (pq_peekbyte() == EOF)
return NULL; /* EOF */
/*
* If the client just disconnects without offering a password,
* don't make a log entry. This is legal per protocol spec and in
* fact commonly done by psql, so complaining just clutters the
* log.
*/
if (mtype != EOF)
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("expected password response, got message type %d",
mtype)));
return NULL; /* EOF or bad message type */
}
initStringInfo(&buf);
......@@ -879,19 +870,6 @@ CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail)
int result;
bool initial;
/*
* SASL auth is not supported for protocol versions before 3, because it
* relies on the overall message length word to determine the SASL payload
* size in AuthenticationSASLContinue and PasswordMessage messages. (We
* used to have a hard rule that protocol messages must be parsable
* without relying on the length word, but we hardly care about older
* protocol version anymore.)
*/
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
ereport(FATAL,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SASL authentication is not supported in protocol version 2")));
/*
* Send the SASL authentication request to user. It includes the list of
* authentication mechanisms that are supported.
......@@ -1041,19 +1019,6 @@ pg_GSS_recvauth(Port *port)
StringInfoData buf;
gss_buffer_desc gbuf;
/*
* GSS auth is not supported for protocol versions before 3, because it
* relies on the overall message length word to determine the GSS payload
* size in AuthenticationGSSContinue and PasswordMessage messages. (This
* is, in fact, a design error in our GSS support, because protocol
* messages are supposed to be parsable without relying on the length
* word; but it's not worth changing it now.)
*/
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
ereport(FATAL,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("GSSAPI is not supported in protocol version 2")));
/*
* Use the configured keytab, if there is one. Unfortunately, Heimdal
* doesn't support the cred store extensions, so use the env var.
......@@ -1323,19 +1288,6 @@ pg_SSPI_recvauth(Port *port)
QUERY_SECURITY_CONTEXT_TOKEN_FN _QuerySecurityContextToken;
/*
* SSPI auth is not supported for protocol versions before 3, because it
* relies on the overall message length word to determine the SSPI payload
* size in AuthenticationGSSContinue and PasswordMessage messages. (This
* is, in fact, a design error in our SSPI support, because protocol
* messages are supposed to be parsable without relying on the length
* word; but it's not worth changing it now.)
*/
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
ereport(FATAL,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SSPI is not supported in protocol version 2")));
/*
* Acquire a handle to the server credentials.
*/
......
This diff is collapsed.
......@@ -33,8 +33,6 @@ static int mq_flush_if_writable(void);
static bool mq_is_send_pending(void);
static int mq_putmessage(char msgtype, const char *s, size_t len);
static void mq_putmessage_noblock(char msgtype, const char *s, size_t len);
static void mq_startcopyout(void);
static void mq_endcopyout(bool errorAbort);
static const PQcommMethods PqCommMqMethods = {
mq_comm_reset,
......@@ -42,9 +40,7 @@ static const PQcommMethods PqCommMqMethods = {
mq_flush_if_writable,
mq_is_send_pending,
mq_putmessage,
mq_putmessage_noblock,
mq_startcopyout,
mq_endcopyout
mq_putmessage_noblock
};
/*
......@@ -195,18 +191,6 @@ mq_putmessage_noblock(char msgtype, const char *s, size_t len)
elog(ERROR, "not currently supported");
}
static void
mq_startcopyout(void)
{
/* Nothing to do. */
}
static void
mq_endcopyout(bool errorAbort)
{
/* Nothing to do. */
}
/*
* Parse an ErrorResponse or NoticeResponse payload and populate an ErrorData
* structure with the results.
......
......@@ -1934,7 +1934,7 @@ static int
ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
{
int32 len;
void *buf;
char *buf;
ProtocolVersion proto;
MemoryContext oldcontext;
......@@ -1984,15 +1984,12 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
}
/*
* Allocate at least the size of an old-style startup packet, plus one
* extra byte, and make sure all are zeroes. This ensures we will have
* null termination of all strings, in both fixed- and variable-length
* packet layouts.
* Allocate space to hold the startup packet, plus one extra byte that's
* initialized to be zero. This ensures we will have null termination of
* all strings inside the packet.
*/
if (len <= (int32) sizeof(StartupPacket))
buf = palloc0(sizeof(StartupPacket) + 1);
else
buf = palloc0(len + 1);
buf = palloc(len + 1);
buf[len] = '\0';
if (pq_getbytes(buf, len) == EOF)
{
......@@ -2115,7 +2112,7 @@ retry1:
*/
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
if (PG_PROTOCOL_MAJOR(proto) >= 3)
/* Handle protocol version 3 startup packet */
{
int32 offset = sizeof(ProtocolVersion);
List *unrecognized_protocol_options = NIL;
......@@ -2129,7 +2126,7 @@ retry1:
while (offset < len)
{
char *nameptr = ((char *) buf) + offset;
char *nameptr = buf + offset;
int32 valoffset;
char *valptr;
......@@ -2138,7 +2135,7 @@ retry1:
valoffset = offset + strlen(nameptr) + 1;
if (valoffset >= len)
break; /* missing value, will complain below */
valptr = ((char *) buf) + valoffset;
valptr = buf + valoffset;
if (strcmp(nameptr, "database") == 0)
port->database_name = pstrdup(valptr);
......@@ -2223,27 +2220,6 @@ retry1:
unrecognized_protocol_options != NIL)
SendNegotiateProtocolVersion(unrecognized_protocol_options);
}
else
{
/*
* Get the parameters from the old-style, fixed-width-fields startup
* packet as C strings. The packet destination was cleared first so a
* short packet has zeros silently added. We have to be prepared to
* truncate the pstrdup result for oversize fields, though.
*/
StartupPacket *packet = (StartupPacket *) buf;
port->database_name = pstrdup(packet->database);
if (strlen(port->database_name) > sizeof(packet->database))
port->database_name[sizeof(packet->database)] = '\0';
port->user_name = pstrdup(packet->user);
if (strlen(port->user_name) > sizeof(packet->user))
port->user_name[sizeof(packet->user)] = '\0';
port->cmdline_options = pstrdup(packet->options);
if (strlen(port->cmdline_options) > sizeof(packet->options))
port->cmdline_options[sizeof(packet->options)] = '\0';
port->guc_options = NIL;
}
/* Check a user name was given. */
if (port->user_name == NULL || port->user_name[0] == '\0')
......
......@@ -226,13 +226,8 @@ EndReplicationCommand(const char *commandTag)
/* ----------------
* NullCommand - tell dest that an empty query string was recognized
*
* In FE/BE protocol version 1.0, this hack is necessary to support
* libpq's crufty way of determining whether a multiple-command
* query string is done. In protocol 2.0 it's probably not really
* necessary to distinguish empty queries anymore, but we still do it
* for backwards compatibility with 1.0. In protocol 3.0 it has some
* use again, since it ensures that there will be a recognizable end
* to the response to an Execute message.
* This ensures that there will be a recognizable end to the response
* to an Execute message in the extended query protocol.
* ----------------
*/
void
......@@ -244,14 +239,8 @@ NullCommand(CommandDest dest)
case DestRemoteExecute:
case DestRemoteSimple:
/*
* tell the fe that we saw an empty query string. In protocols
* before 3.0 this has a useless empty-string message body.
*/
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
pq_putemptymessage('I');
else
pq_putmessage('I', "", 1);
/* Tell the FE that we saw an empty query string */
pq_putemptymessage('I');
break;
case DestNone:
......@@ -286,7 +275,6 @@ ReadyForQuery(CommandDest dest)
case DestRemote:
case DestRemoteExecute:
case DestRemoteSimple:
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
StringInfoData buf;
......@@ -294,8 +282,6 @@ ReadyForQuery(CommandDest dest)
pq_sendbyte(&buf, TransactionBlockStatusCode());
pq_endmessage(&buf);
}
else
pq_putemptymessage('Z');
/* Flush output at end of cycle in any case. */
pq_flush();
break;
......
......@@ -58,98 +58,24 @@ struct fp_info
static int16 parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
FunctionCallInfo fcinfo);
static int16 parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
FunctionCallInfo fcinfo);
/* ----------------
* GetOldFunctionMessage
*
* In pre-3.0 protocol, there is no length word on the message, so we have
* to have code that understands the message layout to absorb the message
* into a buffer. We want to do this before we start execution, so that
* we do not lose sync with the frontend if there's an error.
*
* The caller should already have initialized buf to empty.
* ----------------
*/
int
GetOldFunctionMessage(StringInfo buf)
{
int32 ibuf;
int nargs;
/* Dummy string argument */
if (pq_getstring(buf))
return EOF;
/* Function OID */
if (pq_getbytes((char *) &ibuf, 4))
return EOF;
appendBinaryStringInfo(buf, (char *) &ibuf, 4);
/* Number of arguments */
if (pq_getbytes((char *) &ibuf, 4))
return EOF;
appendBinaryStringInfo(buf, (char *) &ibuf, 4);
nargs = pg_ntoh32(ibuf);
/* For each argument ... */
while (nargs-- > 0)
{
int argsize;
/* argsize */
if (pq_getbytes((char *) &ibuf, 4))
return EOF;
appendBinaryStringInfo(buf, (char *) &ibuf, 4);
argsize = pg_ntoh32(ibuf);
if (argsize < -1)
{
/* FATAL here since no hope of regaining message sync */
ereport(FATAL,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid argument size %d in function call message",
argsize)));
}
/* and arg contents */
if (argsize > 0)
{
/* Allocate space for arg */
enlargeStringInfo(buf, argsize);
/* And grab it */
if (pq_getbytes(buf->data + buf->len, argsize))
return EOF;
buf->len += argsize;
/* Place a trailing null per StringInfo convention */
buf->data[buf->len] = '\0';
}
}
return 0;
}
/* ----------------
* SendFunctionResult
*
* Note: although this routine doesn't check, the format had better be 1
* (binary) when talking to a pre-3.0 client.
* ----------------
*/
static void
SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
{
bool newstyle = (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3);
StringInfoData buf;
pq_beginmessage(&buf, 'V');
if (isnull)
{
if (newstyle)
pq_sendint32(&buf, -1);
pq_sendint32(&buf, -1);
}
else
{
if (!newstyle)
pq_sendbyte(&buf, 'G');
if (format == 0)
{
Oid typoutput;
......@@ -180,9 +106,6 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
errmsg("unsupported format code: %d", format)));
}
if (!newstyle)
pq_sendbyte(&buf, '0');
pq_endmessage(&buf);
}
......@@ -288,9 +211,6 @@ HandleFunctionRequest(StringInfo msgBuf)
/*
* Begin parsing the buffer contents.
*/
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
(void) pq_getmsgstring(msgBuf); /* dummy string */
fid = (Oid) pq_getmsgint(msgBuf, 4); /* function oid */
/*
......@@ -334,10 +254,7 @@ HandleFunctionRequest(StringInfo msgBuf)
*/
InitFunctionCallInfoData(*fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
rformat = parse_fcall_arguments(msgBuf, fip, fcinfo);
else
rformat = parse_fcall_arguments_20(msgBuf, fip, fcinfo);
rformat = parse_fcall_arguments(msgBuf, fip, fcinfo);
/* Verify we reached the end of the message where expected. */
pq_getmsgend(msgBuf);
......@@ -533,81 +450,3 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
/* Return result format code */
return (int16) pq_getmsgint(msgBuf, 2);
}
/*
* Parse function arguments in a 2.0 protocol message
*
* Argument values are loaded into *fcinfo, and the desired result format
* is returned.
*/
static int16
parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
FunctionCallInfo fcinfo)
{
int nargs;
int i;
StringInfoData abuf;
nargs = pq_getmsgint(msgBuf, 4); /* # of arguments */
if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("function call message contains %d arguments but function requires %d",
nargs, fip->flinfo.fn_nargs)));
fcinfo->nargs = nargs;
initStringInfo(&abuf);
/*
* Copy supplied arguments into arg vector. In protocol 2.0 these are
* always assumed to be supplied in binary format.
*
* Note: although the original protocol 2.0 code did not have any way for
* the frontend to specify a NULL argument, we now choose to interpret
* length == -1 as meaning a NULL.
*/
for (i = 0; i < nargs; ++i)
{
int argsize;
Oid typreceive;
Oid typioparam;
getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
argsize = pq_getmsgint(msgBuf, 4);
if (argsize == -1)
{
fcinfo->args[i].isnull = true;
fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, NULL,
typioparam, -1);
continue;
}
fcinfo->args[i].isnull = false;
if (argsize < 0)
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid argument size %d in function call message",
argsize)));
/* Reset abuf to empty, and insert raw data into it */
resetStringInfo(&abuf);
appendBinaryStringInfo(&abuf,
pq_getmsgbytes(msgBuf, argsize),
argsize);
fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, &abuf,
typioparam, -1);
/* Trouble if it didn't eat the whole buffer */
if (abuf.cursor != abuf.len)
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("incorrect binary data format in function argument %d",
i + 1)));
}
/* Desired result format is always binary in protocol 2.0 */
return 1;
}
......@@ -370,57 +370,10 @@ SocketBackend(StringInfo inBuf)
{
case 'Q': /* simple query */
doing_extended_query_message = false;
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
{
/* old style without length word; convert */
if (pq_getstring(inBuf))
{
if (IsTransactionState())
ereport(COMMERROR,
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("unexpected EOF on client connection with an open transaction")));
else
{
/*
* Can't send DEBUG log messages to client at this
* point. Since we're disconnecting right away, we
* don't need to restore whereToSendOutput.
*/
whereToSendOutput = DestNone;
ereport(DEBUG1,
(errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST),
errmsg_internal("unexpected EOF on client connection")));
}
return EOF;
}
}
break;
case 'F': /* fastpath function call */
doing_extended_query_message = false;
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
{
if (GetOldFunctionMessage(inBuf))
{
if (IsTransactionState())
ereport(COMMERROR,
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("unexpected EOF on client connection with an open transaction")));
else
{
/*
* Can't send DEBUG log messages to client at this
* point. Since we're disconnecting right away, we
* don't need to restore whereToSendOutput.
*/
whereToSendOutput = DestNone;
ereport(DEBUG1,
(errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST),
errmsg_internal("unexpected EOF on client connection")));
}
return EOF;
}
}
break;
case 'X': /* terminate */
......@@ -435,11 +388,6 @@ SocketBackend(StringInfo inBuf)
case 'H': /* flush */
case 'P': /* parse */
doing_extended_query_message = true;
/* these are only legal in protocol 3 */
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
ereport(FATAL,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid frontend message type %d", qtype)));
break;
case 'S': /* sync */
......@@ -447,22 +395,12 @@ SocketBackend(StringInfo inBuf)
ignore_till_sync = false;
/* mark not-extended, so that a new error doesn't begin skip */
doing_extended_query_message = false;
/* only legal in protocol 3 */
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
ereport(FATAL,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid frontend message type %d", qtype)));
break;
case 'd': /* copy data */
case 'c': /* copy done */
case 'f': /* copy fail */
doing_extended_query_message = false;
/* these are only legal in protocol 3 */
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
ereport(FATAL,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid frontend message type %d", qtype)));
break;
default:
......@@ -483,13 +421,8 @@ SocketBackend(StringInfo inBuf)
* after the type code; we can read the message contents independently of
* the type.
*/
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
if (pq_getmessage(inBuf, 0))
return EOF; /* suitable message already logged */
}
else
pq_endmsgread();
if (pq_getmessage(inBuf, 0))
return EOF; /* suitable message already logged */
RESUME_CANCEL_INTERRUPTS();
return qtype;
......
......@@ -589,16 +589,6 @@ errfinish(const char *filename, int lineno, const char *funcname)
PG_RE_THROW();
}
/*
* If we are doing FATAL or PANIC, abort any old-style COPY OUT in
* progress, so that we can report the message before dying. (Without
* this, pq_putmessage will refuse to send the message at all, which is
* what we want for NOTICE messages, but not for fatal exits.) This hack
* is necessary because of poor design of old-style copy protocol.
*/
if (elevel >= FATAL && whereToSendOutput == DestRemote)
pq_endcopyout(true);
/* Emit the message to the right places */
EmitErrorReport();
......@@ -1261,28 +1251,6 @@ errhidecontext(bool hide_ctx)
return 0; /* return value does not matter */
}
/*
* errfunction --- add reporting function name to the current error
*
* This is used when backwards compatibility demands that the function
* name appear in messages sent to old-protocol clients. Note that the
* passed string is expected to be a non-freeable constant string.
*/
int
errfunction(const char *funcname)
{
ErrorData *edata = &errordata[errordata_stack_depth];
/* we don't bother incrementing recursion_depth */
CHECK_STACK_DEPTH();
edata->funcname = funcname;
edata->show_funcname = true;
return 0; /* return value does not matter */
}
/*
* errposition --- add cursor position to the current error
*/
......@@ -3291,10 +3259,14 @@ send_message_to_frontend(ErrorData *edata)
{
StringInfoData msgbuf;
/* 'N' (Notice) is for nonfatal conditions, 'E' is for errors */
pq_beginmessage(&msgbuf, (edata->elevel < ERROR) ? 'N' : 'E');
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
/*
* We no longer support pre-3.0 FE/BE protocol, except here. If a client
* tries to connect using an older protocol version, it's nice to send the
* "protocol version not supported" error in a format the client
* understands. If protocol hasn't been set yet, early in backend
* startup, assume modern protocol.
*/
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3 || FrontendProtocol == 0)
{
/* New style with separate fields */
const char *sev;
......@@ -3302,6 +3274,9 @@ send_message_to_frontend(ErrorData *edata)
int ssval;
int i;
/* 'N' (Notice) is for nonfatal conditions, 'E' is for errors */
pq_beginmessage(&msgbuf, (edata->elevel < ERROR) ? 'N' : 'E');
sev = error_severity(edata->elevel);
pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY);
err_sendstring(&msgbuf, _(sev));
......@@ -3417,6 +3392,8 @@ send_message_to_frontend(ErrorData *edata)
}
pq_sendbyte(&msgbuf, '\0'); /* terminator */
pq_endmessage(&msgbuf);
}
else
{
......@@ -3427,30 +3404,19 @@ send_message_to_frontend(ErrorData *edata)
appendStringInfo(&buf, "%s: ", _(error_severity(edata->elevel)));
if (edata->show_funcname && edata->funcname)
appendStringInfo(&buf, "%s: ", edata->funcname);
if (edata->message)
appendStringInfoString(&buf, edata->message);
else
appendStringInfoString(&buf, _("missing error text"));
if (edata->cursorpos > 0)
appendStringInfo(&buf, _(" at character %d"),
edata->cursorpos);
else if (edata->internalpos > 0)
appendStringInfo(&buf, _(" at character %d"),
edata->internalpos);
appendStringInfoChar(&buf, '\n');
err_sendstring(&msgbuf, buf.data);
/* 'N' (Notice) is for nonfatal conditions, 'E' is for errors */
pq_putmessage_v2((edata->elevel < ERROR) ? 'N' : 'E', buf.data, buf.len + 1);
pfree(buf.data);
}
pq_endmessage(&msgbuf);
/*
* This flush is normally not necessary, since postgres.c will flush out
* waiting data when control returns to the main loop. But it seems best
......
......@@ -6306,11 +6306,9 @@ BeginReportingGUCOptions(void)
int i;
/*
* Don't do anything unless talking to an interactive frontend of protocol
* 3.0 or later.
* Don't do anything unless talking to an interactive frontend.
*/
if (whereToSendOutput != DestRemote ||
PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
if (whereToSendOutput != DestRemote)
return;
reporting_enabled = true;
......
......@@ -2154,9 +2154,6 @@ is_select_command(const char *query)
/*
* Test if the current user is a database superuser.
*
* Note: this will correctly detect superuserness only with a protocol-3.0
* or newer backend; otherwise it will always say "false".
*/
bool
is_superuser(void)
......@@ -2177,9 +2174,6 @@ is_superuser(void)
/*
* Test if the current session uses standard string literals.
*
* Note: With a pre-protocol-3.0 connection this will always say "false",
* which should be the right answer.
*/
bool
standard_strings(void)
......@@ -2200,10 +2194,6 @@ standard_strings(void)
/*
* Return the session user of the current connection.
*
* Note: this will correctly detect the session user only with a
* protocol-3.0 or newer backend; otherwise it will return the
* connection user.
*/
const char *
session_username(void)
......
......@@ -662,7 +662,9 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
/*
* Terminate data transfer. We can't send an error message if we're using
* protocol version 2.
* protocol version 2. (libpq no longer supports protocol version 2, but
* keep the version checks just in case you're using a pre-v14 libpq.so at
* runtime)
*/
if (PQputCopyEnd(conn,
(OK || PQprotocolVersion(conn) < 3) ? NULL :
......
......@@ -24,8 +24,7 @@
typedef enum CopySource
{
COPY_FILE, /* from file (or a piped program) */
COPY_OLD_FE, /* from frontend (2.0 protocol) */
COPY_NEW_FE, /* from frontend (3.0 protocol) */
COPY_FRONTEND, /* from frontend */
COPY_CALLBACK /* from callback function */
} CopySource;
......
......@@ -29,8 +29,6 @@ typedef struct
bool (*is_send_pending) (void);
int (*putmessage) (char msgtype, const char *s, size_t len);
void (*putmessage_noblock) (char msgtype, const char *s, size_t len);
void (*startcopyout) (void);
void (*endcopyout) (bool errorAbort);
} PQcommMethods;
extern const PGDLLIMPORT PQcommMethods *PqCommMethods;
......@@ -43,8 +41,6 @@ extern const PGDLLIMPORT PQcommMethods *PqCommMethods;
(PqCommMethods->putmessage(msgtype, s, len))
#define pq_putmessage_noblock(msgtype, s, len) \
(PqCommMethods->putmessage_noblock(msgtype, s, len))
#define pq_startcopyout() (PqCommMethods->startcopyout())
#define pq_endcopyout(errorAbort) (PqCommMethods->endcopyout(errorAbort))
/*
* External functions.
......@@ -67,7 +63,6 @@ extern void TouchSocketFiles(void);
extern void RemoveSocketFiles(void);
extern void pq_init(void);
extern int pq_getbytes(char *s, size_t len);
extern int pq_getstring(StringInfo s);
extern void pq_startmsgread(void);
extern void pq_endmsgread(void);
extern bool pq_is_reading_msg(void);
......@@ -75,7 +70,7 @@ extern int pq_getmessage(StringInfo s, int maxlen);
extern int pq_getbyte(void);
extern int pq_peekbyte(void);
extern int pq_getbyte_if_available(unsigned char *c);
extern int pq_putbytes(const char *s, size_t len);
extern int pq_putmessage_v2(char msgtype, const char *s, size_t len);
/*
* prototypes for functions in be-secure.c
......
......@@ -114,9 +114,12 @@ is_unixsock_path(const char *path)
#define PG_PROTOCOL_MINOR(v) ((v) & 0x0000ffff)
#define PG_PROTOCOL(m,n) (((m) << 16) | (n))
/* The earliest and latest frontend/backend protocol version supported. */
/*
* The earliest and latest frontend/backend protocol version supported.
* (Only protocol version 3 is currently supported)
*/
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(2,0)
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(3,0)
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,0)
typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
......@@ -132,32 +135,6 @@ typedef ProtocolVersion MsgType;
typedef uint32 PacketLen;
/*
* Old-style startup packet layout with fixed-width fields. This is used in
* protocol 1.0 and 2.0, but not in later versions. Note that the fields
* in this layout are '\0' terminated only if there is room.
*/
#define SM_DATABASE 64
#define SM_USER 32
/* We append database name if db_user_namespace true. */
#define SM_DATABASE_USER (SM_DATABASE+SM_USER+1) /* +1 for @ */
#define SM_OPTIONS 64
#define SM_UNUSED 64
#define SM_TTY 64
typedef struct StartupPacket
{
ProtocolVersion protoVersion; /* Protocol version */
char database[SM_DATABASE]; /* Database name */
/* Db_user_namespace appends dbname */
char user[SM_USER]; /* User name */
char options[SM_OPTIONS]; /* Optional additional args */
char unused[SM_UNUSED]; /* Unused */
char tty[SM_TTY]; /* Tty for debug output */
} StartupPacket;
extern bool Db_user_namespace;
/*
......
......@@ -15,7 +15,6 @@
#include "lib/stringinfo.h"
extern int GetOldFunctionMessage(StringInfo buf);
extern void HandleFunctionRequest(StringInfo msgBuf);
#endif /* FASTPATH_H */
......@@ -207,7 +207,6 @@ extern int errhidecontext(bool hide_ctx);
extern int errbacktrace(void);
extern int errfunction(const char *funcname);
extern int errposition(int cursorpos);
extern int internalerrposition(int cursorpos);
......@@ -367,7 +366,6 @@ typedef struct ErrorData
int elevel; /* error level */
bool output_to_server; /* will report to server log? */
bool output_to_client; /* will report to client? */
bool show_funcname; /* true to force funcname inclusion */
bool hide_stmt; /* true to prevent STATEMENT: inclusion */
bool hide_ctx; /* true to prevent CONTEXT: inclusion */
const char *filename; /* __FILE__ of ereport() call */
......
......@@ -37,7 +37,6 @@ OBJS = \
fe-lobj.o \
fe-misc.o \
fe-print.o \
fe-protocol2.o \
fe-protocol3.o \
fe-secure.o \
legacy-pqsignal.o \
......
......@@ -579,7 +579,7 @@ pg_SASL_init(PGconn *conn, int payloadlen)
/*
* Build a SASLInitialResponse message, and send it.
*/
if (pqPutMsgStart('p', true, conn))
if (pqPutMsgStart('p', conn))
goto error;
if (pqPuts(selected_mechanism, conn))
goto error;
......@@ -798,11 +798,7 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
default:
return STATUS_ERROR;
}
/* Packet has a message type as of protocol 3.0 */
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
else
ret = pqPacketSend(conn, 0, pwd_to_send, strlen(pwd_to_send) + 1);
ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
if (crypt_pwd)
free(crypt_pwd);
return ret;
......
......@@ -2289,10 +2289,6 @@ PQconnectPoll(PGconn *conn)
case CONNECTION_MADE:
break;
/* We allow pqSetenvPoll to decide whether to proceed. */
case CONNECTION_SETENV:
break;
/* Special cases: proceed without waiting. */
case CONNECTION_SSL_STARTUP:
case CONNECTION_NEEDED:
......@@ -2956,12 +2952,8 @@ keep_going: /* We will come back to here until there is
/*
* Build the startup packet.
*/
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
startpacket = pqBuildStartupPacket3(conn, &packetlen,
EnvironmentOptions);
else
startpacket = pqBuildStartupPacket2(conn, &packetlen,
EnvironmentOptions);
startpacket = pqBuildStartupPacket3(conn, &packetlen,
EnvironmentOptions);
if (!startpacket)
{
appendPQExpBufferStr(&conn->errorMessage,
......@@ -3247,19 +3239,11 @@ keep_going: /* We will come back to here until there is
goto error_return;
}
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
/* Read message length word */
if (pqGetInt(&msgLength, 4, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
}
else
/* Read message length word */
if (pqGetInt(&msgLength, 4, conn))
{
/* Set phony message length to disable checks below */
msgLength = 8;
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/*
......@@ -3268,7 +3252,9 @@ keep_going: /* We will come back to here until there is
* auth requests may not be that small. Errors can be a
* little larger, but not huge. If we see a large apparent
* length in an error, it means we're really talking to a
* pre-3.0-protocol server; cope.
* pre-3.0-protocol server; cope. (Before version 14, the
* server also used the old protocol for errors that happened
* before processing the startup packet.)
*/
if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
{
......@@ -3296,25 +3282,11 @@ keep_going: /* We will come back to here until there is
*/
appendPQExpBufferChar(&conn->errorMessage, '\n');
/*
* If we tried to open the connection in 3.0 protocol,
* fall back to 2.0 protocol.
*/
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
conn->pversion = PG_PROTOCOL(2, 0);
need_new_connection = true;
goto keep_going;
}
goto error_return;
}
/*
* Can't process if message body isn't all here yet.
*
* (In protocol 2.0 case, we are assuming messages carry at
* least 4 bytes of data.)
*/
msgLength -= 4;
avail = conn->inEnd - conn->inCursor;
......@@ -3335,21 +3307,10 @@ keep_going: /* We will come back to here until there is
/* Handle errors. */
if (beresp == 'E')
{
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
if (pqGetErrorNotice3(conn, true))
{
if (pqGetErrorNotice3(conn, true))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
}
else
{
if (pqGets_append(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/* OK, we read the message; mark data consumed */
conn->inStart = conn->inCursor;
......@@ -3433,33 +3394,6 @@ keep_going: /* We will come back to here until there is
}
msgLength -= 4;
/*
* Ensure the password salt is in the input buffer, if it's an
* MD5 request. All the other authentication methods that
* contain extra data in the authentication request are only
* supported in protocol version 3, in which case we already
* read the whole message above.
*/
if (areq == AUTH_REQ_MD5 && PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{
msgLength += 4;
avail = conn->inEnd - conn->inCursor;
if (avail < 4)
{
/*
* Before returning, try to enlarge the input buffer
* if needed to hold the whole message; see notes in
* pqParseInput3.
*/
if (pqCheckInBufferSpace(conn->inCursor + (size_t) 4,
conn))
goto error_return;
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
}
/*
* Process the rest of the authentication request message, and
* respond to it if necessary.
......@@ -3567,15 +3501,6 @@ keep_going: /* We will come back to here until there is
goto error_return;
}
/* Fire up post-connection housekeeping if needed */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{
conn->status = CONNECTION_SETENV;
conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_SEND;
conn->next_eo = EnvironmentOptions;
return PGRES_POLLING_WRITING;
}
/* Almost there now ... */
conn->status = CONNECTION_CHECK_TARGET;
goto keep_going;
......@@ -3596,17 +3521,9 @@ keep_going: /* We will come back to here until there is
* If the server didn't report
* "default_transaction_read_only" or "in_hot_standby" at
* startup, we must determine its state by sending the
* query "SHOW transaction_read_only". Servers before 7.4
* lack the transaction_read_only GUC, but by the same
* token they don't have any read-only mode, so we may
* just assume the results.
* query "SHOW transaction_read_only". This GUC exists in
* all server versions that support 3.0 protocol.
*/
if (conn->sversion < 70400)
{
conn->default_transaction_read_only = PG_BOOL_NO;
conn->in_hot_standby = PG_BOOL_NO;
}
if (conn->default_transaction_read_only == PG_BOOL_UNKNOWN ||
conn->in_hot_standby == PG_BOOL_UNKNOWN)
{
......@@ -3719,39 +3636,6 @@ keep_going: /* We will come back to here until there is
return PGRES_POLLING_OK;
}
case CONNECTION_SETENV:
{
/*
* Do post-connection housekeeping (only needed in protocol
* 2.0).
*
* We pretend that the connection is OK for the duration of
* these queries.
*/
conn->status = CONNECTION_OK;
switch (pqSetenvPoll(conn))
{
case PGRES_POLLING_OK: /* Success */
break;
case PGRES_POLLING_READING: /* Still going */
conn->status = CONNECTION_SETENV;
return PGRES_POLLING_READING;
case PGRES_POLLING_WRITING: /* Still going */
conn->status = CONNECTION_SETENV;
return PGRES_POLLING_WRITING;
default:
goto error_return;
}
/* Almost there now ... */
conn->status = CONNECTION_CHECK_TARGET;
goto keep_going;
}
case CONNECTION_CONSUME:
{
/*
......@@ -4042,7 +3926,6 @@ makeEmptyPGconn(void)
conn->xactStatus = PQTRANS_IDLE;
conn->options_valid = false;
conn->nonblocking = false;
conn->setenv_state = SETENV_STATE_IDLE;
conn->client_encoding = PG_SQL_ASCII;
conn->std_strings = false; /* unless server says differently */
conn->default_transaction_read_only = PG_BOOL_UNKNOWN;
......@@ -4259,7 +4142,7 @@ sendTerminateConn(PGconn *conn)
* Try to send "close connection" message to backend. Ignore any
* error.
*/
pqPutMsgStart('X', false, conn);
pqPutMsgStart('X', conn);
pqPutMsgEnd(conn);
(void) pqFlush(conn);
}
......@@ -4652,16 +4535,13 @@ PQrequestCancel(PGconn *conn)
*
* RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
* SIDE_EFFECTS: may block.
*
* Note: all messages sent with this routine have a length word, whether
* it's protocol 2.0 or 3.0.
*/
int
pqPacketSend(PGconn *conn, char pack_type,
const void *buf, size_t buf_len)
{
/* Start the message. */
if (pqPutMsgStart(pack_type, true, conn))
if (pqPutMsgStart(pack_type, conn))
return STATUS_ERROR;
/* Send the message body. */
......@@ -6917,13 +6797,9 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
else
{
/*
* In protocol 2 we have to assume the setting will stick, and adjust
* our state immediately. In protocol 3 and up we can rely on the
* backend to report the parameter value, and we'll change state at
* that time.
* We rely on the backend to report the parameter value, and we'll
* change state at that time.
*/
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
pqSaveParameterStatus(conn, "client_encoding", encoding);
status = 0; /* everything is ok */
}
PQclear(res);
......
This diff is collapsed.
......@@ -884,38 +884,26 @@ lo_initialize(PGconn *conn)
MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
/*
* Execute the query to get all the functions at once. In 7.3 and later
* we need to be schema-safe. lo_create only exists in 8.1 and up.
* lo_truncate only exists in 8.3 and up.
* Execute the query to get all the functions at once. (Not all of them
* may exist in older server versions.)
*/
if (conn->sversion >= 70300)
query = "select proname, oid from pg_catalog.pg_proc "
"where proname in ("
"'lo_open', "
"'lo_close', "
"'lo_creat', "
"'lo_create', "
"'lo_unlink', "
"'lo_lseek', "
"'lo_lseek64', "
"'lo_tell', "
"'lo_tell64', "
"'lo_truncate', "
"'lo_truncate64', "
"'loread', "
"'lowrite') "
"and pronamespace = (select oid from pg_catalog.pg_namespace "
"where nspname = 'pg_catalog')";
else
query = "select proname, oid from pg_proc "
"where proname = 'lo_open' "
"or proname = 'lo_close' "
"or proname = 'lo_creat' "
"or proname = 'lo_unlink' "
"or proname = 'lo_lseek' "
"or proname = 'lo_tell' "
"or proname = 'loread' "
"or proname = 'lowrite'";
query = "select proname, oid from pg_catalog.pg_proc "
"where proname in ("
"'lo_open', "
"'lo_close', "
"'lo_creat', "
"'lo_create', "
"'lo_unlink', "
"'lo_lseek', "
"'lo_lseek64', "
"'lo_tell', "
"'lo_tell64', "
"'lo_truncate', "
"'lo_truncate64', "
"'loread', "
"'lowrite') "
"and pronamespace = (select oid from pg_catalog.pg_namespace "
"where nspname = 'pg_catalog')";
res = PQexec(conn, query);
if (res == NULL)
......
......@@ -484,9 +484,6 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
* msg_type is the message type byte, or 0 for a message without type byte
* (only startup messages have no type byte)
*
* force_len forces the message to have a length word; otherwise, we add
* a length word if protocol 3.
*
* Returns 0 on success, EOF on error
*
* The idea here is that we construct the message in conn->outBuffer,
......@@ -497,12 +494,11 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
*
* The state variable conn->outMsgStart points to the incomplete message's
* length word: it is either outCount or outCount+1 depending on whether
* there is a type byte. If we are sending a message without length word
* (pre protocol 3.0 only), then outMsgStart is -1. The state variable
* conn->outMsgEnd is the end of the data collected so far.
* there is a type byte. The state variable conn->outMsgEnd is the end of
* the data collected so far.
*/
int
pqPutMsgStart(char msg_type, bool force_len, PGconn *conn)
pqPutMsgStart(char msg_type, PGconn *conn)
{
int lenPos;
int endPos;
......@@ -514,14 +510,9 @@ pqPutMsgStart(char msg_type, bool force_len, PGconn *conn)
endPos = conn->outCount;
/* do we want a length word? */
if (force_len || PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
lenPos = endPos;
/* allow room for message length */
endPos += 4;
}
else
lenPos = -1;
lenPos = endPos;
/* allow room for message length */
endPos += 4;
/* make sure there is room for message header */
if (pqCheckOutBufferSpace(endPos, conn))
......
This diff is collapsed.
......@@ -1843,7 +1843,7 @@ pqEndcopy3(PGconn *conn)
if (conn->asyncStatus == PGASYNC_COPY_IN ||
conn->asyncStatus == PGASYNC_COPY_BOTH)
{
if (pqPutMsgStart('c', false, conn) < 0 ||
if (pqPutMsgStart('c', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return 1;
......@@ -1853,7 +1853,7 @@ pqEndcopy3(PGconn *conn)
*/
if (conn->queryclass != PGQUERY_SIMPLE)
{
if (pqPutMsgStart('S', false, conn) < 0 ||
if (pqPutMsgStart('S', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return 1;
}
......@@ -1933,7 +1933,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid,
/* PQfn already validated connection state */
if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */
if (pqPutMsgStart('F', conn) < 0 || /* function call msg */
pqPutInt(fnid, 4, conn) < 0 || /* function id */
pqPutInt(1, 2, conn) < 0 || /* # of format codes */
pqPutInt(1, 2, conn) < 0 || /* format code: BINARY */
......
......@@ -60,7 +60,7 @@ typedef enum
* postmaster. */
CONNECTION_AUTH_OK, /* Received authentication; waiting for
* backend startup. */
CONNECTION_SETENV, /* Negotiating environment. */
CONNECTION_SETENV, /* This state is no longer used. */
CONNECTION_SSL_STARTUP, /* Negotiating SSL. */
CONNECTION_NEEDED, /* Internal state: connect() needed */
CONNECTION_CHECK_WRITABLE, /* Checking if session is read-write. */
......
......@@ -252,22 +252,6 @@ typedef enum
PG_BOOL_NO /* No (false) */
} PGTernaryBool;
/* PGSetenvStatusType defines the state of the pqSetenv state machine */
/* (this is used only for 2.0-protocol connections) */
typedef enum
{
SETENV_STATE_CLIENT_ENCODING_SEND, /* About to send an Environment Option */
SETENV_STATE_CLIENT_ENCODING_WAIT, /* Waiting for above send to complete */
SETENV_STATE_OPTION_SEND, /* About to send an Environment Option */
SETENV_STATE_OPTION_WAIT, /* Waiting for above send to complete */
SETENV_STATE_QUERY1_SEND, /* About to send a status query */
SETENV_STATE_QUERY1_WAIT, /* Waiting for query to complete */
SETENV_STATE_QUERY2_SEND, /* About to send a status query */
SETENV_STATE_QUERY2_WAIT, /* Waiting for query to complete */
SETENV_STATE_IDLE
} PGSetenvStatusType;
/* Typedef for the EnvironmentOptions[] array */
typedef struct PQEnvironmentOption
{
......@@ -446,8 +430,6 @@ struct pg_conn
struct addrinfo *addrlist; /* list of addresses for current connhost */
struct addrinfo *addr_cur; /* the one currently being tried */
int addrlist_family; /* needed to know how to free addrlist */
PGSetenvStatusType setenv_state; /* for 2.0 protocol only */
const PQEnvironmentOption *next_eo;
bool send_appname; /* okay to send application_name? */
/* Miscellaneous stuff */
......@@ -639,22 +621,6 @@ extern void pqSaveParameterStatus(PGconn *conn, const char *name,
extern int pqRowProcessor(PGconn *conn, const char **errmsgp);
extern int PQsendQueryContinue(PGconn *conn, const char *query);
/* === in fe-protocol2.c === */
extern PostgresPollingStatusType pqSetenvPoll(PGconn *conn);
extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen,
const PQEnvironmentOption *options);
extern void pqParseInput2(PGconn *conn);
extern int pqGetCopyData2(PGconn *conn, char **buffer, int async);
extern int pqGetline2(PGconn *conn, char *s, int maxlen);
extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize);
extern int pqEndcopy2(PGconn *conn);
extern PGresult *pqFunctionCall2(PGconn *conn, Oid fnid,
int *result_buf, int *actual_result_len,
int result_is_int,
const PQArgBlock *args, int nargs);
/* === in fe-protocol3.c === */
extern char *pqBuildStartupPacket3(PGconn *conn, int *packetlen,
......@@ -691,7 +657,7 @@ extern int pqSkipnchar(size_t len, PGconn *conn);
extern int pqPutnchar(const char *s, size_t len, PGconn *conn);
extern int pqGetInt(int *result, size_t bytes, PGconn *conn);
extern int pqPutInt(int value, size_t bytes, PGconn *conn);
extern int pqPutMsgStart(char msg_type, bool force_len, PGconn *conn);
extern int pqPutMsgStart(char msg_type, PGconn *conn);
extern int pqPutMsgEnd(PGconn *conn);
extern int pqReadData(PGconn *conn);
extern int pqFlush(PGconn *conn);
......
# src/interfaces/libpq/nls.mk
CATALOG_NAME = libpq
AVAIL_LANGUAGES = cs de es fr he it ja ko pl pt_BR ru sv tr uk zh_CN zh_TW
GETTEXT_FILES = fe-auth.c fe-auth-scram.c fe-connect.c fe-exec.c fe-gssapi-common.c fe-lobj.c fe-misc.c fe-protocol2.c fe-protocol3.c fe-secure.c fe-secure-common.c fe-secure-gssapi.c fe-secure-openssl.c win32.c
GETTEXT_FILES = fe-auth.c fe-auth-scram.c fe-connect.c fe-exec.c fe-gssapi-common.c fe-lobj.c fe-misc.c fe-protocol3.c fe-secure.c fe-secure-common.c fe-secure-gssapi.c fe-secure-openssl.c win32.c
GETTEXT_TRIGGERS = libpq_gettext pqInternalNotice:2
GETTEXT_FLAGS = libpq_gettext:1:pass-c-format pqInternalNotice:2:c-format
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment