Fix bug in quote_standby_name() function (#3161)

According to Postgres docs "ANY" and "FIRST" keywords are supposed to be double-quoted.

Ref: https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-SYNCHRONOUS-STANDBY-NAMES
This commit is contained in:
Alexander Kukushkin
2024-09-13 14:21:22 +02:00
committed by GitHub
parent 4c951a2937
commit 74a72e4f78
2 changed files with 12 additions and 7 deletions
+10 -5
View File
@@ -8,7 +8,7 @@ from typing import Collection, List, NamedTuple, Optional, TYPE_CHECKING
from .. import global_config
from ..collections import CaseInsensitiveDict, CaseInsensitiveSet
from ..dcs import Cluster
from ..psycopg import quote_ident as _quote_ident
from ..psycopg import quote_ident
if TYPE_CHECKING: # pragma: no cover
from . import Postgresql
@@ -31,9 +31,14 @@ SYNC_REP_PARSER_RE = re.compile(r"""
""", re.X)
def quote_ident(value: str) -> str:
"""Very simplified version of `psycopg` :func:`quote_ident` function."""
return value if SYNC_STANDBY_NAME_RE.match(value) else _quote_ident(value)
def quote_standby_name(value: str) -> str:
"""Quote provided *value* if it is nenecessary.
:param value: name of a synchronous standby.
:returns: a quoted value if it is required or the original one.
"""
return value if SYNC_STANDBY_NAME_RE.match(value) and value.lower() not in ('first', 'any') else quote_ident(value)
class _SSN(NamedTuple):
@@ -391,7 +396,7 @@ END;$$""")
if has_asterisk:
sync = ['*']
else:
sync = [quote_ident(x) for x in sorted(sync)]
sync = [quote_standby_name(x) for x in sorted(sync)]
if self._postgresql.supports_multiple_sync and len(sync) > 1:
if num is None:
+2 -2
View File
@@ -128,9 +128,9 @@ class TestSync(BaseTestPostgresql):
self.assertEqual(value_in_conf(), "synchronous_standby_names = 'ANY 1 (*)'")
mock_reload.reset_mock()
self.s.set_synchronous_standby_names(['a', 'b'], 1)
self.s.set_synchronous_standby_names(['any', 'b'], 1)
mock_reload.assert_called()
self.assertEqual(value_in_conf(), "synchronous_standby_names = 'ANY 1 (a,b)'")
self.assertEqual(value_in_conf(), "synchronous_standby_names = 'ANY 1 (\"any\",b)'")
mock_reload.reset_mock()
self.s.set_synchronous_standby_names(['a', 'b'], 3)