1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge 1995 - 2018 */
6 /* Copyright (c) The Exim Maintainers 2020 */
7 /* See the file NOTICE for conditions of use and distribution. */
11 #include "lf_functions.h"
15 /*************************************************
16 * Call SQL server(s) to run an actual query *
17 *************************************************/
19 /* All the SQL lookups are of the same form, with a list of servers to try
20 until one can be accessed. It is now also possible to provide the server data
21 as part of the query. This function manages server selection and looping; each
22 lookup has its own function for actually performing the lookup.
25 name the lookup name, e.g. "MySQL"
26 optionname the name of the servers option, e.g. "mysql_servers"
27 optserverlist the value of the servers option
29 result where to pass back the result
30 errmsg where to pass back an error message
31 do_cache to be set zero if data is changed
32 func the lookup function to call
34 Returns: the return from the lookup function, or DEFER
38 lf_sqlperform(const uschar *name, const uschar *optionname,
39 const uschar *optserverlist, const uschar *query,
40 uschar **result, uschar **errmsg, uint *do_cache, const uschar * opts,
41 int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *, const uschar *))
45 BOOL defer_break = FALSE;
47 DEBUG(D_lookup) debug_printf_indent("%s query: \"%s\" opts '%s'\n", name, query, opts);
49 /* Handle queries that do have server information at the start. */
51 if (Ustrncmp(query, "servers", 7) == 0)
55 const uschar *qserverlist;
62 *errmsg = string_sprintf("missing = after \"servers\" in %s lookup", name);
70 *errmsg = string_sprintf("missing ; after \"servers=\" in %s lookup",
77 *errmsg = string_sprintf("\"servers=\" defines no servers in \"%s\"",
82 qserverlist = string_sprintf("%.*s", (int)(ss - s), s);
84 while ((qserver = string_nextinlist(&qserverlist, &qsep, NULL, 0)))
86 if (Ustrchr(qserver, '/'))
90 int len = Ustrlen(qserver);
91 const uschar * serverlist = optserverlist;
93 for (int sep = 0; server = string_nextinlist(&serverlist, &sep, NULL, 0);)
94 if (Ustrncmp(server, qserver, len) == 0 && server[len] == '/')
99 *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
100 qserver, optionname);
105 if (is_tainted(server))
107 *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
111 rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts);
112 if (rc != DEFER || defer_break) return rc;
116 /* Handle queries that do not have server information at the start. */
120 const uschar * serverlist = NULL;
122 /* If options are present, scan for a server definition. Default to
123 the "optserverlist" srgument. */
128 for (int sep = ','; ele = string_nextinlist(&opts, &sep, NULL, 0); )
129 if (Ustrncmp(ele, "servers=", 8) == 0)
130 { serverlist = ele + 8; break; }
134 serverlist = optserverlist;
136 *errmsg = string_sprintf("no %s servers defined (%s option)", name,
139 for (int d = 0; (server = string_nextinlist(&serverlist, &d, NULL, 0)); )
141 /* If not a full spec assume from options; scan main list for matching
144 if (!Ustrchr(server, '/'))
146 int len = Ustrlen(server);
147 const uschar * slist = optserverlist;
149 for (int sep = 0; ele = string_nextinlist(&slist, &sep, NULL, 0); )
150 if (Ustrncmp(ele, server, len) == 0 && ele[len] == '/')
154 *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
161 if (is_tainted(server))
163 *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
167 rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
168 if (rc != DEFER || defer_break) return rc;
175 /* End of lf_sqlperform.c */