From a5ef6cc738123b6ad2032a20ab0a8cc983cf2f0e Mon Sep 17 00:00:00 2001 From: Badrul Chowdhury Date: Wed, 18 Oct 2017 15:26:33 -0700 Subject: [PATCH] BE changes for pgwire v3.1. --- src/backend/postmaster/postmaster.c | 80 +++++++++++++++++++++++++++++++++++-- src/include/libpq/libpq-be.h | 1 + 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 95180b2ef5..1eafdea87b 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -387,6 +387,7 @@ static DNSServiceRef bonjour_sdref = NULL; /* * postmaster.c - function prototypes */ +static int NegotiateServerProtocol(Port *port); static void CloseServerPorts(int status, Datum arg); static void unlink_external_pid_file(int status, Datum arg); static void getInstallationPaths(const char *argv0); @@ -1368,6 +1369,48 @@ PostmasterMain(int argc, char *argv[]) abort(); /* not reached */ } +static int +NegotiateServerProtocol(Port *port) +{ + StringInfoData buf; + char *name; + ListCell *optional_params; + + /* + * NegotiateServerProtocol packet structure + * + * [ 'Y' | msgLength | min_version | max_version | param_list_len | list + * of param names ] + */ + + /* PG message type */ + pq_beginmessage(&buf, 'Y'); + + /* Protocol version numbers */ + pq_sendint(&buf, PG_PROTOCOL_EARLIEST, sizeof(int32)); /* min */ + pq_sendint(&buf, PG_PROTOCOL_LATEST, sizeof(int32)); /* max */ + + /* Length of parameter list; parameter list consists of (key, value) pairs */ + pq_sendint(&buf, list_length(port->optional_parameters) / 2, sizeof(int32)); + + optional_params = list_head(port->optional_parameters); + while (optional_params) + { + /* First comes key, which we need. */ + name = lfirst(optional_params); + optional_params = lnext(optional_params); + + /* Then comes value, which we don't need. */ + optional_params = lnext(optional_params); + + pq_sendstring(&buf, name); + } + + pq_endmessage(&buf); + + /* Ensure that the message buffer is flushed */ + pq_flush(); +} /* * on_proc_exit callback to close server's listen sockets @@ -2050,12 +2093,10 @@ retry1: */ FrontendProtocol = proto; - /* Check we can handle the protocol the frontend is using. */ + /* Check we can handle the major protocol the frontend is using. */ 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", @@ -2126,6 +2167,13 @@ retry1: valptr), errhint("Valid values are: \"false\", 0, \"true\", 1, \"database\"."))); } + else if (strlen(nameptr) > 4 && strncmp(nameptr, "_pq_", 4) == 0) + { + port->optional_parameters = lappend(port->optional_parameters, + pstrdup(nameptr)); + port->optional_parameters = lappend(port->optional_parameters, + pstrdup(valptr)); + } else { /* Assume it's a generic GUC option */ @@ -2145,9 +2193,33 @@ retry1: ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid startup packet layout: expected terminator as last byte"))); + + /* + * Need to negotiate pgwire protocol if FE version is not the same + * as BE version and FE version is not 3.0 + */ + if (FrontendProtocol != PG_PROTOCOL_LATEST + && FrontendProtocol != PG_PROTOCOL(3, 0)) + { + /* Negotiate parameters after all the error-checking is done */ + if (NegotiateServerProtocol(port)) + return STATUS_ERROR; + } } else { + /* Check we can handle the minor protocol the frontend is using. */ + + if (PG_PROTOCOL_MAJOR(proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) && + PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)) + ereport(FATAL, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u", + PG_PROTOCOL_MAJOR(proto), PG_PROTOCOL_MINOR(proto), + PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST), + PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST), + PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))); + /* * Get the parameters from the old-style, fixed-width-fields startup * packet as C strings. The packet destination was cleared first so a diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index 7bde744d51..8b2ef62580 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -137,6 +137,7 @@ typedef struct Port char *user_name; char *cmdline_options; List *guc_options; + List *optional_parameters; /* * Information that needs to be held during the authentication cycle. -- 2.13.2.windows.1