mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-28 20:57:56 +00:00
postfix-3.9-20230419
This commit is contained in:
parent
60a45f8f21
commit
38163b3ac4
@ -27055,3 +27055,26 @@ Apologies for any names omitted.
|
|||||||
Cleanup: in source-code comments, replaced redundant (and
|
Cleanup: in source-code comments, replaced redundant (and
|
||||||
sometimes incomplete) lookup table configuration info with
|
sometimes incomplete) lookup table configuration info with
|
||||||
a reference to the corresponding *_table(5) manpage.
|
a reference to the corresponding *_table(5) manpage.
|
||||||
|
|
||||||
|
20230417
|
||||||
|
|
||||||
|
Cleanup: in the MySQL client configuration file, the default
|
||||||
|
characterset is now configurable with the "charset" attribute.
|
||||||
|
Previously, the default was determined by the MySQL
|
||||||
|
implementation (utf8mb4 as of MySQL 8.0, latin1 with older
|
||||||
|
versions). This setting implicitly controls the collation
|
||||||
|
order. Files: proto/mysql_table, global/dict_mysql.c.
|
||||||
|
|
||||||
|
20230418
|
||||||
|
|
||||||
|
Bugfix (introduced: Postfix 3.2): the MySQL client could
|
||||||
|
return "not found" instead of "error" (for example, resulting
|
||||||
|
in a 5XX SMTP status instead of 4XX) during the time that
|
||||||
|
all MySQL server connections were turned down after error.
|
||||||
|
Found during code maintenance. File: global/dict_mysql.c.
|
||||||
|
|
||||||
|
20230419
|
||||||
|
|
||||||
|
Cleanup: in the PostgreSQL client, cosmetic changes to make
|
||||||
|
the code easier to maintain (in preparation for adding new
|
||||||
|
functionality). File: global/dict_pgsql.c.
|
||||||
|
@ -25,3 +25,11 @@ now also distributed with the more recent Eclipse Public License
|
|||||||
(EPL) 2.0. Recipients can choose to take the software under the
|
(EPL) 2.0. Recipients can choose to take the software under the
|
||||||
license of their choice. Those who are more comfortable with the
|
license of their choice. Those who are more comfortable with the
|
||||||
IPL can continue with that license.
|
IPL can continue with that license.
|
||||||
|
|
||||||
|
Incompatible changes with snapshot 20230419
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
The MySQL client default characterset is now configurable with the
|
||||||
|
"charset" configuration file attribute. The default is "utf8mb4",
|
||||||
|
consistent with the MySQL 8.0 built-in default, but different from
|
||||||
|
earlier MySQL versions where the built-in default was "latin1".
|
||||||
|
@ -18,6 +18,9 @@ Wish list:
|
|||||||
|
|
||||||
Follow https://github.com/vdukhovni/postfix/commits/rpk
|
Follow https://github.com/vdukhovni/postfix/commits/rpk
|
||||||
|
|
||||||
|
Figure out which mysql_*escape_string*() variant to use and
|
||||||
|
handle error results accordingly.
|
||||||
|
|
||||||
Multi-recipient support in sender/recipient_bcc_maps and
|
Multi-recipient support in sender/recipient_bcc_maps and
|
||||||
always_bcc.
|
always_bcc.
|
||||||
|
|
||||||
|
@ -72,56 +72,64 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
<b>dbname</b> The database name on the servers. Example:
|
<b>dbname</b> The database name on the servers. Example:
|
||||||
dbname = customer_database
|
dbname = customer_database
|
||||||
|
|
||||||
<b>query</b> The SQL query template used to search the database, where <b>%s</b> is
|
<b>charset (default: utf8mb4)</b>
|
||||||
a substitute for the address Postfix is trying to resolve, e.g.
|
The default MySQL client character set; this also implies the
|
||||||
|
collation order.
|
||||||
|
|
||||||
|
This parameter is available with Postfix 3.9 and later. With
|
||||||
|
earlier Postfix versions, the default was chosen by the MySQL
|
||||||
|
implementation (<b>utf8mb4</b> as of MySQL 8.0, <b>latin1</b> historically).
|
||||||
|
|
||||||
|
<b>query</b> The SQL query template used to search the database, where <b>%s</b> is
|
||||||
|
a substitute for the address Postfix is trying to resolve, e.g.
|
||||||
query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
||||||
|
|
||||||
By default, every query must return a result set (instead of
|
By default, every query must return a result set (instead of
|
||||||
storing its results in a table); with "<b>require_result_set = no</b>"
|
storing its results in a table); with "<b>require_result_set = no</b>"
|
||||||
(Postfix 3.2 and later), the absence of a result set is treated
|
(Postfix 3.2 and later), the absence of a result set is treated
|
||||||
as "not found".
|
as "not found".
|
||||||
|
|
||||||
This parameter supports the following '%' expansions:
|
This parameter supports the following '%' expansions:
|
||||||
|
|
||||||
<b>%%</b> This is replaced by a literal '%' character.
|
<b>%%</b> This is replaced by a literal '%' character.
|
||||||
|
|
||||||
<b>%s</b> This is replaced by the input key. SQL quoting is used
|
<b>%s</b> This is replaced by the input key. SQL quoting is used
|
||||||
to make sure that the input key does not add unexpected
|
to make sure that the input key does not add unexpected
|
||||||
metacharacters.
|
metacharacters.
|
||||||
|
|
||||||
<b>%u</b> When the input key is an address of the form user@domain,
|
<b>%u</b> When the input key is an address of the form user@domain,
|
||||||
<b>%u</b> is replaced by the SQL quoted local part of the
|
<b>%u</b> is replaced by the SQL quoted local part of the
|
||||||
address. Otherwise, <b>%u</b> is replaced by the entire search
|
address. Otherwise, <b>%u</b> is replaced by the entire search
|
||||||
string. If the localpart is empty, the query is sup-
|
string. If the localpart is empty, the query is sup-
|
||||||
pressed and returns no results.
|
pressed and returns no results.
|
||||||
|
|
||||||
<b>%d</b> When the input key is an address of the form user@domain,
|
<b>%d</b> When the input key is an address of the form user@domain,
|
||||||
<b>%d</b> is replaced by the SQL quoted domain part of the
|
<b>%d</b> is replaced by the SQL quoted domain part of the
|
||||||
address. Otherwise, the query is suppressed and returns
|
address. Otherwise, the query is suppressed and returns
|
||||||
no results.
|
no results.
|
||||||
|
|
||||||
<b>%[SUD]</b> The upper-case equivalents of the above expansions behave
|
<b>%[SUD]</b> The upper-case equivalents of the above expansions behave
|
||||||
in the <b>query</b> parameter identically to their lower-case
|
in the <b>query</b> parameter identically to their lower-case
|
||||||
counter-parts. With the <b>result_format</b> parameter (see
|
counter-parts. With the <b>result_format</b> parameter (see
|
||||||
below), they expand the input key rather than the result
|
below), they expand the input key rather than the result
|
||||||
value.
|
value.
|
||||||
|
|
||||||
<b>%[1-9]</b> The patterns %1, %2, ... %9 are replaced by the corre-
|
<b>%[1-9]</b> The patterns %1, %2, ... %9 are replaced by the corre-
|
||||||
sponding most significant component of the input key's
|
sponding most significant component of the input key's
|
||||||
domain. If the input key is <i>user@mail.example.com</i>, then
|
domain. If the input key is <i>user@mail.example.com</i>, then
|
||||||
%1 is <b>com</b>, %2 is <b>example</b> and %3 is <b>mail</b>. If the input key
|
%1 is <b>com</b>, %2 is <b>example</b> and %3 is <b>mail</b>. If the input key
|
||||||
is unqualified or does not have enough domain components
|
is unqualified or does not have enough domain components
|
||||||
to satisfy all the specified patterns, the query is sup-
|
to satisfy all the specified patterns, the query is sup-
|
||||||
pressed and returns no results.
|
pressed and returns no results.
|
||||||
|
|
||||||
The <b>domain</b> parameter described below limits the input keys to
|
The <b>domain</b> parameter described below limits the input keys to
|
||||||
addresses in matching domains. When the <b>domain</b> parameter is
|
addresses in matching domains. When the <b>domain</b> parameter is
|
||||||
non-empty, SQL queries for unqualified addresses or addresses in
|
non-empty, SQL queries for unqualified addresses or addresses in
|
||||||
non-matching domains are suppressed and return no results.
|
non-matching domains are suppressed and return no results.
|
||||||
|
|
||||||
This parameter is available with Postfix 2.2. In prior releases
|
This parameter is available with Postfix 2.2. In prior releases
|
||||||
the SQL query was built from the separate parameters:
|
the SQL query was built from the separate parameters:
|
||||||
<b>select_field</b>, <b>table</b>, <b>where_field</b> and <b>additional_conditions</b>. The
|
<b>select_field</b>, <b>table</b>, <b>where_field</b> and <b>additional_conditions</b>. The
|
||||||
mapping from the old parameters to the equivalent query is:
|
mapping from the old parameters to the equivalent query is:
|
||||||
|
|
||||||
SELECT [<b>select_field</b>]
|
SELECT [<b>select_field</b>]
|
||||||
@ -129,50 +137,50 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
WHERE [<b>where_field</b>] = '%s'
|
WHERE [<b>where_field</b>] = '%s'
|
||||||
[<b>additional_conditions</b>]
|
[<b>additional_conditions</b>]
|
||||||
|
|
||||||
The '%s' in the <b>WHERE</b> clause expands to the escaped search
|
The '%s' in the <b>WHERE</b> clause expands to the escaped search
|
||||||
string. With Postfix 2.2 these legacy parameters are used if
|
string. With Postfix 2.2 these legacy parameters are used if
|
||||||
the <b>query</b> parameter is not specified.
|
the <b>query</b> parameter is not specified.
|
||||||
|
|
||||||
NOTE: DO NOT put quotes around the query parameter.
|
NOTE: DO NOT put quotes around the query parameter.
|
||||||
|
|
||||||
<b>result_format (default: %s</b>)
|
<b>result_format (default: %s</b>)
|
||||||
Format template applied to result attributes. Most commonly used
|
Format template applied to result attributes. Most commonly used
|
||||||
to append (or prepend) text to the result. This parameter sup-
|
to append (or prepend) text to the result. This parameter sup-
|
||||||
ports the following '%' expansions:
|
ports the following '%' expansions:
|
||||||
|
|
||||||
<b>%%</b> This is replaced by a literal '%' character.
|
<b>%%</b> This is replaced by a literal '%' character.
|
||||||
|
|
||||||
<b>%s</b> This is replaced by the value of the result attribute.
|
<b>%s</b> This is replaced by the value of the result attribute.
|
||||||
When result is empty it is skipped.
|
When result is empty it is skipped.
|
||||||
|
|
||||||
<b>%u</b> When the result attribute value is an address of the form
|
<b>%u</b> When the result attribute value is an address of the form
|
||||||
user@domain, <b>%u</b> is replaced by the local part of the
|
user@domain, <b>%u</b> is replaced by the local part of the
|
||||||
address. When the result has an empty localpart it is
|
address. When the result has an empty localpart it is
|
||||||
skipped.
|
skipped.
|
||||||
|
|
||||||
<b>%d</b> When a result attribute value is an address of the form
|
<b>%d</b> When a result attribute value is an address of the form
|
||||||
user@domain, <b>%d</b> is replaced by the domain part of the
|
user@domain, <b>%d</b> is replaced by the domain part of the
|
||||||
attribute value. When the result is unqualified it is
|
attribute value. When the result is unqualified it is
|
||||||
skipped.
|
skipped.
|
||||||
|
|
||||||
<b>%[SUD1-9]</b>
|
<b>%[SUD1-9]</b>
|
||||||
The upper-case and decimal digit expansions interpolate
|
The upper-case and decimal digit expansions interpolate
|
||||||
the parts of the input key rather than the result. Their
|
the parts of the input key rather than the result. Their
|
||||||
behavior is identical to that described with <b>query</b>, and
|
behavior is identical to that described with <b>query</b>, and
|
||||||
in fact because the input key is known in advance,
|
in fact because the input key is known in advance,
|
||||||
queries whose key does not contain all the information
|
queries whose key does not contain all the information
|
||||||
specified in the result template are suppressed and
|
specified in the result template are suppressed and
|
||||||
return no results.
|
return no results.
|
||||||
|
|
||||||
For example, using "result_format = <a href="smtp.8.html">smtp</a>:[%s]" allows one to use
|
For example, using "result_format = <a href="smtp.8.html">smtp</a>:[%s]" allows one to use
|
||||||
a mailHost attribute as the basis of a <a href="transport.5.html">transport(5)</a> table. After
|
a mailHost attribute as the basis of a <a href="transport.5.html">transport(5)</a> table. After
|
||||||
applying the result format, multiple values are concatenated as
|
applying the result format, multiple values are concatenated as
|
||||||
comma separated strings. The expansion_limit and parameter
|
comma separated strings. The expansion_limit and parameter
|
||||||
explained below allows one to restrict the number of values in
|
explained below allows one to restrict the number of values in
|
||||||
the result, which is especially useful for maps that must return
|
the result, which is especially useful for maps that must return
|
||||||
at most one value.
|
at most one value.
|
||||||
|
|
||||||
The default value <b>%s</b> specifies that each result value should be
|
The default value <b>%s</b> specifies that each result value should be
|
||||||
used as is.
|
used as is.
|
||||||
|
|
||||||
This parameter is available with Postfix 2.2 and later.
|
This parameter is available with Postfix 2.2 and later.
|
||||||
@ -180,15 +188,15 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
NOTE: DO NOT put quotes around the result format!
|
NOTE: DO NOT put quotes around the result format!
|
||||||
|
|
||||||
<b>domain (default: no domain list)</b>
|
<b>domain (default: no domain list)</b>
|
||||||
This is a list of domain names, paths to files, or "<a href="DATABASE_README.html">type:table</a>"
|
This is a list of domain names, paths to files, or "<a href="DATABASE_README.html">type:table</a>"
|
||||||
databases. When specified, only fully qualified search keys with
|
databases. When specified, only fully qualified search keys with
|
||||||
a *non-empty* localpart and a matching domain are eligible for
|
a *non-empty* localpart and a matching domain are eligible for
|
||||||
lookup: 'user' lookups, bare domain lookups and "@domain"
|
lookup: 'user' lookups, bare domain lookups and "@domain"
|
||||||
lookups are not performed. This can significantly reduce the
|
lookups are not performed. This can significantly reduce the
|
||||||
query load on the MySQL server.
|
query load on the MySQL server.
|
||||||
domain = postfix.org, <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/searchdomains
|
domain = postfix.org, <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/searchdomains
|
||||||
|
|
||||||
It is best not to use SQL to store the domains eligible for SQL
|
It is best not to use SQL to store the domains eligible for SQL
|
||||||
lookups.
|
lookups.
|
||||||
|
|
||||||
This parameter is available with Postfix 2.2 and later.
|
This parameter is available with Postfix 2.2 and later.
|
||||||
@ -197,37 +205,37 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
the input keys are always unqualified.
|
the input keys are always unqualified.
|
||||||
|
|
||||||
<b>expansion_limit (default: 0)</b>
|
<b>expansion_limit (default: 0)</b>
|
||||||
A limit on the total number of result elements returned (as a
|
A limit on the total number of result elements returned (as a
|
||||||
comma separated list) by a lookup against the map. A setting of
|
comma separated list) by a lookup against the map. A setting of
|
||||||
zero disables the limit. Lookups fail with a temporary error if
|
zero disables the limit. Lookups fail with a temporary error if
|
||||||
the limit is exceeded. Setting the limit to 1 ensures that
|
the limit is exceeded. Setting the limit to 1 ensures that
|
||||||
lookups do not return multiple values.
|
lookups do not return multiple values.
|
||||||
|
|
||||||
<b>option_file</b>
|
<b>option_file</b>
|
||||||
Read options from the given file instead of the default my.cnf
|
Read options from the given file instead of the default my.cnf
|
||||||
location. This reads options from the <b>[client]</b> option group,
|
location. This reads options from the <b>[client]</b> option group,
|
||||||
optionally followed by options from the group given with
|
optionally followed by options from the group given with
|
||||||
<b>option_group</b>.
|
<b>option_group</b>.
|
||||||
|
|
||||||
This parameter is available with Postfix 2.11 and later.
|
This parameter is available with Postfix 2.11 and later.
|
||||||
|
|
||||||
<b>option_group (default: Postfix</b> ><b>=3.2: client,</b> <<b>= 3.1: empty)</b>
|
<b>option_group (default: Postfix</b> ><b>=3.2: client,</b> <<b>= 3.1: empty)</b>
|
||||||
Read options from the given group of the mysql options file,
|
Read options from the given group of the mysql options file,
|
||||||
after reading options from the <b>[client]</b> group.
|
after reading options from the <b>[client]</b> group.
|
||||||
|
|
||||||
Postfix 3.2 and later read <b>[client]</b> option group settings by
|
Postfix 3.2 and later read <b>[client]</b> option group settings by
|
||||||
default. To disable this specify no <b>option_file</b> and specify
|
default. To disable this specify no <b>option_file</b> and specify
|
||||||
"<b>option_group =</b>" (i.e. an empty value).
|
"<b>option_group =</b>" (i.e. an empty value).
|
||||||
|
|
||||||
Postfix 3.1 and earlier don't read <b>[client]</b> option group set-
|
Postfix 3.1 and earlier don't read <b>[client]</b> option group set-
|
||||||
tings unless a non-empty <b>option_file</b> or <b>option_group</b> value are
|
tings unless a non-empty <b>option_file</b> or <b>option_group</b> value are
|
||||||
specified. To enable this, specify, for example, "<b>option_group =</b>
|
specified. To enable this, specify, for example, "<b>option_group =</b>
|
||||||
<b>client</b>".
|
<b>client</b>".
|
||||||
|
|
||||||
This parameter is available with Postfix 2.11 and later.
|
This parameter is available with Postfix 2.11 and later.
|
||||||
|
|
||||||
<b>require_result_set (default: yes)</b>
|
<b>require_result_set (default: yes)</b>
|
||||||
If "<b>yes</b>", require that every query returns a result set. If
|
If "<b>yes</b>", require that every query returns a result set. If
|
||||||
"<b>no</b>", treat the absence of a result set as "not found".
|
"<b>no</b>", treat the absence of a result set as "not found".
|
||||||
|
|
||||||
This parameter is available with Postfix 3.2 and later.
|
This parameter is available with Postfix 3.2 and later.
|
||||||
@ -238,19 +246,19 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
This parameter is available with Postfix 2.11 and later.
|
This parameter is available with Postfix 2.11 and later.
|
||||||
|
|
||||||
<b>tls_key_file</b>
|
<b>tls_key_file</b>
|
||||||
File containing the private key corresponding to <b>tls_cert_file</b>.
|
File containing the private key corresponding to <b>tls_cert_file</b>.
|
||||||
|
|
||||||
This parameter is available with Postfix 2.11 and later.
|
This parameter is available with Postfix 2.11 and later.
|
||||||
|
|
||||||
<b>tls_CAfile</b>
|
<b>tls_CAfile</b>
|
||||||
File containing certificates for all of the X509 Certification
|
File containing certificates for all of the X509 Certification
|
||||||
Authorities the client will recognize. Takes precedence over
|
Authorities the client will recognize. Takes precedence over
|
||||||
<b>tls_CApath</b>.
|
<b>tls_CApath</b>.
|
||||||
|
|
||||||
This parameter is available with Postfix 2.11 and later.
|
This parameter is available with Postfix 2.11 and later.
|
||||||
|
|
||||||
<b>tls_CApath</b>
|
<b>tls_CApath</b>
|
||||||
Directory containing X509 Certification Authority certificates
|
Directory containing X509 Certification Authority certificates
|
||||||
in separate individual files.
|
in separate individual files.
|
||||||
|
|
||||||
This parameter is available with Postfix 2.11 and later.
|
This parameter is available with Postfix 2.11 and later.
|
||||||
@ -261,13 +269,13 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
This parameter is available with Postfix 2.11 and later.
|
This parameter is available with Postfix 2.11 and later.
|
||||||
|
|
||||||
<b>tls_verify_cert (default: no)</b>
|
<b>tls_verify_cert (default: no)</b>
|
||||||
Verify that the server's name matches the common name in the
|
Verify that the server's name matches the common name in the
|
||||||
certificate.
|
certificate.
|
||||||
|
|
||||||
This parameter is available with Postfix 2.11 and later.
|
This parameter is available with Postfix 2.11 and later.
|
||||||
|
|
||||||
<b>USING MYSQL STORED PROCEDURES</b>
|
<b>USING MYSQL STORED PROCEDURES</b>
|
||||||
Postfix 3.2 and later support calling a stored procedure instead of
|
Postfix 3.2 and later support calling a stored procedure instead of
|
||||||
using a SELECT statement in the query, e.g.
|
using a SELECT statement in the query, e.g.
|
||||||
|
|
||||||
<b>query</b> = CALL lookup('%s')
|
<b>query</b> = CALL lookup('%s')
|
||||||
@ -275,17 +283,17 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
The previously described '%' expansions can be used in the parameter(s)
|
The previously described '%' expansions can be used in the parameter(s)
|
||||||
to the stored procedure.
|
to the stored procedure.
|
||||||
|
|
||||||
By default, every stored procedure call must return a result set, i.e.
|
By default, every stored procedure call must return a result set, i.e.
|
||||||
every code path must execute a SELECT statement that returns a result
|
every code path must execute a SELECT statement that returns a result
|
||||||
set (instead of storing its results in a table). With
|
set (instead of storing its results in a table). With
|
||||||
"<b>require_result_set = no</b>", the absence of a result set is treated as
|
"<b>require_result_set = no</b>", the absence of a result set is treated as
|
||||||
"not found".
|
"not found".
|
||||||
|
|
||||||
A stored procedure must not return multiple result sets. That is,
|
A stored procedure must not return multiple result sets. That is,
|
||||||
there must be no code path that executes multiple SELECT statements
|
there must be no code path that executes multiple SELECT statements
|
||||||
that return a result (instead of storing their results in a table).
|
that return a result (instead of storing their results in a table).
|
||||||
|
|
||||||
The following is an example of a stored procedure returning a single
|
The following is an example of a stored procedure returning a single
|
||||||
result set:
|
result set:
|
||||||
|
|
||||||
CREATE [DEFINER=`user`@`host`] PROCEDURE
|
CREATE [DEFINER=`user`@`host`] PROCEDURE
|
||||||
@ -297,26 +305,26 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
END
|
END
|
||||||
|
|
||||||
<b>OBSOLETE MAIN.CF PARAMETERS</b>
|
<b>OBSOLETE MAIN.CF PARAMETERS</b>
|
||||||
For compatibility with other Postfix lookup tables, MySQL parameters
|
For compatibility with other Postfix lookup tables, MySQL parameters
|
||||||
can also be defined in <a href="postconf.5.html">main.cf</a>. In order to do that, specify as MySQL
|
can also be defined in <a href="postconf.5.html">main.cf</a>. In order to do that, specify as MySQL
|
||||||
source a name that doesn't begin with a slash or a dot. The MySQL
|
source a name that doesn't begin with a slash or a dot. The MySQL
|
||||||
parameters will then be accessible as the name you've given the source
|
parameters will then be accessible as the name you've given the source
|
||||||
in its definition, an underscore, and the name of the parameter. For
|
in its definition, an underscore, and the name of the parameter. For
|
||||||
example, if the map is specified as "<a href="mysql_table.5.html">mysql</a>:<i>mysqlname</i>", the parameter
|
example, if the map is specified as "<a href="mysql_table.5.html">mysql</a>:<i>mysqlname</i>", the parameter
|
||||||
"hosts" would be defined in <a href="postconf.5.html">main.cf</a> as "<i>mysqlname</i>_hosts".
|
"hosts" would be defined in <a href="postconf.5.html">main.cf</a> as "<i>mysqlname</i>_hosts".
|
||||||
|
|
||||||
Note: with this form, the passwords for the MySQL sources are written
|
Note: with this form, the passwords for the MySQL sources are written
|
||||||
in <a href="postconf.5.html">main.cf</a>, which is normally world-readable. Support for this form
|
in <a href="postconf.5.html">main.cf</a>, which is normally world-readable. Support for this form
|
||||||
will be removed in a future Postfix version.
|
will be removed in a future Postfix version.
|
||||||
|
|
||||||
<b>OBSOLETE QUERY INTERFACE</b>
|
<b>OBSOLETE QUERY INTERFACE</b>
|
||||||
This section describes an interface that is deprecated as of Postfix
|
This section describes an interface that is deprecated as of Postfix
|
||||||
2.2. It is replaced by the more general <b>query</b> interface described
|
2.2. It is replaced by the more general <b>query</b> interface described
|
||||||
above. If the <b>query</b> parameter is defined, the legacy parameters
|
above. If the <b>query</b> parameter is defined, the legacy parameters
|
||||||
described here ignored. Please migrate to the new interface as the
|
described here ignored. Please migrate to the new interface as the
|
||||||
legacy interface may be removed in a future release.
|
legacy interface may be removed in a future release.
|
||||||
|
|
||||||
The following parameters can be used to fill in a SELECT template
|
The following parameters can be used to fill in a SELECT template
|
||||||
statement of the form:
|
statement of the form:
|
||||||
|
|
||||||
SELECT [<b>select_field</b>]
|
SELECT [<b>select_field</b>]
|
||||||
@ -325,7 +333,7 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
[<b>additional_conditions</b>]
|
[<b>additional_conditions</b>]
|
||||||
|
|
||||||
The specifier %s is replaced by the search string, and is escaped so if
|
The specifier %s is replaced by the search string, and is escaped so if
|
||||||
it contains single quotes or other odd characters, it will not cause a
|
it contains single quotes or other odd characters, it will not cause a
|
||||||
parse error, or worse, a security problem.
|
parse error, or worse, a security problem.
|
||||||
|
|
||||||
<b>select_field</b>
|
<b>select_field</b>
|
||||||
|
@ -89,6 +89,14 @@ The database name on the servers. Example:
|
|||||||
.nf
|
.nf
|
||||||
dbname = customer_database
|
dbname = customer_database
|
||||||
.fi
|
.fi
|
||||||
|
.IP "\fBcharset (default: utf8mb4)\fR"
|
||||||
|
The default MySQL client character set; this also implies
|
||||||
|
the collation order.
|
||||||
|
|
||||||
|
This parameter is available with Postfix 3.9 and later.
|
||||||
|
With earlier Postfix versions, the default was chosen by
|
||||||
|
the MySQL implementation (\fButf8mb4\fR as of MySQL 8.0,
|
||||||
|
\fBlatin1\fR historically).
|
||||||
.IP "\fBquery\fR"
|
.IP "\fBquery\fR"
|
||||||
The SQL query template used to search the database, where \fB%s\fR
|
The SQL query template used to search the database, where \fB%s\fR
|
||||||
is a substitute for the address Postfix is trying to resolve,
|
is a substitute for the address Postfix is trying to resolve,
|
||||||
|
@ -79,6 +79,14 @@
|
|||||||
# .nf
|
# .nf
|
||||||
# dbname = customer_database
|
# dbname = customer_database
|
||||||
# .fi
|
# .fi
|
||||||
|
# .IP "\fBcharset (default: utf8mb4)\fR"
|
||||||
|
# The default MySQL client character set; this also implies
|
||||||
|
# the collation order.
|
||||||
|
#
|
||||||
|
# This parameter is available with Postfix 3.9 and later.
|
||||||
|
# With earlier Postfix versions, the default was chosen by
|
||||||
|
# the MySQL implementation (\fButf8mb4\fR as of MySQL 8.0,
|
||||||
|
# \fBlatin1\fR historically).
|
||||||
# .IP "\fBquery\fR"
|
# .IP "\fBquery\fR"
|
||||||
# The SQL query template used to search the database, where \fB%s\fR
|
# The SQL query template used to search the database, where \fB%s\fR
|
||||||
# is a substitute for the address Postfix is trying to resolve,
|
# is a substitute for the address Postfix is trying to resolve,
|
||||||
|
@ -1577,3 +1577,6 @@ Korbar
|
|||||||
ffdhe
|
ffdhe
|
||||||
srv
|
srv
|
||||||
stderr
|
stderr
|
||||||
|
charset
|
||||||
|
latin
|
||||||
|
utf
|
||||||
|
@ -1443,7 +1443,7 @@ tv
|
|||||||
txn
|
txn
|
||||||
TXT
|
TXT
|
||||||
Typechecking
|
Typechecking
|
||||||
TYPECONNSTRING
|
TYPECONNSTR
|
||||||
typedef
|
typedef
|
||||||
typedefs
|
typedefs
|
||||||
TYPEINET
|
TYPEINET
|
||||||
|
@ -147,6 +147,7 @@ typedef struct {
|
|||||||
char *username;
|
char *username;
|
||||||
char *password;
|
char *password;
|
||||||
char *dbname;
|
char *dbname;
|
||||||
|
char *charset;
|
||||||
ARGV *hosts;
|
ARGV *hosts;
|
||||||
PLMYSQL *pldb;
|
PLMYSQL *pldb;
|
||||||
#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
|
#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
|
||||||
@ -439,7 +440,7 @@ static int plmysql_query(DICT_MYSQL *dict_mysql,
|
|||||||
{
|
{
|
||||||
HOST *host;
|
HOST *host;
|
||||||
MYSQL_RES *first_result = 0;
|
MYSQL_RES *first_result = 0;
|
||||||
int query_error;
|
int query_error = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper to avoid spamming the log with warnings.
|
* Helper to avoid spamming the log with warnings.
|
||||||
@ -602,6 +603,12 @@ static void plmysql_connect_single(DICT_MYSQL *dict_mysql, HOST *host)
|
|||||||
host->port,
|
host->port,
|
||||||
(host->type == TYPEUNIX ? host->name : 0),
|
(host->type == TYPEUNIX ? host->name : 0),
|
||||||
CLIENT_MULTI_RESULTS)) {
|
CLIENT_MULTI_RESULTS)) {
|
||||||
|
if (mysql_set_character_set(host->db, dict_mysql->charset) != 0) {
|
||||||
|
msg_warn("dict_mysql: mysql_set_character_set '%s' failed: %s",
|
||||||
|
dict_mysql->charset, mysql_error(host->db));
|
||||||
|
plmysql_down_host(host);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("dict_mysql: successful connection to host %s",
|
msg_info("dict_mysql: successful connection to host %s",
|
||||||
host->hostname);
|
host->hostname);
|
||||||
@ -646,6 +653,7 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf)
|
|||||||
dict_mysql->username = cfg_get_str(p, "user", "", 0, 0);
|
dict_mysql->username = cfg_get_str(p, "user", "", 0, 0);
|
||||||
dict_mysql->password = cfg_get_str(p, "password", "", 0, 0);
|
dict_mysql->password = cfg_get_str(p, "password", "", 0, 0);
|
||||||
dict_mysql->dbname = cfg_get_str(p, "dbname", "", 1, 0);
|
dict_mysql->dbname = cfg_get_str(p, "dbname", "", 1, 0);
|
||||||
|
dict_mysql->charset = cfg_get_str(p, "charset", "utf8mb4", 1, 0);
|
||||||
dict_mysql->result_format = cfg_get_str(p, "result_format", "%s", 1, 0);
|
dict_mysql->result_format = cfg_get_str(p, "result_format", "%s", 1, 0);
|
||||||
dict_mysql->option_file = cfg_get_str(p, "option_file", NULL, 0, 0);
|
dict_mysql->option_file = cfg_get_str(p, "option_file", NULL, 0, 0);
|
||||||
dict_mysql->option_group = cfg_get_str(p, "option_group", "client", 0, 0);
|
dict_mysql->option_group = cfg_get_str(p, "option_group", "client", 0, 0);
|
||||||
@ -826,6 +834,7 @@ static void dict_mysql_close(DICT *dict)
|
|||||||
myfree(dict_mysql->username);
|
myfree(dict_mysql->username);
|
||||||
myfree(dict_mysql->password);
|
myfree(dict_mysql->password);
|
||||||
myfree(dict_mysql->dbname);
|
myfree(dict_mysql->dbname);
|
||||||
|
myfree(dict_mysql->charset);
|
||||||
myfree(dict_mysql->query);
|
myfree(dict_mysql->query);
|
||||||
myfree(dict_mysql->result_format);
|
myfree(dict_mysql->result_format);
|
||||||
if (dict_mysql->option_file)
|
if (dict_mysql->option_file)
|
||||||
|
@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
#define TYPEUNIX (1<<0)
|
#define TYPEUNIX (1<<0)
|
||||||
#define TYPEINET (1<<1)
|
#define TYPEINET (1<<1)
|
||||||
#define TYPECONNSTRING (1<<2)
|
#define TYPECONNSTR (1<<2)
|
||||||
|
|
||||||
#define RETRY_CONN_MAX 100
|
#define RETRY_CONN_MAX 100
|
||||||
#define RETRY_CONN_INTV 60 /* 1 minute */
|
#define RETRY_CONN_INTV 60 /* 1 minute */
|
||||||
@ -119,7 +119,7 @@ typedef struct {
|
|||||||
char *hostname;
|
char *hostname;
|
||||||
char *name;
|
char *name;
|
||||||
char *port;
|
char *port;
|
||||||
unsigned type; /* TYPEUNIX | TYPEINET | TYPECONNSTRING */
|
unsigned type; /* TYPEUNIX | TYPEINET | TYPECONNSTR */
|
||||||
unsigned stat; /* STATUNTRIED | STATFAIL | STATCUR */
|
unsigned stat; /* STATUNTRIED | STATFAIL | STATCUR */
|
||||||
time_t ts; /* used for attempting reconnection */
|
time_t ts; /* used for attempting reconnection */
|
||||||
} HOST;
|
} HOST;
|
||||||
@ -152,12 +152,11 @@ typedef struct {
|
|||||||
|
|
||||||
/* internal function declarations */
|
/* internal function declarations */
|
||||||
static PLPGSQL *plpgsql_init(ARGV *);
|
static PLPGSQL *plpgsql_init(ARGV *);
|
||||||
static PGSQL_RES *plpgsql_query(DICT_PGSQL *, const char *, VSTRING *, char *,
|
static PGSQL_RES *plpgsql_query(DICT_PGSQL *, const char *, VSTRING *);
|
||||||
char *, char *, char *);
|
|
||||||
static void plpgsql_dealloc(PLPGSQL *);
|
static void plpgsql_dealloc(PLPGSQL *);
|
||||||
static void plpgsql_close_host(HOST *);
|
static void plpgsql_close_host(HOST *);
|
||||||
static void plpgsql_down_host(HOST *);
|
static void plpgsql_down_host(HOST *);
|
||||||
static void plpgsql_connect_single(HOST *, char *, char *, char *, char *);
|
static void plpgsql_connect_single(DICT_PGSQL *, HOST *);
|
||||||
static const char *dict_pgsql_lookup(DICT *, const char *);
|
static const char *dict_pgsql_lookup(DICT *, const char *);
|
||||||
DICT *dict_pgsql_open(const char *, int, int);
|
DICT *dict_pgsql_open(const char *, int, int);
|
||||||
static void dict_pgsql_close(DICT *);
|
static void dict_pgsql_close(DICT *);
|
||||||
@ -324,11 +323,7 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name)
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/* do the query - set dict->error & cleanup if there's an error */
|
/* do the query - set dict->error & cleanup if there's an error */
|
||||||
if ((query_res = plpgsql_query(dict_pgsql, name, query,
|
if ((query_res = plpgsql_query(dict_pgsql, name, query)) == 0) {
|
||||||
dict_pgsql->dbname,
|
|
||||||
dict_pgsql->encoding,
|
|
||||||
dict_pgsql->username,
|
|
||||||
dict_pgsql->password)) == 0) {
|
|
||||||
dict->error = DICT_ERR_RETRY;
|
dict->error = DICT_ERR_RETRY;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -404,8 +399,7 @@ static HOST *dict_pgsql_find_host(PLPGSQL *PLDB, unsigned stat, unsigned type)
|
|||||||
|
|
||||||
/* dict_pgsql_get_active - get an active connection */
|
/* dict_pgsql_get_active - get an active connection */
|
||||||
|
|
||||||
static HOST *dict_pgsql_get_active(PLPGSQL *PLDB, char *dbname, char *encoding,
|
static HOST *dict_pgsql_get_active(DICT_PGSQL *dict_pgsql, PLPGSQL *PLDB)
|
||||||
char *username, char *password)
|
|
||||||
{
|
{
|
||||||
const char *myname = "dict_pgsql_get_active";
|
const char *myname = "dict_pgsql_get_active";
|
||||||
HOST *host;
|
HOST *host;
|
||||||
@ -414,7 +408,7 @@ static HOST *dict_pgsql_get_active(PLPGSQL *PLDB, char *dbname, char *encoding,
|
|||||||
/* try the active connections first; prefer the ones to UNIX sockets */
|
/* try the active connections first; prefer the ones to UNIX sockets */
|
||||||
if ((host = dict_pgsql_find_host(PLDB, STATACTIVE, TYPEUNIX)) != NULL ||
|
if ((host = dict_pgsql_find_host(PLDB, STATACTIVE, TYPEUNIX)) != NULL ||
|
||||||
(host = dict_pgsql_find_host(PLDB, STATACTIVE, TYPEINET)) != NULL ||
|
(host = dict_pgsql_find_host(PLDB, STATACTIVE, TYPEINET)) != NULL ||
|
||||||
(host = dict_pgsql_find_host(PLDB, STATACTIVE, TYPECONNSTRING)) != NULL) {
|
(host = dict_pgsql_find_host(PLDB, STATACTIVE, TYPECONNSTR)) != NULL) {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: found active connection to host %s", myname,
|
msg_info("%s: found active connection to host %s", myname,
|
||||||
host->hostname);
|
host->hostname);
|
||||||
@ -432,11 +426,11 @@ static HOST *dict_pgsql_get_active(PLPGSQL *PLDB, char *dbname, char *encoding,
|
|||||||
(host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL,
|
(host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL,
|
||||||
TYPEINET)) != NULL ||
|
TYPEINET)) != NULL ||
|
||||||
(host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL,
|
(host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL,
|
||||||
TYPECONNSTRING)) != NULL)) {
|
TYPECONNSTR)) != NULL)) {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: attempting to connect to host %s", myname,
|
msg_info("%s: attempting to connect to host %s", myname,
|
||||||
host->hostname);
|
host->hostname);
|
||||||
plpgsql_connect_single(host, dbname, encoding, username, password);
|
plpgsql_connect_single(dict_pgsql, host);
|
||||||
if (host->stat == STATACTIVE)
|
if (host->stat == STATACTIVE)
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
@ -464,18 +458,14 @@ static void dict_pgsql_event(int unused_event, void *context)
|
|||||||
|
|
||||||
static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql,
|
static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql,
|
||||||
const char *name,
|
const char *name,
|
||||||
VSTRING *query,
|
VSTRING *query)
|
||||||
char *dbname,
|
|
||||||
char *encoding,
|
|
||||||
char *username,
|
|
||||||
char *password)
|
|
||||||
{
|
{
|
||||||
PLPGSQL *PLDB = dict_pgsql->pldb;
|
PLPGSQL *PLDB = dict_pgsql->pldb;
|
||||||
HOST *host;
|
HOST *host;
|
||||||
PGSQL_RES *res = 0;
|
PGSQL_RES *res = 0;
|
||||||
ExecStatusType status;
|
ExecStatusType status;
|
||||||
|
|
||||||
while ((host = dict_pgsql_get_active(PLDB, dbname, encoding, username, password)) != NULL) {
|
while ((host = dict_pgsql_get_active(dict_pgsql, PLDB)) != NULL) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The active host is used to escape strings in the context of the
|
* The active host is used to escape strings in the context of the
|
||||||
@ -570,13 +560,14 @@ static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql,
|
|||||||
* used to reconnect to a single database when one is down or none is
|
* used to reconnect to a single database when one is down or none is
|
||||||
* connected yet. Log all errors and set the stat field of host accordingly
|
* connected yet. Log all errors and set the stat field of host accordingly
|
||||||
*/
|
*/
|
||||||
static void plpgsql_connect_single(HOST *host, char *dbname, char *encoding, char *username, char *password)
|
static void plpgsql_connect_single(DICT_PGSQL *dict_pgsql, HOST *host)
|
||||||
{
|
{
|
||||||
if (host->type == TYPECONNSTRING) {
|
if (host->type == TYPECONNSTR) {
|
||||||
host->db = PQconnectdb(host->name);
|
host->db = PQconnectdb(host->name);
|
||||||
} else {
|
} else {
|
||||||
host->db = PQsetdbLogin(host->name, host->port, NULL, NULL,
|
host->db = PQsetdbLogin(host->name, host->port, NULL, NULL,
|
||||||
dbname, username, password);
|
dict_pgsql->dbname, dict_pgsql->username,
|
||||||
|
dict_pgsql->password);
|
||||||
}
|
}
|
||||||
if (host->db == NULL || PQstatus(host->db) != CONNECTION_OK) {
|
if (host->db == NULL || PQstatus(host->db) != CONNECTION_OK) {
|
||||||
msg_warn("connect to pgsql server %s: %s",
|
msg_warn("connect to pgsql server %s: %s",
|
||||||
@ -584,9 +575,9 @@ static void plpgsql_connect_single(HOST *host, char *dbname, char *encoding, cha
|
|||||||
plpgsql_down_host(host);
|
plpgsql_down_host(host);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (PQsetClientEncoding(host->db, encoding) != 0) {
|
if (PQsetClientEncoding(host->db, dict_pgsql->encoding) != 0) {
|
||||||
msg_warn("dict_pgsql: cannot set the encoding to %s, skipping %s",
|
msg_warn("dict_pgsql: cannot set the encoding to %s, skipping %s",
|
||||||
encoding, host->hostname);
|
dict_pgsql->encoding, host->hostname);
|
||||||
plpgsql_down_host(host);
|
plpgsql_down_host(host);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -764,7 +755,7 @@ static HOST *host_init(const char *hostname)
|
|||||||
* Modern syntax: "postgresql://connection-info".
|
* Modern syntax: "postgresql://connection-info".
|
||||||
*/
|
*/
|
||||||
if (strncmp(d, "postgresql:", 11) == 0) {
|
if (strncmp(d, "postgresql:", 11) == 0) {
|
||||||
host->type = TYPECONNSTRING;
|
host->type = TYPECONNSTR;
|
||||||
host->name = mystrdup(d);
|
host->name = mystrdup(d);
|
||||||
host->port = 0;
|
host->port = 0;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||||
* patchlevel; they change the release date only.
|
* patchlevel; they change the release date only.
|
||||||
*/
|
*/
|
||||||
#define MAIL_RELEASE_DATE "20230416"
|
#define MAIL_RELEASE_DATE "20230419"
|
||||||
#define MAIL_VERSION_NUMBER "3.9"
|
#define MAIL_VERSION_NUMBER "3.9"
|
||||||
|
|
||||||
#ifdef SNAPSHOT
|
#ifdef SNAPSHOT
|
||||||
|
Loading…
x
Reference in New Issue
Block a user