[dovecot-cvs] dovecot/src/lib-sql driver-mysql.c, 1.25, 1.26 driver-pgsql.c, 1.20, 1.21 driver-sqlite.c, 1.8, 1.9 sql-api-private.h, 1.9, 1.10 sql-api.c, 1.14, 1.15 sql-api.h, 1.13, 1.14

tss at dovecot.org tss at dovecot.org
Tue Apr 3 08:34:52 EEST 2007


Update of /var/lib/cvs/dovecot/src/lib-sql
In directory talvi:/tmp/cvs-serv8813

Modified Files:
	driver-mysql.c driver-pgsql.c driver-sqlite.c 
	sql-api-private.h sql-api.c sql-api.h 
Log Message:
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.



Index: driver-mysql.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-sql/driver-mysql.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- driver-mysql.c	10 Sep 2006 12:48:22 -0000	1.25
+++ driver-mysql.c	3 Apr 2007 05:34:50 -0000	1.26
@@ -520,6 +520,14 @@
 	return (const char *)result->row[idx];
 }
 
+static const unsigned char *
+driver_mysql_result_get_field_value_binary(struct sql_result *_result,
+					   unsigned int idx, size_t *size_r)
+{
+	// FIXME
+	return NULL;
+}
+
 static const char *
 driver_mysql_result_find_field_value(struct sql_result *result,
 				     const char *field_name)
@@ -667,19 +675,18 @@
 };
 
 struct sql_result driver_mysql_result = {
-	NULL,
-
-	driver_mysql_result_free,
-	driver_mysql_result_next_row,
-	driver_mysql_result_get_fields_count,
-	driver_mysql_result_get_field_name,
-	driver_mysql_result_find_field,
-	driver_mysql_result_get_field_value,
-	driver_mysql_result_find_field_value,
-	driver_mysql_result_get_values,
-	driver_mysql_result_get_error,
-
-	FALSE
+	MEMBER(v) {
+		driver_mysql_result_free,
+		driver_mysql_result_next_row,
+		driver_mysql_result_get_fields_count,
+		driver_mysql_result_get_field_name,
+		driver_mysql_result_find_field,
+		driver_mysql_result_get_field_value,
+		driver_mysql_result_get_field_value_binary,
+		driver_mysql_result_find_field_value,
+		driver_mysql_result_get_values,
+		driver_mysql_result_get_error
+	}
 };
 
 static int
@@ -689,14 +696,12 @@
 }
 
 struct sql_result driver_mysql_error_result = {
-	NULL,
-
-	driver_mysql_result_free,
-	driver_mysql_result_error_next_row,
-	NULL, NULL, NULL, NULL, NULL, NULL,
-	driver_mysql_result_get_error,
-
-	FALSE
+	MEMBER(v) {
+		driver_mysql_result_free,
+		driver_mysql_result_error_next_row,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		driver_mysql_result_get_error
+	}
 };
 
 void driver_mysql_init(void);

Index: driver-pgsql.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-sql/driver-pgsql.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- driver-pgsql.c	3 Apr 2007 05:11:48 -0000	1.20
+++ driver-pgsql.c	3 Apr 2007 05:34:50 -0000	1.21
@@ -1,6 +1,7 @@
 /* Copyright (C) 2004 Timo Sirainen */
 
 #include "lib.h"
+#include "array.h"
 #include "ioloop.h"
 #include "ioloop-internal.h" /* kind of dirty, but it should be fine.. */
 #include "sql-api-private.h"
@@ -34,6 +35,11 @@
 	unsigned int query_finished:1;
 };
 
+struct pgsql_binary_value {
+	unsigned char *value;
+	size_t size;
+};
+
 struct pgsql_result {
 	struct sql_result api;
 	PGresult *pgres;
@@ -43,6 +49,8 @@
 	const char **fields;
 	const char **values;
 
+	ARRAY_DEFINE(binary_values, struct pgsql_binary_value);
+
 	sql_query_callback_t *callback;
 	void *context;
 };
@@ -249,6 +257,16 @@
 		db->querying = FALSE;
 	}
 
+	if (array_is_created(&result->binary_values)) {
+		struct pgsql_binary_value *values;
+		unsigned int i, count;
+
+		values = array_get_modifiable(&result->binary_values, &count);
+		for (i = 0; i < count; i++)
+			PQfreemem(values[i].value);
+		array_free(&result->binary_values);
+	}
+
 	i_free(result->fields);
 	i_free(result->values);
 	i_free(result);
@@ -620,6 +638,35 @@
 	return PQgetvalue(result->pgres, result->rownum, idx);
 }
 
+static const unsigned char *
+driver_pgsql_result_get_field_value_binary(struct sql_result *_result,
+					   unsigned int idx, size_t *size_r)
+{
+	struct pgsql_result *result = (struct pgsql_result *)_result;
+	const char *value;
+	struct pgsql_binary_value *binary_value;
+
+	if (PQgetisnull(result->pgres, result->rownum, idx)) {
+		*size_r = 0;
+		return NULL;
+	}
+
+	value = PQgetvalue(result->pgres, result->rownum, idx);
+
+	if (!array_is_created(&result->binary_values))
+		i_array_init(&result->binary_values, idx + 1);
+
+	binary_value = array_idx_modifiable(&result->binary_values, idx);
+	if (binary_value->value == NULL) {
+		binary_value->value =
+			PQunescapeBytea((const unsigned char *)value,
+					&binary_value->size);
+	}
+
+	*size_r = binary_value->size;
+	return binary_value->value;
+}
+
 static const char *
 driver_pgsql_result_find_field_value(struct sql_result *result,
 				     const char *field_name)
@@ -807,19 +854,18 @@
 };
 
 struct sql_result driver_pgsql_result = {
-	NULL,
-
-	driver_pgsql_result_free,
-	driver_pgsql_result_next_row,
-	driver_pgsql_result_get_fields_count,
-	driver_pgsql_result_get_field_name,
-	driver_pgsql_result_find_field,
-	driver_pgsql_result_get_field_value,
-	driver_pgsql_result_find_field_value,
-	driver_pgsql_result_get_values,
-	driver_pgsql_result_get_error,
-
-	FALSE
+	MEMBER(v) {
+		driver_pgsql_result_free,
+		driver_pgsql_result_next_row,
+		driver_pgsql_result_get_fields_count,
+		driver_pgsql_result_get_field_name,
+		driver_pgsql_result_find_field,
+		driver_pgsql_result_get_field_value,
+		driver_pgsql_result_get_field_value_binary,
+		driver_pgsql_result_find_field_value,
+		driver_pgsql_result_get_values,
+		driver_pgsql_result_get_error
+	}
 };
 
 void driver_pgsql_init(void);

Index: driver-sqlite.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-sql/driver-sqlite.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- driver-sqlite.c	1 Jul 2006 17:24:11 -0000	1.8
+++ driver-sqlite.c	3 Apr 2007 05:34:50 -0000	1.9
@@ -130,7 +130,7 @@
 }
 
 static void driver_sqlite_query(struct sql_db *db, const char *query,
-			       sql_query_callback_t *callback, void *context)
+				sql_query_callback_t *callback, void *context)
 {
 	struct sql_result *result;
 
@@ -233,13 +233,23 @@
 
 static const char *
 driver_sqlite_result_get_field_value(struct sql_result *_result,
-				    unsigned int idx)
+				     unsigned int idx)
 {
 	struct sqlite_result *result = (struct sqlite_result *)_result;
 
 	return (const char*)sqlite3_column_text(result->stmt, idx);
 }
 
+static const unsigned char *
+driver_sqlite_result_get_field_value_binary(struct sql_result *_result,
+					    unsigned int idx, size_t *size_r)
+{
+	struct sqlite_result *result = (struct sqlite_result *)_result;
+
+	*size_r = sqlite3_column_bytes(result->stmt, idx);
+	return sqlite3_column_blob(result->stmt, idx);
+}
+
 static const char *
 driver_sqlite_result_find_field_value(struct sql_result *result,
 				     const char *field_name)
@@ -381,19 +391,18 @@
 };
 
 struct sql_result driver_sqlite_result = {
-	NULL,
-
-	driver_sqlite_result_free,
-	driver_sqlite_result_next_row,
-	driver_sqlite_result_get_fields_count,
-	driver_sqlite_result_get_field_name,
-	driver_sqlite_result_find_field,
-	driver_sqlite_result_get_field_value,
-	driver_sqlite_result_find_field_value,
-	driver_sqlite_result_get_values,
-	driver_sqlite_result_get_error,
-
-	FALSE
+	MEMBER(v) {
+		driver_sqlite_result_free,
+		driver_sqlite_result_next_row,
+		driver_sqlite_result_get_fields_count,
+		driver_sqlite_result_get_field_name,
+		driver_sqlite_result_find_field,
+		driver_sqlite_result_get_field_value,
+		driver_sqlite_result_get_field_value_binary,
+		driver_sqlite_result_find_field_value,
+		driver_sqlite_result_get_values,
+		driver_sqlite_result_get_error
+	}
 };
 
 static int
@@ -403,14 +412,12 @@
 }
 
 struct sql_result driver_sqlite_error_result = {
-	NULL,
-
-	driver_sqlite_result_free,
-	driver_sqlite_result_error_next_row,
-	NULL, NULL, NULL, NULL, NULL, NULL,
-	driver_sqlite_result_get_error,
-
-	FALSE
+	MEMBER(v) {
+		driver_sqlite_result_free,
+		driver_sqlite_result_error_next_row,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		driver_sqlite_result_get_error
+	}
 };
 
 void driver_sqlite_init(void);

Index: sql-api-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-sql/sql-api-private.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- sql-api-private.h	1 Jul 2006 17:24:11 -0000	1.9
+++ sql-api-private.h	3 Apr 2007 05:34:50 -0000	1.10
@@ -29,9 +29,7 @@
 	void (*update)(struct sql_transaction_context *ctx, const char *query);
 };
 
-struct sql_result {
-	struct sql_db *db;
-
+struct sql_result_vfuncs {
 	void (*free)(struct sql_result *result);
 	int (*next_row)(struct sql_result *result);
 
@@ -42,11 +40,32 @@
 
 	const char *(*get_field_value)(struct sql_result *result,
 				       unsigned int idx);
+	const unsigned char *
+		(*get_field_value_binary)(struct sql_result *result,
+					  unsigned int idx,
+					  size_t *size_r);
 	const char *(*find_field_value)(struct sql_result *result,
 					const char *field_name);
 	const char *const *(*get_values)(struct sql_result *result);
 
 	const char *(*get_error)(struct sql_result *result);
+};
+
+struct sql_field_map {
+	enum sql_field_type type;
+	size_t offset;
+};
+
+struct sql_result {
+	struct sql_result_vfuncs v;
+
+	struct sql_db *db;
+	const struct sql_field_def *fields;
+
+	unsigned int map_size;
+	struct sql_field_map *map;
+	void *fetch_dest;
+	size_t fetch_dest_size;
 
 	unsigned int callback:1;
 };

Index: sql-api.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-sql/sql-api.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- sql-api.c	15 Dec 2006 16:55:43 -0000	1.14
+++ sql-api.c	3 Apr 2007 05:34:50 -0000	1.15
@@ -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
+	}
 };

Index: sql-api.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-sql/sql-api.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- sql-api.h	15 Dec 2006 18:38:16 -0000	1.13
+++ sql-api.h	3 Apr 2007 05:34:50 -0000	1.14
@@ -9,6 +9,33 @@
 	SQL_DB_FLAG_BLOCKING		= 0x01
 };
 
+enum sql_field_type {
+	SQL_TYPE_STR,
+	SQL_TYPE_UINT,
+	SQL_TYPE_ULLONG,
+	SQL_TYPE_BOOL
+};
+
+struct sql_field_def {
+	enum sql_field_type type;
+	const char *name;
+	size_t offset;
+};
+
+#define SQL_DEF_STRUCT(name, struct_name, type, c_type) \
+	{ (type) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+		((struct struct_name *)0)->name, c_type), \
+	  #name, offsetof(struct struct_name, name) }
+
+#define SQL_DEF_STRUCT_STR(name, struct_name) \
+	SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_STR, const char *)
+#define SQL_DEF_STRUCT_UINT(name, struct_name) \
+	SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_UINT, unsigned int)
+#define SQL_DEF_STRUCT_ULLONG(name, struct_name) \
+	SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_ULLONG, unsigned long long)
+#define SQL_DEF_STRUCT_BOOL(name, struct_name) \
+	SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_BOOL, bool)
+
 struct sql_db;
 struct sql_result;
 
@@ -42,7 +69,9 @@
 
 /* Execute SQL query without waiting for results. */
 void sql_exec(struct sql_db *db, const char *query);
-/* Execute SQL query and return result in callback. */
+/* Execute SQL query and return result in callback. If fields list is given,
+   the returned fields are validated to be of correct type, and you can use
+   sql_result_next_row_get() */
 void sql_query(struct sql_db *db, const char *query,
 	       sql_query_callback_t *callback, void *context);
 #ifdef CONTEXT_TYPE_SAFETY
@@ -52,11 +81,15 @@
 		(sql_query_callback_t *)callback, context); })
 #else
 #  define sql_query(db, query, callback, context) \
-	  sql_query(db, query, (sql_query_callback_t *)callback, context)
+	sql_query(db, query, (sql_query_callback_t *)callback, context)
 #endif
 /* Execute blocking SQL query and return result. */
 struct sql_result *sql_query_s(struct sql_db *db, const char *query);
 
+void sql_result_setup_fetch(struct sql_result *result,
+			    const struct sql_field_def *fields,
+			    void *dest, size_t dest_size);
+
 /* Go to next row, returns 1 if ok, 0 if this was the last row or -1 if error
    occurred. This needs to be the first call for result. */
 int sql_result_next_row(struct sql_result *result);
@@ -75,6 +108,9 @@
 /* Returns value of given field as string. */
 const char *sql_result_get_field_value(struct sql_result *result,
 				       unsigned int idx);
+const unsigned char *
+sql_result_get_field_value_binary(struct sql_result *result,
+				  unsigned int idx, size_t *size_r);
 const char *sql_result_find_field_value(struct sql_result *result,
 					const char *field_name);
 /* Return all values of current row. */



More information about the dovecot-cvs mailing list