summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/dialects/postgresql/_psycopg_common.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2022-08-01 10:29:13 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2022-08-01 15:21:04 -0400
commitddc326585a5a40d5c5e18444b14022e78751cdbb (patch)
tree08ca4205f3197a8b393eb1fac62d7bf43c3144d6 /lib/sqlalchemy/dialects/postgresql/_psycopg_common.py
parent3ff18812d8d80b2016ceeea98c808a76cae85e48 (diff)
downloadsqlalchemy-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.py27
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()