postgresql plugin: Added support for custom queries.
[collectd.git] / src / postgresql.c
1 /**
2  * collectd - src/postgresql.c
3  * Copyright (C) 2008  Sebastian Harl
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Author:
19  *   Sebastian Harl <sh at tokkee.org>
20  **/
21
22 /*
23  * This module collects PostgreSQL database statistics.
24  */
25
26 #include "collectd.h"
27 #include "common.h"
28
29 #include "configfile.h"
30 #include "plugin.h"
31
32 #include "utils_complain.h"
33
34 #include <pg_config_manual.h>
35 #include <libpq-fe.h>
36
37 #define log_err(...) ERROR ("postgresql: " __VA_ARGS__)
38 #define log_warn(...) WARNING ("postgresql: " __VA_ARGS__)
39 #define log_info(...) INFO ("postgresql: " __VA_ARGS__)
40
41 /* Appends the (parameter, value) pair to the string
42  * pointed to by 'buf' suitable to be used as argument
43  * for PQconnectdb(). If value equals NULL, the pair
44  * is ignored. */
45 #define C_PSQL_PAR_APPEND(buf, buf_len, parameter, value) \
46         if ((0 < (buf_len)) && (NULL != (value)) && ('\0' != *(value))) { \
47                 int s = ssnprintf (buf, buf_len, " %s = '%s'", parameter, value); \
48                 if (0 < s) { \
49                         buf     += s; \
50                         buf_len -= s; \
51                 } \
52         }
53
54 /* Returns the tuple (major, minor, patchlevel)
55  * for the given version number. */
56 #define C_PSQL_SERVER_VERSION3(server_version) \
57         (server_version) / 10000, \
58         (server_version) / 100 - (int)((server_version) / 10000) * 100, \
59         (server_version) - (int)((server_version) / 100) * 100
60
61 /* Returns true if the given host specifies a
62  * UNIX domain socket. */
63 #define C_PSQL_IS_UNIX_DOMAIN_SOCKET(host) \
64         ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
65
66 /* Returns the tuple (host, delimiter, port) for a
67  * given (host, port) pair. Depending on the value of
68  * 'host' a UNIX domain socket or a TCP socket is
69  * assumed. */
70 #define C_PSQL_SOCKET3(host, port) \
71         ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, \
72         C_PSQL_IS_UNIX_DOMAIN_SOCKET (host) ? "/.s.PGSQL." : ":", \
73         port
74
75 typedef struct {
76         char *type;
77         char *type_instance;
78         int   ds_type;
79 } c_psql_col_t;
80
81 typedef struct {
82         char *name;
83         char *query;
84
85         c_psql_col_t *cols;
86         int           cols_num;
87 } c_psql_query_t;
88
89 typedef struct {
90         PGconn      *conn;
91         c_complain_t conn_complaint;
92
93         /* user configuration */
94         c_psql_query_t **queries;
95         int              queries_num;
96
97         char *host;
98         char *port;
99         char *database;
100         char *user;
101         char *password;
102
103         char *sslmode;
104
105         char *krbsrvname;
106
107         char *service;
108 } c_psql_database_t;
109
110 static c_psql_query_t *queries          = NULL;
111 static int             queries_num      = 0;
112
113 static c_psql_database_t *databases     = NULL;
114 static int                databases_num = 0;
115
116 static c_psql_query_t *c_psql_query_new (const char *name)
117 {
118         c_psql_query_t *query;
119
120         ++queries_num;
121         if (NULL == (queries = (c_psql_query_t *)realloc (queries,
122                                 queries_num * sizeof (*queries)))) {
123                 log_err ("Out of memory.");
124                 exit (5);
125         }
126         query = queries + queries_num - 1;
127
128         query->name  = sstrdup (name);
129         query->query = NULL;
130
131         query->cols     = NULL;
132         query->cols_num = 0;
133         return query;
134 } /* c_psql_query_new */
135
136 static void c_psql_query_delete (c_psql_query_t *query)
137 {
138         int i;
139
140         sfree (query->name);
141         sfree (query->query);
142
143         for (i = 0; i < query->cols_num; ++i) {
144                 sfree (query->cols[i].type);
145                 sfree (query->cols[i].type_instance);
146         }
147         sfree (query->cols);
148         query->cols_num = 0;
149         return;
150 } /* c_psql_query_delete */
151
152 static c_psql_query_t *c_psql_query_get (const char *name)
153 {
154         int i;
155
156         for (i = 0; i < queries_num; ++i)
157                 if (0 == strcasecmp (name, queries[i].name))
158                         return queries + i;
159         return NULL;
160 } /* c_psql_query_get */
161
162 static c_psql_database_t *c_psql_database_new (const char *name)
163 {
164         c_psql_database_t *db;
165
166         ++databases_num;
167         if (NULL == (databases = (c_psql_database_t *)realloc (databases,
168                                 databases_num * sizeof (*databases)))) {
169                 log_err ("Out of memory.");
170                 exit (5);
171         }
172
173         db = databases + (databases_num - 1);
174
175         db->conn = NULL;
176
177         db->conn_complaint.last     = 0;
178         db->conn_complaint.interval = 0;
179
180         db->queries     = NULL;
181         db->queries_num = 0;
182
183         db->database   = sstrdup (name);
184         db->host       = NULL;
185         db->port       = NULL;
186         db->user       = NULL;
187         db->password   = NULL;
188
189         db->sslmode    = NULL;
190
191         db->krbsrvname = NULL;
192
193         db->service    = NULL;
194         return db;
195 } /* c_psql_database_new */
196
197 static void c_psql_database_delete (c_psql_database_t *db)
198 {
199         PQfinish (db->conn);
200
201         sfree (db->queries);
202         db->queries_num = 0;
203
204         sfree (db->database);
205         sfree (db->host);
206         sfree (db->port);
207         sfree (db->user);
208         sfree (db->password);
209
210         sfree (db->sslmode);
211
212         sfree (db->krbsrvname);
213
214         sfree (db->service);
215         return;
216 } /* c_psql_database_delete */
217
218 static void submit (const c_psql_database_t *db,
219                 const char *type, const char *type_instance,
220                 value_t *values, size_t values_len)
221 {
222         value_list_t vl = VALUE_LIST_INIT;
223
224         vl.values     = values;
225         vl.values_len = values_len;
226         vl.time       = time (NULL);
227
228         if (C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host)
229                         || (0 == strcmp (db->host, "localhost")))
230                 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
231         else
232                 sstrncpy (vl.host, db->host, sizeof (vl.host));
233
234         sstrncpy (vl.plugin, "postgresql", sizeof (vl.plugin));
235         sstrncpy (vl.plugin_instance, db->database, sizeof (vl.plugin_instance));
236
237         sstrncpy (vl.type, type, sizeof (vl.type));
238
239         if (NULL != type_instance)
240                 sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
241
242         plugin_dispatch_values (&vl);
243         return;
244 } /* submit */
245
246 static void submit_counter (const c_psql_database_t *db,
247                 const char *type, const char *type_instance,
248                 const char *value)
249 {
250         value_t values[1];
251
252         if ((NULL == value) || ('\0' == *value))
253                 return;
254
255         values[0].counter = atoll (value);
256         submit (db, type, type_instance, values, 1);
257         return;
258 } /* submit_counter */
259
260 static void submit_gauge (const c_psql_database_t *db,
261                 const char *type, const char *type_instance,
262                 const char *value)
263 {
264         value_t values[1];
265
266         if ((NULL == value) || ('\0' == *value))
267                 return;
268
269         values[0].gauge = atof (value);
270         submit (db, type, type_instance, values, 1);
271         return;
272 } /* submit_gauge */
273
274 static int c_psql_check_connection (c_psql_database_t *db)
275 {
276         /* "ping" */
277         PQclear (PQexec (db->conn, "SELECT 42;"));
278
279         if (CONNECTION_OK != PQstatus (db->conn)) {
280                 PQreset (db->conn);
281
282                 /* trigger c_release() */
283                 if (0 == db->conn_complaint.interval)
284                         db->conn_complaint.interval = 1;
285
286                 if (CONNECTION_OK != PQstatus (db->conn)) {
287                         c_complain (LOG_ERR, &db->conn_complaint,
288                                         "Failed to connect to database %s: %s",
289                                         db->database, PQerrorMessage (db->conn));
290                         return -1;
291                 }
292         }
293
294         c_release (LOG_INFO, &db->conn_complaint,
295                         "Successfully reconnected to database %s", PQdb (db->conn));
296         return 0;
297 } /* c_psql_check_connection */
298
299 static int c_psql_exec_query (c_psql_database_t *db, int idx)
300 {
301         c_psql_query_t *query;
302         PGresult       *res;
303
304         int rows, cols;
305         int i;
306
307         if (idx >= db->queries_num)
308                 return -1;
309
310         query = db->queries[idx];
311
312         res = PQexec (db->conn, query->query);
313
314         if (PGRES_TUPLES_OK != PQresultStatus (res)) {
315                 log_err ("Failed to execute SQL query: %s",
316                                 PQerrorMessage (db->conn));
317                 log_info ("SQL query was: %s", query->query);
318                 PQclear (res);
319                 return -1;
320         }
321
322         rows = PQntuples (res);
323         if (1 > rows)
324                 return 0;
325
326         cols = PQnfields (res);
327         if (query->cols_num != cols) {
328                 log_err ("SQL query returned wrong number of fields "
329                                 "(expected: %i, got: %i)", query->cols_num, cols);
330                 log_info ("SQL query was: %s", query->query);
331                 return -1;
332         }
333
334         for (i = 0; i < rows; ++i) {
335                 int j;
336
337                 for (j = 0; j < cols; ++j) {
338                         c_psql_col_t col = query->cols[j];
339
340                         char *value = PQgetvalue (res, i, j);
341
342                         if (col.ds_type == DS_TYPE_COUNTER)
343                                 submit_counter (db, col.type, col.type_instance, value);
344                         else if (col.ds_type == DS_TYPE_GAUGE)
345                                 submit_gauge (db, col.type, col.type_instance, value);
346                 }
347         }
348         return 0;
349 } /* c_psql_exec_query */
350
351 static int c_psql_stat_database (c_psql_database_t *db)
352 {
353         const char *const query =
354                 "SELECT numbackends, xact_commit, xact_rollback "
355                         "FROM pg_stat_database "
356                         "WHERE datname = $1;";
357
358         PGresult *res;
359
360         int n;
361
362         res = PQexecParams (db->conn, query, /* number of parameters */ 1,
363                         NULL, (const char *const *)&db->database, NULL, NULL,
364                         /* return text data */ 0);
365
366         if (PGRES_TUPLES_OK != PQresultStatus (res)) {
367                 log_err ("Failed to execute SQL query: %s",
368                                 PQerrorMessage (db->conn));
369                 log_info ("SQL query was: %s", query);
370                 PQclear (res);
371                 return -1;
372         }
373
374         n = PQntuples (res);
375         if (1 < n) {
376                 log_warn ("pg_stat_database has more than one entry "
377                                 "for database %s - ignoring additional results.",
378                                 db->database);
379         }
380         else if (1 > n) {
381                 log_err ("pg_stat_database has no entry for database %s",
382                                 db->database);
383                 PQclear (res);
384                 return -1;
385         }
386
387         submit_gauge (db, "pg_numbackends", NULL,  PQgetvalue (res, 0, 0));
388
389         submit_counter (db, "pg_xact", "commit",   PQgetvalue (res, 0, 1));
390         submit_counter (db, "pg_xact", "rollback", PQgetvalue (res, 0, 2));
391
392         PQclear (res);
393         return 0;
394 } /* c_psql_stat_database */
395
396 static int c_psql_stat_user_tables (c_psql_database_t *db)
397 {
398         const char *const query =
399                 "SELECT sum(seq_scan), sum(seq_tup_read), "
400                                 "sum(idx_scan), sum(idx_tup_fetch), "
401                                 "sum(n_tup_ins), sum(n_tup_upd), sum(n_tup_del), "
402                                 "sum(n_tup_hot_upd), sum(n_live_tup), sum(n_dead_tup) "
403                         "FROM pg_stat_user_tables;";
404
405         PGresult *res;
406
407         int n;
408
409         res = PQexec (db->conn, query);
410
411         if (PGRES_TUPLES_OK != PQresultStatus (res)) {
412                 log_err ("Failed to execute SQL query: %s",
413                                 PQerrorMessage (db->conn));
414                 log_info ("SQL query was: %s", query);
415                 PQclear (res);
416                 return -1;
417         }
418
419         n = PQntuples (res);
420         assert (1 >= n);
421
422         if (1 > n) /* no user tables */
423                 return 0;
424
425         submit_counter (db, "pg_scan", "seq",           PQgetvalue (res, 0, 0));
426         submit_counter (db, "pg_scan", "seq_tup_read",  PQgetvalue (res, 0, 1));
427         submit_counter (db, "pg_scan", "idx",           PQgetvalue (res, 0, 2));
428         submit_counter (db, "pg_scan", "idx_tup_fetch", PQgetvalue (res, 0, 3));
429
430         submit_counter (db, "pg_n_tup_c", "ins",        PQgetvalue (res, 0, 4));
431         submit_counter (db, "pg_n_tup_c", "upd",        PQgetvalue (res, 0, 5));
432         submit_counter (db, "pg_n_tup_c", "del",        PQgetvalue (res, 0, 6));
433         submit_counter (db, "pg_n_tup_c", "hot_upd",    PQgetvalue (res, 0, 7));
434
435         submit_gauge (db, "pg_n_tup_g", "live",         PQgetvalue (res, 0, 8));
436         submit_gauge (db, "pg_n_tup_g", "dead",         PQgetvalue (res, 0, 9));
437
438         PQclear (res);
439         return 0;
440 } /* c_psql_stat_user_tables */
441
442 static int c_psql_statio_user_tables (c_psql_database_t *db)
443 {
444         const char *const query =
445                 "SELECT sum(heap_blks_read), sum(heap_blks_hit), "
446                                 "sum(idx_blks_read), sum(idx_blks_hit), "
447                                 "sum(toast_blks_read), sum(toast_blks_hit), "
448                                 "sum(tidx_blks_read), sum(tidx_blks_hit) "
449                         "FROM pg_statio_user_tables;";
450
451         PGresult *res;
452
453         int n;
454
455         res = PQexec (db->conn, query);
456
457         if (PGRES_TUPLES_OK != PQresultStatus (res)) {
458                 log_err ("Failed to execute SQL query: %s",
459                                 PQerrorMessage (db->conn));
460                 log_info ("SQL query was: %s", query);
461                 PQclear (res);
462                 return -1;
463         }
464
465         n = PQntuples (res);
466         assert (1 >= n);
467
468         if (1 > n) /* no user tables */
469                 return 0;
470
471         submit_counter (db, "pg_blks", "heap_read",  PQgetvalue (res, 0, 0));
472         submit_counter (db, "pg_blks", "heap_hit",   PQgetvalue (res, 0, 1));
473
474         submit_counter (db, "pg_blks", "idx_read",   PQgetvalue (res, 0, 2));
475         submit_counter (db, "pg_blks", "idx_hit",    PQgetvalue (res, 0, 3));
476
477         submit_counter (db, "pg_blks", "toast_read", PQgetvalue (res, 0, 4));
478         submit_counter (db, "pg_blks", "toast_hit",  PQgetvalue (res, 0, 5));
479
480         submit_counter (db, "pg_blks", "tidx_read",  PQgetvalue (res, 0, 6));
481         submit_counter (db, "pg_blks", "tidx_hit",   PQgetvalue (res, 0, 7));
482
483         PQclear (res);
484         return 0;
485 } /* c_psql_statio_user_tables */
486
487 static int c_psql_read (void)
488 {
489         int success = 0;
490         int i;
491
492         for (i = 0; i < databases_num; ++i) {
493                 c_psql_database_t *db = databases + i;
494
495                 int j;
496
497                 assert (NULL != db->database);
498
499                 if (0 != c_psql_check_connection (db))
500                         continue;
501
502                 c_psql_stat_database (db);
503                 c_psql_stat_user_tables (db);
504                 c_psql_statio_user_tables (db);
505
506                 for (j = 0; j < db->queries_num; ++j)
507                         c_psql_exec_query (db, j);
508
509                 ++success;
510         }
511
512         if (! success)
513                 return -1;
514         return 0;
515 } /* c_psql_read */
516
517 static int c_psql_shutdown (void)
518 {
519         int i;
520
521         if ((NULL == databases) || (0 == databases_num))
522                 return 0;
523
524         plugin_unregister_read ("postgresql");
525         plugin_unregister_shutdown ("postgresql");
526
527         for (i = 0; i < databases_num; ++i) {
528                 c_psql_database_t *db = databases + i;
529                 c_psql_database_delete (db);
530         }
531
532         sfree (databases);
533         databases_num = 0;
534
535         for (i = 0; i < queries_num; ++i) {
536                 c_psql_query_t *query = queries + i;
537                 c_psql_query_delete (query);
538         }
539
540         sfree (queries);
541         queries_num = 0;
542         return 0;
543 } /* c_psql_shutdown */
544
545 static int c_psql_init (void)
546 {
547         int i;
548
549         if ((NULL == databases) || (0 == databases_num))
550                 return 0;
551
552         for (i = 0; i < queries_num; ++i) {
553                 c_psql_query_t *query = queries + i;
554                 int j;
555
556                 for (j = 0; j < query->cols_num; ++j) {
557                         c_psql_col_t     *col = query->cols + j;
558                         const data_set_t *ds;
559
560                         ds = plugin_get_ds (col->type);
561                         if (NULL == ds) {
562                                 log_err ("Column: Unknown type \"%s\".", col->type);
563                                 c_psql_shutdown ();
564                                 return -1;
565                         }
566
567                         if (1 != ds->ds_num) {
568                                 log_err ("Column: Invalid type \"%s\" - types defining "
569                                                 "one data source are supported only (got: %i).",
570                                                 col->type, ds->ds_num);
571                                 c_psql_shutdown ();
572                                 return -1;
573                         }
574
575                         col->ds_type = ds->ds[0].type;
576                 }
577         }
578
579         for (i = 0; i < databases_num; ++i) {
580                 c_psql_database_t *db = databases + i;
581
582                 char  conninfo[4096];
583                 char *buf     = conninfo;
584                 int   buf_len = sizeof (conninfo);
585                 int   status;
586
587                 char *server_host;
588                 int   server_version;
589
590                 status = ssnprintf (buf, buf_len, "dbname = '%s'", db->database);
591                 if (0 < status) {
592                         buf     += status;
593                         buf_len -= status;
594                 }
595
596                 C_PSQL_PAR_APPEND (buf, buf_len, "host",       db->host);
597                 C_PSQL_PAR_APPEND (buf, buf_len, "port",       db->port);
598                 C_PSQL_PAR_APPEND (buf, buf_len, "user",       db->user);
599                 C_PSQL_PAR_APPEND (buf, buf_len, "password",   db->password);
600                 C_PSQL_PAR_APPEND (buf, buf_len, "sslmode",    db->sslmode);
601                 C_PSQL_PAR_APPEND (buf, buf_len, "krbsrvname", db->krbsrvname);
602                 C_PSQL_PAR_APPEND (buf, buf_len, "service",    db->service);
603
604                 db->conn = PQconnectdb (conninfo);
605                 if (0 != c_psql_check_connection (db))
606                         continue;
607
608                 server_host    = PQhost (db->conn);
609                 server_version = PQserverVersion (db->conn);
610                 log_info ("Sucessfully connected to database %s (user %s) "
611                                 "at server %s%s%s (server version: %d.%d.%d, "
612                                 "protocol version: %d, pid: %d)",
613                                 PQdb (db->conn), PQuser (db->conn),
614                                 C_PSQL_SOCKET3 (server_host, PQport (db->conn)),
615                                 C_PSQL_SERVER_VERSION3 (server_version),
616                                 PQprotocolVersion (db->conn), PQbackendPID (db->conn));
617         }
618
619         plugin_register_read ("postgresql", c_psql_read);
620         plugin_register_shutdown ("postgresql", c_psql_shutdown);
621         return 0;
622 } /* c_psql_init */
623
624 static int config_set (char *name, char **var, const oconfig_item_t *ci)
625 {
626         if ((0 != ci->children_num) || (1 != ci->values_num)
627                         || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
628                 log_err ("%s expects a single string argument.", name);
629                 return 1;
630         }
631
632         sfree (*var);
633         *var = sstrdup (ci->values[0].value.string);
634         return 0;
635 } /* config_set */
636
637 static int config_set_column (c_psql_query_t *query, const oconfig_item_t *ci)
638 {
639         c_psql_col_t *col;
640
641         int i;
642
643         if ((0 != ci->children_num)
644                         || (1 > ci->values_num) || (2 < ci->values_num)) {
645                 log_err ("Column expects either one or two arguments.");
646                 return 1;
647         }
648
649         for (i = 0; i < ci->values_num; ++i) {
650                 if (OCONFIG_TYPE_STRING != ci->values[i].type) {
651                         log_err ("Column expects either one or two string arguments.");
652                         return 1;
653                 }
654         }
655
656         ++query->cols_num;
657         if (NULL == (query->cols = (c_psql_col_t *)realloc (query->cols,
658                                 query->cols_num * sizeof (*query->cols)))) {
659                 log_err ("Out of memory.");
660                 exit (5);
661         }
662
663         col = query->cols + query->cols_num - 1;
664
665         col->ds_type = -1;
666
667         col->type = sstrdup (ci->values[0].value.string);
668         col->type_instance = (2 == ci->values_num)
669                 ? sstrdup (ci->values[1].value.string) : NULL;
670         return 0;
671 } /* config_set_column */
672
673 static int config_set_query (c_psql_database_t *db, const oconfig_item_t *ci)
674 {
675         c_psql_query_t *query;
676
677         if ((0 != ci->children_num) || (1 != ci->values_num)
678                         || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
679                 log_err ("Query expects a single string argument.");
680                 return 1;
681         }
682
683         query = c_psql_query_get (ci->values[0].value.string);
684         if (NULL == query) {
685                 log_err ("Query \"%s\" not found - please check your configuration.",
686                                 ci->values[0].value.string);
687                 return 1;
688         }
689
690         ++db->queries_num;
691         if (NULL == (db->queries = (c_psql_query_t **)realloc (db->queries,
692                                 db->queries_num * sizeof (*db->queries)))) {
693                 log_err ("Out of memory.");
694                 exit (5);
695         }
696
697         db->queries[db->queries_num - 1] = query;
698         return 0;
699 } /* config_set_query */
700
701 static int c_psql_config_query (oconfig_item_t *ci)
702 {
703         c_psql_query_t *query;
704
705         int i;
706
707         if ((1 != ci->values_num)
708                         || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
709                 log_err ("<Query> expects a single string argument.");
710                 return 1;
711         }
712
713         query = c_psql_query_new (ci->values[0].value.string);
714
715         for (i = 0; i < ci->children_num; ++i) {
716                 oconfig_item_t *c = ci->children + i;
717
718                 if (0 == strcasecmp (c->key, "Query"))
719                         config_set ("Query", &query->query, c);
720                 else if (0 == strcasecmp (c->key, "Column"))
721                         config_set_column (query, c);
722                 else
723                         log_warn ("Ignoring unknown config key \"%s\".", c->key);
724         }
725         return 0;
726 } /* c_psql_config_query */
727
728 static int c_psql_config_database (oconfig_item_t *ci)
729 {
730         c_psql_database_t *db;
731
732         int i;
733
734         if ((1 != ci->values_num)
735                         || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
736                 log_err ("<Database> expects a single string argument.");
737                 return 1;
738         }
739
740         db = c_psql_database_new (ci->values[0].value.string);
741
742         for (i = 0; i < ci->children_num; ++i) {
743                 oconfig_item_t *c = ci->children + i;
744
745                 if (0 == strcasecmp (c->key, "Host"))
746                         config_set ("Host", &db->host, c);
747                 else if (0 == strcasecmp (c->key, "Port"))
748                         config_set ("Port", &db->port, c);
749                 else if (0 == strcasecmp (c->key, "User"))
750                         config_set ("User", &db->user, c);
751                 else if (0 == strcasecmp (c->key, "Password"))
752                         config_set ("Password", &db->password, c);
753                 else if (0 == strcasecmp (c->key, "SSLMode"))
754                         config_set ("SSLMode", &db->sslmode, c);
755                 else if (0 == strcasecmp (c->key, "KRBSrvName"))
756                         config_set ("KRBSrvName", &db->krbsrvname, c);
757                 else if (0 == strcasecmp (c->key, "Service"))
758                         config_set ("Service", &db->service, c);
759                 else if (0 == strcasecmp (c->key, "Query"))
760                         config_set_query (db, c);
761                 else
762                         log_warn ("Ignoring unknown config key \"%s\".", c->key);
763         }
764         return 0;
765 }
766
767 static int c_psql_config (oconfig_item_t *ci)
768 {
769         int i;
770
771         for (i = 0; i < ci->children_num; ++i) {
772                 oconfig_item_t *c = ci->children + i;
773
774                 if (0 == strcasecmp (c->key, "Query"))
775                         c_psql_config_query (c);
776                 else if (0 == strcasecmp (c->key, "Database"))
777                         c_psql_config_database (c);
778                 else
779                         log_warn ("Ignoring unknown config key \"%s\".", c->key);
780         }
781         return 0;
782 } /* c_psql_config */
783
784 void module_register (void)
785 {
786         plugin_register_complex_config ("postgresql", c_psql_config);
787         plugin_register_init ("postgresql", c_psql_init);
788 } /* module_register */
789
790 /* vim: set sw=4 ts=4 tw=78 noexpandtab : */
791