MySQL, pgsql: per-query server options outside the lookup string. Bug 2546
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 5 Apr 2020 23:28:06 +0000 (00:28 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Mon, 6 Apr 2020 12:14:05 +0000 (13:14 +0100)
14 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/acl.c
src/src/lookups/lf_functions.h
src/src/lookups/lf_sqlperform.c
src/src/lookups/mysql.c
src/src/lookups/pgsql.c
src/src/lookups/redis.c
src/src/string.c
src/src/verify.c
test/confs/2610
test/confs/2620
test/stderr/2610
test/stderr/2620

index 9a7f9113eb8b09ee377b09dd7af8eced6fb19fd7..8e7cb4d9275e0b55ad3c84ba0158add9a65393ed 100644 (file)
@@ -8016,12 +8016,14 @@ The &%quote_redis%& expansion operator
 escapes whitespace and backslash characters with a backslash.
 
 .section "Specifying the server in the query" "SECTspeserque"
+.new
 For MySQL, PostgreSQL and Redis lookups (but not currently for Oracle and InterBase),
 it is possible to specify a list of servers with an individual query. This is
-done by starting the query with
+done by appending a comma-separated option to the query type:
 .display
-&`servers=`&&'server1:server2:server3:...'&&`;`&
 .endd
+&`,servers=`&&'server1:server2:server3:...'&
+.wen
 Each item in the list may take one of two forms:
 .olist
 If it contains no slashes it is assumed to be just a host name. The appropriate
@@ -8046,14 +8048,25 @@ mysql_servers = slave1/db/name/pw:\
 .endd
 In an updating lookup, you could then write:
 .code
-${lookup mysql{servers=master; UPDATE ...} }
+${lookup mysql,servers=master {UPDATE ...} }
 .endd
 That query would then be sent only to the master server. If, on the other hand,
 the master is not to be used for reading, and so is not present in the global
 option, you can still update it by a query of this form:
 .code
-${lookup pgsql{servers=master/db/name/pw; UPDATE ...} }
+${lookup pgsql,servers=master/db/name/pw {UPDATE ...} }
+.endd
+
+.new
+An older syntax places the servers speciification before the qury,
+semicolon separated:
+.code
+${lookup mysql{servers=master; UPDATE ...} }
 .endd
+The new version avoids potential issues with tainted
+arguments in the query, for explicit expansion.
+&*Note*&: server specifications in list-style lookups are still problematic.
+.wen
 
 
 .section "Special MySQL features" "SECID73"
@@ -8619,6 +8632,14 @@ whether or not the query succeeds. However, when a lookup is used for the
 &%domains%& option on a router, the data is preserved in the &$domain_data$&
 variable and can be referred to in other options.
 .next
+.new
+If the pattern starts with the name of a lookup type
+of either kind (single-key or query-style) it may be
+followed by a command and options,
+The options are lookup-type specific and consist of a comma-separated list.
+Each item starts with a tag and and equals "=".
+.wen
+.next
 .cindex "domain list" "matching literal domain name"
 If none of the above cases apply, a caseless textual comparison is made
 between the pattern and the domain.
index 1573f3485d9108b1dbc9680af6488d60dc35514d..80d35254368413ee1e3023f84659794e53d224a1 100644 (file)
@@ -47,10 +47,13 @@ Version 4.94
     lookup string.  The older method fails when tainted variables are used
     in the lookup, as the filename becomes tainted.  The new method keeps the
     filename separate.
-12. An option on the dsearch lookup, to return the full path.
-12. Options on the dsearch lookup, to return the full path and to filter
+
+13. Options on the dsearch lookup, to return the full path and to filter
     filetypes for matching.
 
+14. Options on pgsql and mysql lookups, to specify server separate from the
+    lookup string.
+
 
 
 Version 4.93
index 02251b197281ce65cf8f3b8127cefd38ed7988c5..3ea8df1b135e8f028973c47565da6c9ce14bc17f 100644 (file)
@@ -3477,13 +3477,13 @@ for (; cb; cb = cb->next)
       {
       uschar *endcipher = NULL;
       uschar *cipher = Ustrchr(tls_in.cipher, ':');
-      if (cipher == NULL) cipher = tls_in.cipher; else
+      if (!cipher) cipher = tls_in.cipher; else
         {
         endcipher = Ustrchr(++cipher, ':');
-        if (endcipher != NULL) *endcipher = 0;
+        if (endcipher) *endcipher = 0;
         }
       rc = match_isinlist(cipher, &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL);
-      if (endcipher != NULL) *endcipher = ':';
+      if (endcipher) *endcipher = ':';
       }
     break;
 
@@ -3496,8 +3496,7 @@ for (; cb; cb = cb->next)
 
     case ACLC_HOSTS:
     rc = verify_check_this_host(&arg, sender_host_cache, NULL,
-      (sender_host_address == NULL)? US"" : sender_host_address,
-      CUSS &host_data);
+      sender_host_address ? sender_host_address : US"", CUSS &host_data);
     if (rc == DEFER) *log_msgptr = search_error_message;
     if (host_data) host_data = string_copy_perm(host_data, TRUE);
     break;
index 4d9ae9595758167d96bfa1d342500d174e89f154..7e7ac4d24abafd91ec83b7ac7938f7efd68b1c13 100644 (file)
@@ -12,7 +12,8 @@ extern int     lf_check_file(int, const uschar *, int, int, uid_t *, gid_t *,
 extern gstring *lf_quote(uschar *, uschar *, int, gstring *);
 extern int     lf_sqlperform(const uschar *, const uschar *, const uschar *,
                 const uschar *, uschar **,
-                 uschar **, uint *, int(*)(const uschar *, uschar *, uschar **,
-                 uschar **, BOOL *, uint *));
+                 uschar **, uint *, const uschar *,
+                int(*)(const uschar *, uschar *, uschar **,
+                 uschar **, BOOL *, uint *, const uschar *));
 
 /* End of lf_functions.h */
index cc894e0ed89083725d8f59198de7e2d58e8feaf4..e2636bfe9468e28c85ce44bde7e87c6ecbe5631e 100644 (file)
@@ -36,55 +36,35 @@ Returns:         the return from the lookup function, or DEFER
 int
 lf_sqlperform(const uschar *name, const uschar *optionname,
   const uschar *optserverlist, const uschar *query,
-  uschar **result, uschar **errmsg, uint *do_cache,
-  int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *))
+  uschar **result, uschar **errmsg, uint *do_cache, const uschar * opts,
+  int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *, const uschar *))
 {
-int sep, rc;
+int rc;
 uschar *server;
-const uschar *serverlist;
-uschar buffer[512];
 BOOL defer_break = FALSE;
 
-DEBUG(D_lookup) debug_printf_indent("%s query: %s\n", name, query);
-
-/* Handle queries that do not have server information at the start. */
-
-if (Ustrncmp(query, "servers", 7) != 0)
-  {
-  sep = 0;
-  serverlist = optserverlist;
-  while ((server = string_nextinlist(&serverlist, &sep, buffer,
-          sizeof(buffer))) != NULL)
-    {
-    rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache);
-    if (rc != DEFER || defer_break) return rc;
-    }
-  if (optserverlist == NULL)
-    *errmsg = string_sprintf("no %s servers defined (%s option)", name,
-      optionname);
-  }
+DEBUG(D_lookup) debug_printf_indent("%s query: \"%s\" opts '%s'\n", name, query, opts);
 
 /* Handle queries that do have server information at the start. */
 
-else
+if (Ustrncmp(query, "servers", 7) == 0)
   {
-  int qsep;
+  int qsep = 0;
   const uschar *s, *ss;
   const uschar *qserverlist;
   uschar *qserver;
-  uschar qbuffer[512];
 
   s = query + 7;
-  while (isspace(*s)) s++;
+  skip_whitespace(&s);
   if (*s++ != '=')
     {
     *errmsg = string_sprintf("missing = after \"servers\" in %s lookup", name);
     return DEFER;
     }
-  while (isspace(*s)) s++;
+  skip_whitespace(&s);
 
   ss = Ustrchr(s, ';');
-  if (ss == NULL)
+  if (!ss)
     {
     *errmsg = string_sprintf("missing ; after \"servers=\" in %s lookup",
       name);
@@ -99,27 +79,21 @@ else
     }
 
   qserverlist = string_sprintf("%.*s", (int)(ss - s), s);
-  qsep = 0;
 
-  while ((qserver = string_nextinlist(&qserverlist, &qsep, qbuffer,
-           sizeof(qbuffer))) != NULL)
+  while ((qserver = string_nextinlist(&qserverlist, &qsep, NULL, 0)))
     {
-    if (Ustrchr(qserver, '/') != NULL)
+    if (Ustrchr(qserver, '/'))
       server = qserver;
     else
       {
       int len = Ustrlen(qserver);
+      const uschar * serverlist = optserverlist;
 
-      sep = 0;
-      serverlist = optserverlist;
-      while ((server = string_nextinlist(&serverlist, &sep, buffer,
-              sizeof(buffer))) != NULL)
-        {
+      for (int sep = 0; server = string_nextinlist(&serverlist, &sep, NULL, 0);)
         if (Ustrncmp(server, qserver, len) == 0 && server[len] == '/')
           break;
-        }
 
-      if (server == NULL)
+      if (!server)
         {
         *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
           qserver, optionname);
@@ -127,11 +101,73 @@ else
         }
       }
 
-    rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache);
+    if (is_tainted(server))
+      {
+      *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
+      return DEFER;
+      }
+
+    rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts);
     if (rc != DEFER || defer_break) return rc;
     }
   }
 
+/* Handle queries that do not have server information at the start. */
+
+else
+  {
+  const uschar * serverlist = NULL;
+
+  /* If options are present, scan for a server definition.  Default to
+  the "optserverlist" srgument. */
+
+  if (opts)
+    {
+    uschar * ele;
+    for (int sep = ','; ele = string_nextinlist(&opts, &sep, NULL, 0); )
+      if (Ustrncmp(ele, "servers=", 8) == 0)
+       { serverlist = ele + 8; break; }
+    }
+
+  if (!serverlist)
+    serverlist = optserverlist;
+  if (!serverlist)
+    *errmsg = string_sprintf("no %s servers defined (%s option)", name,
+      optionname);
+  else
+    for (int d = 0; (server = string_nextinlist(&serverlist, &d, NULL, 0)); )
+      {
+      /* If not a full spec assume from options; scan main list for matching
+      hostname */
+
+      if (!Ustrchr(server, '/'))
+       {
+       int len = Ustrlen(server);
+       const uschar * slist = optserverlist;
+       uschar * ele;
+       for (int sep = 0; ele = string_nextinlist(&slist, &sep, NULL, 0); )
+         if (Ustrncmp(ele, server, len) == 0 && ele[len] == '/')
+           break;
+       if (!ele)
+         {
+         *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
+           server, optionname);
+         return DEFER;
+         }
+       server = ele;
+       }
+
+      if (is_tainted(server))
+        {
+        *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
+        return DEFER;
+        }
+
+      rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
+      if (rc != DEFER || defer_break) return rc;
+      }
+  }
+
 return DEFER;
 }
 
index 7651353a22281819cc0c6271ec53b8e3da92f29f..220aba1c39f2317b456204320441818e4f792f46 100644 (file)
@@ -122,6 +122,7 @@ Arguments:
   errmsg       where to point an error message
   defer_break  TRUE if no more servers are to be tried after DEFER
   do_cache     set zero if data is changed
+  opts        options
 
 The server string is of the form "host/dbname/user/password". The host can be
 host:port. This string is in a nextinlist temporary buffer, so can be
@@ -132,7 +133,7 @@ Returns:       OK, FAIL, or DEFER
 
 static int
 perform_mysql_search(const uschar *query, uschar *server, uschar **resultptr,
-  uschar **errmsg, BOOL *defer_break, uint *do_cache)
+  uschar **errmsg, BOOL *defer_break, uint *do_cache, const uschar * opts)
 {
 MYSQL *mysql_handle = NULL;        /* Keep compilers happy */
 MYSQL_RES *mysql_result = NULL;
@@ -155,7 +156,7 @@ has the password removed. This copy is also used for debugging output. */
 for (int i = 3; i > 0; i--)
   {
   uschar *pp = Ustrrchr(server, '/');
-  if (pp == NULL)
+  if (!pp)
     {
     *errmsg = string_sprintf("incomplete MySQL server data: %s",
       (i == 3)? server : server_copy);
@@ -172,10 +173,7 @@ sdata[0] = server;   /* What's left at the start */
 
 for (cn = mysql_connections; cn; cn = cn->next)
   if (Ustrcmp(cn->server, server_copy) == 0)
-    {
-    mysql_handle = cn->handle;
-    break;
-    }
+    { mysql_handle = cn->handle; break; }
 
 /* If no cached connection, we must set one up. Mysql allows for a host name
 and port to be specified. It also allows the name of a Unix socket to be used.
@@ -283,7 +281,7 @@ up. Setting do_cache zero requests this. */
 
 if (!(mysql_result = mysql_use_result(mysql_handle)))
   {
-  if ( mysql_field_count(mysql_handle) == 0 )
+  if (mysql_field_count(mysql_handle) == 0)
     {
     DEBUG(D_lookup) debug_printf_indent("MYSQL: query was not one that returns data\n");
     result = string_cat(result,
@@ -328,18 +326,15 @@ while ((mysql_row_data = mysql_fetch_row(mysql_result)))
    we don't expect any more results. */
 
 while((i = mysql_next_result(mysql_handle)) >= 0)
-  {
-  if(i == 0)   /* Just ignore more results */
+  if(i != 0)
     {
-    DEBUG(D_lookup) debug_printf_indent("MYSQL: got unexpected more results\n");
-    continue;
+    *errmsg = string_sprintf(
+         "MYSQL: lookup result error when checking for more results: %s\n",
+         mysql_error(mysql_handle));
+    goto MYSQL_EXIT;
     }
-
-  *errmsg = string_sprintf(
-       "MYSQL: lookup result error when checking for more results: %s\n",
-       mysql_error(mysql_handle));
-  goto MYSQL_EXIT;
-  }
+  else /* just ignore more results */
+    DEBUG(D_lookup) debug_printf_indent("MYSQL: got unexpected more results\n");
 
 /* If result is NULL then no data has been found and so we return FAIL.
 Otherwise, we must terminate the string which has been built; string_cat()
@@ -394,7 +389,7 @@ mysql_find(void * handle, const uschar * filename, const uschar * query,
   const uschar * opts)
 {
 return lf_sqlperform(US"MySQL", US"mysql_servers", mysql_servers, query,
-  result, errmsg, do_cache, perform_mysql_search);
+  result, errmsg, do_cache, opts, perform_mysql_search);
 }
 
 
index 90dda601a2aec608a09924076f906fb6b5a5c6ea..505f5e5ce7b952d43ac128e3e6aa59e41d529901 100644 (file)
@@ -113,13 +113,14 @@ Arguments:
   errmsg       where to point an error message
   defer_break  set TRUE if no more servers are to be tried after DEFER
   do_cache     set FALSE if data is changed
+  opts        options list
 
 Returns:       OK, FAIL, or DEFER
 */
 
 static int
 perform_pgsql_search(const uschar *query, uschar *server, uschar **resultptr,
-  uschar **errmsg, BOOL *defer_break, uint *do_cache)
+  uschar **errmsg, BOOL *defer_break, uint *do_cache, const uschar * opts)
 {
 PGconn *pg_conn = NULL;
 PGresult *pg_result = NULL;
@@ -386,7 +387,7 @@ pgsql_find(void * handle, const uschar * filename, const uschar * query,
   const uschar * opts)
 {
 return lf_sqlperform(US"PostgreSQL", US"pgsql_servers", pgsql_servers, query,
-  result, errmsg, do_cache, perform_pgsql_search);
+  result, errmsg, do_cache, opts, perform_pgsql_search);
 }
 
 
index 84a2dc6c7c06aa5d291eb8f305cf9239db32b941..337fdae152d4aa130606fd100f3131e40d128772 100644 (file)
@@ -63,6 +63,7 @@ single server.
       errmsg       where to point an error message
       defer_break  TRUE if no more servers are to be tried after DEFER
       do_cache     set false if data is changed
+      opts        options
 
     The server string is of the form "host/dbnumber/password". The host can be
     host:port. This string is in a nextinlist temporary buffer, so can be
@@ -73,7 +74,7 @@ single server.
 
 static int
 perform_redis_search(const uschar *command, uschar *server, uschar **resultptr,
-  uschar **errmsg, BOOL *defer_break, uint *do_cache)
+  uschar **errmsg, BOOL *defer_break, uint *do_cache, const uschar * opts)
 {
 redisContext *redis_handle = NULL;        /* Keep compilers happy */
 redisReply *redis_reply = NULL;
@@ -380,7 +381,7 @@ redis_find(void * handle __attribute__((unused)),
   uint * do_cache, const uschar * opts)
 {
 return lf_sqlperform(US"Redis", US"redis_servers", redis_servers, command,
-  result, errmsg, do_cache, perform_redis_search);
+  result, errmsg, do_cache, opts, perform_redis_search);
 }
 
 
index 80cf49fdf1b297d14f0d25d43708b98c92e20660..1192a554e9ad9e8529a50b8b0a9d56eedea4ba70 100644 (file)
@@ -574,18 +574,14 @@ uschar *ss = yield = store_get(Ustrlen(s) + 1, is_tainted(s));
 while (*s != 0)
   {
   if (*s != '\\')
-    {
     *ss++ = *s++;
-    }
   else if (isdigit(s[1]))
     {
     *ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0';
     s += 4;
     }
   else if (*(++s) != 0)
-    {
     *ss++ = *s++;
-    }
   }
 
 *ss = 0;
index cd9df1f71b81eef70d8c718a0ecf7b80010ee8f1..dda51a5a260e30bd2553d1df7b66019fbb464a12 100644 (file)
@@ -2909,7 +2909,6 @@ provided that host name matching is permitted; if it's "@[]" match against the
 local host's IP addresses. */
 
 if (*ss == '@')
-  {
   if (ss[1] == 0)
     {
     if (isiponly) return ERROR;
@@ -2921,7 +2920,6 @@ if (*ss == '@')
       if (Ustrcmp(ip->address, cb->host_address) == 0) return OK;
     return FAIL;
     }
-  }
 
 /* If the pattern is an IP address, optionally followed by a bitmask count, do
 a (possibly masked) comparison with the current IP address. */
@@ -2951,6 +2949,11 @@ if (*t == 0 || (*t == '/' && t != ss))
 
 if ((semicolon = Ustrchr(ss, ';')))
   endname = (opts = Ustrchr(ss, ',')) ? opts : semicolon;
+if (opts)
+  {
+  opts++;
+  opts = string_copyn(opts, semicolon - opts);
+  }
 
 /* If we are doing an IP address only match, then all lookups must be IP
 address lookups, even if there is no "net-". */
index 9e2217215924458089f57ed0c6d45d861ec8bd8d..5a964276e86a73196bc547ad6fe60f9e1adf14df 100644 (file)
@@ -11,7 +11,9 @@ hostlist   relay_hosts = net-mysql;select * from them where id='$sender_host_add
 
 acl_smtp_rcpt = check_recipient
 
-mysql_servers = 127.0.0.1::PORT_N/test/root/
+PARTIAL = 127.0.0.1::PORT_N
+SSPEC = PARTIAL/test/root/
+mysql_servers = SSPEC
 
 
 # ----- ACL -----
@@ -19,6 +21,29 @@ mysql_servers = 127.0.0.1::PORT_N/test/root/
 begin acl
 
 check_recipient:
+         # Tainted-data checks
+  warn
+         # taint only in lookup string
+         set acl_m0 =  ok:   ${lookup mysql                    {select name from them where id = '$local_part'}}
+         # option on lookup type unaffected
+         set acl_m0 =  ok:   ${lookup mysql,servers=SSPEC      {select name from them where id = '$local_part'}}
+         # partial server-spec, indexing main-option, works
+         set acl_m0 =  ok:   ${lookup mysql,servers=PARTIAL    {select name from them where id = '$local_part'}}
+         # oldstyle server spec, prepended to lookup string, fails with taint
+         set acl_m0 =  FAIL: ${lookup mysql     {servers=SSPEC; select name from them where id = '$local_part'}}
+
+         # In list-stle lookup, tainted lookup string is ok if server spec comes from main-option
+  warn   set acl_m0 =  ok:   hostlist
+         hosts =       net-mysql;select * from them where id='$local_part'
+         # ... but setting a per-query servers spec fails due to the taint
+  warn   set acl_m0 =  FAIL: hostlist
+         hosts =       <& net-mysql;servers=SSPEC; select * from them where id='$local_part'
+
+         # The newer server-list-as-option-to-lookup-type is not a solution to tainted data in the lookup, because
+         # string-expansion is done before list-expansion so the taint contaminates the entire list.
+  warn   set acl_m0 =  FAIL: hostlist
+         hosts =       <& net-mysql,servers=SSPEC; select * from them where id='$local_part'
+
   accept  domains = +local_domains
   accept  hosts = +relay_hosts
   deny    message = relay not permitted
index 009e74fd8540f6010a83328bea471f75849e10eb..e63fca28617f19ddc46074f2fc99882aa488690f 100644 (file)
@@ -1,6 +1,7 @@
 # Exim test configuration 2620
 
-SERVERS=localhost::PORT_N/test/CALLER/
+PARTIAL=localhost::PORT_N
+SERVERS=PARTIAL/test/CALLER/
 
 .include DIR/aux-var/std_conf_prefix
 
@@ -22,6 +23,29 @@ pgsql_servers = SERVERS
 begin acl
 
 check_recipient:
+         # Tainted-data checks
+  warn
+         # taint only in lookup string
+         set acl_m0 =  ok:   ${lookup pgsql                    {select name from them where id = '$local_part'}}
+         # option on lookup type unaffected
+         set acl_m0 =  ok:   ${lookup pgsql,servers=SSPEC      {select name from them where id = '$local_part'}}
+         # partial server-spec, indexing main-option, works
+         set acl_m0 =  ok:   ${lookup pgsql,servers=PARTIAL    {select name from them where id = '$local_part'}}
+         # oldstyle server spec, prepended to lookup string, fails with taint
+         set acl_m0 =  FAIL: ${lookup pgsql     {servers=SSPEC; select name from them where id = '$local_part'}}
+
+         # In list-stle lookup, tainted lookup string is ok if server spec comes from main-option
+  warn   set acl_m0 =  ok:   hostlist
+         hosts =       net-pgsql;select * from them where id='$local_part'
+         # ... but setting a per-query servers spec fails due to the taint
+  warn   set acl_m0 =  FAIL: hostlist
+         hosts =       <& net-pgsql;servers=SSPEC; select * from them where id='$local_part'
+
+         # The newer server-list-as-option-to-lookup-type is not a solution to tainted data in the lookup, because
+         # string-expansion is done before list-expansion so the taint contaminates the entire list.
+  warn   set acl_m0 =  FAIL: hostlist
+         hosts =       <& net-pgsql,servers=SSPEC; select * from them where id='$local_part'
+
   accept  domains = +local_domains
   accept  hosts = +relay_hosts
   deny    message = relay not permitted
index a59624c158d3b4a3f4ccb4f7f7f4958681d27ca8..951ddecff75f04970d0157da1d8f49d72d9e6859 100644 (file)
@@ -9,7 +9,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="select name from them where id='ph10';" opts=NULL
  database lookup required for select name from them where id='ph10';
- MySQL query: select name from them where id='ph10';
+ MySQL query: "select name from them where id='ph10';" opts 'NULL'
  MYSQL new connection: host=127.0.0.1 port=1223 socket=NULL database=test user=root
  lookup yielded: Philip Hazel
  search_open: mysql "NULL"
@@ -29,7 +29,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="select name from them where id='xxxx';" opts=NULL
  database lookup required for select name from them where id='xxxx';
- MySQL query: select name from them where id='xxxx';
+ MySQL query: "select name from them where id='xxxx';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  MYSQL: no data found
  lookup failed
@@ -41,7 +41,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="select name from them where id='nothing';" opts=NULL
  database lookup required for select name from them where id='nothing';
- MySQL query: select name from them where id='nothing';
+ MySQL query: "select name from them where id='nothing';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  lookup yielded: 
  search_open: mysql "NULL"
@@ -52,7 +52,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="select id,name from them where id='nothing';" opts=NULL
  database lookup required for select id,name from them where id='nothing';
- MySQL query: select id,name from them where id='nothing';
+ MySQL query: "select id,name from them where id='nothing';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  lookup yielded: id=nothing name="" 
  search_open: mysql "NULL"
@@ -63,7 +63,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="delete from them where id='nonexist';" opts=NULL
  database lookup required for delete from them where id='nonexist';
- MySQL query: delete from them where id='nonexist';
+ MySQL query: "delete from them where id='nonexist';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  MYSQL: query was not one that returns data
  lookup forced cache cleanup
@@ -76,7 +76,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="select * from them where id='quote';" opts=NULL
  database lookup required for select * from them where id='quote';
- MySQL query: select * from them where id='quote';
+ MySQL query: "select * from them where id='quote';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  MYSQL: no data found
  lookup failed
@@ -88,7 +88,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="select * from them where id='filter';" opts=NULL
  database lookup required for select * from them where id='filter';
- MySQL query: select * from them where id='filter';
+ MySQL query: "select * from them where id='filter';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  MYSQL: no data found
  lookup failed
@@ -100,7 +100,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="select * from them where id='quote2';" opts=NULL
  database lookup required for select * from them where id='quote2';
- MySQL query: select * from them where id='quote2';
+ MySQL query: "select * from them where id='quote2';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  lookup yielded: name="\"stquot" id=quote2 
  search_open: mysql "NULL"
@@ -111,7 +111,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="select * from them where id='nlonly';" opts=NULL
  database lookup required for select * from them where id='nlonly';
- MySQL query: select * from them where id='nlonly';
+ MySQL query: "select * from them where id='nlonly';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  MYSQL: no data found
  lookup failed
@@ -123,7 +123,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="servers=x:127.0.0.1::1223; select name from them where id='ph10';" opts=NULL
  database lookup required for servers=x:127.0.0.1::1223; select name from them where id='ph10';
- MySQL query: servers=x:127.0.0.1::1223; select name from them where id='ph10';
+ MySQL query: "servers=x:127.0.0.1::1223; select name from them where id='ph10';" opts 'NULL'
  lookup deferred: MySQL server "x" not found in mysql_servers
  search_open: mysql "NULL"
    cached open
@@ -133,7 +133,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="servers=127.0.0.1::1223:x; select name from them where id='ph10';" opts=NULL
  database lookup required for servers=127.0.0.1::1223:x; select name from them where id='ph10';
- MySQL query: servers=127.0.0.1::1223:x; select name from them where id='ph10';
+ MySQL query: "servers=127.0.0.1::1223:x; select name from them where id='ph10';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  lookup yielded: Philip Hazel
  search_open: mysql "NULL"
@@ -144,7 +144,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="servers=127.0.0.1::1223/test/root/:x; select name from them where id='ph10';" opts=NULL
  database lookup required for servers=127.0.0.1::1223/test/root/:x; select name from them where id='ph10';
- MySQL query: servers=127.0.0.1::1223/test/root/:x; select name from them where id='ph10';
+ MySQL query: "servers=127.0.0.1::1223/test/root/:x; select name from them where id='ph10';" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  lookup yielded: Philip Hazel
  search_open: mysql "NULL"
@@ -155,7 +155,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="servers=ip4.ip4.ip4.ip4::1223/test/root/:127.0.0.1::1223; select name from them where id='ph10';" opts=NULL
  database lookup required for servers=ip4.ip4.ip4.ip4::1223/test/root/:127.0.0.1::1223; select name from them where id='ph10';
- MySQL query: servers=ip4.ip4.ip4.ip4::1223/test/root/:127.0.0.1::1223; select name from them where id='ph10';
+ MySQL query: "servers=ip4.ip4.ip4.ip4::1223/test/root/:127.0.0.1::1223; select name from them where id='ph10';" opts 'NULL'
  MYSQL new connection: host=ip4.ip4.ip4.ip4 port=1223 socket=NULL database=test user=root
  lookup yielded: Philip Hazel
  search_open: mysql "NULL"
@@ -166,7 +166,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="servers=localhost(TESTSUITE/mysql/sock)/test/root/; select name from them where id='ph10';" opts=NULL
  database lookup required for servers=localhost(TESTSUITE/mysql/sock)/test/root/; select name from them where id='ph10';
- MySQL query: servers=localhost(TESTSUITE/mysql/sock)/test/root/; select name from them where id='ph10';
+ MySQL query: "servers=localhost(TESTSUITE/mysql/sock)/test/root/; select name from them where id='ph10';" opts 'NULL'
  MYSQL new connection: host=localhost port=0 socket=TESTSUITE/mysql/sock database=test user=root
  lookup yielded: Philip Hazel
  search_open: mysql "NULL"
@@ -177,7 +177,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="SELECT name FROM them WHERE id IN ('ph10', 'aaaa');" opts=NULL
  database lookup required for SELECT name FROM them WHERE id IN ('ph10', 'aaaa');
- MySQL query: SELECT name FROM them WHERE id IN ('ph10', 'aaaa');
+ MySQL query: "SELECT name FROM them WHERE id IN ('ph10', 'aaaa');" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  lookup yielded: Philip Hazel
  Aristotle
@@ -189,7 +189,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="SELECT *    FROM them WHERE id IN ('ph10', 'aaaa');" opts=NULL
  database lookup required for SELECT *    FROM them WHERE id IN ('ph10', 'aaaa');
- MySQL query: SELECT *    FROM them WHERE id IN ('ph10', 'aaaa');
+ MySQL query: "SELECT *    FROM them WHERE id IN ('ph10', 'aaaa');" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  lookup yielded: name="Philip Hazel" id=ph10 
  name=Aristotle id=aaaa 
@@ -201,7 +201,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=mysql key="delete from them where id='aaaa'" opts=NULL
  database lookup required for delete from them where id='aaaa'
- MySQL query: delete from them where id='aaaa'
+ MySQL query: "delete from them where id='aaaa'" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  MYSQL: query was not one that returns data
  lookup forced cache cleanup
@@ -243,28 +243,135 @@ log directory space = nnnnnK inodes = nnnnn check_space = 10240K inodes = 100
 SMTP>> 250 OK
 SMTP<< rcpt to:<c@d>
 using ACL "check_recipient"
-processing "accept" (TESTSUITE/test-config 22)
+processing "warn" (TESTSUITE/test-config 25)
+ search_open: mysql "NULL"
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts=NULL
+ LRU list:
+ internal_search_find: file="NULL"
+   type=mysql key="select name from them where id = 'c'" opts=NULL
+ database lookup required for select name from them where id = 'c'
+ MySQL query: "select name from them where id = 'c'" opts 'NULL'
+ MYSQL new connection: host=127.0.0.1 port=1223 socket=NULL database=test user=root
+ MYSQL: no data found
+ lookup failed
+check set acl_m0 = ok:   ${lookup mysql                    {select name from them where id = '$local_part'}}
+                 = ok:   
+ search_open: mysql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts="servers=127.0.0.1::1223/test/root/"
+ LRU list:
+ internal_search_find: file="NULL"
+   type=mysql key="select name from them where id = 'c'" opts="servers=127.0.0.1::1223/test/root/"
+ cached data found but either wrong opts or dated;  database lookup required for select name from them where id = 'c'
+ MySQL query: "select name from them where id = 'c'" opts 'servers=127.0.0.1::1223/test/root/'
+ MYSQL using cached connection for 127.0.0.1:1223/test/root
+ MYSQL: no data found
+ lookup failed
+check set acl_m0 = ok:   ${lookup mysql,servers=127.0.0.1::1223/test/root/      {select name from them where id = '$local_part'}}
+                 = ok:   
+ search_open: mysql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts="servers=127.0.0.1::1223"
+ LRU list:
+ internal_search_find: file="NULL"
+   type=mysql key="select name from them where id = 'c'" opts="servers=127.0.0.1::1223"
+ cached data found but either wrong opts or dated;  database lookup required for select name from them where id = 'c'
+ MySQL query: "select name from them where id = 'c'" opts 'servers=127.0.0.1::1223'
+ MYSQL using cached connection for 127.0.0.1:1223/test/root
+ MYSQL: no data found
+ lookup failed
+check set acl_m0 = ok:   ${lookup mysql,servers=127.0.0.1::1223    {select name from them where id = '$local_part'}}
+                 = ok:   
+ search_open: mysql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="servers=127.0.0.1::1223/test/root/; select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts=NULL
+ LRU list:
+ internal_search_find: file="NULL"
+   type=mysql key="servers=127.0.0.1::1223/test/root/; select name from them where id = 'c'" opts=NULL
+ database lookup required for servers=127.0.0.1::1223/test/root/; select name from them where id = 'c'
+ MySQL query: "servers=127.0.0.1::1223/test/root/; select name from them where id = 'c'" opts 'NULL'
+ lookup deferred: MySQL server "127.0.0.1:1223/test/root/" is tainted
+warn: condition test deferred in ACL "check_recipient"
+LOG: MAIN
+  H=[10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: MySQL server "127.0.0.1:1223/test/root/" is tainted
+processing "warn" (TESTSUITE/test-config 36)
+check set acl_m0 = ok:   hostlist
+check hosts = net-mysql;select * from them where id='$local_part'
+search_open: mysql "NULL"
+  cached open
+search_find: file="NULL"
+  key="select * from them where id='c'" partial=-1 affix=NULL starflags=0 opts=NULL
+LRU list:
+internal_search_find: file="NULL"
+  type=mysql key="select * from them where id='c'" opts=NULL
+database lookup required for select * from them where id='c'
+MySQL query: "select * from them where id='c'" opts 'NULL'
+MYSQL using cached connection for 127.0.0.1:1223/test/root
+MYSQL: no data found
+lookup failed
+host in "net-mysql;select * from them where id='c'"? no (end of list)
+warn: condition test failed in ACL "check_recipient"
+processing "warn" (TESTSUITE/test-config 39)
+check set acl_m0 = FAIL: hostlist
+check hosts = <& net-mysql;servers=127.0.0.1::1223/test/root/; select * from them where id='$local_part'
+search_open: mysql "NULL"
+  cached open
+search_find: file="NULL"
+  key="servers=127.0.0.1::1223/test/root/; select * from them where id='c'" partial=-1 affix=NULL starflags=0 opts=NULL
+LRU list:
+internal_search_find: file="NULL"
+  type=mysql key="servers=127.0.0.1::1223/test/root/; select * from them where id='c'" opts=NULL
+database lookup required for servers=127.0.0.1::1223/test/root/; select * from them where id='c'
+MySQL query: "servers=127.0.0.1::1223/test/root/; select * from them where id='c'" opts 'NULL'
+lookup deferred: MySQL server "127.0.0.1:1223/test/root/" is tainted
+host in "<& net-mysql;servers=127.0.0.1::1223/test/root/; select * from them where id='c'"? list match deferred for net-mysql;servers=127.0.0.1::1223/test/root/; select * from them where id='c'
+warn: condition test deferred in ACL "check_recipient"
+LOG: MAIN
+  H=[10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: MySQL server "127.0.0.1:1223/test/root/" is tainted
+processing "warn" (TESTSUITE/test-config 44)
+check set acl_m0 = FAIL: hostlist
+check hosts = <& net-mysql,servers=127.0.0.1::1223/test/root/; select * from them where id='$local_part'
+search_open: mysql "NULL"
+  cached open
+search_find: file="NULL"
+  key=" select * from them where id='c'" partial=-1 affix=NULL starflags=0 opts="servers=127.0.0.1::1223/test/root/"
+LRU list:
+internal_search_find: file="NULL"
+  type=mysql key=" select * from them where id='c'" opts="servers=127.0.0.1::1223/test/root/"
+database lookup required for  select * from them where id='c'
+MySQL query: " select * from them where id='c'" opts 'servers=127.0.0.1::1223/test/root/'
+lookup deferred: MySQL server "127.0.0.1:1223/test/root/" is tainted
+host in "<& net-mysql,servers=127.0.0.1::1223/test/root/; select * from them where id='c'"? list match deferred for net-mysql,servers=127.0.0.1::1223/test/root/; select * from them where id='c'
+warn: condition test deferred in ACL "check_recipient"
+LOG: MAIN
+  H=[10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: MySQL server "127.0.0.1:1223/test/root/" is tainted
+processing "accept" (TESTSUITE/test-config 47)
 check domains = +local_domains
 d in "@"? no (end of list)
 d in "+local_domains"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "accept" (TESTSUITE/test-config 23)
+processing "accept" (TESTSUITE/test-config 48)
 check hosts = +relay_hosts
 search_open: mysql "NULL"
+  cached open
 search_find: file="NULL"
   key="select * from them where id='10.0.0.0'" partial=-1 affix=NULL starflags=0 opts=NULL
 LRU list:
 internal_search_find: file="NULL"
   type=mysql key="select * from them where id='10.0.0.0'" opts=NULL
 database lookup required for select * from them where id='10.0.0.0'
-MySQL query: select * from them where id='10.0.0.0'
-MYSQL new connection: host=127.0.0.1 port=1223 socket=NULL database=test user=root
+MySQL query: "select * from them where id='10.0.0.0'" opts 'NULL'
+MYSQL using cached connection for 127.0.0.1:1223/test/root
 MYSQL: no data found
 lookup failed
 host in "net-mysql;select * from them where id='10.0.0.0'"? no (end of list)
 host in "+relay_hosts"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "deny" (TESTSUITE/test-config 24)
+processing "deny" (TESTSUITE/test-config 49)
   message: relay not permitted
 deny: condition test succeeded in ACL "check_recipient"
 end of ACL "check_recipient": DENY
@@ -374,7 +481,7 @@ processing address_data
  internal_search_find: file="NULL"
    type=mysql key="select name from them where id='ph10'" opts=NULL
  database lookup required for select name from them where id='ph10'
- MySQL query: select name from them where id='ph10'
+ MySQL query: "select name from them where id='ph10'" opts 'NULL'
  MYSQL new connection: host=127.0.0.1 port=1223 socket=NULL database=test user=root
  lookup yielded: Philip Hazel
 calling r1 router
@@ -418,7 +525,7 @@ appendfile transport entered
  internal_search_find: file="NULL"
    type=mysql key="select id from them where id='ph10'" opts=NULL
  database lookup required for select id from them where id='ph10'
- MySQL query: select id from them where id='ph10'
+ MySQL query: "select id from them where id='ph10'" opts 'NULL'
  MYSQL new connection: host=127.0.0.1 port=1223 socket=NULL database=test user=root
  lookup yielded: ph10
 appendfile: mode=600 notify_comsat=0 quota=0 warning=0
index 2eae8eeca7bfeabb3b7ffc37b39f35bd504af030..337d518507b47fb9ef16b3ee91e81d8c68cc1f1c 100644 (file)
@@ -13,7 +13,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id='ph10';" opts=NULL
  database lookup required for select name from them where id='ph10';
- PostgreSQL query: select name from them where id='ph10';
+ PostgreSQL query: "select name from them where id='ph10';" opts 'NULL'
  PGSQL new connection: host=localhost port=1223 database=test user=CALLER
  lookup yielded: Philip Hazel
  search_open: pgsql "NULL"
@@ -33,7 +33,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id='xxxx';" opts=NULL
  database lookup required for select name from them where id='xxxx';
- PostgreSQL query: select name from them where id='xxxx';
+ PostgreSQL query: "select name from them where id='xxxx';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  PGSQL: no data found
  lookup failed
@@ -45,7 +45,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id='nothing';" opts=NULL
  database lookup required for select name from them where id='nothing';
- PostgreSQL query: select name from them where id='nothing';
+ PostgreSQL query: "select name from them where id='nothing';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: 
  search_open: pgsql "NULL"
@@ -56,7 +56,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="select id,name from them where id='nothing';" opts=NULL
  database lookup required for select id,name from them where id='nothing';
- PostgreSQL query: select id,name from them where id='nothing';
+ PostgreSQL query: "select id,name from them where id='nothing';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: id=nothing name="" 
  search_open: pgsql "NULL"
@@ -67,7 +67,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="delete from them where id='nonexist';" opts=NULL
  database lookup required for delete from them where id='nonexist';
- PostgreSQL query: delete from them where id='nonexist';
+ PostgreSQL query: "delete from them where id='nonexist';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  PGSQL: command does not return any data but was successful. Rows affected: 0
  lookup forced cache cleanup
@@ -80,7 +80,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="select * from them where id='quote2';" opts=NULL
  database lookup required for select * from them where id='quote2';
- PostgreSQL query: select * from them where id='quote2';
+ PostgreSQL query: "select * from them where id='quote2';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: name="\"stquot" id=quote2 
  search_open: pgsql "NULL"
@@ -91,7 +91,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="select * from them where id='newline';" opts=NULL
  database lookup required for select * from them where id='newline';
- PostgreSQL query: select * from them where id='newline';
+ PostgreSQL query: "select * from them where id='newline';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: name="before\r
  after" id=newline 
@@ -103,7 +103,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="select * from them where id='tab';" opts=NULL
  database lookup required for select * from them where id='tab';
- PostgreSQL query: select * from them where id='tab';
+ PostgreSQL query: "select * from them where id='tab';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: name="x       x" id=tab 
  search_open: pgsql "NULL"
@@ -114,7 +114,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="select * from them where name='''stquot';" opts=NULL
  database lookup required for select * from them where name='''stquot';
- PostgreSQL query: select * from them where name='''stquot';
+ PostgreSQL query: "select * from them where name='''stquot';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: name='stquot id=quote1 
  search_open: pgsql "NULL"
@@ -125,7 +125,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="servers=x:localhost; select name from them where id='ph10';" opts=NULL
  database lookup required for servers=x:localhost; select name from them where id='ph10';
- PostgreSQL query: servers=x:localhost; select name from them where id='ph10';
+ PostgreSQL query: "servers=x:localhost; select name from them where id='ph10';" opts 'NULL'
  lookup deferred: PostgreSQL server "x" not found in pgsql_servers
  search_open: pgsql "NULL"
    cached open
@@ -135,7 +135,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="servers=localhost::1223:x; select name from them where id='ph10';" opts=NULL
  database lookup required for servers=localhost::1223:x; select name from them where id='ph10';
- PostgreSQL query: servers=localhost::1223:x; select name from them where id='ph10';
+ PostgreSQL query: "servers=localhost::1223:x; select name from them where id='ph10';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: Philip Hazel
  search_open: pgsql "NULL"
@@ -146,7 +146,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="servers=localhost::1223/test/CALLER/:x; select name from them where id='ph10';" opts=NULL
  database lookup required for servers=localhost::1223/test/CALLER/:x; select name from them where id='ph10';
- PostgreSQL query: servers=localhost::1223/test/CALLER/:x; select name from them where id='ph10';
+ PostgreSQL query: "servers=localhost::1223/test/CALLER/:x; select name from them where id='ph10';" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: Philip Hazel
  search_open: pgsql "NULL"
@@ -157,7 +157,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="servers=(TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER/:x; select name from them where id='ph10';" opts=NULL
  database lookup required for servers=(TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER/:x; select name from them where id='ph10';
- PostgreSQL query: servers=(TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER/:x; select name from them where id='ph10';
+ PostgreSQL query: "servers=(TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER/:x; select name from them where id='ph10';" opts 'NULL'
  PGSQL new connection: socket=TESTSUITE/pgsql/.s.PGSQL.1223 database=test user=CALLER
  lookup yielded: Philip Hazel
  search_open: pgsql "NULL"
@@ -168,7 +168,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="SELECT name FROM them WHERE id IN ('ph10', 'aaaa');" opts=NULL
  database lookup required for SELECT name FROM them WHERE id IN ('ph10', 'aaaa');
- PostgreSQL query: SELECT name FROM them WHERE id IN ('ph10', 'aaaa');
+ PostgreSQL query: "SELECT name FROM them WHERE id IN ('ph10', 'aaaa');" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: Philip Hazel
  Aristotle
@@ -180,7 +180,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="SELECT *    FROM them WHERE id IN ('ph10', 'aaaa');" opts=NULL
  database lookup required for SELECT *    FROM them WHERE id IN ('ph10', 'aaaa');
- PostgreSQL query: SELECT *    FROM them WHERE id IN ('ph10', 'aaaa');
+ PostgreSQL query: "SELECT *    FROM them WHERE id IN ('ph10', 'aaaa');" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  lookup yielded: name="Philip Hazel" id=ph10 
  name=Aristotle id=aaaa 
@@ -192,7 +192,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="delete from them where id='aaaa'" opts=NULL
  database lookup required for delete from them where id='aaaa'
- PostgreSQL query: delete from them where id='aaaa'
+ PostgreSQL query: "delete from them where id='aaaa'" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  PGSQL: command does not return any data but was successful. Rows affected: 1
  lookup forced cache cleanup
@@ -233,28 +233,107 @@ log directory space = nnnnnK inodes = nnnnn check_space = 10240K inodes = 100
 SMTP>> 250 OK
 SMTP<< rcpt to:<c@d>
 using ACL "check_recipient"
-processing "accept" (TESTSUITE/test-config 25)
+processing "warn" (TESTSUITE/test-config 27)
+ search_open: pgsql "NULL"
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts=NULL
+ LRU list:
+ internal_search_find: file="NULL"
+   type=pgsql key="select name from them where id = 'c'" opts=NULL
+ database lookup required for select name from them where id = 'c'
+ PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
+ PGSQL new connection: host=localhost port=1223 database=test user=CALLER
+ PGSQL: no data found
+ lookup failed
+check set acl_m0 = ok:   ${lookup pgsql                    {select name from them where id = '$local_part'}}
+                 = ok:   
+ search_open: pgsql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts="servers=SSPEC"
+ LRU list:
+ internal_search_find: file="NULL"
+   type=pgsql key="select name from them where id = 'c'" opts="servers=SSPEC"
+ cached data found but either wrong opts or dated;  database lookup required for select name from them where id = 'c'
+ PostgreSQL query: "select name from them where id = 'c'" opts 'servers=SSPEC'
+ lookup deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+warn: condition test deferred in ACL "check_recipient"
+LOG: MAIN
+  H=[10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+processing "warn" (TESTSUITE/test-config 38)
+check set acl_m0 = ok:   hostlist
+check hosts = net-pgsql;select * from them where id='$local_part'
+search_open: pgsql "NULL"
+  cached open
+search_find: file="NULL"
+  key="select * from them where id='c'" partial=-1 affix=NULL starflags=0 opts=NULL
+LRU list:
+internal_search_find: file="NULL"
+  type=pgsql key="select * from them where id='c'" opts=NULL
+database lookup required for select * from them where id='c'
+PostgreSQL query: "select * from them where id='c'" opts 'NULL'
+PGSQL using cached connection for localhost:1223/test/CALLER
+PGSQL: no data found
+lookup failed
+host in "net-pgsql;select * from them where id='c'"? no (end of list)
+warn: condition test failed in ACL "check_recipient"
+processing "warn" (TESTSUITE/test-config 41)
+check set acl_m0 = FAIL: hostlist
+check hosts = <& net-pgsql;servers=SSPEC; select * from them where id='$local_part'
+search_open: pgsql "NULL"
+  cached open
+search_find: file="NULL"
+  key="servers=SSPEC; select * from them where id='c'" partial=-1 affix=NULL starflags=0 opts=NULL
+LRU list:
+internal_search_find: file="NULL"
+  type=pgsql key="servers=SSPEC; select * from them where id='c'" opts=NULL
+database lookup required for servers=SSPEC; select * from them where id='c'
+PostgreSQL query: "servers=SSPEC; select * from them where id='c'" opts 'NULL'
+lookup deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+host in "<& net-pgsql;servers=SSPEC; select * from them where id='c'"? list match deferred for net-pgsql;servers=SSPEC; select * from them where id='c'
+warn: condition test deferred in ACL "check_recipient"
+LOG: MAIN
+  H=[10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+processing "warn" (TESTSUITE/test-config 46)
+check set acl_m0 = FAIL: hostlist
+check hosts = <& net-pgsql,servers=SSPEC; select * from them where id='$local_part'
+search_open: pgsql "NULL"
+  cached open
+search_find: file="NULL"
+  key=" select * from them where id='c'" partial=-1 affix=NULL starflags=0 opts="servers=SSPEC"
+LRU list:
+internal_search_find: file="NULL"
+  type=pgsql key=" select * from them where id='c'" opts="servers=SSPEC"
+database lookup required for  select * from them where id='c'
+PostgreSQL query: " select * from them where id='c'" opts 'servers=SSPEC'
+lookup deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+host in "<& net-pgsql,servers=SSPEC; select * from them where id='c'"? list match deferred for net-pgsql,servers=SSPEC; select * from them where id='c'
+warn: condition test deferred in ACL "check_recipient"
+LOG: MAIN
+  H=[10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+processing "accept" (TESTSUITE/test-config 49)
 check domains = +local_domains
 d in "@"? no (end of list)
 d in "+local_domains"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "accept" (TESTSUITE/test-config 26)
+processing "accept" (TESTSUITE/test-config 50)
 check hosts = +relay_hosts
 search_open: pgsql "NULL"
+  cached open
 search_find: file="NULL"
   key="select * from them where id='10.0.0.0'" partial=-1 affix=NULL starflags=0 opts=NULL
 LRU list:
 internal_search_find: file="NULL"
   type=pgsql key="select * from them where id='10.0.0.0'" opts=NULL
 database lookup required for select * from them where id='10.0.0.0'
-PostgreSQL query: select * from them where id='10.0.0.0'
-PGSQL new connection: host=localhost port=1223 database=test user=CALLER
+PostgreSQL query: "select * from them where id='10.0.0.0'" opts 'NULL'
+PGSQL using cached connection for localhost:1223/test/CALLER
 PGSQL: no data found
 lookup failed
 host in "net-pgsql;select * from them where id='10.0.0.0'"? no (end of list)
 host in "+relay_hosts"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "deny" (TESTSUITE/test-config 27)
+processing "deny" (TESTSUITE/test-config 51)
   message: relay not permitted
 deny: condition test succeeded in ACL "check_recipient"
 end of ACL "check_recipient": DENY
@@ -263,12 +342,85 @@ LOG: MAIN REJECT
   H=[10.0.0.0] F=<a@b> rejected RCPT <c@d>: relay not permitted
 SMTP<< rcpt to:<c@d>
 using ACL "check_recipient"
-processing "accept" (TESTSUITE/test-config 25)
+processing "warn" (TESTSUITE/test-config 27)
+ search_open: pgsql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts=NULL
+ LRU list:
+ internal_search_find: file="NULL"
+   type=pgsql key="select name from them where id = 'c'" opts=NULL
+ cached data used for lookup of select name from them where id = 'c'
+ lookup failed
+check set acl_m0 = ok:   ${lookup pgsql                    {select name from them where id = '$local_part'}}
+                 = ok:   
+ search_open: pgsql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts="servers=SSPEC"
+ LRU list:
+ internal_search_find: file="NULL"
+   type=pgsql key="select name from them where id = 'c'" opts="servers=SSPEC"
+ cached data found but either wrong opts or dated;  database lookup required for select name from them where id = 'c'
+ PostgreSQL query: "select name from them where id = 'c'" opts 'servers=SSPEC'
+ lookup deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+warn: condition test deferred in ACL "check_recipient"
+LOG: MAIN
+  H=[10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+processing "warn" (TESTSUITE/test-config 38)
+check set acl_m0 = ok:   hostlist
+check hosts = net-pgsql;select * from them where id='$local_part'
+search_open: pgsql "NULL"
+  cached open
+search_find: file="NULL"
+  key="select * from them where id='c'" partial=-1 affix=NULL starflags=0 opts=NULL
+LRU list:
+internal_search_find: file="NULL"
+  type=pgsql key="select * from them where id='c'" opts=NULL
+cached data used for lookup of select * from them where id='c'
+lookup failed
+host in "net-pgsql;select * from them where id='c'"? no (end of list)
+warn: condition test failed in ACL "check_recipient"
+processing "warn" (TESTSUITE/test-config 41)
+check set acl_m0 = FAIL: hostlist
+check hosts = <& net-pgsql;servers=SSPEC; select * from them where id='$local_part'
+search_open: pgsql "NULL"
+  cached open
+search_find: file="NULL"
+  key="servers=SSPEC; select * from them where id='c'" partial=-1 affix=NULL starflags=0 opts=NULL
+LRU list:
+internal_search_find: file="NULL"
+  type=pgsql key="servers=SSPEC; select * from them where id='c'" opts=NULL
+database lookup required for servers=SSPEC; select * from them where id='c'
+PostgreSQL query: "servers=SSPEC; select * from them where id='c'" opts 'NULL'
+lookup deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+host in "<& net-pgsql;servers=SSPEC; select * from them where id='c'"? list match deferred for net-pgsql;servers=SSPEC; select * from them where id='c'
+warn: condition test deferred in ACL "check_recipient"
+LOG: MAIN
+  H=[10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+processing "warn" (TESTSUITE/test-config 46)
+check set acl_m0 = FAIL: hostlist
+check hosts = <& net-pgsql,servers=SSPEC; select * from them where id='$local_part'
+search_open: pgsql "NULL"
+  cached open
+search_find: file="NULL"
+  key=" select * from them where id='c'" partial=-1 affix=NULL starflags=0 opts="servers=SSPEC"
+LRU list:
+internal_search_find: file="NULL"
+  type=pgsql key=" select * from them where id='c'" opts="servers=SSPEC"
+database lookup required for  select * from them where id='c'
+PostgreSQL query: " select * from them where id='c'" opts 'servers=SSPEC'
+lookup deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+host in "<& net-pgsql,servers=SSPEC; select * from them where id='c'"? list match deferred for net-pgsql,servers=SSPEC; select * from them where id='c'
+warn: condition test deferred in ACL "check_recipient"
+LOG: MAIN
+  H=[10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "SSPEC" not found in pgsql_servers
+processing "accept" (TESTSUITE/test-config 49)
 check domains = +local_domains
 d in "@"? no (end of list)
 d in "+local_domains"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "accept" (TESTSUITE/test-config 26)
+processing "accept" (TESTSUITE/test-config 50)
 check hosts = +relay_hosts
 search_open: pgsql "NULL"
   cached open
@@ -282,7 +434,7 @@ lookup failed
 host in "net-pgsql;select * from them where id='10.0.0.0'"? no (end of list)
 host in "+relay_hosts"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "deny" (TESTSUITE/test-config 27)
+processing "deny" (TESTSUITE/test-config 51)
   message: relay not permitted
 deny: condition test succeeded in ACL "check_recipient"
 end of ACL "check_recipient": DENY
@@ -392,7 +544,7 @@ processing address_data
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id='ph10'" opts=NULL
  database lookup required for select name from them where id='ph10'
- PostgreSQL query: select name from them where id='ph10'
+ PostgreSQL query: "select name from them where id='ph10'" opts 'NULL'
  PGSQL new connection: host=localhost port=1223 database=test user=CALLER
  lookup yielded: Philip Hazel
 calling r1 router
@@ -436,7 +588,7 @@ appendfile transport entered
  internal_search_find: file="NULL"
    type=pgsql key="select id from them where id='ph10'" opts=NULL
  database lookup required for select id from them where id='ph10'
- PostgreSQL query: select id from them where id='ph10'
+ PostgreSQL query: "select id from them where id='ph10'" opts 'NULL'
  PGSQL new connection: host=localhost port=1223 database=test user=CALLER
  lookup yielded: ph10
 appendfile: mode=600 notify_comsat=0 quota=0 warning=0
@@ -500,7 +652,7 @@ dropping to exim gid; retaining priv uid
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id='ph10';" opts=NULL
  database lookup required for select name from them where id='ph10';
- PostgreSQL query: select name from them where id='ph10';
+ PostgreSQL query: "select name from them where id='ph10';" opts 'NULL'
  PGSQL new connection: socket=TESTSUITE/pgsql/.s.PGSQL.1223 database=test user=CALLER
  lookup yielded: Philip Hazel
 search_tidyup called