[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