diff src/lib-sql/sql-api.c @ 5496:72ee0521dfaf HEAD

Added sql_result_setup_fetch() which makes it easier to fetch rows into structures. Added sql_result_get_field_value_binary(), which is currently not implemented for MySQL.
author Timo Sirainen <tss@iki.fi>
date Tue, 03 Apr 2007 08:34:50 +0300
parents 204d7edc7cdc
children 6a64e64fa3a3
line wrap: on
line diff
--- a/src/lib-sql/sql-api.c	Tue Apr 03 08:11:48 2007 +0300
+++ b/src/lib-sql/sql-api.c	Tue Apr 03 08:34:50 2007 +0300
@@ -4,6 +4,8 @@
 #include "array.h"
 #include "sql-api-private.h"
 
+#include <stdlib.h>
+
 ARRAY_TYPE(sql_drivers) sql_drivers;
 
 void sql_drivers_init(void)
@@ -90,50 +92,170 @@
 
 void sql_result_free(struct sql_result *result)
 {
-	result->free(result);
+	i_free(result->map);
+	result->v.free(result);
+}
+
+static const struct sql_field_def *
+sql_field_def_find(const struct sql_field_def *fields, const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; fields[i].name != NULL; i++) {
+		if (strcasecmp(fields[i].name, name) == 0)
+			return &fields[i];
+	}
+	return NULL;
+}
+
+static void
+sql_result_build_map(struct sql_result *result,
+		     const struct sql_field_def *fields, size_t dest_size)
+{
+	const struct sql_field_def *def;
+	const char *name;
+	unsigned int i, count, field_size = 0;
+
+	count = sql_result_get_fields_count(result);
+
+	result->map_size = count;
+	result->map = i_new(struct sql_field_map, result->map_size);
+	for (i = 0; i < count; i++) {
+		name = sql_result_get_field_name(result, i);
+		def = sql_field_def_find(fields, name);
+		if (def != NULL) {
+			result->map[i].type = def->type;
+			result->map[i].offset = def->offset;
+			switch (def->type) {
+			case SQL_TYPE_STR:
+				field_size = sizeof(const char *);
+				break;
+			case SQL_TYPE_UINT:
+				field_size = sizeof(unsigned int);
+				break;
+			case SQL_TYPE_ULLONG:
+				field_size = sizeof(unsigned long long);
+				break;
+			case SQL_TYPE_BOOL:
+				field_size = sizeof(bool);
+				break;
+			}
+			i_assert(def->offset + field_size <= dest_size);
+		} else {
+			result->map[i].offset = (size_t)-1;
+		}
+	}
+}
+
+void sql_result_setup_fetch(struct sql_result *result,
+			    const struct sql_field_def *fields,
+			    void *dest, size_t dest_size)
+{
+	if (result->map == NULL)
+		sql_result_build_map(result, fields, dest_size);
+	result->fetch_dest = dest;
+	result->fetch_dest_size = dest_size;
+}
+
+static void sql_result_fetch(struct sql_result *result)
+{
+	unsigned int i, count;
+	const char *value;
+	void *ptr;
+
+	memset(result->fetch_dest, 0, result->fetch_dest_size);
+	count = result->map_size;
+	for (i = 0; i < count; i++) {
+		if (result->map[i].offset == (size_t)-1)
+			continue;
+
+		value = sql_result_get_field_value(result, i);
+		ptr = STRUCT_MEMBER_P(result->fetch_dest,
+				      result->map[i].offset);
+
+		switch (result->map[i].type) {
+		case SQL_TYPE_STR: {
+			*((const char **)ptr) = value;
+			break;
+		}
+		case SQL_TYPE_UINT: {
+			if (value != NULL) {
+				*((unsigned int *)ptr) =
+					strtoul(value, NULL, 10);
+			}
+			break;
+		}
+		case SQL_TYPE_ULLONG: {
+			if (value != NULL) {
+				*((unsigned long long *)ptr) =
+					strtoull(value, NULL, 10);
+			}
+			break;
+		}
+		case SQL_TYPE_BOOL: {
+			if (value != NULL && (*value == 't' || *value == '1'))
+				*((bool *)ptr) = TRUE;
+			break;
+		}
+		}
+	}
 }
 
 int sql_result_next_row(struct sql_result *result)
 {
-	return result->next_row(result);
+	int ret;
+
+	if ((ret = result->v.next_row(result)) <= 0)
+		return ret;
+
+	if (result->fetch_dest != NULL)
+		sql_result_fetch(result);
+	return 1;
 }
 
 unsigned int sql_result_get_fields_count(struct sql_result *result)
 {
-	return result->get_fields_count(result);
+	return result->v.get_fields_count(result);
 }
 
 const char *sql_result_get_field_name(struct sql_result *result,
 				      unsigned int idx)
 {
-	return result->get_field_name(result, idx);
+	return result->v.get_field_name(result, idx);
 }
 
 int sql_result_find_field(struct sql_result *result, const char *field_name)
 {
-	return result->find_field(result, field_name);
+	return result->v.find_field(result, field_name);
 }
 
 const char *sql_result_get_field_value(struct sql_result *result,
 				       unsigned int idx)
 {
-	return result->get_field_value(result, idx);
+	return result->v.get_field_value(result, idx);
+}
+
+const unsigned char *
+sql_result_get_field_value_binary(struct sql_result *result,
+				  unsigned int idx, size_t *size_r)
+{
+	return result->v.get_field_value_binary(result, idx, size_r);
 }
 
 const char *sql_result_find_field_value(struct sql_result *result,
 					const char *field_name)
 {
-	return result->find_field_value(result, field_name);
+	return result->v.find_field_value(result, field_name);
 }
 
 const char *const *sql_result_get_values(struct sql_result *result)
 {
-	return result->get_values(result);
+	return result->v.get_values(result);
 }
 
 const char *sql_result_get_error(struct sql_result *result)
 {
-	return result->get_error(result);
+	return result->v.get_error(result);
 }
 
 static void
@@ -191,12 +313,10 @@
 }
 
 struct sql_result sql_not_connected_result = {
-	NULL,
-
-	sql_result_not_connected_free,
-	sql_result_not_connected_next_row,
-	NULL, NULL, NULL, NULL, NULL, NULL,
-	sql_result_not_connected_get_error,
-
-	FALSE
+	MEMBER(v) {
+		sql_result_not_connected_free,
+		sql_result_not_connected_next_row,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		sql_result_not_connected_get_error
+	}
 };