aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/libpq.sgml79
-rw-r--r--src/backend/access/common/printtup.c248
-rw-r--r--src/backend/commands/async.c3
-rw-r--r--src/backend/commands/copyfrom.c7
-rw-r--r--src/backend/commands/copyfromparse.c83
-rw-r--r--src/backend/commands/copyto.c127
-rw-r--r--src/backend/libpq/auth.c80
-rw-r--r--src/backend/libpq/pqcomm.c215
-rw-r--r--src/backend/libpq/pqmq.c18
-rw-r--r--src/backend/postmaster/postmaster.c42
-rw-r--r--src/backend/tcop/dest.c22
-rw-r--r--src/backend/tcop/fastpath.c165
-rw-r--r--src/backend/tcop/postgres.c71
-rw-r--r--src/backend/utils/error/elog.c64
-rw-r--r--src/backend/utils/misc/guc.c6
-rw-r--r--src/bin/psql/common.c10
-rw-r--r--src/bin/psql/copy.c4
-rw-r--r--src/include/commands/copyfrom_internal.h3
-rw-r--r--src/include/libpq/libpq.h7
-rw-r--r--src/include/libpq/pqcomm.h33
-rw-r--r--src/include/tcop/fastpath.h1
-rw-r--r--src/include/utils/elog.h2
-rw-r--r--src/interfaces/libpq/Makefile1
-rw-r--r--src/interfaces/libpq/fe-auth.c8
-rw-r--r--src/interfaces/libpq/fe-connect.c160
-rw-r--r--src/interfaces/libpq/fe-exec.c231
-rw-r--r--src/interfaces/libpq/fe-lobj.c50
-rw-r--r--src/interfaces/libpq/fe-misc.c21
-rw-r--r--src/interfaces/libpq/fe-protocol2.c1610
-rw-r--r--src/interfaces/libpq/fe-protocol3.c6
-rw-r--r--src/interfaces/libpq/libpq-fe.h2
-rw-r--r--src/interfaces/libpq/libpq-int.h36
-rw-r--r--src/interfaces/libpq/nls.mk2
33 files changed, 303 insertions, 3114 deletions
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index cc20b0f234a..05532793142 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -2275,20 +2275,6 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName);
</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
are treated as escapes in string literals. Also, the presence of
@@ -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>
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 4468480e9b3..54b539f6fb6 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -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
@@ -456,84 +379,6 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
}
/* ----------------
- * 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;
-}
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 42b232d98b1..4b16fb56825 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -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);
/*
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 796ca7b3f7b..f05e2d23476 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -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);
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 315b16fd7af..ce24a1528bd 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -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
{
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index e04ec1e331b..46155015cfd 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -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');
@@ -780,42 +739,6 @@ BeginCopyTo(ParseState *pstate,
}
/*
- * 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.
*/
void
@@ -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)
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index baa0712c0f7..994251e7d9d 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -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);
@@ -880,19 +871,6 @@ CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail)
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.
*/
@@ -1042,19 +1020,6 @@ pg_GSS_recvauth(Port *port)
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.
*/
@@ -1324,19 +1289,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.
*/
r = AcquireCredentialsHandle(NULL,
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 27a298f1101..4c7b1e7bfdf 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -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).
- *
- * 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.
+ * msgtype is a message type code to place before the message body.
*
- * 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.)
+ * 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.
*
- * 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
+ *
+ * msgtype is a message type code to place before the message body.
*
- * 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.
+ * 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;
}
/*
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index f468441b7a2..d1a1f47a788 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -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.
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 3f1ce135a85..edab95a19e4 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -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')
diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c
index 4316137a9d3..1dfadfa8e1d 100644
--- a/src/backend/tcop/dest.c
+++ b/src/backend/tcop/dest.c
@@ -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;
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 1b76653caa4..77d17ebca94 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -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;
-}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index bb5ccb4578b..8a0332dde9d 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -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;
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 80c26724612..e729ebece7b 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -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
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 4bcf705a30d..3fd1a5fbe26 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -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;
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 925fe34a3fd..7a95465111a 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -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)
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 78f0dc5a507..e1fee8e0992 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -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 :
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index e37942df391..705f5b615be 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -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;
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index e4e5c215655..b20deeb5550 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -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
diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h
index a86b895b268..be9d9705744 100644
--- a/src/include/libpq/pqcomm.h
+++ b/src/include/libpq/pqcomm.h
@@ -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;
/*
diff --git a/src/include/tcop/fastpath.h b/src/include/tcop/fastpath.h
index b67c44fe69e..c4d7a47dd72 100644
--- a/src/include/tcop/fastpath.h
+++ b/src/include/tcop/fastpath.h
@@ -15,7 +15,6 @@
#include "lib/stringinfo.h"
-extern int GetOldFunctionMessage(StringInfo buf);
extern void HandleFunctionRequest(StringInfo msgBuf);
#endif /* FASTPATH_H */
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 3c0e57621fc..b59651289e4 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.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 */
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index f74677eaf9b..2aca882a2be 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -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 \
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 168b3df52bf..e8062647e60 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -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;
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 9812a14662d..c16a7bd9f22 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -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;
@@ -3434,33 +3395,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);
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index a5507538555..9a038043b2c 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -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 */
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index b9c52eb50c2..ffd9926dc4e 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -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)
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 2bfb6acd895..ce2d24b91fc 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -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))
diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c
deleted file mode 100644
index 6efa53d8b71..00000000000
--- a/src/interfaces/libpq/fe-protocol2.c
+++ /dev/null
@@ -1,1610 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * fe-protocol2.c
- * functions that are specific to frontend/backend protocol version 2
- *
- * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * src/interfaces/libpq/fe-protocol2.c
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres_fe.h"
-
-#include <ctype.h>
-#include <fcntl.h>
-
-#ifdef WIN32
-#include "win32.h"
-#else
-#include <unistd.h>
-#ifdef HAVE_NETINET_TCP_H
-#include <netinet/tcp.h>
-#endif
-#endif
-
-#include "libpq-fe.h"
-#include "libpq-int.h"
-#include "port/pg_bswap.h"
-
-static int getRowDescriptions(PGconn *conn);
-static int getAnotherTuple(PGconn *conn, bool binary);
-static int pqGetErrorNotice2(PGconn *conn, bool isError);
-static void checkXactStatus(PGconn *conn, const char *cmdTag);
-static int getNotify(PGconn *conn);
-
-
-/*
- * pqSetenvPoll
- *
- * Polls the process of passing the values of a standard set of environment
- * variables to the backend.
- */
-PostgresPollingStatusType
-pqSetenvPoll(PGconn *conn)
-{
- PGresult *res;
-
- if (conn == NULL || conn->status == CONNECTION_BAD)
- return PGRES_POLLING_FAILED;
-
- /* Check whether there are any data for us */
- switch (conn->setenv_state)
- {
- /* These are reading states */
- case SETENV_STATE_CLIENT_ENCODING_WAIT:
- case SETENV_STATE_OPTION_WAIT:
- case SETENV_STATE_QUERY1_WAIT:
- case SETENV_STATE_QUERY2_WAIT:
- {
- /* Load waiting data */
- int n = pqReadData(conn);
-
- if (n < 0)
- goto error_return;
- if (n == 0)
- return PGRES_POLLING_READING;
-
- break;
- }
-
- /* These are writing states, so we just proceed. */
- case SETENV_STATE_CLIENT_ENCODING_SEND:
- case SETENV_STATE_OPTION_SEND:
- case SETENV_STATE_QUERY1_SEND:
- case SETENV_STATE_QUERY2_SEND:
- break;
-
- /* Should we raise an error if called when not active? */
- case SETENV_STATE_IDLE:
- return PGRES_POLLING_OK;
-
- default:
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("invalid setenv state %c, probably indicative of memory corruption\n"),
- conn->setenv_state);
- goto error_return;
- }
-
- /* We will loop here until there is nothing left to do in this call. */
- for (;;)
- {
- switch (conn->setenv_state)
- {
- /*
- * The _CLIENT_ENCODING_SEND code is slightly different from
- * _OPTION_SEND below (e.g., no getenv() call), which is why a
- * different state is used.
- */
- case SETENV_STATE_CLIENT_ENCODING_SEND:
- {
- char setQuery[100]; /* note length limit in
- * sprintf below */
- const char *val = conn->client_encoding_initial;
-
- if (val)
- {
- if (pg_strcasecmp(val, "default") == 0)
- sprintf(setQuery, "SET client_encoding = DEFAULT");
- else
- sprintf(setQuery, "SET client_encoding = '%.60s'",
- val);
-#ifdef CONNECTDEBUG
- fprintf(stderr,
- "Sending client_encoding with %s\n",
- setQuery);
-#endif
- if (!PQsendQuery(conn, setQuery))
- goto error_return;
-
- conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_WAIT;
- }
- else
- conn->setenv_state = SETENV_STATE_OPTION_SEND;
- break;
- }
-
- case SETENV_STATE_OPTION_SEND:
- {
- /*
- * Send SET commands for stuff directed by Environment
- * Options. Note: we assume that SET commands won't start
- * transaction blocks, even in a 7.3 server with
- * autocommit off.
- */
- char setQuery[100]; /* note length limit in
- * sprintf below */
-
- if (conn->next_eo->envName)
- {
- const char *val;
-
- if ((val = getenv(conn->next_eo->envName)))
- {
- if (pg_strcasecmp(val, "default") == 0)
- sprintf(setQuery, "SET %s = DEFAULT",
- conn->next_eo->pgName);
- else
- sprintf(setQuery, "SET %s = '%.60s'",
- conn->next_eo->pgName, val);
-#ifdef CONNECTDEBUG
- fprintf(stderr,
- "Use environment variable %s to send %s\n",
- conn->next_eo->envName, setQuery);
-#endif
- if (!PQsendQuery(conn, setQuery))
- goto error_return;
-
- conn->setenv_state = SETENV_STATE_OPTION_WAIT;
- }
- else
- conn->next_eo++;
- }
- else
- {
- /* No more options to send, so move on to querying */
- conn->setenv_state = SETENV_STATE_QUERY1_SEND;
- }
- break;
- }
-
- case SETENV_STATE_CLIENT_ENCODING_WAIT:
- {
- if (PQisBusy(conn))
- return PGRES_POLLING_READING;
-
- res = PQgetResult(conn);
-
- if (res)
- {
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- PQclear(res);
- goto error_return;
- }
- PQclear(res);
- /* Keep reading until PQgetResult returns NULL */
- }
- else
- {
- /* Query finished, so send the next option */
- conn->setenv_state = SETENV_STATE_OPTION_SEND;
- }
- break;
- }
-
- case SETENV_STATE_OPTION_WAIT:
- {
- if (PQisBusy(conn))
- return PGRES_POLLING_READING;
-
- res = PQgetResult(conn);
-
- if (res)
- {
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- PQclear(res);
- goto error_return;
- }
- PQclear(res);
- /* Keep reading until PQgetResult returns NULL */
- }
- else
- {
- /* Query finished, so send the next option */
- conn->next_eo++;
- conn->setenv_state = SETENV_STATE_OPTION_SEND;
- }
- break;
- }
-
- case SETENV_STATE_QUERY1_SEND:
- {
- /*
- * Issue query to get information we need. Here we must
- * use begin/commit in case autocommit is off by default
- * in a 7.3 server.
- *
- * Note: version() exists in all protocol-2.0-supporting
- * backends. In 7.3 it would be safer to write
- * pg_catalog.version(), but we can't do that without
- * causing problems on older versions.
- */
- if (!PQsendQuery(conn, "begin; select version(); end"))
- goto error_return;
-
- conn->setenv_state = SETENV_STATE_QUERY1_WAIT;
- return PGRES_POLLING_READING;
- }
-
- case SETENV_STATE_QUERY1_WAIT:
- {
- if (PQisBusy(conn))
- return PGRES_POLLING_READING;
-
- res = PQgetResult(conn);
-
- if (res)
- {
- char *val;
-
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- /* ignore begin/commit command results */
- PQclear(res);
- continue;
- }
-
- if (PQresultStatus(res) != PGRES_TUPLES_OK ||
- PQntuples(res) != 1)
- {
- PQclear(res);
- goto error_return;
- }
-
- /*
- * Extract server version and save as if
- * ParameterStatus
- */
- val = PQgetvalue(res, 0, 0);
- if (val && strncmp(val, "PostgreSQL ", 11) == 0)
- {
- char *ptr;
-
- /* strip off PostgreSQL part */
- val += 11;
-
- /*
- * strip off platform part (scribbles on result,
- * naughty naughty)
- */
- ptr = strchr(val, ' ');
- if (ptr)
- *ptr = '\0';
-
- pqSaveParameterStatus(conn, "server_version",
- val);
- }
-
- PQclear(res);
- /* Keep reading until PQgetResult returns NULL */
- }
- else
- {
- /* Query finished, move to next */
- conn->setenv_state = SETENV_STATE_QUERY2_SEND;
- }
- break;
- }
-
- case SETENV_STATE_QUERY2_SEND:
- {
- const char *query;
-
- /*
- * pg_client_encoding does not exist in pre-7.2 servers.
- * So we need to be prepared for an error here. Do *not*
- * start a transaction block, except in 7.3 servers where
- * we need to prevent autocommit-off from starting a
- * transaction anyway.
- */
- if (conn->sversion >= 70300 &&
- conn->sversion < 70400)
- query = "begin; select pg_catalog.pg_client_encoding(); end";
- else
- query = "select pg_client_encoding()";
- if (!PQsendQuery(conn, query))
- goto error_return;
-
- conn->setenv_state = SETENV_STATE_QUERY2_WAIT;
- return PGRES_POLLING_READING;
- }
-
- case SETENV_STATE_QUERY2_WAIT:
- {
- if (PQisBusy(conn))
- return PGRES_POLLING_READING;
-
- res = PQgetResult(conn);
-
- if (res)
- {
- const char *val;
-
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- /* ignore begin/commit command results */
- PQclear(res);
- continue;
- }
-
- if (PQresultStatus(res) == PGRES_TUPLES_OK &&
- PQntuples(res) == 1)
- {
- /* Extract client encoding and save it */
- val = PQgetvalue(res, 0, 0);
- if (val && *val) /* null should not happen, but */
- pqSaveParameterStatus(conn, "client_encoding",
- val);
- }
- else
- {
- /*
- * Error: presumably function not available, so
- * use PGCLIENTENCODING or SQL_ASCII as the
- * fallback.
- */
- val = getenv("PGCLIENTENCODING");
- if (val && *val)
- pqSaveParameterStatus(conn, "client_encoding",
- val);
- else
- pqSaveParameterStatus(conn, "client_encoding",
- "SQL_ASCII");
- }
-
- PQclear(res);
- /* Keep reading until PQgetResult returns NULL */
- }
- else
- {
- /* Query finished, so we're done */
- conn->setenv_state = SETENV_STATE_IDLE;
- return PGRES_POLLING_OK;
- }
- break;
- }
-
- default:
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("invalid state %c, "
- "probably indicative of memory corruption\n"),
- conn->setenv_state);
- goto error_return;
- }
- }
-
- /* Unreachable */
-
-error_return:
- conn->setenv_state = SETENV_STATE_IDLE;
- return PGRES_POLLING_FAILED;
-}
-
-
-/*
- * parseInput: if appropriate, parse input data from backend
- * until input is exhausted or a stopping state is reached.
- * Note that this function will NOT attempt to read more data from the backend.
- */
-void
-pqParseInput2(PGconn *conn)
-{
- char id;
-
- /*
- * Loop to parse successive complete messages available in the buffer.
- */
- for (;;)
- {
- /*
- * Quit if in COPY_OUT state: we expect raw data from the server until
- * PQendcopy is called. Don't try to parse it according to the normal
- * protocol. (This is bogus. The data lines ought to be part of the
- * protocol and have identifying leading characters.)
- */
- if (conn->asyncStatus == PGASYNC_COPY_OUT)
- return;
-
- /*
- * OK to try to read a message type code.
- */
- conn->inCursor = conn->inStart;
- if (pqGetc(&id, conn))
- return;
-
- /*
- * NOTIFY and NOTICE messages can happen in any state besides COPY
- * OUT; always process them right away.
- *
- * Most other messages should only be processed while in BUSY state.
- * (In particular, in READY state we hold off further parsing until
- * the application collects the current PGresult.)
- *
- * However, if the state is IDLE then we got trouble; we need to deal
- * with the unexpected message somehow.
- */
- if (id == 'A')
- {
- if (getNotify(conn))
- return;
- }
- else if (id == 'N')
- {
- if (pqGetErrorNotice2(conn, false))
- return;
- }
- else if (conn->asyncStatus != PGASYNC_BUSY)
- {
- /* If not IDLE state, just wait ... */
- if (conn->asyncStatus != PGASYNC_IDLE)
- return;
-
- /*
- * Unexpected message in IDLE state; need to recover somehow.
- * ERROR messages are displayed using the notice processor;
- * anything else is just dropped on the floor after displaying a
- * suitable warning notice. (An ERROR is very possibly the
- * backend telling us why it is about to close the connection, so
- * we don't want to just discard it...)
- */
- if (id == 'E')
- {
- if (pqGetErrorNotice2(conn, false /* treat as notice */ ))
- return;
- }
- else
- {
- pqInternalNotice(&conn->noticeHooks,
- "message type 0x%02x arrived from server while idle",
- id);
- /* Discard the unexpected message; good idea?? */
- conn->inStart = conn->inEnd;
- break;
- }
- }
- else
- {
- /*
- * In BUSY state, we can process everything.
- */
- switch (id)
- {
- case 'C': /* command complete */
- if (pqGets(&conn->workBuffer, conn))
- return;
- if (conn->result == NULL)
- {
- conn->result = PQmakeEmptyPGresult(conn,
- PGRES_COMMAND_OK);
- if (!conn->result)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("out of memory"));
- pqSaveErrorResult(conn);
- }
- }
- if (conn->result)
- {
- strlcpy(conn->result->cmdStatus, conn->workBuffer.data,
- CMDSTATUS_LEN);
- }
- checkXactStatus(conn, conn->workBuffer.data);
- conn->asyncStatus = PGASYNC_READY;
- break;
- case 'E': /* error return */
- if (pqGetErrorNotice2(conn, true))
- return;
- conn->asyncStatus = PGASYNC_READY;
- break;
- case 'Z': /* backend is ready for new query */
- conn->asyncStatus = PGASYNC_IDLE;
- break;
- case 'I': /* empty query */
- /* read and throw away the closing '\0' */
- if (pqGetc(&id, conn))
- return;
- if (id != '\0')
- pqInternalNotice(&conn->noticeHooks,
- "unexpected character %c following empty query response (\"I\" message)",
- id);
- if (conn->result == NULL)
- {
- conn->result = PQmakeEmptyPGresult(conn,
- PGRES_EMPTY_QUERY);
- if (!conn->result)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("out of memory"));
- pqSaveErrorResult(conn);
- }
- }
- conn->asyncStatus = PGASYNC_READY;
- break;
- case 'K': /* secret key data from the backend */
-
- /*
- * This is expected only during backend startup, but it's
- * just as easy to handle it as part of the main loop.
- * Save the data and continue processing.
- */
- if (pqGetInt(&(conn->be_pid), 4, conn))
- return;
- if (pqGetInt(&(conn->be_key), 4, conn))
- return;
- break;
- case 'P': /* synchronous (normal) portal */
- if (pqGets(&conn->workBuffer, conn))
- return;
- /* We pretty much ignore this message type... */
- break;
- case 'T': /* row descriptions (start of query results) */
- if (conn->result == NULL)
- {
- /* First 'T' in a query sequence */
- if (getRowDescriptions(conn))
- return;
- /* getRowDescriptions() moves inStart itself */
- continue;
- }
- else
- {
- /*
- * A new 'T' message is treated as the start of
- * another PGresult. (It is not clear that this is
- * really possible with the current backend.) We stop
- * parsing until the application accepts the current
- * result.
- */
- conn->asyncStatus = PGASYNC_READY;
- return;
- }
- break;
- case 'D': /* ASCII data tuple */
- if (conn->result != NULL)
- {
- /* Read another tuple of a normal query response */
- if (getAnotherTuple(conn, false))
- return;
- /* getAnotherTuple() moves inStart itself */
- continue;
- }
- else
- {
- pqInternalNotice(&conn->noticeHooks,
- "server sent data (\"D\" message) without prior row description (\"T\" message)");
- /* Discard the unexpected message; good idea?? */
- conn->inStart = conn->inEnd;
- return;
- }
- break;
- case 'B': /* Binary data tuple */
- if (conn->result != NULL)
- {
- /* Read another tuple of a normal query response */
- if (getAnotherTuple(conn, true))
- return;
- /* getAnotherTuple() moves inStart itself */
- continue;
- }
- else
- {
- pqInternalNotice(&conn->noticeHooks,
- "server sent binary data (\"B\" message) without prior row description (\"T\" message)");
- /* Discard the unexpected message; good idea?? */
- conn->inStart = conn->inEnd;
- return;
- }
- break;
- case 'G': /* Start Copy In */
- conn->asyncStatus = PGASYNC_COPY_IN;
- break;
- case 'H': /* Start Copy Out */
- conn->asyncStatus = PGASYNC_COPY_OUT;
- break;
-
- /*
- * Don't need to process CopyBothResponse here because it
- * never arrives from the server during protocol 2.0.
- */
- default:
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("unexpected response from server; first received character was \"%c\"\n"),
- id);
- /* build an error result holding the error message */
- pqSaveErrorResult(conn);
- /* Discard the unexpected message; good idea?? */
- conn->inStart = conn->inEnd;
- conn->asyncStatus = PGASYNC_READY;
- return;
- } /* switch on protocol character */
- }
- /* Successfully consumed this message */
- conn->inStart = conn->inCursor;
- }
-}
-
-/*
- * parseInput subroutine to read a 'T' (row descriptions) message.
- * We build a PGresult structure containing the attribute data.
- * Returns: 0 if completed message, EOF if error or not enough data
- * received yet.
- *
- * Note that if we run out of data, we have to suspend and reprocess
- * the message after more data is received. Otherwise, conn->inStart
- * must get advanced past the processed data.
- */
-static int
-getRowDescriptions(PGconn *conn)
-{
- PGresult *result;
- int nfields;
- const char *errmsg;
- int i;
-
- result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
- if (!result)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
-
- /* parseInput already read the 'T' label. */
- /* the next two bytes are the number of fields */
- if (pqGetInt(&(result->numAttributes), 2, conn))
- goto EOFexit;
- nfields = result->numAttributes;
-
- /* allocate space for the attribute descriptors */
- if (nfields > 0)
- {
- result->attDescs = (PGresAttDesc *)
- pqResultAlloc(result, nfields * sizeof(PGresAttDesc), true);
- if (!result->attDescs)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
- MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
- }
-
- /* get type info */
- for (i = 0; i < nfields; i++)
- {
- int typid;
- int typlen;
- int atttypmod;
-
- if (pqGets(&conn->workBuffer, conn) ||
- pqGetInt(&typid, 4, conn) ||
- pqGetInt(&typlen, 2, conn) ||
- pqGetInt(&atttypmod, 4, conn))
- goto EOFexit;
-
- /*
- * Since pqGetInt treats 2-byte integers as unsigned, we need to
- * coerce the result to signed form.
- */
- typlen = (int) ((int16) typlen);
-
- result->attDescs[i].name = pqResultStrdup(result,
- conn->workBuffer.data);
- if (!result->attDescs[i].name)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
- result->attDescs[i].tableid = 0;
- result->attDescs[i].columnid = 0;
- result->attDescs[i].format = 0;
- result->attDescs[i].typid = typid;
- result->attDescs[i].typlen = typlen;
- result->attDescs[i].atttypmod = atttypmod;
- }
-
- /* Success! */
- conn->result = result;
-
- /* Advance inStart to show that the "T" message has been processed. */
- conn->inStart = conn->inCursor;
-
- /*
- * We could perform additional setup for the new result set here, but for
- * now there's nothing else to do.
- */
-
- /* And we're done. */
- return 0;
-
-advance_and_error:
-
- /*
- * Discard the failed message. Unfortunately we don't know for sure where
- * the end is, so just throw away everything in the input buffer. This is
- * not very desirable but it's the best we can do in protocol v2.
- */
- conn->inStart = conn->inEnd;
-
- /*
- * Replace partially constructed result with an error result. First
- * discard the old result to try to win back some memory.
- */
- pqClearAsyncResult(conn);
-
- /*
- * If preceding code didn't provide an error message, assume "out of
- * memory" was meant. The advantage of having this special case is that
- * freeing the old result first greatly improves the odds that gettext()
- * will succeed in providing a translation.
- */
- if (!errmsg)
- errmsg = libpq_gettext("out of memory for query result");
-
- appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
-
- /*
- * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can
- * do to recover...
- */
- conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
- conn->asyncStatus = PGASYNC_READY;
-
-EOFexit:
- if (result && result != conn->result)
- PQclear(result);
- return EOF;
-}
-
-/*
- * parseInput subroutine to read a 'B' or 'D' (row data) message.
- * We fill rowbuf with column pointers and then call the row processor.
- * Returns: 0 if completed message, EOF if error or not enough data
- * received yet.
- *
- * Note that if we run out of data, we have to suspend and reprocess
- * the message after more data is received. Otherwise, conn->inStart
- * must get advanced past the processed data.
- */
-static int
-getAnotherTuple(PGconn *conn, bool binary)
-{
- PGresult *result = conn->result;
- int nfields = result->numAttributes;
- const char *errmsg;
- PGdataValue *rowbuf;
-
- /* the backend sends us a bitmap of which attributes are null */
- char std_bitmap[64]; /* used unless it doesn't fit */
- char *bitmap = std_bitmap;
- int i;
- size_t nbytes; /* the number of bytes in bitmap */
- char bmap; /* One byte of the bitmap */
- int bitmap_index; /* Its index */
- int bitcnt; /* number of bits examined in current byte */
- int vlen; /* length of the current field value */
-
- /* Resize row buffer if needed */
- rowbuf = conn->rowBuf;
- if (nfields > conn->rowBufLen)
- {
- rowbuf = (PGdataValue *) realloc(rowbuf,
- nfields * sizeof(PGdataValue));
- if (!rowbuf)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
- conn->rowBuf = rowbuf;
- conn->rowBufLen = nfields;
- }
-
- /* Save format specifier */
- result->binary = binary;
-
- /*
- * If it's binary, fix the column format indicators. We assume the
- * backend will consistently send either B or D, not a mix.
- */
- if (binary)
- {
- for (i = 0; i < nfields; i++)
- result->attDescs[i].format = 1;
- }
-
- /* Get the null-value bitmap */
- nbytes = (nfields + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
- /* malloc() only for unusually large field counts... */
- if (nbytes > sizeof(std_bitmap))
- {
- bitmap = (char *) malloc(nbytes);
- if (!bitmap)
- {
- errmsg = NULL; /* means "out of memory", see below */
- goto advance_and_error;
- }
- }
-
- if (pqGetnchar(bitmap, nbytes, conn))
- goto EOFexit;
-
- /* Scan the fields */
- bitmap_index = 0;
- bmap = bitmap[bitmap_index];
- bitcnt = 0;
-
- for (i = 0; i < nfields; i++)
- {
- /* get the value length */
- if (!(bmap & 0200))
- vlen = NULL_LEN;
- else if (pqGetInt(&vlen, 4, conn))
- goto EOFexit;
- else
- {
- if (!binary)
- vlen = vlen - 4;
- if (vlen < 0)
- vlen = 0;
- }
- rowbuf[i].len = vlen;
-
- /*
- * rowbuf[i].value always points to the next address in the data
- * buffer even if the value is NULL. This allows row processors to
- * estimate data sizes more easily.
- */
- rowbuf[i].value = conn->inBuffer + conn->inCursor;
-
- /* Skip over the data value */
- if (vlen > 0)
- {
- if (pqSkipnchar(vlen, conn))
- goto EOFexit;
- }
-
- /* advance the bitmap stuff */
- bitcnt++;
- if (bitcnt == BITS_PER_BYTE)
- {
- bitmap_index++;
- bmap = bitmap[bitmap_index];
- bitcnt = 0;
- }
- else
- bmap <<= 1;
- }
-
- /* Release bitmap now if we allocated it */
- if (bitmap != std_bitmap)
- free(bitmap);
- bitmap = NULL;
-
- /* Advance inStart to show that the "D" message has been processed. */
- conn->inStart = conn->inCursor;
-
- /* Process the collected row */
- errmsg = NULL;
- if (pqRowProcessor(conn, &errmsg))
- return 0; /* normal, successful exit */
-
- goto set_error_result; /* pqRowProcessor failed, report it */
-
-advance_and_error:
-
- /*
- * Discard the failed message. Unfortunately we don't know for sure where
- * the end is, so just throw away everything in the input buffer. This is
- * not very desirable but it's the best we can do in protocol v2.
- */
- conn->inStart = conn->inEnd;
-
-set_error_result:
-
- /*
- * Replace partially constructed result with an error result. First
- * discard the old result to try to win back some memory.
- */
- pqClearAsyncResult(conn);
-
- /*
- * If preceding code didn't provide an error message, assume "out of
- * memory" was meant. The advantage of having this special case is that
- * freeing the old result first greatly improves the odds that gettext()
- * will succeed in providing a translation.
- */
- if (!errmsg)
- errmsg = libpq_gettext("out of memory for query result");
-
- appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
-
- /*
- * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can
- * do to recover...
- */
- conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
- conn->asyncStatus = PGASYNC_READY;
-
-EOFexit:
- if (bitmap != NULL && bitmap != std_bitmap)
- free(bitmap);
- return EOF;
-}
-
-
-/*
- * Attempt to read an Error or Notice response message.
- * This is possible in several places, so we break it out as a subroutine.
- * Entry: 'E' or 'N' message type has already been consumed.
- * Exit: returns 0 if successfully consumed message.
- * returns EOF if not enough data.
- */
-static int
-pqGetErrorNotice2(PGconn *conn, bool isError)
-{
- PGresult *res = NULL;
- PQExpBufferData workBuf;
- char *startp;
- char *splitp;
-
- /*
- * If this is an error message, pre-emptively clear any incomplete query
- * result we may have. We'd just throw it away below anyway, and
- * releasing it before collecting the error might avoid out-of-memory.
- */
- if (isError)
- pqClearAsyncResult(conn);
-
- /*
- * Since the message might be pretty long, we create a temporary
- * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended
- * for stuff that is expected to be short.
- */
- initPQExpBuffer(&workBuf);
- if (pqGets(&workBuf, conn))
- goto failure;
-
- /*
- * Make a PGresult to hold the message. We temporarily lie about the
- * result status, so that PQmakeEmptyPGresult doesn't uselessly copy
- * conn->errorMessage.
- *
- * NB: This allocation can fail, if you run out of memory. The rest of the
- * function handles that gracefully, and we still try to set the error
- * message as the connection's error message.
- */
- res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
- if (res)
- {
- res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
- res->errMsg = pqResultStrdup(res, workBuf.data);
- }
-
- /*
- * Break the message into fields. We can't do very much here, but we can
- * split the severity code off, and remove trailing newlines. Also, we use
- * the heuristic that the primary message extends only to the first
- * newline --- anything after that is detail message. (In some cases it'd
- * be better classed as hint, but we can hardly be expected to guess that
- * here.)
- */
- while (workBuf.len > 0 && workBuf.data[workBuf.len - 1] == '\n')
- workBuf.data[--workBuf.len] = '\0';
- splitp = strstr(workBuf.data, ": ");
- if (splitp)
- {
- /* what comes before the colon is severity */
- *splitp = '\0';
- pqSaveMessageField(res, PG_DIAG_SEVERITY, workBuf.data);
- startp = splitp + 3;
- }
- else
- {
- /* can't find a colon? oh well... */
- startp = workBuf.data;
- }
- splitp = strchr(startp, '\n');
- if (splitp)
- {
- /* what comes before the newline is primary message */
- *splitp++ = '\0';
- pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp);
- /* the rest is detail; strip any leading whitespace */
- while (*splitp && isspace((unsigned char) *splitp))
- splitp++;
- pqSaveMessageField(res, PG_DIAG_MESSAGE_DETAIL, splitp);
- }
- else
- {
- /* single-line message, so all primary */
- pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp);
- }
-
- /*
- * Either save error as current async result, or just emit the notice.
- * Also, if it's an error and we were in a transaction block, assume the
- * server has now gone to error-in-transaction state.
- */
- if (isError)
- {
- pqClearAsyncResult(conn); /* redundant, but be safe */
- conn->result = res;
- if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg)
- appendPQExpBufferStr(&conn->errorMessage, res->errMsg);
- else
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("out of memory"));
- if (conn->xactStatus == PQTRANS_INTRANS)
- conn->xactStatus = PQTRANS_INERROR;
- }
- else
- {
- if (res)
- {
- if (res->noticeHooks.noticeRec != NULL)
- res->noticeHooks.noticeRec(res->noticeHooks.noticeRecArg, res);
- PQclear(res);
- }
- }
-
- termPQExpBuffer(&workBuf);
- return 0;
-
-failure:
- if (res)
- PQclear(res);
- termPQExpBuffer(&workBuf);
- return EOF;
-}
-
-/*
- * checkXactStatus - attempt to track transaction-block status of server
- *
- * This is called each time we receive a command-complete message. By
- * watching for messages from BEGIN/COMMIT/ROLLBACK commands, we can do
- * a passable job of tracking the server's xact status. BUT: this does
- * not work at all on 7.3 servers with AUTOCOMMIT OFF. (Man, was that
- * feature ever a mistake.) Caveat user.
- *
- * The tags known here are all those used as far back as 7.0; is it worth
- * adding those from even-older servers?
- */
-static void
-checkXactStatus(PGconn *conn, const char *cmdTag)
-{
- if (strcmp(cmdTag, "BEGIN") == 0)
- conn->xactStatus = PQTRANS_INTRANS;
- else if (strcmp(cmdTag, "COMMIT") == 0)
- conn->xactStatus = PQTRANS_IDLE;
- else if (strcmp(cmdTag, "ROLLBACK") == 0)
- conn->xactStatus = PQTRANS_IDLE;
- else if (strcmp(cmdTag, "START TRANSACTION") == 0) /* 7.3 only */
- conn->xactStatus = PQTRANS_INTRANS;
-
- /*
- * Normally we get into INERROR state by detecting an Error message.
- * However, if we see one of these tags then we know for sure the server
- * is in abort state ...
- */
- else if (strcmp(cmdTag, "*ABORT STATE*") == 0) /* pre-7.3 only */
- conn->xactStatus = PQTRANS_INERROR;
-}
-
-/*
- * Attempt to read a Notify response message.
- * This is possible in several places, so we break it out as a subroutine.
- * Entry: 'A' message type and length have already been consumed.
- * Exit: returns 0 if successfully consumed Notify message.
- * returns EOF if not enough data.
- */
-static int
-getNotify(PGconn *conn)
-{
- int be_pid;
- int nmlen;
- PGnotify *newNotify;
-
- if (pqGetInt(&be_pid, 4, conn))
- return EOF;
- if (pqGets(&conn->workBuffer, conn))
- return EOF;
-
- /*
- * Store the relation name right after the PQnotify structure so it can
- * all be freed at once. We don't use NAMEDATALEN because we don't want
- * to tie this interface to a specific server name length.
- */
- nmlen = strlen(conn->workBuffer.data);
- newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + 1);
- if (newNotify)
- {
- newNotify->relname = (char *) newNotify + sizeof(PGnotify);
- strcpy(newNotify->relname, conn->workBuffer.data);
- /* fake up an empty-string extra field */
- newNotify->extra = newNotify->relname + nmlen;
- newNotify->be_pid = be_pid;
- newNotify->next = NULL;
- if (conn->notifyTail)
- conn->notifyTail->next = newNotify;
- else
- conn->notifyHead = newNotify;
- conn->notifyTail = newNotify;
- }
-
- return 0;
-}
-
-
-/*
- * PQgetCopyData - read a row of data from the backend during COPY OUT
- *
- * If successful, sets *buffer to point to a malloc'd row of data, and
- * returns row length (always > 0) as result.
- * Returns 0 if no row available yet (only possible if async is true),
- * -1 if end of copy (consult PQgetResult), or -2 if error (consult
- * PQerrorMessage).
- */
-int
-pqGetCopyData2(PGconn *conn, char **buffer, int async)
-{
- bool found;
- int msgLength;
-
- for (;;)
- {
- /*
- * Do we have a complete line of data?
- */
- conn->inCursor = conn->inStart;
- found = false;
- while (conn->inCursor < conn->inEnd)
- {
- char c = conn->inBuffer[conn->inCursor++];
-
- if (c == '\n')
- {
- found = true;
- break;
- }
- }
- if (!found)
- goto nodata;
- msgLength = conn->inCursor - conn->inStart;
-
- /*
- * If it's the end-of-data marker, consume it, exit COPY_OUT mode, and
- * let caller read status with PQgetResult().
- */
- if (msgLength == 3 &&
- strncmp(&conn->inBuffer[conn->inStart], "\\.\n", 3) == 0)
- {
- conn->inStart = conn->inCursor;
- conn->asyncStatus = PGASYNC_BUSY;
- return -1;
- }
-
- /*
- * Pass the line back to the caller.
- */
- *buffer = (char *) malloc(msgLength + 1);
- if (*buffer == NULL)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("out of memory\n"));
- return -2;
- }
- memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength);
- (*buffer)[msgLength] = '\0'; /* Add terminating null */
-
- /* Mark message consumed */
- conn->inStart = conn->inCursor;
-
- return msgLength;
-
-nodata:
- /* Don't block if async read requested */
- if (async)
- return 0;
- /* Need to load more data */
- if (pqWait(true, false, conn) ||
- pqReadData(conn) < 0)
- return -2;
- }
-}
-
-
-/*
- * PQgetline - gets a newline-terminated string from the backend.
- *
- * See fe-exec.c for documentation.
- */
-int
-pqGetline2(PGconn *conn, char *s, int maxlen)
-{
- int result = 1; /* return value if buffer overflows */
-
- if (conn->sock == PGINVALID_SOCKET ||
- conn->asyncStatus != PGASYNC_COPY_OUT)
- {
- *s = '\0';
- return EOF;
- }
-
- /*
- * Since this is a purely synchronous routine, we don't bother to maintain
- * conn->inCursor; there is no need to back up.
- */
- while (maxlen > 1)
- {
- if (conn->inStart < conn->inEnd)
- {
- char c = conn->inBuffer[conn->inStart++];
-
- if (c == '\n')
- {
- result = 0; /* success exit */
- break;
- }
- *s++ = c;
- maxlen--;
- }
- else
- {
- /* need to load more data */
- if (pqWait(true, false, conn) ||
- pqReadData(conn) < 0)
- {
- result = EOF;
- break;
- }
- }
- }
- *s = '\0';
-
- return result;
-}
-
-/*
- * PQgetlineAsync - gets a COPY data row without blocking.
- *
- * See fe-exec.c for documentation.
- */
-int
-pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize)
-{
- int avail;
-
- if (conn->asyncStatus != PGASYNC_COPY_OUT)
- return -1; /* we are not doing a copy... */
-
- /*
- * Move data from libpq's buffer to the caller's. We want to accept data
- * only in units of whole lines, not partial lines. This ensures that we
- * can recognize the terminator line "\\.\n". (Otherwise, if it happened
- * to cross a packet/buffer boundary, we might hand the first one or two
- * characters off to the caller, which we shouldn't.)
- */
-
- conn->inCursor = conn->inStart;
-
- avail = bufsize;
- while (avail > 0 && conn->inCursor < conn->inEnd)
- {
- char c = conn->inBuffer[conn->inCursor++];
-
- *buffer++ = c;
- --avail;
- if (c == '\n')
- {
- /* Got a complete line; mark the data removed from libpq */
- conn->inStart = conn->inCursor;
- /* Is it the endmarker line? */
- if (bufsize - avail == 3 && buffer[-3] == '\\' && buffer[-2] == '.')
- return -1;
- /* No, return the data line to the caller */
- return bufsize - avail;
- }
- }
-
- /*
- * We don't have a complete line. We'd prefer to leave it in libpq's
- * buffer until the rest arrives, but there is a special case: what if the
- * line is longer than the buffer the caller is offering us? In that case
- * we'd better hand over a partial line, else we'd get into an infinite
- * loop. Do this in a way that ensures we can't misrecognize a terminator
- * line later: leave last 3 characters in libpq buffer.
- */
- if (avail == 0 && bufsize > 3)
- {
- conn->inStart = conn->inCursor - 3;
- return bufsize - 3;
- }
- return 0;
-}
-
-/*
- * PQendcopy
- *
- * See fe-exec.c for documentation.
- */
-int
-pqEndcopy2(PGconn *conn)
-{
- PGresult *result;
-
- if (conn->asyncStatus != PGASYNC_COPY_IN &&
- conn->asyncStatus != PGASYNC_COPY_OUT)
- {
- appendPQExpBufferStr(&conn->errorMessage,
- libpq_gettext("no COPY in progress\n"));
- return 1;
- }
-
- /*
- * make sure no data is waiting to be sent, abort if we are non-blocking
- * and the flush fails
- */
- if (pqFlush(conn) && pqIsnonblocking(conn))
- return 1;
-
- /* non blocking connections may have to abort at this point. */
- if (pqIsnonblocking(conn) && PQisBusy(conn))
- return 1;
-
- /* Return to active duty */
- conn->asyncStatus = PGASYNC_BUSY;
-
- /* Wait for the completion response */
- result = PQgetResult(conn);
-
- /* Expecting a successful result */
- if (result && result->resultStatus == PGRES_COMMAND_OK)
- {
- PQclear(result);
- return 0;
- }
-
- /*
- * Trouble. For backwards-compatibility reasons, we issue the error
- * message as if it were a notice (would be nice to get rid of this
- * silliness, but too many apps probably don't handle errors from
- * PQendcopy reasonably). Note that the app can still obtain the error
- * status from the PGconn object.
- */
- if (conn->errorMessage.len > 0)
- {
- /* We have to strip the trailing newline ... pain in neck... */
- char svLast = conn->errorMessage.data[conn->errorMessage.len - 1];
-
- if (svLast == '\n')
- conn->errorMessage.data[conn->errorMessage.len - 1] = '\0';
- pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data);
- conn->errorMessage.data[conn->errorMessage.len - 1] = svLast;
- }
-
- PQclear(result);
-
- /*
- * The worst case is that we've lost sync with the backend entirely due to
- * application screwup of the copy in/out protocol. To recover, reset the
- * connection (talk about using a sledgehammer...)
- */
- pqInternalNotice(&conn->noticeHooks,
- "lost synchronization with server, resetting connection");
-
- /*
- * Users doing non-blocking connections need to handle the reset
- * themselves, they'll need to check the connection status if we return an
- * error.
- */
- if (pqIsnonblocking(conn))
- PQresetStart(conn);
- else
- PQreset(conn);
-
- return 1;
-}
-
-
-/*
- * PQfn - Send a function call to the POSTGRES backend.
- *
- * See fe-exec.c for documentation.
- */
-PGresult *
-pqFunctionCall2(PGconn *conn, Oid fnid,
- int *result_buf, int *actual_result_len,
- int result_is_int,
- const PQArgBlock *args, int nargs)
-{
- bool needInput = false;
- ExecStatusType status = PGRES_FATAL_ERROR;
- char id;
- int i;
-
- /* PQfn already validated connection state */
-
- if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */
- pqPuts(" ", conn) < 0 || /* dummy string */
- pqPutInt(fnid, 4, conn) != 0 || /* function id */
- pqPutInt(nargs, 4, conn) != 0) /* # of args */
- {
- /* error message should be set up already */
- return NULL;
- }
-
- for (i = 0; i < nargs; ++i)
- { /* len.int4 + contents */
- if (pqPutInt(args[i].len, 4, conn))
- return NULL;
-
- if (args[i].isint)
- {
- if (pqPutInt(args[i].u.integer, 4, conn))
- return NULL;
- }
- else
- {
- if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn))
- return NULL;
- }
- }
-
- if (pqPutMsgEnd(conn) < 0 ||
- pqFlush(conn))
- return NULL;
-
- for (;;)
- {
- if (needInput)
- {
- /* Wait for some data to arrive (or for the channel to close) */
- if (pqWait(true, false, conn) ||
- pqReadData(conn) < 0)
- break;
- }
-
- /*
- * Scan the message. If we run out of data, loop around to try again.
- */
- conn->inCursor = conn->inStart;
- needInput = true;
-
- if (pqGetc(&id, conn))
- continue;
-
- /*
- * We should see V or E response to the command, but might get N
- * and/or A notices first. We also need to swallow the final Z before
- * returning.
- */
- switch (id)
- {
- case 'V': /* function result */
- if (pqGetc(&id, conn))
- continue;
- if (id == 'G')
- {
- /* function returned nonempty value */
- if (pqGetInt(actual_result_len, 4, conn))
- continue;
- if (result_is_int)
- {
- if (pqGetInt(result_buf, 4, conn))
- continue;
- }
- else
- {
- if (pqGetnchar((char *) result_buf,
- *actual_result_len,
- conn))
- continue;
- }
- if (pqGetc(&id, conn)) /* get the last '0' */
- continue;
- }
- if (id == '0')
- {
- /* correctly finished function result message */
- status = PGRES_COMMAND_OK;
- }
- else
- {
- /* The backend violates the protocol. */
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("protocol error: id=0x%x\n"),
- id);
- pqSaveErrorResult(conn);
- conn->inStart = conn->inCursor;
- return pqPrepareAsyncResult(conn);
- }
- break;
- case 'E': /* error return */
- if (pqGetErrorNotice2(conn, true))
- continue;
- status = PGRES_FATAL_ERROR;
- break;
- case 'A': /* notify message */
- /* handle notify and go back to processing return values */
- if (getNotify(conn))
- continue;
- break;
- case 'N': /* notice */
- /* handle notice and go back to processing return values */
- if (pqGetErrorNotice2(conn, false))
- continue;
- break;
- case 'Z': /* backend is ready for new query */
- /* consume the message and exit */
- conn->inStart = conn->inCursor;
- /* if we saved a result object (probably an error), use it */
- if (conn->result)
- return pqPrepareAsyncResult(conn);
- return PQmakeEmptyPGresult(conn, status);
- default:
- /* The backend violates the protocol. */
- appendPQExpBuffer(&conn->errorMessage,
- libpq_gettext("protocol error: id=0x%x\n"),
- id);
- pqSaveErrorResult(conn);
- conn->inStart = conn->inCursor;
- return pqPrepareAsyncResult(conn);
- }
- /* Completed this message, keep going */
- conn->inStart = conn->inCursor;
- needInput = false;
- }
-
- /*
- * We fall out of the loop only upon failing to read data.
- * conn->errorMessage has been set by pqWait or pqReadData. We want to
- * append it to any already-received error message.
- */
- pqSaveErrorResult(conn);
- return pqPrepareAsyncResult(conn);
-}
-
-
-/*
- * Construct startup packet
- *
- * Returns a malloc'd packet buffer, or NULL if out of memory
- */
-char *
-pqBuildStartupPacket2(PGconn *conn, int *packetlen,
- const PQEnvironmentOption *options)
-{
- StartupPacket *startpacket;
-
- *packetlen = sizeof(StartupPacket);
- startpacket = (StartupPacket *) malloc(sizeof(StartupPacket));
- if (!startpacket)
- return NULL;
-
- MemSet(startpacket, 0, sizeof(StartupPacket));
-
- startpacket->protoVersion = pg_hton32(conn->pversion);
-
- /* strncpy is safe here: postmaster will handle full fields correctly */
- strncpy(startpacket->user, conn->pguser, SM_USER);
- strncpy(startpacket->database, conn->dbName, SM_DATABASE);
- strncpy(startpacket->tty, conn->pgtty, SM_TTY);
-
- if (conn->pgoptions)
- strncpy(startpacket->options, conn->pgoptions, SM_OPTIONS);
-
- return (char *) startpacket;
-}
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index e4ee9d69d25..2ca8c057b9d 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -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 */
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 47a098b4b93..fa9b62a8449 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -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. */
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 0c9e95f1a7a..8d51e6ed9ff 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -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);
diff --git a/src/interfaces/libpq/nls.mk b/src/interfaces/libpq/nls.mk
index 3175ae3e1c3..f64101b2a6a 100644
--- a/src/interfaces/libpq/nls.mk
+++ b/src/interfaces/libpq/nls.mk
@@ -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