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

@ -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>

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;
}

View File

@ -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);
/*

View File

@ -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);

View File

@ -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
{

View File

@ -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)

View File

@ -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.
*/

View File

@ -5,23 +5,13 @@
*
* 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 old COPY OUT protocol.
* Unfortunately, COPY OUT was 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 ereport(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. (New COPY-OUT is message-based and does *not*
* set the DoingCopyOut flag.)
* channel, and are ignorant of the semantics of the data.
*
* 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 ensures
* that the channel will not be clogged by an incomplete message if execution
* is aborted by ereport(ERROR) partway through the message. The only
* non-libpq code that should call pq_putbytes directly is old-style COPY OUT.
* To emit an outgoing message, use the routines in pqformat.c to construct
* the message in a buffer and then emit it in one call to pq_putmessage.
* There are no functions to send raw bytes or partial messages; this
* ensures that the channel will not be clogged by an incomplete message if
* execution is aborted by ereport(ERROR) partway through the message.
*
* At one time, libpq was shared between frontend and backend, but now
* the backend's "backend/libpq" is quite separate from "interfaces/libpq".
@ -49,20 +39,16 @@
*
* low-level I/O:
* pq_getbytes - get a known number of bytes from connection
* pq_getstring - get a null terminated string from connection
* pq_getmessage - get a message with length word from connection
* pq_getbyte - get next byte 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
* pq_flush_if_writable - flush pending output if writable without blocking
* pq_getbyte_if_available - get a byte if available without blocking
*
* message-level I/O (and old-style-COPY-OUT cruft):
* message-level I/O
* pq_putmessage - send a normal message (suppressed in COPY OUT mode)
* pq_putmessage_noblock - buffer a normal message (suppressed in COPY OUT)
* pq_startcopyout - inform libpq that a COPY OUT transfer is beginning
* pq_endcopyout - end a COPY OUT transfer
*
*------------------------
*/
@ -146,7 +132,6 @@ static int PqRecvLength; /* End of data available in PqRecvBuffer */
*/
static bool PqCommBusy; /* busy sending data to the client */
static bool PqCommReadingMsg; /* in the middle of reading a message */
static bool DoingCopyOut; /* in old-protocol COPY OUT processing */
/* Internal functions */
@ -158,8 +143,6 @@ static int socket_flush_if_writable(void);
static bool socket_is_send_pending(void);
static int socket_putmessage(char msgtype, const char *s, size_t len);
static void socket_putmessage_noblock(char msgtype, const char *s, size_t len);
static void socket_startcopyout(void);
static void socket_endcopyout(bool errorAbort);
static int internal_putbytes(const char *s, size_t len);
static int internal_flush(void);
@ -174,9 +157,7 @@ static const PQcommMethods PqCommSocketMethods = {
socket_flush_if_writable,
socket_is_send_pending,
socket_putmessage,
socket_putmessage_noblock,
socket_startcopyout,
socket_endcopyout
socket_putmessage_noblock
};
const PQcommMethods *PqCommMethods = &PqCommSocketMethods;
@ -200,7 +181,6 @@ pq_init(void)
PqSendPointer = PqSendStart = PqRecvPointer = PqRecvLength = 0;
PqCommBusy = false;
PqCommReadingMsg = false;
DoingCopyOut = false;
/* set up process-exit hook to close the socket */
on_proc_exit(socket_close, 0);
@ -250,8 +230,6 @@ socket_comm_reset(void)
{
/* Do not throw away pending data, but do reset the busy flag */
PqCommBusy = false;
/* We can abort any old-style COPY OUT, too */
pq_endcopyout(true);
}
/* --------------------------------
@ -1158,58 +1136,6 @@ pq_discardbytes(size_t len)
return 0;
}
/* --------------------------------
* pq_getstring - get a null terminated string from connection
*
* The return value is placed in an expansible StringInfo, which has
* already been initialized by the caller.
*
* This is used only for dealing with old-protocol clients. The idea
* is to produce a StringInfo that looks the same as we would get from
* pq_getmessage() with a newer client; we will then process it with
* pq_getmsgstring. Therefore, no character set conversion is done here,
* even though this is presumably useful only for text.
*
* returns 0 if OK, EOF if trouble
* --------------------------------
*/
int
pq_getstring(StringInfo s)
{
int i;
Assert(PqCommReadingMsg);
resetStringInfo(s);
/* Read until we get the terminating '\0' */
for (;;)
{
while (PqRecvPointer >= PqRecvLength)
{
if (pq_recvbuf()) /* If nothing in buffer, then recv some */
return EOF; /* Failed to recv data */
}
for (i = PqRecvPointer; i < PqRecvLength; i++)
{
if (PqRecvBuffer[i] == '\0')
{
/* include the '\0' in the copy */
appendBinaryStringInfo(s, PqRecvBuffer + PqRecvPointer,
i - PqRecvPointer + 1);
PqRecvPointer = i + 1; /* advance past \0 */
return 0;
}
}
/* If we're here we haven't got the \0 in the buffer yet. */
appendBinaryStringInfo(s, PqRecvBuffer + PqRecvPointer,
PqRecvLength - PqRecvPointer);
PqRecvPointer = PqRecvLength;
}
}
/* --------------------------------
* pq_startmsgread - begin reading a message from the client.
@ -1236,9 +1162,9 @@ pq_startmsgread(void)
/* --------------------------------
* pq_endmsgread - finish reading message.
*
* This must be called after reading a V2 protocol message with
* pq_getstring() and friends, to indicate that we have read the whole
* message. In V3 protocol, pq_getmessage() does this implicitly.
* This must be called after reading a message with pq_getbytes()
* and friends, to indicate that we have read the whole message.
* pq_getmessage() does this implicitly.
* --------------------------------
*/
void
@ -1354,28 +1280,6 @@ pq_getmessage(StringInfo s, int maxlen)
}
/* --------------------------------
* 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)
{
int res;
/* Should only be called by old-style COPY OUT */
Assert(DoingCopyOut);
/* No-op if reentrant call */
if (PqCommBusy)
return 0;
PqCommBusy = true;
res = internal_putbytes(s, len);
PqCommBusy = false;
return res;
}
static int
internal_putbytes(const char *s, size_t len)
{
@ -1536,8 +1440,6 @@ socket_is_send_pending(void)
/* --------------------------------
* Message-level I/O routines begin here.
*
* These routines understand about the old-style COPY OUT protocol.
* --------------------------------
*/
@ -1545,20 +1447,13 @@ socket_is_send_pending(void)
/* --------------------------------
* socket_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. If msgtype is '\0', then the message has no type
* code (this is only valid in pre-3.0 protocols).
* msgtype is a message type code to place before the message body.
*
* len is the length of the message body data at *s. In protocol 3.0
* and later, a message length word (equal to len+4 because it counts
* itself too) is inserted by this routine.
* len is the length of the message body data at *s. A message length
* word (equal to len+4 because it counts itself too) is inserted by this
* routine.
*
* All normal messages are suppressed while old-style COPY OUT is in
* progress. (In practice only a few notice messages might get emitted
* then; dropping them is annoying, but at least they will still appear
* in the postmaster log.)
*
* We also suppress messages generated while pqcomm.c is busy. This
* We suppress messages generated while pqcomm.c is busy. This
* avoids any possibility of messages being inserted within other
* messages. The only known trouble case arises if SIGQUIT occurs
* during a pqcomm.c routine --- quickdie() will try to send a warning
@ -1570,20 +1465,20 @@ socket_is_send_pending(void)
static int
socket_putmessage(char msgtype, const char *s, size_t len)
{
if (DoingCopyOut || PqCommBusy)
uint32 n32;
Assert(msgtype != 0);
if (PqCommBusy)
return 0;
PqCommBusy = true;
if (msgtype)
if (internal_putbytes(&msgtype, 1))
goto fail;
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{
uint32 n32;
if (internal_putbytes(&msgtype, 1))
goto fail;
n32 = pg_hton32((uint32) (len + 4));
if (internal_putbytes((char *) &n32, 4))
goto fail;
n32 = pg_hton32((uint32) (len + 4));
if (internal_putbytes((char *) &n32, 4))
goto fail;
}
if (internal_putbytes(s, len))
goto fail;
PqCommBusy = false;
@ -1621,37 +1516,41 @@ socket_putmessage_noblock(char msgtype, const char *s, size_t len)
* buffer */
}
/* --------------------------------
* socket_startcopyout - inform libpq that an old-style COPY OUT transfer
* is beginning
* --------------------------------
*/
static void
socket_startcopyout(void)
{
DoingCopyOut = true;
}
/* --------------------------------
* socket_endcopyout - end an old-style COPY OUT transfer
* pq_putmessage_v2 - send a message in protocol version 2
*
* 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...) Note that old-style COPY OUT does
* not allow binary transfers, so a textual terminator is always correct.
* msgtype is a message type code to place before the message body.
*
* We no longer support protocol version 2, but we have kept this
* function so that if a client tries to connect with protocol version 2,
* as a courtesy we can still send the "unsupported protocol version"
* error to the client in the old format.
*
* Like in pq_putmessage(), we suppress messages generated while
* pqcomm.c is busy.
*
* returns 0 if OK, EOF if trouble
* --------------------------------
*/
static void
socket_endcopyout(bool errorAbort)
int
pq_putmessage_v2(char msgtype, const char *s, size_t len)
{
if (!DoingCopyOut)
return;
if (errorAbort)
pq_putbytes("\n\n\\.\n", 5);
/* in non-error case, copyto.c will have emitted the terminator line */
DoingCopyOut = false;
Assert(msgtype != 0);
if (PqCommBusy)
return 0;
PqCommBusy = true;
if (internal_putbytes(&msgtype, 1))
goto fail;
if (internal_putbytes(s, len))
goto fail;
PqCommBusy = false;
return 0;
fail:
PqCommBusy = false;
return EOF;
}
/*

View File

@ -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.

View File

@ -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')

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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 :

View File

@ -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;

View File

@ -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

View File

@ -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;
/*

View File

@ -15,7 +15,6 @@
#include "lib/stringinfo.h"
extern int GetOldFunctionMessage(StringInfo buf);
extern void HandleFunctionRequest(StringInfo msgBuf);
#endif /* FASTPATH_H */

View File

@ -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 */

View File

@ -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 \

View File

@ -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;

View File

@ -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))
{
/* Read message length word */
if (pqGetInt(&msgLength, 4, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
}
else
{
/* 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);

View File

@ -1221,7 +1221,7 @@ PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery)
}
/* construct the outgoing Query message */
if (pqPutMsgStart('Q', false, conn) < 0 ||
if (pqPutMsgStart('Q', conn) < 0 ||
pqPuts(query, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
{
@ -1255,7 +1255,7 @@ PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery)
/*
* PQsendQueryParams
* Like PQsendQuery, but use protocol 3.0 so we can pass parameters
* Like PQsendQuery, but use extended query protocol so we can pass parameters
*/
int
PQsendQueryParams(PGconn *conn,
@ -1330,16 +1330,8 @@ PQsendPrepare(PGconn *conn,
return 0;
}
/* This isn't gonna work on a 2.0 server */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{
appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("function requires at least protocol version 3.0\n"));
return 0;
}
/* construct the Parse message */
if (pqPutMsgStart('P', false, conn) < 0 ||
if (pqPutMsgStart('P', conn) < 0 ||
pqPuts(stmtName, conn) < 0 ||
pqPuts(query, conn) < 0)
goto sendFailed;
@ -1365,7 +1357,7 @@ PQsendPrepare(PGconn *conn,
goto sendFailed;
/* construct the Sync message */
if (pqPutMsgStart('S', false, conn) < 0 ||
if (pqPutMsgStart('S', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
@ -1397,7 +1389,7 @@ sendFailed:
/*
* PQsendQueryPrepared
* Like PQsendQuery, but execute a previously prepared statement,
* using protocol 3.0 so we can pass parameters
* using extended query protocol so we can pass parameters
*/
int
PQsendQueryPrepared(PGconn *conn,
@ -1478,7 +1470,7 @@ PQsendQueryStart(PGconn *conn, bool newQuery)
/*
* PQsendQueryGuts
* Common code for protocol-3.0 query sending
* Common code for sending a query with extended query protocol
* PQsendQueryStart should be done already
*
* command may be NULL to indicate we use an already-prepared statement
@ -1496,14 +1488,6 @@ PQsendQueryGuts(PGconn *conn,
{
int i;
/* This isn't gonna work on a 2.0 server */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{
appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("function requires at least protocol version 3.0\n"));
return 0;
}
/*
* We will send Parse (if needed), Bind, Describe Portal, Execute, Sync,
* using specified statement name and the unnamed portal.
@ -1512,7 +1496,7 @@ PQsendQueryGuts(PGconn *conn,
if (command)
{
/* construct the Parse message */
if (pqPutMsgStart('P', false, conn) < 0 ||
if (pqPutMsgStart('P', conn) < 0 ||
pqPuts(stmtName, conn) < 0 ||
pqPuts(command, conn) < 0)
goto sendFailed;
@ -1536,7 +1520,7 @@ PQsendQueryGuts(PGconn *conn,
}
/* Construct the Bind message */
if (pqPutMsgStart('B', false, conn) < 0 ||
if (pqPutMsgStart('B', conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPuts(stmtName, conn) < 0)
goto sendFailed;
@ -1603,21 +1587,21 @@ PQsendQueryGuts(PGconn *conn,
goto sendFailed;
/* construct the Describe Portal message */
if (pqPutMsgStart('D', false, conn) < 0 ||
if (pqPutMsgStart('D', conn) < 0 ||
pqPutc('P', conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Execute message */
if (pqPutMsgStart('E', false, conn) < 0 ||
if (pqPutMsgStart('E', conn) < 0 ||
pqPuts("", conn) < 0 ||
pqPutInt(0, 4, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Sync message */
if (pqPutMsgStart('S', false, conn) < 0 ||
if (pqPutMsgStart('S', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
@ -1718,10 +1702,7 @@ PQconsumeInput(PGconn *conn)
static void
parseInput(PGconn *conn)
{
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
pqParseInput3(conn);
else
pqParseInput2(conn);
pqParseInput3(conn);
}
/*
@ -1926,7 +1907,7 @@ PQexec(PGconn *conn, const char *query)
/*
* PQexecParams
* Like PQexec, but use protocol 3.0 so we can pass parameters
* Like PQexec, but use extended query protocol so we can pass parameters
*/
PGresult *
PQexecParams(PGconn *conn,
@ -1949,7 +1930,7 @@ PQexecParams(PGconn *conn,
/*
* PQprepare
* Creates a prepared statement by issuing a v3.0 parse message.
* Creates a prepared statement by issuing a Parse message.
*
* If the query was not even sent, return NULL; conn->errorMessage is set to
* a relevant message.
@ -1973,7 +1954,7 @@ PQprepare(PGconn *conn,
/*
* PQexecPrepared
* Like PQexec, but execute a previously prepared statement,
* using protocol 3.0 so we can pass parameters
* using extended query protocol so we can pass parameters
*/
PGresult *
PQexecPrepared(PGconn *conn,
@ -2020,41 +2001,20 @@ PQexecStart(PGconn *conn)
PQclear(result); /* only need its status */
if (resultStatus == PGRES_COPY_IN)
{
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
/* In protocol 3, we can get out of a COPY IN state */
if (PQputCopyEnd(conn,
libpq_gettext("COPY terminated by new PQexec")) < 0)
return false;
/* keep waiting to swallow the copy's failure message */
}
else
{
/* In older protocols we have to punt */
appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("COPY IN state must be terminated first\n"));
/* get out of a COPY IN state */
if (PQputCopyEnd(conn,
libpq_gettext("COPY terminated by new PQexec")) < 0)
return false;
}
/* keep waiting to swallow the copy's failure message */
}
else if (resultStatus == PGRES_COPY_OUT)
{
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
/*
* In protocol 3, we can get out of a COPY OUT state: we just
* switch back to BUSY and allow the remaining COPY data to be
* dropped on the floor.
*/
conn->asyncStatus = PGASYNC_BUSY;
/* keep waiting to swallow the copy's completion message */
}
else
{
/* In older protocols we have to punt */
appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("COPY OUT state must be terminated first\n"));
return false;
}
/*
* Get out of a COPY OUT state: we just switch back to BUSY and
* allow the remaining COPY data to be dropped on the floor.
*/
conn->asyncStatus = PGASYNC_BUSY;
/* keep waiting to swallow the copy's completion message */
}
else if (resultStatus == PGRES_COPY_BOTH)
{
@ -2195,23 +2155,15 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
if (!PQsendQueryStart(conn, true))
return 0;
/* This isn't gonna work on a 2.0 server */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{
appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("function requires at least protocol version 3.0\n"));
return 0;
}
/* construct the Describe message */
if (pqPutMsgStart('D', false, conn) < 0 ||
if (pqPutMsgStart('D', conn) < 0 ||
pqPutc(desc_type, conn) < 0 ||
pqPuts(desc_target, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
/* construct the Sync message */
if (pqPutMsgStart('S', false, conn) < 0 ||
if (pqPutMsgStart('S', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
goto sendFailed;
@ -2311,8 +2263,7 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
* Try to flush any previously sent data in preference to growing the
* output buffer. If we can't enlarge the buffer enough to hold the
* data, return 0 in the nonblock case, else hard error. (For
* simplicity, always assume 5 bytes of overhead even in protocol 2.0
* case.)
* simplicity, always assume 5 bytes of overhead.)
*/
if ((conn->outBufSize - conn->outCount - 5) < nbytes)
{
@ -2323,20 +2274,10 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
return pqIsnonblocking(conn) ? 0 : -1;
}
/* Send the data (too simple to delegate to fe-protocol files) */
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
if (pqPutMsgStart('d', false, conn) < 0 ||
pqPutnchar(buffer, nbytes, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
else
{
if (pqPutMsgStart(0, false, conn) < 0 ||
pqPutnchar(buffer, nbytes, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
if (pqPutMsgStart('d', conn) < 0 ||
pqPutnchar(buffer, nbytes, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
return 1;
}
@ -2366,52 +2307,31 @@ PQputCopyEnd(PGconn *conn, const char *errormsg)
* Send the COPY END indicator. This is simple enough that we don't
* bother delegating it to the fe-protocol files.
*/
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
if (errormsg)
{
if (errormsg)
{
/* Send COPY FAIL */
if (pqPutMsgStart('f', false, conn) < 0 ||
pqPuts(errormsg, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
else
{
/* Send COPY DONE */
if (pqPutMsgStart('c', false, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
/*
* If we sent the COPY command in extended-query mode, we must issue a
* Sync as well.
*/
if (conn->queryclass != PGQUERY_SIMPLE)
{
if (pqPutMsgStart('S', false, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
/* Send COPY FAIL */
if (pqPutMsgStart('f', conn) < 0 ||
pqPuts(errormsg, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
else
{
if (errormsg)
{
/* Oops, no way to do this in 2.0 */
appendPQExpBufferStr(&conn->errorMessage,
libpq_gettext("function requires at least protocol version 3.0\n"));
/* Send COPY DONE */
if (pqPutMsgStart('c', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
/*
* If we sent the COPY command in extended-query mode, we must issue a
* Sync as well.
*/
if (conn->queryclass != PGQUERY_SIMPLE)
{
if (pqPutMsgStart('S', conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
else
{
/* Send old-style end-of-data marker */
if (pqPutMsgStart(0, false, conn) < 0 ||
pqPutnchar("\\.\n", 3, conn) < 0 ||
pqPutMsgEnd(conn) < 0)
return -1;
}
}
/* Return to active duty */
@ -2450,10 +2370,7 @@ PQgetCopyData(PGconn *conn, char **buffer, int async)
libpq_gettext("no COPY in progress\n"));
return -2;
}
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
return pqGetCopyData3(conn, buffer, async);
else
return pqGetCopyData2(conn, buffer, async);
return pqGetCopyData3(conn, buffer, async);
}
/*
@ -2492,10 +2409,7 @@ PQgetline(PGconn *conn, char *s, int maxlen)
if (!conn)
return EOF;
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
return pqGetline3(conn, s, maxlen);
else
return pqGetline2(conn, s, maxlen);
return pqGetline3(conn, s, maxlen);
}
/*
@ -2535,10 +2449,7 @@ PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)
if (!conn)
return -1;
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
return pqGetlineAsync3(conn, buffer, bufsize);
else
return pqGetlineAsync2(conn, buffer, bufsize);
return pqGetlineAsync3(conn, buffer, bufsize);
}
/*
@ -2573,10 +2484,8 @@ PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
* After completing the data transfer portion of a copy in/out,
* the application must call this routine to finish the command protocol.
*
* When using protocol 3.0 this is deprecated; it's cleaner to use PQgetResult
* to get the transfer status. Note however that when using 2.0 protocol,
* recovering from a copy failure often requires a PQreset. PQendcopy will
* take care of that, PQgetResult won't.
* This is deprecated; it's cleaner to use PQgetResult to get the transfer
* status.
*
* RETURNS:
* 0 on success
@ -2588,10 +2497,7 @@ PQendcopy(PGconn *conn)
if (!conn)
return 0;
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
return pqEndcopy3(conn);
else
return pqEndcopy2(conn);
return pqEndcopy3(conn);
}
@ -2643,16 +2549,10 @@ PQfn(PGconn *conn,
return NULL;
}
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
return pqFunctionCall3(conn, fnid,
result_buf, result_len,
result_is_int,
args, nargs);
else
return pqFunctionCall2(conn, fnid,
result_buf, result_len,
result_is_int,
args, nargs);
return pqFunctionCall3(conn, fnid,
result_buf, result_len,
result_is_int,
args, nargs);
}
@ -2701,13 +2601,6 @@ PQresultVerboseErrorMessage(const PGresult *res,
initPQExpBuffer(&workBuf);
/*
* Currently, we pass this off to fe-protocol3.c in all cases; it will
* behave reasonably sanely with an error reported by fe-protocol2.c as
* well. If necessary, we could record the protocol version in PGresults
* so as to be able to invoke a version-specific message formatter, but
* for now there's no need.
*/
pqBuildErrorMessage3(&workBuf, res, verbosity, show_context);
/* If insufficient memory to format the message, fail cleanly */

View File

@ -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)

View File

@ -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))

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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. */

View File

@ -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);

View File

@ -1,6 +1,6 @@
# 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