X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fpostgresql.c;h=faad16cd9b02b404c5326279bd8fa1aa85e64624;hb=074b4980bc75bea6826e6a38dcc6e193a721b2a8;hp=fbc117b09547349bd623a4cb843abdf588014370;hpb=3f0678c1e368e5236a538fb5ea817f5f0adae79a;p=collectd.git diff --git a/src/postgresql.c b/src/postgresql.c index fbc117b0..faad16cd 100644 --- a/src/postgresql.c +++ b/src/postgresql.c @@ -97,6 +97,9 @@ typedef struct { c_psql_col_t *cols; int cols_num; + + int min_pg_version; + int max_pg_version; } c_psql_query_t; typedef struct { @@ -161,6 +164,9 @@ static c_psql_query_t *c_psql_query_new (const char *name) query->cols = NULL; query->cols_num = 0; + + query->min_pg_version = 0; + query->max_pg_version = INT_MAX; return query; } /* c_psql_query_new */ @@ -183,12 +189,15 @@ static void c_psql_query_delete (c_psql_query_t *query) return; } /* c_psql_query_delete */ -static c_psql_query_t *c_psql_query_get (const char *name) +static c_psql_query_t *c_psql_query_get (const char *name, int server_version) { int i; for (i = 0; i < queries_num; ++i) - if (0 == strcasecmp (name, queries[i].name)) + if (0 == strcasecmp (name, queries[i].name) + && ((-1 == server_version) + || ((queries[i].min_pg_version <= server_version) + && (server_version <= queries[i].max_pg_version)))) return queries + i; return NULL; } /* c_psql_query_get */ @@ -235,6 +244,7 @@ static c_psql_database_t *c_psql_database_new (const char *name) static void c_psql_database_delete (c_psql_database_t *db) { PQfinish (db->conn); + db->conn = NULL; sfree (db->queries); db->queries_num = 0; @@ -408,14 +418,17 @@ static int c_psql_exec_query (c_psql_database_t *db, int idx) } rows = PQntuples (res); - if (1 > rows) + if (1 > rows) { + PQclear (res); return 0; + } cols = PQnfields (res); if (query->cols_num != cols) { log_err ("SQL query returned wrong number of fields " "(expected: %i, got: %i)", query->cols_num, cols); log_info ("SQL query was: %s", query->query); + PQclear (res); return -1; } @@ -433,6 +446,7 @@ static int c_psql_exec_query (c_psql_database_t *db, int idx) submit_gauge (db, col.type, col.type_instance, value); } } + PQclear (res); return 0; } /* c_psql_exec_query */ @@ -535,6 +549,14 @@ static int c_psql_init (void) char *server_host; int server_version; + int j; + + /* this will happen during reinitialization */ + if (NULL != db->conn) { + c_psql_check_connection (db); + continue; + } + status = ssnprintf (buf, buf_len, "dbname = '%s'", db->database); if (0 < status) { buf += status; @@ -568,6 +590,33 @@ static int c_psql_init (void) if (3 > db->proto_version) log_warn ("Protocol version %d does not support parameters.", db->proto_version); + + /* Now that we know the PostgreSQL server version, we can get the + * right version of each query definition. */ + for (j = 0; j < db->queries_num; ++j) { + c_psql_query_t *tmp; + + tmp = c_psql_query_get (db->queries[j]->name, server_version); + + if (tmp == db->queries[j]) + continue; + + if (NULL == tmp) { + log_err ("Query \"%s\" not found for server version %i - " + "please check your configuration.", + db->queries[j]->name, server_version); + + if (db->queries_num - j - 1 > 0) + memmove (db->queries + j, db->queries + j + 1, + (db->queries_num - j - 1) * sizeof (*db->queries)); + + --db->queries_num; + --j; + continue; + } + + db->queries[j] = tmp; + } } plugin_register_read ("postgresql", c_psql_read); @@ -575,7 +624,7 @@ static int c_psql_init (void) return 0; } /* c_psql_init */ -static int config_set (char *name, char **var, const oconfig_item_t *ci) +static int config_set_s (char *name, char **var, const oconfig_item_t *ci) { if ((0 != ci->children_num) || (1 != ci->values_num) || (OCONFIG_TYPE_STRING != ci->values[0].type)) { @@ -586,7 +635,19 @@ static int config_set (char *name, char **var, const oconfig_item_t *ci) sfree (*var); *var = sstrdup (ci->values[0].value.string); return 0; -} /* config_set */ +} /* config_set_s */ + +static int config_set_i (char *name, int *var, const oconfig_item_t *ci) +{ + if ((0 != ci->children_num) || (1 != ci->values_num) + || (OCONFIG_TYPE_NUMBER != ci->values[0].type)) { + log_err ("%s expects a single number argument.", name); + return 1; + } + + *var = (int)ci->values[0].value.number; + return 0; +} /* config_set_i */ static int config_set_param (c_psql_query_t *query, const oconfig_item_t *ci) { @@ -662,7 +723,7 @@ static int set_query (c_psql_database_t *db, const char *name) { c_psql_query_t *query; - query = c_psql_query_get (name); + query = c_psql_query_get (name, -1); if (NULL == query) { log_err ("Query \"%s\" not found - please check your configuration.", name); @@ -711,14 +772,48 @@ static int c_psql_config_query (oconfig_item_t *ci) oconfig_item_t *c = ci->children + i; if (0 == strcasecmp (c->key, "Query")) - config_set ("Query", &query->query, c); + config_set_s ("Query", &query->query, c); else if (0 == strcasecmp (c->key, "Param")) config_set_param (query, c); else if (0 == strcasecmp (c->key, "Column")) config_set_column (query, c); + else if (0 == strcasecmp (c->key, "MinPGVersion")) + config_set_i ("MinPGVersion", &query->min_pg_version, c); + else if (0 == strcasecmp (c->key, "MaxPGVersion")) + config_set_i ("MaxPGVersion", &query->max_pg_version, c); else log_warn ("Ignoring unknown config key \"%s\".", c->key); } + + for (i = 0; i < queries_num - 1; ++i) { + c_psql_query_t *q = queries + i; + + if ((0 == strcasecmp (q->name, query->name)) + && (q->min_pg_version <= query->max_pg_version) + && (query->min_pg_version <= q->max_pg_version)) { + log_err ("Ignoring redefinition (with overlapping version ranges) " + "of query \"%s\".", query->name); + c_psql_query_delete (query); + --queries_num; + return 1; + } + } + + if (query->min_pg_version > query->max_pg_version) { + log_err ("Query \"%s\": MinPGVersion > MaxPGVersion.", + query->name); + c_psql_query_delete (query); + --queries_num; + return 1; + } + + if (NULL == query->query) { + log_err ("Query \"%s\" does not include an SQL query string - " + "please check your configuration.", query->name); + c_psql_query_delete (query); + --queries_num; + return 1; + } return 0; } /* c_psql_config_query */ @@ -740,19 +835,19 @@ static int c_psql_config_database (oconfig_item_t *ci) oconfig_item_t *c = ci->children + i; if (0 == strcasecmp (c->key, "Host")) - config_set ("Host", &db->host, c); + config_set_s ("Host", &db->host, c); else if (0 == strcasecmp (c->key, "Port")) - config_set ("Port", &db->port, c); + config_set_s ("Port", &db->port, c); else if (0 == strcasecmp (c->key, "User")) - config_set ("User", &db->user, c); + config_set_s ("User", &db->user, c); else if (0 == strcasecmp (c->key, "Password")) - config_set ("Password", &db->password, c); + config_set_s ("Password", &db->password, c); else if (0 == strcasecmp (c->key, "SSLMode")) - config_set ("SSLMode", &db->sslmode, c); + config_set_s ("SSLMode", &db->sslmode, c); else if (0 == strcasecmp (c->key, "KRBSrvName")) - config_set ("KRBSrvName", &db->krbsrvname, c); + config_set_s ("KRBSrvName", &db->krbsrvname, c); else if (0 == strcasecmp (c->key, "Service")) - config_set ("Service", &db->service, c); + config_set_s ("Service", &db->service, c); else if (0 == strcasecmp (c->key, "Query")) config_set_query (db, c); else