From: Jeremy Sowden <jeremy@azazel.net>
To: Netfilter Devel <netfilter-devel@vger.kernel.org>
Subject: [PATCH ulogd2 v2 v2 14/34] output: de-duplicate allocation of input keys
Date: Tue, 29 Nov 2022 21:47:29 +0000 [thread overview]
Message-ID: <20221129214749.247878-15-jeremy@azazel.net> (raw)
In-Reply-To: <20221129214749.247878-1-jeremy@azazel.net>
The three DB output plug-ins which use the ulogd_db API all derive the
names of their input keys from DB column names, and do so in almost
identical fashion. Create a common ulogd_db implementation and update
them to use it.
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
---
include/ulogd/db.h | 11 ++++-
output/dbi/ulogd_output_DBI.c | 67 ++++++++++++++-----------------
output/mysql/ulogd_output_MYSQL.c | 46 ++++++++-------------
output/pgsql/ulogd_output_PGSQL.c | 43 ++++++--------------
util/db.c | 48 ++++++++++++++++++++++
5 files changed, 116 insertions(+), 99 deletions(-)
diff --git a/include/ulogd/db.h b/include/ulogd/db.h
index a6fd25b4c043..7c0649583f1d 100644
--- a/include/ulogd/db.h
+++ b/include/ulogd/db.h
@@ -12,13 +12,19 @@
#include <ulogd/ulogd.h>
struct db_driver {
+
int (*get_columns)(struct ulogd_pluginstance *upi);
+ const char *(*get_column)(void *, unsigned int);
+ char *(*format_key)(char *);
+
int (*open_db)(struct ulogd_pluginstance *upi);
int (*close_db)(struct ulogd_pluginstance *upi);
+
int (*escape_string)(struct ulogd_pluginstance *upi,
char *dst, const char *src, unsigned int len);
int (*execute)(struct ulogd_pluginstance *upi,
const char *stmt, unsigned int len);
+
};
enum {
@@ -116,7 +122,8 @@ int ulogd_db_start(struct ulogd_pluginstance *upi);
int ulogd_db_stop(struct ulogd_pluginstance *upi);
int ulogd_db_interp(struct ulogd_pluginstance *upi);
int ulogd_db_configure(struct ulogd_pluginstance *upi,
- struct ulogd_pluginstance_stack *stack);
-
+ struct ulogd_pluginstance_stack *stack);
+int ulogd_db_alloc_input_keys(struct ulogd_pluginstance *upi,
+ unsigned int num_keys, void *arg);
#endif
diff --git a/output/dbi/ulogd_output_DBI.c b/output/dbi/ulogd_output_DBI.c
index 6312ac1649e2..5c10c787fb6a 100644
--- a/output/dbi/ulogd_output_DBI.c
+++ b/output/dbi/ulogd_output_DBI.c
@@ -92,7 +92,7 @@ static int get_columns_dbi(struct ulogd_pluginstance *upi)
struct dbi_instance *pi = (struct dbi_instance *) upi->private;
char *table = table_ce(upi->config_kset).u.string;
char query[256];
- unsigned int ui;
+ int rv;
if (!pi->dbh) {
ulogd_log(ULOGD_ERROR, "no database handle\n");
@@ -111,48 +111,39 @@ static int get_columns_dbi(struct ulogd_pluginstance *upi)
return -1;
}
- if (upi->input.keys)
- free(upi->input.keys);
+ rv = ulogd_db_alloc_input_keys(upi,
+ dbi_result_get_numfields(pi->result),
+ pi->result);
- upi->input.num_keys = dbi_result_get_numfields(pi->result);
- ulogd_log(ULOGD_DEBUG, "%u fields in table\n", upi->input.num_keys);
-
- upi->input.keys = calloc(upi->input.num_keys, sizeof(*upi->input.keys));
- if (!upi->input.keys) {
- upi->input.num_keys = 0;
- ulogd_log(ULOGD_ERROR, "ENOMEM\n");
- dbi_result_free(pi->result);
- return -ENOMEM;
- }
-
- for (ui=1; ui<=upi->input.num_keys; ui++) {
- const char *field_name = dbi_result_get_field_name(pi->result, ui);
- char *cp;
+ /* ID is a sequence */
+ if (!rv)
+ upi->input.keys[0].flags |= ULOGD_KEYF_INACTIVE;
- if (!field_name)
- break;
+ dbi_result_free(pi->result);
+ return rv;
+}
- snprintf(upi->input.keys[ui - 1].name,
- sizeof(upi->input.keys[ui - 1].name),
- "%s", field_name);
+static const char *
+get_column_dbi(void *vp, unsigned int i)
+{
+ dbi_result result = vp;
- /* down-case and replace all underscores with dots */
- for (cp = upi->input.keys[ui - 1].name; *cp; cp++) {
- if (*cp == '_')
- *cp = '.';
- else
- *cp = tolower(*cp);
- }
+ return dbi_result_get_field_name(result, i + 1);
+}
- DEBUGP("field '%s' found: ", upi->input.keys[ui - 1].name);
+static char *
+format_key_dbi(char *key)
+{
+ char *cp;
+
+ /* down-case and replace all underscores with dots */
+ for (cp = key; *cp; cp++) {
+ if (*cp == '_')
+ *cp = '.';
+ else
+ *cp = tolower(*cp);
}
-
- /* ID is a sequence */
- upi->input.keys[0].flags |= ULOGD_KEYF_INACTIVE;
-
- dbi_result_free(pi->result);
-
- return 0;
+ return key;
}
static int close_db_dbi(struct ulogd_pluginstance *upi)
@@ -270,6 +261,8 @@ static int execute_dbi(struct ulogd_pluginstance *upi,
static struct db_driver db_driver_dbi = {
.get_columns = &get_columns_dbi,
+ .get_column = &get_column_dbi,
+ .format_key = &format_key_dbi,
.open_db = &open_db_dbi,
.close_db = &close_db_dbi,
.escape_string = &escape_string_dbi,
diff --git a/output/mysql/ulogd_output_MYSQL.c b/output/mysql/ulogd_output_MYSQL.c
index 5891207d5990..55059f5c189e 100644
--- a/output/mysql/ulogd_output_MYSQL.c
+++ b/output/mysql/ulogd_output_MYSQL.c
@@ -94,13 +94,13 @@ static struct config_keyset kset_mysql = {
#define user_ce(x) ((x)->ces[DB_CE_NUM + 2])
#define pass_ce(x) ((x)->ces[DB_CE_NUM + 3])
#define port_ce(x) ((x)->ces[DB_CE_NUM + 4])
+
/* find out which columns the table has */
static int get_columns_mysql(struct ulogd_pluginstance *upi)
{
struct mysql_instance *mi = (struct mysql_instance *) upi->private;
MYSQL_RES *result;
- MYSQL_FIELD *field;
- int i;
+ int rv;
if (!mi->dbh) {
ulogd_log(ULOGD_ERROR, "no database handle\n");
@@ -121,38 +121,23 @@ static int get_columns_mysql(struct ulogd_pluginstance *upi)
* in case the core just calls ->configure() and then aborts (and thus
* never free()s the memory we allocate here. FIXME. */
- /* Cleanup before reconnect */
- if (upi->input.keys)
- free(upi->input.keys);
-
- upi->input.num_keys = mysql_num_fields(result);
- ulogd_log(ULOGD_DEBUG, "%u fields in table\n", upi->input.num_keys);
- upi->input.keys = calloc(upi->input.num_keys, sizeof(*upi->input.keys));
- if (!upi->input.keys) {
- upi->input.num_keys = 0;
- ulogd_log(ULOGD_ERROR, "ENOMEM\n");
- return -ENOMEM;
- }
+ rv = ulogd_db_alloc_input_keys(upi, mysql_num_fields(result), result);
- for (i = 0; (field = mysql_fetch_field(result)); i++) {
- char *underscore;
+ /* MySQL Auto increment ... ID :) */
+ if (!rv)
+ upi->input.keys[0].flags |= ULOGD_KEYF_INACTIVE;
- snprintf(upi->input.keys[i].name,
- sizeof(upi->input.keys[i].name),
- "%s", field->name);
+ mysql_free_result(result);
+ return rv;
+}
- /* replace all underscores with dots */
- for (underscore = upi->input.keys[i].name;
- (underscore = strchr(underscore, '_')); )
- *underscore = '.';
+static const char *
+get_column_mysql(void *vp, unsigned int i __attribute__ ((unused)))
+{
+ MYSQL_RES *result = vp;
+ MYSQL_FIELD *field = mysql_fetch_field(result);
- DEBUGP("field '%s' found\n", upi->input.keys[i].name);
- }
- /* MySQL Auto increment ... ID :) */
- upi->input.keys[0].flags |= ULOGD_KEYF_INACTIVE;
-
- mysql_free_result(result);
- return 0;
+ return field->name;
}
static int close_db_mysql(struct ulogd_pluginstance *upi)
@@ -243,6 +228,7 @@ static int execute_mysql(struct ulogd_pluginstance *upi,
static struct db_driver db_driver_mysql = {
.get_columns = &get_columns_mysql,
+ .get_column = &get_column_mysql,
.open_db = &open_db_mysql,
.close_db = &close_db_mysql,
.escape_string = &escape_string_mysql,
diff --git a/output/pgsql/ulogd_output_PGSQL.c b/output/pgsql/ulogd_output_PGSQL.c
index bc0eae7558b3..c5bbc966d66d 100644
--- a/output/pgsql/ulogd_output_PGSQL.c
+++ b/output/pgsql/ulogd_output_PGSQL.c
@@ -137,7 +137,7 @@ static int get_columns_pgsql(struct ulogd_pluginstance *upi)
char pgbuf[strlen(PGSQL_GETCOLUMN_TEMPLATE_SCHEMA)
+ strlen(table_ce(upi->config_kset).u.string)
+ strlen(pi->db_inst.schema) + 2];
- int i;
+ int rv;
if (!pi->dbh) {
ulogd_log(ULOGD_ERROR, "no database handle\n");
@@ -170,40 +170,22 @@ static int get_columns_pgsql(struct ulogd_pluginstance *upi)
return -1;
}
- if (upi->input.keys)
- free(upi->input.keys);
-
- upi->input.num_keys = PQntuples(pi->pgres);
- ulogd_log(ULOGD_DEBUG, "%u fields in table\n", upi->input.num_keys);
- upi->input.keys = calloc(upi->input.num_keys, sizeof(*upi->input.keys));
- if (!upi->input.keys) {
- upi->input.num_keys = 0;
- ulogd_log(ULOGD_ERROR, "ENOMEM\n");
- PQclear(pi->pgres);
- return -ENOMEM;
- }
-
- for (i = 0; i < PQntuples(pi->pgres); i++) {
- char *underscore;
-
- snprintf(upi->input.keys[i].name,
- sizeof(upi->input.keys[i].name),
- "%s", PQgetvalue(pi->pgres, i, 0));
-
- /* replace all underscores with dots */
- for (underscore = upi->input.keys[i].name;
- (underscore = strchr(underscore, '_')); )
- *underscore = '.';
-
- DEBUGP("field '%s' found\n", upi->input.keys[i].name);
- }
+ rv = ulogd_db_alloc_input_keys(upi, PQntuples(pi->pgres), pi->pgres);
/* ID (starting by '.') is a sequence */
- if (upi->input.keys[0].name[0] == '.')
+ if (!rv && upi->input.keys[0].name[0] == '.')
upi->input.keys[0].flags |= ULOGD_KEYF_INACTIVE;
PQclear(pi->pgres);
- return 0;
+ return rv;
+}
+
+static const char *
+get_column_pgsql(void *vp, unsigned int i)
+{
+ PGresult *pgres = vp;
+
+ return PQgetvalue(pgres, i, 0);
}
static int close_db_pgsql(struct ulogd_pluginstance *upi)
@@ -320,6 +302,7 @@ static int execute_pgsql(struct ulogd_pluginstance *upi,
static struct db_driver db_driver_pgsql = {
.get_columns = &get_columns_pgsql,
+ .get_column = &get_column_pgsql,
.open_db = &open_db_pgsql,
.close_db = &close_db_pgsql,
.escape_string = &escape_string_pgsql,
diff --git a/util/db.c b/util/db.c
index 6749079697dc..4ec0af2ea38a 100644
--- a/util/db.c
+++ b/util/db.c
@@ -644,3 +644,51 @@ void ulogd_db_signal(struct ulogd_pluginstance *upi, int signal)
break;
}
}
+
+static char *
+_format_key(char *key)
+{
+ char *cp = key;
+
+ /* replace all underscores with dots */
+ while ((cp = strchr(cp, '_')))
+ *cp = '.';
+
+ return key;
+}
+
+int
+ulogd_db_alloc_input_keys(struct ulogd_pluginstance *upi,
+ unsigned int num_keys, void *arg)
+{
+ struct db_instance *di = (struct db_instance *) &upi->private;
+ char *(*format_key)(char *) = di->driver->format_key ? : _format_key;
+ unsigned int i;
+
+ if (upi->input.keys)
+ free(upi->input.keys);
+
+ upi->input.num_keys = num_keys;
+ ulogd_log(ULOGD_DEBUG, "%u fields in table\n", upi->input.num_keys);
+ upi->input.keys = calloc(upi->input.num_keys, sizeof(upi->input.keys[0]));
+ if (!upi->input.keys) {
+ upi->input.num_keys = 0;
+ ulogd_log(ULOGD_ERROR, "ENOMEM\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num_keys; i++) {
+ const char *col = di->driver->get_column(arg, i);
+
+ if (!col)
+ break;
+
+ snprintf(upi->input.keys[i].name,
+ sizeof(upi->input.keys[i].name),
+ "%s", col);
+
+ format_key(upi->input.keys[i].name);
+ }
+
+ return 0;
+}
--
2.35.1
next prev parent reply other threads:[~2022-11-29 21:59 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-29 21:47 [PATCH ulogd2 v2 v2 00/34] Refactor of the DB output plug-ins Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 01/34] ulogd: fix parse-error check Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 02/34] filter: fix buffer sizes in filter plug-ins Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 03/34] output: JSON: remove incorrect config value check Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 04/34] db: fix back-log capacity checks Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 05/34] build: add checks to configure.ac Jeremy Sowden
2022-11-30 10:04 ` Jan Engelhardt
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 06/34] src: remove some trailing white space Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 07/34] src: remove zero-valued config-key fields Jeremy Sowden
2022-11-30 10:21 ` Jan Engelhardt
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 08/34] src: parenthesize config-entry macro arguments Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 09/34] src: define constructors and destructors consistently Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 10/34] src: remove `TIME_ERR` macro Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 11/34] src: remove superfluous casts Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 12/34] conffile: replace malloc+strcpy with strdup Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 13/34] output: remove zero-initialized `struct ulogd_plugin` members Jeremy Sowden
2022-11-30 10:26 ` Jan Engelhardt
2022-11-29 21:47 ` Jeremy Sowden [this message]
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 15/34] db: reorganize source Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 16/34] db: use consistent integer return values to indicate errors Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 17/34] db: change return type of two functions to `void` Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 18/34] db: open-code `_loop_reconnect_db` Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 19/34] db: improve calculation of sql statement length Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 20/34] db: refactor configuration Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 21/34] db: refactor ring-buffer initialization Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 22/34] db: refactor ring-buffer Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 23/34] db: refactor backlog Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 24/34] db: use `struct db_stmt` objects more widely Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 25/34] db: synchronize access to ring-buffer Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 26/34] db: avoid cancelling ring-buffer thread Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 27/34] db, IP2BIN: defer formatting of raw strings Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 28/34] db: add prep & exec support Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 29/34] output: mysql: " Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 30/34] output: pgsql: remove a couple of struct members Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 31/34] output: pgsql: remove variable-length arrays Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 32/34] output: pgsql: tidy up `open_db_pgsql` and fix memory leak Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 33/34] output: pgsql: add prep & exec support Jeremy Sowden
2022-11-29 21:47 ` [PATCH ulogd2 v2 v2 34/34] output: sqlite3: reimplement using the common DB API Jeremy Sowden
2022-11-30 10:27 ` [PATCH ulogd2 v2 v2 00/34] Refactor of the DB output plug-ins Pablo Neira Ayuso
2022-11-30 16:03 ` Jeremy Sowden
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221129214749.247878-15-jeremy@azazel.net \
--to=jeremy@azazel.net \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).