mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-24 10:58:39 +00:00
postfix-3.2-20161226-nonprod
This commit is contained in:
parent
551bd26bfa
commit
5b0b13c24e
1
postfix/.indent.pro
vendored
1
postfix/.indent.pro
vendored
@ -223,6 +223,7 @@
|
|||||||
-TMVECT
|
-TMVECT
|
||||||
-TMYSQL
|
-TMYSQL
|
||||||
-TMYSQL_NAME
|
-TMYSQL_NAME
|
||||||
|
-TMYSQL_RES
|
||||||
-TNAMADR_LIST
|
-TNAMADR_LIST
|
||||||
-TNAME_ASSIGNMENT
|
-TNAME_ASSIGNMENT
|
||||||
-TNAME_CODE
|
-TNAME_CODE
|
||||||
|
@ -22702,3 +22702,11 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
Cleanup: simplified code structure in the MySQL client
|
Cleanup: simplified code structure in the MySQL client
|
||||||
support for stored procedures. File: global/dict_mysql.c.
|
support for stored procedures. File: global/dict_mysql.c.
|
||||||
|
|
||||||
|
20161226
|
||||||
|
|
||||||
|
Cleanup: more MySQL client code simplification, better error
|
||||||
|
messages, new per-database "require_result_set" parameter
|
||||||
|
(default: yes) which can be set to "no" to avoid the need
|
||||||
|
for dummy SELECT statements in stored procedures. Files:
|
||||||
|
global/dict_mysql.c, proto/mysql_table, postconf/postconf_dbms.c.
|
||||||
|
@ -101,47 +101,52 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
a substitute for the address Postfix is trying to resolve, e.g.
|
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
|
||||||
|
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
|
||||||
|
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>]
|
||||||
@ -149,50 +154,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.
|
||||||
@ -201,14 +206,14 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
|
|
||||||
<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 dictionaries.
|
This is a list of domain names, paths to files, or dictionaries.
|
||||||
When specified, only fully qualified search keys with a
|
When specified, only fully qualified search keys with a
|
||||||
*non-empty* localpart and a matching domain are eligible for
|
*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.
|
||||||
@ -217,35 +222,41 @@ 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>
|
||||||
|
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".
|
||||||
|
|
||||||
|
This parameter is available with Postfix 3.2 and later.
|
||||||
|
|
||||||
<b>tls_cert_file</b>
|
<b>tls_cert_file</b>
|
||||||
File containing client's X509 certificate.
|
File containing client's X509 certificate.
|
||||||
|
|
||||||
@ -284,25 +295,18 @@ 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.
|
||||||
|
|
||||||
The stored procedure must return data with a single result set, that is
|
By default, every stored procedure call must return a result set, i.e.
|
||||||
the stored procedure must execute exactly one SELECT statement on every
|
every code path must execute a SELECT statement that returns a result
|
||||||
code path. If you have complex logic and for some paths you want to
|
set (instead of storing its results in a table). With
|
||||||
return no result you will need to include a SELECT statement that
|
"<b>require_result_set = no</b>", the absence of a result set is treated as
|
||||||
returns no rows. One example of a query that returns no rows is
|
"not found".
|
||||||
|
|
||||||
SELECT 1 FROM DUAL WHERE FALSE
|
A stored procedure must not return multiple result sets. That is,
|
||||||
|
there must be no code path that executes multiple SELECT statements
|
||||||
|
that return a result (instead of storing their results in a table).
|
||||||
|
|
||||||
but you may use your own query.
|
The following is an example of a stored procedure returning a single
|
||||||
|
result set:
|
||||||
Stored procedures that return multiple result sets containing data,
|
|
||||||
that is stored procedures that execute multiple SELECT statements, are
|
|
||||||
not supported. Stored procedures in mysql produce an additional result
|
|
||||||
set without data which indicates the final status of the stored proce-
|
|
||||||
dure. If this final status is an error then any previous returned data
|
|
||||||
will not be used.
|
|
||||||
|
|
||||||
The following is an example of a stored procedure returning a single
|
|
||||||
result set containing data:
|
|
||||||
|
|
||||||
CREATE [DEFINER=`user`@`host`] PROCEDURE
|
CREATE [DEFINER=`user`@`host`] PROCEDURE
|
||||||
`lookup`(IN `param` VARCHAR(255))
|
`lookup`(IN `param` VARCHAR(255))
|
||||||
@ -313,13 +317,13 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
END
|
END
|
||||||
|
|
||||||
<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>]
|
||||||
@ -328,7 +332,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>
|
||||||
@ -376,5 +380,10 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
|
|
||||||
Stored-procedure support by John Fawcett.
|
Stored-procedure support by John Fawcett.
|
||||||
|
|
||||||
|
Wietse Venema
|
||||||
|
Google, Inc.
|
||||||
|
111 8th Avenue
|
||||||
|
New York, NY 10011, USA
|
||||||
|
|
||||||
MYSQL_TABLE(5)
|
MYSQL_TABLE(5)
|
||||||
</pre> </body> </html>
|
</pre> </body> </html>
|
||||||
|
@ -132,6 +132,11 @@ e.g.
|
|||||||
query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
|
By default, every query must return a result set (instead
|
||||||
|
of storing its results in a table); with "\fBrequire_result_set
|
||||||
|
= no\fR" (Postfix 3.2 and later), the absence of a result
|
||||||
|
set is treated as "not found".
|
||||||
|
|
||||||
This parameter supports the following '%' expansions:
|
This parameter supports the following '%' expansions:
|
||||||
.RS
|
.RS
|
||||||
.IP "\fB%%\fR"
|
.IP "\fB%%\fR"
|
||||||
@ -277,6 +282,12 @@ group settings unless a non\-empty \fBoption_file\fR or
|
|||||||
specify, for example, "\fBoption_group = client\fR".
|
specify, for example, "\fBoption_group = client\fR".
|
||||||
.sp
|
.sp
|
||||||
This parameter is available with Postfix 2.11 and later.
|
This parameter is available with Postfix 2.11 and later.
|
||||||
|
.IP "\fBrequire_result_set (default: yes)\fR"
|
||||||
|
If "\fByes\fR", require that every query returns a result
|
||||||
|
set. If "\fBno\fR", treat the absence of a result set as
|
||||||
|
"not found".
|
||||||
|
.sp
|
||||||
|
This parameter is available with Postfix 3.2 and later.
|
||||||
.IP "\fBtls_cert_file\fR"
|
.IP "\fBtls_cert_file\fR"
|
||||||
File containing client's X509 certificate.
|
File containing client's X509 certificate.
|
||||||
.sp
|
.sp
|
||||||
@ -316,29 +327,19 @@ instead of using a SELECT statement in the query, e.g.
|
|||||||
The previously described '%' expansions can be used in the
|
The previously described '%' expansions can be used in the
|
||||||
parameter(s) to the stored procedure.
|
parameter(s) to the stored procedure.
|
||||||
|
|
||||||
The stored procedure must return data with a single result
|
By default, every stored procedure call must return a result
|
||||||
set, that is the stored procedure must execute exactly one
|
set, i.e. every code path must execute a SELECT statement
|
||||||
SELECT statement on every code path. If you have complex
|
that returns a result set (instead of storing its results
|
||||||
logic and for some paths you want to return no result you
|
in a table). With "\fBrequire_result_set = no\fR", the
|
||||||
will need to include a SELECT statement that returns no
|
absence of a result set is treated as "not found".
|
||||||
rows. One example of a query that returns no rows is
|
|
||||||
|
|
||||||
.nf
|
A stored procedure must not return multiple result sets.
|
||||||
SELECT 1 FROM DUAL WHERE FALSE
|
That is, there must be no code path that executes multiple
|
||||||
.fi
|
SELECT statements that return a result (instead of storing
|
||||||
|
their results in a table).
|
||||||
but you may use your own query.
|
|
||||||
|
|
||||||
Stored procedures that return multiple result sets containing
|
|
||||||
data, that is stored procedures that execute multiple SELECT
|
|
||||||
statements, are not supported. Stored procedures in mysql
|
|
||||||
produce an additional result set without data which indicates
|
|
||||||
the final status of the stored procedure. If this final
|
|
||||||
status is an error then any previous returned data will not
|
|
||||||
be used.
|
|
||||||
|
|
||||||
The following is an example of a stored procedure returning
|
The following is an example of a stored procedure returning
|
||||||
a single result set containing data:
|
a single result set:
|
||||||
|
|
||||||
.nf
|
.nf
|
||||||
CREATE [DEFINER=`user`@`host`] PROCEDURE
|
CREATE [DEFINER=`user`@`host`] PROCEDURE
|
||||||
@ -356,7 +357,7 @@ CREATE [DEFINER=`user`@`host`] PROCEDURE
|
|||||||
.fi
|
.fi
|
||||||
This section describes an interface that is deprecated as
|
This section describes an interface that is deprecated as
|
||||||
of Postfix 2.2. It is replaced by the more general \fBquery\fR
|
of Postfix 2.2. It is replaced by the more general \fBquery\fR
|
||||||
interface described above. If the \fBquery\fR parameter
|
interface described above. If the \fBquery\fR parameter
|
||||||
is defined, the legacy parameters described here ignored.
|
is defined, the legacy parameters described here ignored.
|
||||||
Please migrate to the new interface as the legacy interface
|
Please migrate to the new interface as the legacy interface
|
||||||
may be removed in a future release.
|
may be removed in a future release.
|
||||||
@ -437,3 +438,8 @@ P.O. BOX 1\-764
|
|||||||
RO\-014700 Bucharest, ROMANIA
|
RO\-014700 Bucharest, ROMANIA
|
||||||
|
|
||||||
Stored\-procedure support by John Fawcett.
|
Stored\-procedure support by John Fawcett.
|
||||||
|
|
||||||
|
Wietse Venema
|
||||||
|
Google, Inc.
|
||||||
|
111 8th Avenue
|
||||||
|
New York, NY 10011, USA
|
||||||
|
@ -120,6 +120,11 @@
|
|||||||
# query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
# query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
||||||
# .fi
|
# .fi
|
||||||
#
|
#
|
||||||
|
# By default, every query must return a result set (instead
|
||||||
|
# of storing its results in a table); with "\fBrequire_result_set
|
||||||
|
# = no\fR" (Postfix 3.2 and later), the absence of a result
|
||||||
|
# set is treated as "not found".
|
||||||
|
#
|
||||||
# This parameter supports the following '%' expansions:
|
# This parameter supports the following '%' expansions:
|
||||||
# .RS
|
# .RS
|
||||||
# .IP "\fB%%\fR"
|
# .IP "\fB%%\fR"
|
||||||
@ -265,6 +270,12 @@
|
|||||||
# specify, for example, "\fBoption_group = client\fR".
|
# specify, for example, "\fBoption_group = client\fR".
|
||||||
# .sp
|
# .sp
|
||||||
# This parameter is available with Postfix 2.11 and later.
|
# This parameter is available with Postfix 2.11 and later.
|
||||||
|
# .IP "\fBrequire_result_set (default: yes)\fR"
|
||||||
|
# If "\fByes\fR", require that every query returns a result
|
||||||
|
# set. If "\fBno\fR", treat the absence of a result set as
|
||||||
|
# "not found".
|
||||||
|
# .sp
|
||||||
|
# This parameter is available with Postfix 3.2 and later.
|
||||||
# .IP "\fBtls_cert_file\fR"
|
# .IP "\fBtls_cert_file\fR"
|
||||||
# File containing client's X509 certificate.
|
# File containing client's X509 certificate.
|
||||||
# .sp
|
# .sp
|
||||||
@ -302,29 +313,19 @@
|
|||||||
# The previously described '%' expansions can be used in the
|
# The previously described '%' expansions can be used in the
|
||||||
# parameter(s) to the stored procedure.
|
# parameter(s) to the stored procedure.
|
||||||
#
|
#
|
||||||
# The stored procedure must return data with a single result
|
# By default, every stored procedure call must return a result
|
||||||
# set, that is the stored procedure must execute exactly one
|
# set, i.e. every code path must execute a SELECT statement
|
||||||
# SELECT statement on every code path. If you have complex
|
# that returns a result set (instead of storing its results
|
||||||
# logic and for some paths you want to return no result you
|
# in a table). With "\fBrequire_result_set = no\fR", the
|
||||||
# will need to include a SELECT statement that returns no
|
# absence of a result set is treated as "not found".
|
||||||
# rows. One example of a query that returns no rows is
|
|
||||||
#
|
#
|
||||||
# .nf
|
# A stored procedure must not return multiple result sets.
|
||||||
# SELECT 1 FROM DUAL WHERE FALSE
|
# That is, there must be no code path that executes multiple
|
||||||
# .fi
|
# SELECT statements that return a result (instead of storing
|
||||||
#
|
# their results in a table).
|
||||||
# but you may use your own query.
|
|
||||||
#
|
|
||||||
# Stored procedures that return multiple result sets containing
|
|
||||||
# data, that is stored procedures that execute multiple SELECT
|
|
||||||
# statements, are not supported. Stored procedures in mysql
|
|
||||||
# produce an additional result set without data which indicates
|
|
||||||
# the final status of the stored procedure. If this final
|
|
||||||
# status is an error then any previous returned data will not
|
|
||||||
# be used.
|
|
||||||
#
|
#
|
||||||
# The following is an example of a stored procedure returning
|
# The following is an example of a stored procedure returning
|
||||||
# a single result set containing data:
|
# a single result set:
|
||||||
#
|
#
|
||||||
# .nf
|
# .nf
|
||||||
# CREATE [DEFINER=`user`@`host`] PROCEDURE
|
# CREATE [DEFINER=`user`@`host`] PROCEDURE
|
||||||
@ -340,7 +341,7 @@
|
|||||||
# .fi
|
# .fi
|
||||||
# This section describes an interface that is deprecated as
|
# This section describes an interface that is deprecated as
|
||||||
# of Postfix 2.2. It is replaced by the more general \fBquery\fR
|
# of Postfix 2.2. It is replaced by the more general \fBquery\fR
|
||||||
# interface described above. If the \fBquery\fR parameter
|
# interface described above. If the \fBquery\fR parameter
|
||||||
# is defined, the legacy parameters described here ignored.
|
# is defined, the legacy parameters described here ignored.
|
||||||
# Please migrate to the new interface as the legacy interface
|
# Please migrate to the new interface as the legacy interface
|
||||||
# may be removed in a future release.
|
# may be removed in a future release.
|
||||||
@ -411,4 +412,9 @@
|
|||||||
# RO-014700 Bucharest, ROMANIA
|
# RO-014700 Bucharest, ROMANIA
|
||||||
#
|
#
|
||||||
# Stored-procedure support by John Fawcett.
|
# Stored-procedure support by John Fawcett.
|
||||||
|
#
|
||||||
|
# Wietse Venema
|
||||||
|
# Google, Inc.
|
||||||
|
# 111 8th Avenue
|
||||||
|
# New York, NY 10011, USA
|
||||||
#--
|
#--
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
/* location.
|
/* location.
|
||||||
/* .IP option_group
|
/* .IP option_group
|
||||||
/* Read options from the given group.
|
/* Read options from the given group.
|
||||||
|
/* .IP require_result_set
|
||||||
|
/* Require that every query produces a result set.
|
||||||
/* .IP tls_cert_file
|
/* .IP tls_cert_file
|
||||||
/* File containing client's X509 certificate.
|
/* File containing client's X509 certificate.
|
||||||
/* .IP tls_key_file
|
/* .IP tls_key_file
|
||||||
@ -132,44 +134,25 @@
|
|||||||
/* where_field = alias
|
/* where_field = alias
|
||||||
/* .br
|
/* .br
|
||||||
/* hosts = host1.some.domain host2.some.domain
|
/* hosts = host1.some.domain host2.some.domain
|
||||||
/* .IP additional_conditions
|
|
||||||
/* Backward compatibility when \fIquery\fR is not set, additional
|
|
||||||
/* conditions to the WHERE clause.
|
|
||||||
/* .IP hosts
|
|
||||||
/* List of hosts to connect to.
|
|
||||||
/* .PP
|
|
||||||
/* For example, if you want the map to reference databases of
|
|
||||||
/* the name "your_db" and execute a query like this: select
|
|
||||||
/* forw_addr from aliases where alias like '<some username>'
|
|
||||||
/* against any database called "vmailer_info" located on hosts
|
|
||||||
/* host1.some.domain and host2.some.domain, logging in as user
|
|
||||||
/* "vmailer" and password "passwd" then the configuration file
|
|
||||||
/* should read:
|
|
||||||
/* .PP
|
|
||||||
/* user = vmailer
|
|
||||||
/* .br
|
|
||||||
/* password = passwd
|
|
||||||
/* .br
|
|
||||||
/* dbname = vmailer_info
|
|
||||||
/* .br
|
|
||||||
/* table = aliases
|
|
||||||
/* .br
|
|
||||||
/* select_field = forw_addr
|
|
||||||
/* .br
|
|
||||||
/* where_field = alias
|
|
||||||
/* .br
|
|
||||||
/* hosts = host1.some.domain host2.some.domain
|
|
||||||
/* .PP
|
/* .PP
|
||||||
/* SEE ALSO
|
/* SEE ALSO
|
||||||
/* dict(3) generic dictionary manager
|
/* dict(3) generic dictionary manager
|
||||||
/* AUTHOR(S)
|
/* AUTHOR(S)
|
||||||
/* Scott Cotton
|
/* Scott Cotton, Joshua Marcus
|
||||||
/* IC Group, Inc.
|
/* IC Group, Inc.
|
||||||
/* scott@icgroup.com
|
/* scott@icgroup.com
|
||||||
/*
|
/*
|
||||||
/* Joshua Marcus
|
/* Liviu Daia
|
||||||
/* IC Group, Inc.
|
/* Institute of Mathematics of the Romanian Academy
|
||||||
/* josh@icgroup.com
|
/* P.O. BOX 1-764
|
||||||
|
/* RO-014700 Bucharest, ROMANIA
|
||||||
|
/*
|
||||||
|
/* John Fawcett
|
||||||
|
/*
|
||||||
|
/* Wietse Venema
|
||||||
|
/* Google, Inc.
|
||||||
|
/* 111 8th Avenue
|
||||||
|
/* New York, NY 10011, USA
|
||||||
/*--*/
|
/*--*/
|
||||||
|
|
||||||
/* System library. */
|
/* System library. */
|
||||||
@ -258,6 +241,7 @@ typedef struct {
|
|||||||
int tls_verify_cert;
|
int tls_verify_cert;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
int require_result_set;
|
||||||
} DICT_MYSQL;
|
} DICT_MYSQL;
|
||||||
|
|
||||||
#define STATACTIVE (1<<0)
|
#define STATACTIVE (1<<0)
|
||||||
@ -273,7 +257,7 @@ typedef struct {
|
|||||||
|
|
||||||
/* internal function declarations */
|
/* internal function declarations */
|
||||||
static PLMYSQL *plmysql_init(ARGV *);
|
static PLMYSQL *plmysql_init(ARGV *);
|
||||||
static MYSQL_RES *plmysql_query(DICT_MYSQL *, const char *, VSTRING *);
|
static int plmysql_query(DICT_MYSQL *, const char *, VSTRING *, MYSQL_RES **);
|
||||||
static void plmysql_dealloc(PLMYSQL *);
|
static void plmysql_dealloc(PLMYSQL *);
|
||||||
static void plmysql_close_host(HOST *);
|
static void plmysql_close_host(HOST *);
|
||||||
static void plmysql_down_host(HOST *);
|
static void plmysql_down_host(HOST *);
|
||||||
@ -383,10 +367,12 @@ static const char *dict_mysql_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 = plmysql_query(dict_mysql, name, query)) == 0) {
|
if (plmysql_query(dict_mysql, name, query, &query_res) == 0) {
|
||||||
dict->error = DICT_ERR_RETRY;
|
dict->error = DICT_ERR_RETRY;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
if (query_res == 0)
|
||||||
|
return (0);
|
||||||
numrows = mysql_num_rows(query_res);
|
numrows = mysql_num_rows(query_res);
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: retrieved %d rows", myname, numrows);
|
msg_info("%s: retrieved %d rows", myname, numrows);
|
||||||
@ -508,18 +494,20 @@ static void dict_mysql_event(int unused_event, void *context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* plmysql_query - process a MySQL query. Return MYSQL_RES* on success.
|
* plmysql_query - process a MySQL query. Return 'true' on success.
|
||||||
* On failure, log failure and try other db instances.
|
* On failure, log failure and try other db instances.
|
||||||
* on failure of all db instances, return 0;
|
* on failure of all db instances, return 'false';
|
||||||
* close unnecessary active connections
|
* close unnecessary active connections
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
|
static int plmysql_query(DICT_MYSQL *dict_mysql,
|
||||||
const char *name,
|
const char *name,
|
||||||
VSTRING *query)
|
VSTRING *query,
|
||||||
|
MYSQL_RES **result)
|
||||||
{
|
{
|
||||||
HOST *host;
|
HOST *host;
|
||||||
MYSQL_RES *res = 0;
|
MYSQL_RES *first_result = 0;
|
||||||
|
int query_error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper to avoid spamming the log with warnings.
|
* Helper to avoid spamming the log with warnings.
|
||||||
@ -533,7 +521,6 @@ static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
while ((host = dict_mysql_get_active(dict_mysql)) != NULL) {
|
while ((host = dict_mysql_get_active(dict_mysql)) != NULL) {
|
||||||
int query_error = 0;
|
|
||||||
|
|
||||||
#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
|
#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
|
||||||
|
|
||||||
@ -549,56 +536,77 @@ static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
|
|||||||
dict_mysql->active_host = 0;
|
dict_mysql->active_host = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
query_error = 0;
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The query must complete.
|
* The query must complete.
|
||||||
*/
|
*/
|
||||||
if (mysql_query(host->db, vstring_str(query)) != 0) {
|
if (mysql_query(host->db, vstring_str(query)) != 0) {
|
||||||
query_error = 1;
|
query_error = 1;
|
||||||
msg_warn("mysql query failed: %s", mysql_error(host->db));
|
msg_warn("%s:%s: query failed: %s",
|
||||||
|
dict_mysql->dict.type, dict_mysql->dict.name,
|
||||||
|
mysql_error(host->db));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The query must return at least one result.
|
* Collect all result sets to avoid synchronization errors.
|
||||||
*/
|
|
||||||
else if ((res = mysql_store_result(host->db)) == 0) {
|
|
||||||
query_error = 1;
|
|
||||||
msg_warn("mysql query failed: no result set containing data");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Are there more results? -1 = no, 0 = yes, > 0 = error. We must
|
|
||||||
* collect all results to avoid synchronization errors.
|
|
||||||
*/
|
*/
|
||||||
else {
|
else {
|
||||||
int next_res_status;
|
int next_res_status;
|
||||||
MYSQL_RES *temp_res;
|
|
||||||
|
|
||||||
while ((next_res_status = mysql_next_result(host->db)) >= 0) {
|
do {
|
||||||
if (next_res_status > 0) {
|
MYSQL_RES *temp_result;
|
||||||
SET_ERROR_AND_WARN_ONCE(query_error,
|
|
||||||
"mysql query failed (mysql_next_result): %s",
|
|
||||||
mysql_error(host->db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The result must not contain data.
|
* Keep the first result set. Reject multiple result sets.
|
||||||
*/
|
*/
|
||||||
else if ((temp_res = mysql_store_result(host->db)) != 0) {
|
if ((temp_result = mysql_store_result(host->db)) != 0) {
|
||||||
SET_ERROR_AND_WARN_ONCE(query_error,
|
if (first_result == 0) {
|
||||||
"mysql query failed: multiple result sets "
|
first_result = temp_result;
|
||||||
"returning data are not supported");
|
} else {
|
||||||
mysql_free_result(temp_res);
|
SET_ERROR_AND_WARN_ONCE(query_error,
|
||||||
|
"%s:%s: query failed: multiple result sets "
|
||||||
|
"returning data are not supported",
|
||||||
|
dict_mysql->dict.type,
|
||||||
|
dict_mysql->dict.name);
|
||||||
|
mysql_free_result(temp_result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There must be no errors: mysql_field_count() must return 0
|
* No result: the mysql_field_count() function must return 0
|
||||||
* to indicate that the "no data" result was expected.
|
* to indicate that mysql_store_result() completed normally.
|
||||||
*/
|
*/
|
||||||
else if (mysql_field_count(host->db) != 0) {
|
else if (mysql_field_count(host->db) != 0) {
|
||||||
SET_ERROR_AND_WARN_ONCE(query_error,
|
SET_ERROR_AND_WARN_ONCE(query_error,
|
||||||
"mysql query failed (mysql_field_count): %s",
|
"%s:%s: query failed (mysql_store_result): %s",
|
||||||
|
dict_mysql->dict.type,
|
||||||
|
dict_mysql->dict.name,
|
||||||
mysql_error(host->db));
|
mysql_error(host->db));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Are there more results? -1 = no, 0 = yes, > 0 = error.
|
||||||
|
*/
|
||||||
|
if ((next_res_status = mysql_next_result(host->db)) > 0) {
|
||||||
|
SET_ERROR_AND_WARN_ONCE(query_error,
|
||||||
|
"%s:%s: query failed (mysql_next_result): %s",
|
||||||
|
dict_mysql->dict.type,
|
||||||
|
dict_mysql->dict.name,
|
||||||
|
mysql_error(host->db));
|
||||||
|
}
|
||||||
|
} while (next_res_status == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enforce the require_result_set setting.
|
||||||
|
*/
|
||||||
|
if (first_result == 0 && dict_mysql->require_result_set) {
|
||||||
|
SET_ERROR_AND_WARN_ONCE(query_error,
|
||||||
|
"%s:%s: query failed: query returned no result set"
|
||||||
|
"(require_result_set = yes)",
|
||||||
|
dict_mysql->dict.type,
|
||||||
|
dict_mysql->dict.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,13 +617,14 @@ static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
|
|||||||
plmysql_down_host(host);
|
plmysql_down_host(host);
|
||||||
if (errno == 0)
|
if (errno == 0)
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
if (res) {
|
if (first_result) {
|
||||||
mysql_free_result(res);
|
mysql_free_result(first_result);
|
||||||
res = 0;
|
first_result = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("dict_mysql: successful query result from host %s",
|
msg_info("%s:%s: successful query result from host %s",
|
||||||
|
dict_mysql->dict.type, dict_mysql->dict.name,
|
||||||
host->hostname);
|
host->hostname);
|
||||||
event_request_timer(dict_mysql_event, (void *) host,
|
event_request_timer(dict_mysql_event, (void *) host,
|
||||||
IDLE_CONN_INTV);
|
IDLE_CONN_INTV);
|
||||||
@ -623,7 +632,8 @@ static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
*result = first_result;
|
||||||
|
return (query_error == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -717,6 +727,7 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf)
|
|||||||
dict_mysql->tls_verify_cert = cfg_get_bool(p, "tls_verify_cert", -1);
|
dict_mysql->tls_verify_cert = cfg_get_bool(p, "tls_verify_cert", -1);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
dict_mysql->require_result_set = cfg_get_bool(p, "require_result_set", 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: The default should be non-zero for safety, but that is not
|
* XXX: The default should be non-zero for safety, but that is not
|
||||||
|
@ -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 "20161225"
|
#define MAIL_RELEASE_DATE "20161226"
|
||||||
#define MAIL_VERSION_NUMBER "3.2"
|
#define MAIL_VERSION_NUMBER "3.2"
|
||||||
|
|
||||||
#ifdef SNAPSHOT
|
#ifdef SNAPSHOT
|
||||||
|
@ -100,8 +100,8 @@ static const char *pcf_ldap_suffixes[] = {
|
|||||||
|
|
||||||
static const char *pcf_mysql_suffixes[] = {
|
static const char *pcf_mysql_suffixes[] = {
|
||||||
"additional_conditions", "dbname", "domain", "expansion_limit",
|
"additional_conditions", "dbname", "domain", "expansion_limit",
|
||||||
"hosts", "password", "query", "result_format", "select_field",
|
"hosts", "password", "query", "result_format", "require_result_set",
|
||||||
"table", "user", "where_field", 0,
|
"select_field", "table", "user", "where_field", 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* See pgsql_table(5). */
|
/* See pgsql_table(5). */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user