diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-08-01 10:29:13 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-08-01 15:21:04 -0400 |
commit | ddc326585a5a40d5c5e18444b14022e78751cdbb (patch) | |
tree | 08ca4205f3197a8b393eb1fac62d7bf43c3144d6 /lib/sqlalchemy/dialects/postgresql/_psycopg_common.py | |
parent | 3ff18812d8d80b2016ceeea98c808a76cae85e48 (diff) | |
download | sqlalchemy-ddc326585a5a40d5c5e18444b14022e78751cdbb.tar.gz |
repair psycopg2 (and psycopg) multiple hosts format
Fixed issue in psycopg2 dialect where the "multiple hosts" feature
implemented for :ticket:`4392`, where multiple ``host:port`` pairs could be
passed in the query string as
``?host=host1:port1&host=host2:port2&host=host3:port3`` was not implemented
correctly, as it did not propagate the "port" parameter appropriately.
Connections that didn't use a different "port" likely worked without issue,
and connections that had "port" for some of the entries may have
incorrectly passed on that hostname. The format is now corrected to pass
hosts/ports appropriately.
As part of this change, maintained support for another multihost style that
worked unintentionally, which is comma-separated
``?host=h1,h2,h3&port=p1,p2,p3``. This format is more consistent with
libpq's query-string format, whereas the previous format is inspired by a
different aspect of libpq's URI format but is not quite the same thing.
If the two styles are mixed together, an error is raised as this is
ambiguous.
Fixes: #4392
Change-Id: Ic9cc0b0e6e90725e158d9efe73e042853dd1263f
Diffstat (limited to 'lib/sqlalchemy/dialects/postgresql/_psycopg_common.py')
-rw-r--r-- | lib/sqlalchemy/dialects/postgresql/_psycopg_common.py | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/_psycopg_common.py b/lib/sqlalchemy/dialects/postgresql/_psycopg_common.py index 8dcd36c6d..efd1dbe41 100644 --- a/lib/sqlalchemy/dialects/postgresql/_psycopg_common.py +++ b/lib/sqlalchemy/dialects/postgresql/_psycopg_common.py @@ -131,20 +131,27 @@ class _PGDialect_common_psycopg(PGDialect): if "host" in url.query: is_multihost = isinstance(url.query["host"], (list, tuple)) - if opts: + if opts or url.query: + if not opts: + opts = {} if "port" in opts: opts["port"] = int(opts["port"]) opts.update(url.query) if is_multihost: - opts["host"] = ",".join(url.query["host"]) - # send individual dbname, user, password, host, port - # parameters to psycopg2.connect() - return ([], opts) - elif url.query: - # any other connection arguments, pass directly - opts.update(url.query) - if is_multihost: - opts["host"] = ",".join(url.query["host"]) + hosts, ports = zip( + *[ + token.split(":") if ":" in token else (token, "") + for token in url.query["host"] + ] + ) + opts["host"] = ",".join(hosts) + if "port" in opts: + raise exc.ArgumentError( + "Can't mix 'multihost' formats together; use " + '"host=h1,h2,h3&port=p1,p2,p3" or ' + '"host=h1:p1&host=h2:p2&host=h3:p3" separately' + ) + opts["port"] = ",".join(ports) return ([], opts) else: # no connection arguments whatsoever; psycopg2.connect() |