<productname>PostgreSQL</productname> 7.4 and later. For descriptions
of the earlier protocol versions, see previous releases of the
<productname>PostgreSQL</productname> documentation. A single server
- can support multiple protocol versions. The initial
- startup-request message tells the server which protocol version the
- client is attempting to use, and then the server follows that protocol
- if it is able.
+ can support multiple protocol versions. The initial startup-request
+ message tells the server which protocol version the client is attempting to
+ use. If the major version requested by the client is not supported by
+ the server, the connection will be rejected (for example, this would occur
+ if the client requested protocol version 4.0, which does not exist as of
+ this writing). If the minor version requested by the client is not
+ supported by the server (e.g. the client requests version 3.1, but the
+ server supports only 3.0), the server may either reject the connection or
+ may respond with a NegotiateProtocolVersion message containing the highest
+ minor protocol version which it supports. The client may then choose either
+ to continue with the connection using the specified protocol version or
+ to abort the connection.
</para>
<para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>NegotiateProtocolVersion</term>
+ <listitem>
+ <para>
+ The server does not support the minor protocol version requested
+ by the client, but does support an earlier version of the protocol;
+ this message indicates the highest supported minor version. This
+ message will also be sent if the client requested unsupported protocol
+ options (i.e. beginning with <literal>_pq_.</literal>) in the
+ startup packet. This message will be followed by an ErrorResponse or
+ a message indicating the success or failure of authentication.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
for further messages from the server. In this phase a backend process
is being started, and the frontend is just an interested bystander.
It is still possible for the startup attempt
- to fail (ErrorResponse), but in the normal case the backend will send
- some ParameterStatus messages, BackendKeyData, and finally ReadyForQuery.
+ to fail (ErrorResponse) or the server to decline support for the requested
+ minor protocol version (NegotiateProtocolVersion), but in the normal case
+ the backend will send some ParameterStatus messages, BackendKeyData, and
+ finally ReadyForQuery.
</para>
<para>
</listitem>
</varlistentry>
+<varlistentry>
+<term>
+NegotiateProtocolVersion (B)
+</term>
+<listitem>
+<para>
+
+<variablelist>
+<varlistentry>
+<term>
+ Byte1('v')
+</term>
+<listitem>
+<para>
+ Identifies the message as a protocol version negotiation
+ message.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+ Int32
+</term>
+<listitem>
+<para>
+ Length of message contents in bytes, including self.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+ Int32
+</term>
+<listitem>
+<para>
+ Newest minor protocol version supported by the server
+ for the major protocol version requested by the client.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+ Int32
+</term>
+<listitem>
+<para>
+ Number of protocol options not recognized by the server.
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+ Then, for protocol option not recognized by the server, there
+ is the following:
+<variablelist>
+<varlistentry>
+<term>
+ String
+</term>
+<listitem>
+<para>
+ The option name.
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</para>
+</listitem>
+</varlistentry>
<varlistentry>
<term>
</varlistentry>
</variablelist>
- In addition to the above, any run-time parameter that can be
- set at backend start time might be listed. Such settings
- will be applied during backend start (after parsing the
- command-line arguments if any). The values will act as
- session defaults.
+ In addition to the above, others parameter may be listed.
+ Parameter names beginning with <literal>_pq_.</literal> are
+ reserved for use as protocol extensions, while others are
+ treated as run-time parameters to be set at backend start
+ time. Such settings will be applied during backend start
+ (after parsing the command-line arguments if any) and will
+ act as session defaults.
</para>
</listitem>
</varlistentry>
#include "libpq/auth.h"
#include "libpq/ip.h"
#include "libpq/libpq.h"
+#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pg_getopt.h"
static int ServerLoop(void);
static int BackendStartup(Port *port);
static int ProcessStartupPacket(Port *port, bool SSLdone);
+static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options);
static void processCancelRequest(Port *port, void *pkt);
static int initMasks(fd_set *rmask);
static void report_fork_failure_to_client(Port *port, int errnum);
*/
FrontendProtocol = proto;
- /* Check we can handle the protocol the frontend is using. */
-
+ /* Check that the major protocol version is in range. */
if (PG_PROTOCOL_MAJOR(proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
- PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
- (PG_PROTOCOL_MAJOR(proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
- PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
+ PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST))
ereport(FATAL,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u",
if (PG_PROTOCOL_MAJOR(proto) >= 3)
{
int32 offset = sizeof(ProtocolVersion);
+ List *unrecognized_protocol_options = NIL;
/*
* Scan packet body for name/option pairs. We can assume any string
valptr),
errhint("Valid values are: \"false\", 0, \"true\", 1, \"database\".")));
}
+ else if (strncmp(nameptr, "_pq_.", 5) == 0)
+ {
+ /*
+ * Any option beginning with _pq_. is reserved for use as a
+ * protocol-level option, but at present no such options are
+ * defined.
+ */
+ unrecognized_protocol_options =
+ lappend(unrecognized_protocol_options, pstrdup(nameptr));
+ }
else
{
/* Assume it's a generic GUC option */
ereport(FATAL,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid startup packet layout: expected terminator as last byte")));
+
+ /*
+ * If the client requested a newer protocol version or if the client
+ * requested any protocol options we didn't recognize, let them know
+ * the newest minor protocol version we do support and the names of any
+ * unrecognized options.
+ */
+ if (PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST) ||
+ unrecognized_protocol_options != NIL)
+ SendNegotiateProtocolVersion(unrecognized_protocol_options);
}
else
{
return STATUS_OK;
}
+/*
+ * Send a NegotiateProtocolVersion to the client. This lets the client know
+ * that they have requested a newer minor protocol version than we are able
+ * to speak. We'll speak the highest version we know about; the client can,
+ * of course, abandon the connection if that's a problem.
+ *
+ * We also include in the response a list of protocol options we didn't
+ * understand. This allows clients to include optional parameters that might
+ * be present either in newer protocol versions or third-party protocol
+ * extensions without fear of having to reconnect if those options are not
+ * understood, while at the same time making certain that the client is aware
+ * of which options were actually accepted.
+ */
+static void
+SendNegotiateProtocolVersion(List *unrecognized_protocol_options)
+{
+ StringInfoData buf;
+ ListCell *lc;
+
+ pq_beginmessage(&buf, 'v'); /* NegotiateProtocolVersion */
+ pq_sendint(&buf, PG_PROTOCOL_LATEST, 4);
+ pq_sendint(&buf, list_length(unrecognized_protocol_options), 4);
+ foreach(lc, unrecognized_protocol_options)
+ pq_sendstring(&buf, lfirst(lc));
+ pq_endmessage(&buf);
+
+ /* no need to flush, some other message will follow */
+}
/*
* The client has sent a cancel request packet, not a normal