66
77import yaml
88
9- from ..collections import CaseInsensitiveDict
9+ from ..collections import CaseInsensitiveDict , CaseInsensitiveSet
1010from ..exceptions import PatroniException
1111from ..utils import parse_bool , parse_int , parse_real
1212from .available_parameters import get_validator_files , PathLikeObj
@@ -412,8 +412,9 @@ class in this module.
412412
413413
414414def _transform_parameter_value (validators : MutableMapping [str , Tuple [_Transformable , ...]],
415- version : int , name : str , value : Any ) -> Optional [Any ]:
416- """Validate *value* of GUC *name* for Postgres *version* using defined *validators*.
415+ version : int , name : str , value : Any ,
416+ available_gucs : CaseInsensitiveSet ) -> Optional [Any ]:
417+ """Validate *value* of GUC *name* for Postgres *version* using defined *validators* and *available_gucs*.
417418
418419 :param validators: a dictionary of all GUCs across all Postgres versions. Each key is the name of a Postgres GUC,
419420 and the corresponding value is a variable length tuple of :class:`_Transformable`. Each item is a validation
@@ -422,30 +423,37 @@ def _transform_parameter_value(validators: MutableMapping[str, Tuple[_Transforma
422423 :param version: Postgres version to validate the GUC against.
423424 :param name: name of the Postgres GUC.
424425 :param value: value of the Postgres GUC.
425-
426- * Disallow writing GUCs to ``postgresql.conf`` (or ``recovery.conf``) that does not exist in Postgres *version*;
427- * Avoid ignoring GUC *name* if it does not have a validator in *validators*, but is a valid GUC in Postgres
428- *version*.
426+ :param available_gucs: a set of all GUCs available in Postgres *version*. Each item is the name of a Postgres
427+ GUC. Used to avoid ignoring GUC *name* if it does not have a validator in *validators*, but is a valid GUC
428+ in Postgres *version*.
429429
430430 :returns: the return value may be one among:
431431
432432 * *value* transformed to the expected format for GUC *name* in Postgres *version*, if *name* has a validator
433433 in *validators* for the corresponding Postgres *version*; or
434- * ``None`` if *name* does not have a validator in *validators*.
434+ * ``None`` if *name* does not have a validator in *validators* and is not present in *available_gucs* .
435435 """
436436 for validator in validators .get (name , ()) or ():
437437 if version >= validator .version_from and \
438438 (validator .version_till is None or version < validator .version_till ):
439439 return validator .transform (name , value )
440+ # Ideally we should have a validator in *validators*. However, if none is available, we will not discard a
441+ # setting that exists in Postgres *version*, but rather allow the value with no validation.
442+ if name in available_gucs :
443+ return value
440444 logger .warning ('Removing unexpected parameter=%s value=%s from the config' , name , value )
441445
442446
443- def transform_postgresql_parameter_value (version : int , name : str , value : Any ) -> Optional [Any ]:
444- """Validate *value* of GUC *name* for Postgres *version* using ``parameters``.
447+ def transform_postgresql_parameter_value (version : int , name : str , value : Any ,
448+ available_gucs : CaseInsensitiveSet ) -> Optional [Any ]:
449+ """Validate *value* of GUC *name* for Postgres *version* using ``parameters`` and *available_gucs*.
445450
446451 :param version: Postgres version to validate the GUC against.
447452 :param name: name of the Postgres GUC.
448453 :param value: value of the Postgres GUC.
454+ :param available_gucs: a set of all GUCs available in Postgres *version*. Each item is the name of a Postgres
455+ GUC. Used to avoid ignoring GUC *name* if it does not have a validator in ``parameters``, but is a valid GUC in
456+ Postgres *version*.
449457
450458 :returns: The return value may be one among:
451459
@@ -460,17 +468,28 @@ def transform_postgresql_parameter_value(version: int, name: str, value: Any) ->
460468 return value
461469 if name in recovery_parameters :
462470 return None
463- return _transform_parameter_value (parameters , version , name , value )
471+ return _transform_parameter_value (parameters , version , name , value , available_gucs )
464472
465473
466- def transform_recovery_parameter_value (version : int , name : str , value : Any ) -> Optional [Any ]:
467- """Validate *value* of GUC *name* for Postgres *version* using ``recovery_parameters``.
474+ def transform_recovery_parameter_value (version : int , name : str , value : Any ,
475+ available_gucs : CaseInsensitiveSet ) -> Optional [Any ]:
476+ """Validate *value* of GUC *name* for Postgres *version* using ``recovery_parameters`` and *available_gucs*.
468477
469478 :param version: Postgres version to validate the recovery GUC against.
470479 :param name: name of the Postgres recovery GUC.
471480 :param value: value of the Postgres recovery GUC.
481+ :param available_gucs: a set of all GUCs available in Postgres *version*. Each item is the name of a Postgres
482+ GUC. Used to avoid ignoring GUC *name* if it does not have a validator in ``parameters``, but is a valid GUC in
483+ Postgres *version*.
472484
473485 :returns: *value* transformed to the expected format for recovery GUC *name* in Postgres *version* using validators
474486 defined in ``recovery_parameters``. It can also return ``None``. See :func:`_transform_parameter_value`.
475487 """
476- return _transform_parameter_value (recovery_parameters , version , name , value )
488+ # Recovery settings are not present in ``postgres --describe-config`` output of Postgres <= 11. In that case we
489+ # just pass down the list of settings defined in Patroni validators so :func:`_transform_parameter_value` will not
490+ # discard the recovery GUCs when running Postgres <= 11.
491+ # NOTE: At the moment this change was done Postgres 11 was almost EOL, and had been likely extensively used with
492+ # Patroni, so we should be able to rely solely on Patroni validators as the source of truth.
493+ return _transform_parameter_value (
494+ recovery_parameters , version , name , value ,
495+ available_gucs if version >= 120000 else CaseInsensitiveSet (recovery_parameters .keys ()))
0 commit comments