1 diff -rU3 --new-file postfix-1.1.3-vanilla/PGSQL_README postfix-1.1.3/PGSQL_README
2 --- postfix-1.1.3-vanilla/PGSQL_README Thu Jan 1 01:00:00 1970
3 +++ postfix-1.1.3/PGSQL_README Thu Mar 7 11:48:40 2002
5 +[Code contributed by Mathieu Arnold]
7 +We've written code to add a pgsql map type. It utilizes the pgsql
8 +client library, which can be obtained from:
10 + http://www.postgresql.org/
12 +In order to build postfix with pgsql map support, you will need to add
13 +-DHAS_PGSQL and -I for the directory containing the postgres headers, and
14 +the libpq library (and libcrypt) to AUXLIBS, for example:
16 +make -f Makefile.init makefiles \
17 + 'CCARGS=-DHAS_PGSQL -I/some/where/include/postgresql' \
18 + 'AUXLIBS=/some/where/lib/postgres/libpq.a -lcrypt'
20 +then, just run 'make'.
22 +Postfix installations which may benefit from using pgsql map types
23 +include sites that have a need for instantaneous updates of
24 +forwarding, and sites that may benefit from having mail exchangers
25 +reference a networked database, possibly working in conjunction with a
26 +customer database of sorts.
28 +Once postfix is built with pgsql support, you can specify a map type
29 +in main.cf like this:
31 +alias_maps = pgsql:/etc/postfix/pgsql-aliases.cf
33 +The file /etc/postfix/pgsql-aliases.cf specifies lots of information
34 +telling postfix how to reference the postgresql database. An example
35 +postgresql map config file follows:
38 +# postgresql config file for alias lookups on postfix
42 +# the user name and password to log into the pgsql server
44 +password = some_passwordd
46 +# the database name on the servers
47 +dbname = customer_database
53 +select_field = forw_addr
56 +# you may specify additional_conditions here
57 +additional_conditions = and status = 'paid'
59 +# the above variables will result in a query of
61 +# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
62 +# ($lookup is escaped so if it contains single quotes or other odd
63 +# characters, it will not cause a parse error in the sql).
65 +# the hosts that postfix will try to connect to
66 +# and query from (in the order listed)
67 +hosts = host1.some.domain host2.some.domain
69 +# end postgresql config file
73 +This configuration interface setup allows for multiple postgresql
74 +databases: you can use one for a virtual table, one for an access
75 +table, and one for an aliases table if you want.
77 +Since sites that have a need for multiple mail exchangers may enjoy
78 +the convenience of using a networked mailer database, but do not want
79 +to introduce a single point of failure to their system, we've included
80 +the ability to have postfix reference multiple hosts for access to a
81 +single pgsql map. This will work if sites set up mirrored pgsql
82 +databases on two or more hosts. Whenever queries fail with an error
83 +at one host, the rest of the hosts will be tried in order. Each host
84 +that is in an error state will undergo a reconnection attempt every so
85 +often, and if no pgsql server hosts are reachable, then mail will be
86 +deferred until atleast one of those hosts is reachable.
88 +Performance of postfix with pgsql has not been thoroughly tested,
89 +however, we have found it to be stable. Busy mail servers using pgsql
90 +maps will generate lots of concurrent pgsql clients, so the pgsql
91 +server(s) should be run with this fact in mind. Any further
92 +performance information, in addition to any feedback is most welcome.
93 diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/Makefile.in postfix-1.1.3/src/util/Makefile.in
94 --- postfix-1.1.3-vanilla/src/util/Makefile.in Thu Mar 7 11:47:44 2002
95 +++ postfix-1.1.3/src/util/Makefile.in Thu Mar 7 12:10:56 2002
97 chroot_uid.c clean_env.c close_on_exec.c concatenate.c ctable.c \
98 dict.c dict_alloc.c dict_db.c dict_dbm.c dict_debug.c dict_env.c \
99 dict_ht.c dict_mysql.c dict_ni.c dict_nis.c \
100 - dict_nisplus.c dict_open.c dict_pcre.c dict_regexp.c dict_static.c \
101 + dict_nisplus.c dict_open.c dict_pcre.c dict_pgsql.c dict_regexp.c dict_static.c \
102 dict_tcp.c dict_unix.c dir_forest.c doze.c duplex_pipe.c \
103 environ.c events.c exec_command.c fifo_listen.c fifo_trigger.c \
104 file_limit.c find_inet.c fsspace.c fullname.c get_domainname.c \
106 HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
107 connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \
108 dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \
109 - dict_nisplus.h dict_pcre.h dict_regexp.h dict_static.h dict_tcp.h \
110 + dict_nisplus.h dict_pcre.h dict_pgsql.h dict_regexp.h dict_static.h dict_tcp.h \
111 dict_unix.h dir_forest.h events.h exec_command.h find_inet.h \
112 fsspace.h fullname.h get_domainname.h get_hostname.h get_port.h hex_quote.h \
113 htable.h inet_addr_host.h inet_addr_list.h inet_addr_local.h \
116 PCRESO = dict_pcre.so
117 MYSQLSO = dict_mysql.so
118 +PGSQLSO = dict_pgsql.so
120 TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
121 fifo_rdonly_bug fifo_rdwr_bug fifo_trigger fsspace fullname \
125 INC_DIR = ../../include
126 -LIBS = $(LIB_DIR)/$(LIB) $(LIB_DIR)/$(PCRESO) $(LIB_DIR)/$(MYSQLSO)
127 +LIBS = $(LIB_DIR)/$(LIB) $(LIB_DIR)/$(PCRESO) $(LIB_DIR)/$(MYSQLSO) $(LIB_DIR)/$(PGSQLSO)
129 .c.o:; $(CC) -fPIC $(CFLAGS) -c $*.c
132 $(MYSQLSO): dict_mysql.o
133 gcc -shared -Wl,-soname,dict_mysql.so -o $@ $? -lmysqlclient -L. -lutil
135 +$(PGSQLSO): dict_pgsql.o
136 + gcc -shared -Wl,-soname,dict_pgsql.so -o $@ $? -lpq -lcrypt -L. -lutil
139 gcc -shared -Wl,-soname,libpostfix-util.so.1 -o $(LIB) $(OBJS) -ldl
142 $(LIB_DIR)/$(MYSQLSO): $(MYSQLSO)
143 cp $(MYSQLSO) $(LIB_DIR)
145 +$(LIB_DIR)/$(PGSQLSO): $(PGSQLSO)
146 + cp $(PGSQLSO) $(LIB_DIR)
148 update: $(LIBS) $(HDRS)
155 - rm -f *.o $(LIB) $(PCRESO) $(MYSQLSO) *core $(TESTPROG) \
156 + rm -f *.o $(LIB) $(PCRESO) $(MYSQLSO) $(PGSQLSO) *core $(TESTPROG) \
161 dict_ldap.o: sys_defs.h
162 dict_mysql.o: dict_mysql.c
163 dict_mysql.o: sys_defs.h
164 +dict_pgsql.o: dict_pgsql.c
165 +dict_pgsql.o: sys_defs.h
167 dict_ni.o: sys_defs.h
168 dict_nis.o: dict_nis.c
170 dict_open.o: dict_ni.h
171 dict_open.o: dict_ldap.h
172 dict_open.o: dict_mysql.h
173 +dict_open.o: dict_pgsql.h
174 dict_open.o: dict_pcre.h
175 dict_open.o: dict_regexp.h
176 dict_open.o: dict_static.h
177 diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/dict_open.c postfix-1.1.3/src/util/dict_open.c
178 --- postfix-1.1.3-vanilla/src/util/dict_open.c Thu Mar 7 11:47:44 2002
179 +++ postfix-1.1.3/src/util/dict_open.c Thu Mar 7 11:48:40 2002
182 #include <dict_ldap.h>
183 #include <dict_mysql.h>
184 +#include <dict_pgsql.h>
185 #include <dict_pcre.h>
186 #include <dict_regexp.h>
187 #include <dict_static.h>
190 DICT_TYPE_MYSQL, dict_mysql_open,
193 + DICT_TYPE_PGSQL, dict_pgsql_open,
196 DICT_TYPE_PCRE, dict_pcre_open,
198 diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/dict_pgsql.c postfix-1.1.3/src/util/dict_pgsql.c
199 --- postfix-1.1.3-vanilla/src/util/dict_pgsql.c Thu Jan 1 01:00:00 1970
200 +++ postfix-1.1.3/src/util/dict_pgsql.c Thu Mar 7 11:48:41 2002
207 +/* dictionary manager interface to db files
209 +/* #include <dict.h>
210 +/* #include <dict_pgsql.h>
212 +/* DICT *dict_pgsql_open(name, dummy, unused_dict_flags)
213 +/* const char *name;
215 +/* int unused_dict_flags;
217 +/* dict_pgsql_open() creates a dictionary of type 'pg'. This
218 +/* dictionary is an interface for the postfix key->value mappings
219 +/* to pgsql. The result is a pointer to the installed dictionary,
220 +/* or a null pointer in case of problems.
222 +/* The pgsql dictionary can manage multiple connections to different
223 +/* sql servers on different hosts. It assumes that the underlying data
224 +/* on each host is identical (mirrored) and maintains one connection
225 +/* at any given time. If any connection fails, any other available
226 +/* ones will be opened and used. The intent of this feature is to eliminate
227 +/* a single point of failure for mail systems that would otherwise rely
228 +/* on a single pgsql server.
232 +/* The path of the PostgreSQL configuration file. The file encodes a number of
233 +/* pieces of information: username, password, databasename, table,
234 +/* select_field, where_field, and hosts. For example, if you want the map to
235 +/* reference databases of the name "your_db" and execute a query like this:
236 +/* select forw_addr from aliases where alias like '<some username>' against
237 +/* any database called "vmailer_info" located on hosts host1.some.domain and
238 +/* host2.some.domain, logging in as user "vmailer" and password "passwd" then
239 +/* the configuration file should read:
242 +/* password = passwd
243 +/* DBname = vmailer_info
245 +/* select_field = forw_addr
246 +/* where_field = alias
247 +/* hosts = host1.some.domain host2.some.domain
250 +/* reference for outside use.
251 +/* .IP unusued_flags
254 +/* dict(3) generic dictionary manager
258 +/* mat@absolight.com
260 +/* based on dict_mysql by
264 +/* scott@icgroup.com
271 +/* System library. */
272 +#include "sys_defs.h"
275 +#include <sys/socket.h>
276 +#include <netinet/in.h>
277 +#include <arpa/inet.h>
284 +#include <libpq-fe.h>
286 +/* Utility library. */
289 +#include "mymalloc.h"
290 +#include "dict_pgsql.h"
292 +#include "vstring.h"
293 +#include "split_at.h"
294 +#include "find_inet.h"
296 +/* need some structs to help organize things */
301 + int stat; /* STATUNTRIED | STATFAIL | STATCUR */
302 + time_t ts; /* used for attempting reconnection
303 + * every so often if a host is down */
308 + int len_hosts; /* number of hosts */
309 + HOST *db_hosts; /* the hosts on which the databases
319 + char *select_field;
321 + char *additional_conditions;
333 +#define STATACTIVE 0
335 +#define STATUNTRIED 2
336 +#define RETRY_CONN_INTV 60 /* 1 minute */
338 +/* internal function declarations */
339 +static PLPGSQL *plpgsql_init (char *hostnames[], int);
340 +static PGresult *plpgsql_query (PLPGSQL *, const char *, char *, char *,
343 +static void plpgsql_dealloc (PLPGSQL *);
344 +static void plpgsql_down_host (HOST *);
345 +static void plpgsql_connect_single (HOST *, char *, char *, char *);
346 +static int plpgsql_ready_reconn (HOST *);
347 +static const char *dict_pgsql_lookup (DICT *, const char *);
348 +DICT *dict_pgsql_open (const char *, int, int);
349 +static void dict_pgsql_close (DICT *);
350 +static PGSQL_NAME *pgsqlname_parse (const char *);
351 +static HOST host_init (char *);
352 +void pgsql_escape_string (char *escaped, const char *name, int len);
356 +/**********************************************************************
357 + * public interface dict_pgsql_lookup
358 + * find database entry return 0 if no alias found, set dict_errno
359 + * on errors to DICT_ERRBO_RETRY and set dict_errno to 0 on success
360 + *********************************************************************/
361 +static const char *dict_pgsql_lookup (DICT *dict, const char *name)
363 + PGresult *query_res;
365 + DICT_PGSQL *dict_pgsql;
367 + static VSTRING *result;
368 + static VSTRING *query = 0;
372 + char *name_escaped = 0;
374 + dict_pgsql = (DICT_PGSQL *) dict;
375 + pldb = dict_pgsql->pldb;
376 + /* initialization for query */
377 + query = vstring_alloc (24);
378 + vstring_strcpy (query, "");
381 + (char *) mymalloc ((sizeof (char) * (strlen (name) * 2) + 1))) ==
384 + msg_fatal ("dict_pgsql_lookup: out of memory.");
386 + /* prepare the query */
387 + pgsql_escape_string (name_escaped, name, (unsigned int) strlen (name));
388 + vstring_sprintf (query, "select %s from %s where %s = '%s' %s",
389 + dict_pgsql->name->select_field, dict_pgsql->name->table,
390 + dict_pgsql->name->where_field, name_escaped,
391 + dict_pgsql->name->additional_conditions);
393 + msg_info ("dict_pgsql_lookup using sql query: %s",
394 + vstring_str (query));
395 + /* free mem associated with preparing the query */
396 + myfree (name_escaped);
397 + /* do the query - set dict_errno & cleanup if there's an error */
398 + if ((query_res = plpgsql_query (pldb,
399 + vstring_str (query),
400 + dict_pgsql->name->dbname,
401 + dict_pgsql->name->username,
402 + dict_pgsql->name->password)) == 0)
404 + dict_errno = DICT_ERR_RETRY;
405 + vstring_free (query);
409 + /* free the vstring query */
410 + vstring_free (query);
411 + numrows = PQntuples (query_res);
413 + msg_info ("dict_pgsql_lookup: retrieved %d rows", numrows);
416 + PQclear (query_res);
420 + result = vstring_alloc (10);
421 + vstring_strcpy (result, "");
422 + for (i = 0; i < numrows; i++)
425 + vstring_strcat (result, ",");
426 + for (j = 0; j < PQnfields (query_res); j++)
429 + vstring_strcat (result, ",");
430 + field = PQgetvalue (query_res, i, j);
431 + vstring_strcat (result, field);
432 + if (msg_verbose > 1)
433 + msg_info ("dict_pgsql_lookup: retrieved field: %d: %s", j,
437 + PQclear (query_res);
438 + return vstring_str (result);
442 + * plpgsql_query - process a PGSQL query. Return PGresult* on success.
443 + * On failure, log failure and try other db instances.
444 + * on failure of all db instances, return 0;
445 + * close unnecessary active connections
448 +static PGresult *plpgsql_query (PLPGSQL * PLDB,
450 + char *dbname, char *username, char *password)
455 + ExecStatusType status;
457 + for (i = 0; i < PLDB->len_hosts; i++)
459 + /* can't deal with typing or reading PLDB->db_hosts[i] over & over */
460 + host = &(PLDB->db_hosts[i]);
461 + if (msg_verbose > 1)
462 + msg_info ("dict_pgsql: trying host %s stat %d, last res %p",
463 + host->hostname, host->stat, res);
465 + /* answer already found */
466 + if (res != 0 && host->stat == STATACTIVE)
470 + ("dict_pgsql: closing unnessary connection to %s",
472 + plpgsql_down_host (host);
474 + /* try to connect for the first time if we don't have a result yet */
475 + if (res == 0 && host->stat == STATUNTRIED)
478 + msg_info ("dict_pgsql: attempting to connect to host %s",
480 + plpgsql_connect_single (host, dbname, username, password);
484 + * try to reconnect if we don't have an answer and the host had a
485 + * prob in the past and it's time for it to reconnect
487 + if (res == 0 && host->stat == STATFAIL
488 + && host->ts < time ((time_t *) 0))
492 + ("dict_pgsql: attempting to reconnect to host %s",
494 + plpgsql_connect_single (host, dbname, username, password);
498 + * if we don't have a result and the current host is marked active,
499 + * try the query. If the query fails, mark the host STATFAIL
501 + if (res == 0 && host->stat == STATACTIVE)
503 + res = PQexec (host->db, query);
504 + status = PQresultStatus (res);
506 + && (status = PGRES_COMMAND_OK
507 + || status == PGRES_TUPLES_OK))
511 + ("dict_pgsql: successful query from host %s",
516 + msg_warn ("%s", PQerrorMessage (host->db));
517 + plpgsql_down_host (host);
525 + * plpgsql_connect_single -
526 + * used to reconnect to a single database when one is down or none is
527 + * connected yet. Log all errors and set the stat field of host accordingly
530 +plpgsql_connect_single (HOST *host, char *dbname, char *username,
533 + char *destination = host->hostname;
534 + char *hostname = 0;
536 + VSTRING *conninfo = vstring_alloc (100);
541 + * Ad-hoc parsing code. Expect "unix:pathname" or "inet:host:port", where
542 + * both "inet:" and ":port" are optional.
544 + if (strncmp (destination, "unix:", 5) == 0)
546 + vstring_sprintf_append (conninfo, "host=%s ", destination + 5);
550 + if (strncmp (destination, "inet:", 5) == 0)
552 + hostname = mystrdup (destination);
553 + if ((service = split_at (hostname, ':')) != 0)
555 + port = ntohs (find_inet_port (service, "tcp"));
556 + vstring_sprintf_append (conninfo, "host='%s' port='%d'",
561 + vstring_sprintf_append (conninfo, "host='%s'", hostname);
565 + vstring_sprintf_append (conninfo, " dbname='%s' user='%s' password='%s'", dbname,
566 + username, password);
567 + conn = vstring_export (conninfo);
569 + host->db = PQconnectdb (conn);
571 + if ((host->db != NULL) && (PQstatus (host->db) == CONNECTION_OK))
574 + msg_info ("dict_pgsql: successful connection to host %s",
576 + host->stat = STATACTIVE;
580 + msg_warn ("%s", PQerrorMessage (host->db));
581 + plpgsql_down_host (host);
589 + * plpgsql_down_host - mark a HOST down update ts if marked down
590 + * for the first time so that we'll know when to retry the connection
592 +static void plpgsql_down_host (HOST *host)
594 + if (host->stat != STATFAIL)
596 + host->ts = time ((time_t *) 0) + RETRY_CONN_INTV;
597 + host->stat = STATFAIL;
599 + PQfinish (host->db);
603 +/**********************************************************************
604 + * public interface dict_pgsql_open
605 + * create association with database with appropriate values
606 + * parse the map's config file
608 + **********************************************************************/
609 +DICT *dict_pgsql_open (const char *name, int unused_open_flags,
612 + DICT_PGSQL *dict_pgsql;
615 + dict_pgsql = (DICT_PGSQL *) dict_alloc (DICT_TYPE_PGSQL, name,
616 + sizeof (DICT_PGSQL));
617 + dict_pgsql->dict.lookup = dict_pgsql_lookup;
618 + dict_pgsql->dict.close = dict_pgsql_close;
619 + dict_pgsql->dict.flags = dict_flags | DICT_FLAG_FIXED;
620 + dict_pgsql->name = pgsqlname_parse (name);
621 + dict_pgsql->pldb = plpgsql_init (dict_pgsql->name->hostnames,
622 + dict_pgsql->name->len_hosts);
623 + if (dict_pgsql->pldb == NULL)
624 + msg_fatal ("couldn't intialize pldb!\n");
625 + dict_register (name, (DICT *) dict_pgsql);
626 + return (DICT_DEBUG (&dict_pgsql->dict));
629 +/* pgsqlname_parse - parse pgsql configuration file */
630 +static PGSQL_NAME *pgsqlname_parse (const char *pgsqlcf_path)
635 + PGSQL_NAME *name = (PGSQL_NAME *) mymalloc (sizeof (PGSQL_NAME));
637 + VSTRING *opt_dict_name;
640 + * setup a dict containing info in the pgsql cf file. the dict has a
641 + * name, and a path. The name must be distinct from the path, or the
642 + * dict interface gets confused. The name must be distinct for two
643 + * different paths, or the configuration info will cache across different
644 + * pgsql maps, which can be confusing.
646 + opt_dict_name = vstring_alloc (64);
647 + vstring_sprintf (opt_dict_name, "pgsql opt dict %s", pgsqlcf_path);
648 + dict_load_file (vstring_str (opt_dict_name), pgsqlcf_path);
649 + /* pgsql username lookup */
652 + (char *) dict_lookup (vstring_str (opt_dict_name), "user")) == NULL)
653 + name->username = mystrdup ("");
655 + name->username = mystrdup (nameval);
657 + msg_info ("pgsqlname_parse(): set username to '%s'", name->username);
658 + /* password lookup */
661 + (char *) dict_lookup (vstring_str (opt_dict_name),
662 + "password")) == NULL)
663 + name->password = mystrdup ("");
665 + name->password = mystrdup (nameval);
667 + msg_info ("pgsqlname_parse(): set password to '%s'", name->password);
669 + /* database name lookup */
672 + (char *) dict_lookup (vstring_str (opt_dict_name),
673 + "dbname")) == NULL)
677 + msg_fatal ("%s: pgsql options file does not include database name",
680 + name->dbname = mystrdup (nameval);
682 + msg_info ("pgsqlname_parse(): set database name to '%s'",
688 + (char *) dict_lookup (vstring_str (opt_dict_name), "table")) == NULL)
689 + msg_fatal ("%s: pgsql options file does not include table name",
692 + name->table = mystrdup (nameval);
694 + msg_info ("pgsqlname_parse(): set table name to '%s'", name->table);
696 + /* select field lookup */
699 + (char *) dict_lookup (vstring_str (opt_dict_name),
700 + "select_field")) == NULL)
704 + msg_fatal ("%s: pgsql options file does not include select field",
707 + name->select_field = mystrdup (nameval);
709 + msg_info ("pgsqlname_parse(): set select_field to '%s'",
710 + name->select_field);
712 + /* where field lookup */
715 + (char *) dict_lookup (vstring_str (opt_dict_name),
716 + "where_field")) == NULL)
717 + msg_fatal ("%s: pgsql options file does not include where field",
720 + name->where_field = mystrdup (nameval);
722 + msg_info ("pgsqlname_parse(): set where_field to '%s'",
723 + name->where_field);
725 + /* additional conditions */
728 + (char *) dict_lookup (vstring_str (opt_dict_name),
729 + "additional_conditions")) == NULL)
730 + name->additional_conditions = mystrdup ("");
732 + name->additional_conditions = mystrdup (nameval);
734 + msg_info ("pgsqlname_parse(): set additional_conditions to '%s'",
735 + name->additional_conditions);
737 + /* pgsql server hosts */
740 + (char *) dict_lookup (vstring_str (opt_dict_name), "hosts")) == NULL)
741 + hosts = mystrdup ("");
743 + hosts = mystrdup (nameval);
744 + /* coo argv interface */
745 + hosts_argv = argv_split (hosts, " ,\t\r\n");
747 + if (hosts_argv->argc == 0)
748 + { /* no hosts specified,
749 + * default to 'localhost' */
752 + ("pgsqlname_parse(): no hostnames specified, defaulting to 'localhost'");
753 + argv_add (hosts_argv, "localhost", ARGV_END);
754 + argv_terminate (hosts_argv);
756 + name->len_hosts = hosts_argv->argc;
759 + (char **) mymalloc ((sizeof (char *)) * name->len_hosts);
761 + for (i = 0; hosts_argv->argv[i] != NULL; i++)
763 + name->hostnames[i] = mystrdup (hosts_argv->argv[i]);
766 + ("pgsqlname_parse(): adding host '%s' to list of pgsql server hosts",
767 + name->hostnames[i]);
770 + vstring_free (opt_dict_name);
771 + argv_free (hosts_argv);
777 + * plpgsql_init - initalize a PGSQL database.
778 + * Return NULL on failure, or a PLPGSQL * on success.
780 +static PLPGSQL *plpgsql_init (char *hostnames[], int len_hosts)
786 + if ((PLDB = (PLPGSQL *) mymalloc (sizeof (PLPGSQL))) == NULL)
788 + msg_fatal ("mymalloc of pldb failed");
790 + PLDB->len_hosts = len_hosts;
791 + if ((PLDB->db_hosts = (HOST *) mymalloc (sizeof (HOST) * len_hosts))
795 + for (i = 0; i < len_hosts; i++)
797 + PLDB->db_hosts[i] = host_init (hostnames[i]);
803 +/* host_init - initialize HOST structure */
804 +static HOST host_init (char *hostname)
808 + host.stat = STATUNTRIED;
809 + host.hostname = mystrdup (hostname);
815 +/**********************************************************************
816 + * public interface dict_pgsql_close
817 + * unregister, disassociate from database, freeing appropriate memory
818 + **********************************************************************/
819 +static void dict_pgsql_close (DICT *dict)
822 + DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
824 + plpgsql_dealloc (dict_pgsql->pldb);
825 + myfree (dict_pgsql->name->username);
826 + myfree (dict_pgsql->name->password);
827 + myfree (dict_pgsql->name->dbname);
828 + myfree (dict_pgsql->name->table);
829 + myfree (dict_pgsql->name->select_field);
830 + myfree (dict_pgsql->name->where_field);
831 + myfree (dict_pgsql->name->additional_conditions);
832 + for (i = 0; i < dict_pgsql->name->len_hosts; i++)
834 + myfree (dict_pgsql->name->hostnames[i]);
836 + myfree ((char *) dict_pgsql->name->hostnames);
837 + myfree ((char *) dict_pgsql->name);
841 +/* plpgsql_dealloc - free memory associated with PLPGSQL close databases */
842 +static void plpgsql_dealloc (PLPGSQL * PLDB)
846 + for (i = 0; i < PLDB->len_hosts; i++)
848 + if (PLDB->db_hosts[i].db)
849 + PQfinish (PLDB->db_hosts[i].db);
850 + myfree (PLDB->db_hosts[i].hostname);
852 + myfree ((char *) PLDB->db_hosts);
853 + myfree ((char *) (PLDB));
856 +/* pgsql_escape_string - replace mysql_escape_string */
857 +void pgsql_escape_string (char *escaped, const char *name, int len)
862 + for (i = 0, j = 0; i <= len; i++, j++)
864 + if ((name[i] == '\'') || (name[i] == '\\'))
869 + escaped[j] = name[i];
877 diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/dict_pgsql.h postfix-1.1.3/src/util/dict_pgsql.h
878 --- postfix-1.1.3-vanilla/src/util/dict_pgsql.h Thu Jan 1 01:00:00 1970
879 +++ postfix-1.1.3/src/util/dict_pgsql.h Thu Mar 7 11:48:41 2002
881 +#ifndef _DICT_PGSQL_H_INCLUDED_
882 +#define _DICT_PGSQL_H_INCLUDED_
888 +/* dictionary manager interface to pgsql databases
890 +/* #include <dict_pgsql.h>
900 + * External interface.
902 +#define DICT_TYPE_PGSQL "pgsql"
904 +extern DICT *dict_pgsql_open (const char *, int, int);
909 +/* The Secure Mailer license must be distributed with this software.
913 +/* scott@icgroup.com