Mercurial > dovecot > original-hg > dovecot-1.2
changeset 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 | 888916aeb353 |
children | e57b685ad093 |
files | src/lib-sql/driver-mysql.c src/lib-sql/driver-pgsql.c src/lib-sql/driver-sqlite.c src/lib-sql/sql-api-private.h src/lib-sql/sql-api.c src/lib-sql/sql-api.h |
diffstat | 6 files changed, 312 insertions(+), 79 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-sql/driver-mysql.c Tue Apr 03 08:11:48 2007 +0300 +++ b/src/lib-sql/driver-mysql.c Tue Apr 03 08:34:50 2007 +0300 @@ -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);
--- a/src/lib-sql/driver-pgsql.c Tue Apr 03 08:11:48 2007 +0300 +++ b/src/lib-sql/driver-pgsql.c Tue Apr 03 08:34:50 2007 +0300 @@ -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);
--- a/src/lib-sql/driver-sqlite.c Tue Apr 03 08:11:48 2007 +0300 +++ b/src/lib-sql/driver-sqlite.c Tue Apr 03 08:34:50 2007 +0300 @@ -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);
--- a/src/lib-sql/sql-api-private.h Tue Apr 03 08:11:48 2007 +0300 +++ b/src/lib-sql/sql-api-private.h Tue Apr 03 08:34:50 2007 +0300 @@ -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; };
--- 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 + } };
--- a/src/lib-sql/sql-api.h Tue Apr 03 08:11:48 2007 +0300 +++ b/src/lib-sql/sql-api.h Tue Apr 03 08:34:50 2007 +0300 @@ -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. */