[PATCH ulogd2 v2 v2 19/34] db: improve calculation of sql statement length

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Currently, we calculate the space required from a prefix which doesn't
correspond to anything we use, space for each key, although the SQL
statement may not contain the keys, and a fixed amount for each value.
However, we can use snprintf to tighten up the estimate by using
`snprintf(NULL, 0, ...)` to tell us how much room we actually need for
the parts we know in advance.

Rename a couple of variables and replace `strlen` with `sizeof` where
appropriate.

Sort included headers.

Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx>
---
 util/db.c | 149 ++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 105 insertions(+), 44 deletions(-)

diff --git a/util/db.c b/util/db.c
index afa86a3f137b..ce1273638ae0 100644
--- a/util/db.c
+++ b/util/db.c
@@ -24,15 +24,16 @@
  *
  */
 
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
 #include <errno.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <time.h>
 #include <inttypes.h>
 #include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
 
 #include <ulogd/ulogd.h>
 #include <ulogd/db.h>
@@ -47,6 +48,10 @@ static void _stop_db(struct ulogd_pluginstance *upi);
 
 static char *_format_key(char *key);
 static int _create_sql_stmt(struct ulogd_pluginstance *upi);
+static unsigned int _calc_sql_stmt_size(const char *procedure,
+					const char *schema, const char *table,
+					struct ulogd_key *keys,
+					unsigned int num_keys);
 static void _bind_sql_stmt(struct ulogd_pluginstance *upi,
 			   char *stmt);
 
@@ -410,33 +415,23 @@ _format_key(char *key)
 	return key;
 }
 
-#define SQL_INSERTTEMPL   "SELECT P(Y)"
-#define SQL_VALSIZE	100
-
 /* create the static part of our insert statement */
 static int
 _create_sql_stmt(struct ulogd_pluginstance *upi)
 {
 	struct db_instance *di = (struct db_instance *) upi->private;
+	char *procedure = procedure_ce(upi->config_kset).u.string;
+	char *table = table_ce(upi->config_kset).u.string;
 	unsigned int size;
 	unsigned int i;
-	char *table = table_ce(upi->config_kset).u.string;
-	char *procedure = procedure_ce(upi->config_kset).u.string;
+	char *stmtp;
 
 	if (di->stmt)
 		free(di->stmt);
 
-	/* caclulate the size for the insert statement */
-	size = strlen(SQL_INSERTTEMPL) + strlen(table);
-
-	for (i = 0; i < upi->input.num_keys; i++) {
-		if (upi->input.keys[i].flags & ULOGD_KEYF_INACTIVE)
-			continue;
-		/* we need space for the key and a comma, as well as
-		 * enough space for the values */
-		size += strlen(upi->input.keys[i].name) + 1 + SQL_VALSIZE;
-	}
-	size += strlen(procedure);
+	/* calculate the size for the insert statement */
+	size = _calc_sql_stmt_size(procedure, di->schema, table,
+				   upi->input.keys, upi->input.num_keys);
 
 	ulogd_log(ULOGD_DEBUG, "allocating %u bytes for statement\n", size);
 
@@ -447,22 +442,22 @@ _create_sql_stmt(struct ulogd_pluginstance *upi)
 	}
 	di->ring.length = size + 1;
 
-	if (strncasecmp(procedure,"INSERT", strlen("INSERT")) == 0 &&
-	    (procedure[strlen("INSERT")] == '\0' ||
-			procedure[strlen("INSERT")] == ' ')) {
-		char *stmt_val = di->stmt;
+	stmtp = di->stmt;
+
+	if (strncasecmp(procedure, "INSERT", sizeof("INSERT") - 1) == 0 &&
+	    (procedure[sizeof("INSERT") - 1] == '\0' ||
+	     procedure[sizeof("INSERT") - 1] == ' ')) {
 
-		if(procedure[6] == '\0') {
+		if(procedure[sizeof("INSERT") - 1] == '\0') {
 			/* procedure == "INSERT" */
 			if (di->schema)
-				stmt_val += sprintf(stmt_val,
-						    "insert into %s.%s (",
-						    di->schema, table);
+				stmtp += sprintf(stmtp, "insert into %s.%s (",
+						di->schema, table);
 			else
-				stmt_val += sprintf(stmt_val,
-						    "insert into %s (", table);
+				stmtp += sprintf(stmtp, "insert into %s (",
+						table);
 		} else
-			stmt_val += sprintf(stmt_val, "%s (", procedure);
+			stmtp += sprintf(stmtp, "%s (", procedure);
 
 		for (i = 0; i < upi->input.num_keys; i++) {
 			char *underscore;
@@ -470,30 +465,96 @@ _create_sql_stmt(struct ulogd_pluginstance *upi)
 			if (upi->input.keys[i].flags & ULOGD_KEYF_INACTIVE)
 				continue;
 
-			underscore = stmt_val;
+			underscore = stmtp;
 
-			stmt_val += sprintf(stmt_val, "%s,",
-					    upi->input.keys[i].name);
+			stmtp += sprintf(stmtp, "%s,",
+					upi->input.keys[i].name);
 
 			while ((underscore = strchr(underscore, '.')))
 				*underscore = '_';
 		}
-		*(stmt_val - 1) = ')';
+		stmtp --;
 
-		sprintf(stmt_val, " values (");
-	} else if (strncasecmp(procedure,"CALL", strlen("CALL")) == 0) {
-		sprintf(di->stmt, "CALL %s(", procedure);
-	} else {
-		sprintf(di->stmt, "SELECT %s(", procedure);
-	}
+		stmtp += sprintf(stmtp, ") values (");
+
+	} else if (strncasecmp(procedure, "CALL", sizeof("CALL") - 1) == 0)
+		stmtp += sprintf(stmtp, "CALL %s(", procedure);
+	else
+		stmtp += sprintf(stmtp, "SELECT %s(", procedure);
 
-	di->stmt_offset = strlen(di->stmt);
+	di->stmt_offset = stmtp - di->stmt;
 
 	ulogd_log(ULOGD_DEBUG, "stmt='%s'\n", di->stmt);
 
 	return 0;
 }
 
+#define SQL_VALSIZE 100
+
+static unsigned int
+_calc_sql_stmt_size(const char *procedure,
+		    const char *schema, const char *table,
+		    struct ulogd_key *keys, unsigned int num_keys)
+{
+	unsigned int i, size = 0;
+	bool include_keys;
+
+	/* Fixed size bit */
+
+	if (strncasecmp(procedure, "INSERT", sizeof("INSERT") - 1) == 0 &&
+	    (procedure[sizeof("INSERT") - 1] == '\0' ||
+	     procedure[sizeof("INSERT") - 1] == ' ')) {
+
+		/* insert into t (k0, k1, ...) values (v0, v1, ...) */
+
+		if(procedure[sizeof("INSERT") - 1] == '\0') {
+			/* procedure == "INSERT" */
+			if (schema)
+				size += snprintf(NULL, 0,
+						 "insert into %s.%s (",
+						 schema, table);
+			else
+				size += snprintf(NULL, 0,
+						 "insert into %s (", table);
+		} else
+			size += snprintf(NULL, 0, "%s (", procedure);
+
+		size += snprintf(NULL, 0, ") values (");
+
+		include_keys = true;
+
+	} else {
+
+		/* `call p(v0, v1, ...)` or `select p(v0, v1, ...)` */
+
+		if (strncasecmp(procedure, "CALL", sizeof("CALL") - 1) == 0)
+			size += snprintf(NULL, 0, "CALL %s(", procedure);
+		else
+			size += snprintf(NULL, 0, "SELECT %s(", procedure);
+
+		include_keys = false;
+
+	}
+
+	/* Per-field bits.
+	 *
+	 * We need space for the value and a comma or the closing parenthesis.
+	 * We may also need space for the key and a comma.
+	 */
+
+	for (i = 0; i < num_keys; i++) {
+		if (keys[i].flags & ULOGD_KEYF_INACTIVE)
+			continue;
+		if (include_keys)
+			size += strlen(keys[i].name) + 1;
+		size += SQL_VALSIZE + 1;
+	}
+
+	size++; /* Allow for the final NUL */
+
+	return size;
+}
+
 static void
 _bind_sql_stmt(struct ulogd_pluginstance *upi, char *start)
 {
-- 
2.35.1




[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux