Mercurial > dovecot > core-2.2
changeset 22354:b9a2a6135419
lib-sql: Add API support for asynchronously iterating over rows.
sql_query() can already do an async lookup, but the full result needs
to be available immediately. This can be inefficient for large results.
Add a new SQL_RESULT_NEXT_MORE return value and sql_result_more() for
asynchronously requesting more results.
This changes the API a bit, but isn't done by default by any drivers yet.
Also callers that can't handle this are hopefully checking for "ret < 0",
which allows them to handle such an async-more request as an error
instead.
sql_result_next_row() will be changed to return enum in a separate commit to
keep backwards compatibility in v2.2.x.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Mon, 17 Jul 2017 14:22:35 +0300 |
parents | be6d20b5644f |
children | d950ffd7cbe0 |
files | src/lib-sql/driver-cassandra.c 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 | 7 files changed, 66 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-sql/driver-cassandra.c Thu Jul 06 12:40:33 2017 +0300 +++ b/src/lib-sql/driver-cassandra.c Mon Jul 17 14:22:35 2017 +0300 @@ -1511,7 +1511,8 @@ driver_cassandra_result_get_field_value_binary, driver_cassandra_result_find_field_value, driver_cassandra_result_get_values, - driver_cassandra_result_get_error + driver_cassandra_result_get_error, + NULL, } };
--- a/src/lib-sql/driver-mysql.c Thu Jul 06 12:40:33 2017 +0300 +++ b/src/lib-sql/driver-mysql.c Mon Jul 17 14:22:35 2017 +0300 @@ -694,7 +694,8 @@ driver_mysql_result_get_field_value_binary, driver_mysql_result_find_field_value, driver_mysql_result_get_values, - driver_mysql_result_get_error + driver_mysql_result_get_error, + NULL, } }; @@ -709,7 +710,8 @@ driver_mysql_result_free, driver_mysql_result_error_next_row, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - driver_mysql_result_get_error + driver_mysql_result_get_error, + NULL, }, .failed_try_retry = TRUE };
--- a/src/lib-sql/driver-pgsql.c Thu Jul 06 12:40:33 2017 +0300 +++ b/src/lib-sql/driver-pgsql.c Mon Jul 17 14:22:35 2017 +0300 @@ -1181,7 +1181,8 @@ driver_pgsql_result_get_field_value_binary, driver_pgsql_result_find_field_value, driver_pgsql_result_get_values, - driver_pgsql_result_get_error + driver_pgsql_result_get_error, + NULL, } };
--- a/src/lib-sql/driver-sqlite.c Thu Jul 06 12:40:33 2017 +0300 +++ b/src/lib-sql/driver-sqlite.c Mon Jul 17 14:22:35 2017 +0300 @@ -441,7 +441,8 @@ driver_sqlite_result_get_field_value_binary, driver_sqlite_result_find_field_value, driver_sqlite_result_get_values, - driver_sqlite_result_get_error + driver_sqlite_result_get_error, + NULL, } }; @@ -456,7 +457,8 @@ driver_sqlite_result_free, driver_sqlite_result_error_next_row, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - driver_sqlite_result_get_error + driver_sqlite_result_get_error, + NULL, } };
--- a/src/lib-sql/sql-api-private.h Thu Jul 06 12:40:33 2017 +0300 +++ b/src/lib-sql/sql-api-private.h Mon Jul 17 14:22:35 2017 +0300 @@ -126,6 +126,8 @@ const char *const *(*get_values)(struct sql_result *result); const char *(*get_error)(struct sql_result *result); + void (*more)(struct sql_result **result, bool async, + sql_query_callback_t *callback, void *context); }; struct sql_field_map {
--- a/src/lib-sql/sql-api.c Thu Jul 06 12:40:33 2017 +0300 +++ b/src/lib-sql/sql-api.c Mon Jul 17 14:22:35 2017 +0300 @@ -278,6 +278,30 @@ return 1; } +#undef sql_result_more +void sql_result_more(struct sql_result **result, + sql_query_callback_t *callback, void *context) +{ + i_assert((*result)->v.more != NULL); + + (*result)->v.more(result, TRUE, callback, context); +} + +static void +sql_result_more_sync_callback(struct sql_result *result, void *context) +{ + struct sql_result **dest_result = context; + + *dest_result = result; +} + +void sql_result_more_s(struct sql_result **result) +{ + i_assert((*result)->v.more != NULL); + + (*result)->v.more(result, FALSE, sql_result_more_sync_callback, result); +} + unsigned int sql_result_get_fields_count(struct sql_result *result) { return result->v.get_fields_count(result); @@ -480,7 +504,8 @@ sql_result_not_connected_free, sql_result_not_connected_next_row, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - sql_result_not_connected_get_error + sql_result_not_connected_get_error, + NULL, }, .failed_try_retry = TRUE };
--- a/src/lib-sql/sql-api.h Thu Jul 06 12:40:33 2017 +0300 +++ b/src/lib-sql/sql-api.h Mon Jul 17 14:22:35 2017 +0300 @@ -31,6 +31,17 @@ SQL_RESULT_ERROR_TYPE_WRITE_UNCERTAIN }; +enum sql_result_next { + /* Row was returned */ + SQL_RESULT_NEXT_OK = 1, + /* There are no more rows */ + SQL_RESULT_NEXT_LAST = 0, + /* Error occurred - see sql_result_get_error*() */ + SQL_RESULT_NEXT_ERROR = -1, + /* There are more results - call sql_result_more() */ + SQL_RESULT_NEXT_MORE = -99 +}; + #define SQL_DEF_STRUCT(name, struct_name, type, c_type) \ { (type) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \ ((struct struct_name *)0)->name, c_type), \ @@ -106,10 +117,23 @@ 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. */ +/* Go to next row. See enum sql_result_next. */ int sql_result_next_row(struct sql_result *result); +/* If sql_result_next_row() returned SQL_RESULT_NEXT_MORE, this can be called + to continue returning more results. The result is freed with this call, so + it must not be accesed anymore until the callback is finished. */ +void sql_result_more(struct sql_result **result, + sql_query_callback_t *callback, void *context); +#define sql_result_more(result, callback, context) \ + sql_result_more(result + \ + CALLBACK_TYPECHECK(callback, void (*)( \ + struct sql_result *, typeof(context))), \ + (sql_query_callback_t *)callback, context) +/* Synchronous version of sql_result_more(). The result will be replaced with + the new result. */ +void sql_result_more_s(struct sql_result **result); + void sql_result_ref(struct sql_result *result); /* Needs to be called only with sql_query_s() or when result has been explicitly referenced. */