sql-api.c revision 1601169d6f6004e0656238ed7691c16f3aab61aa
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2004-2016 Dovecot authors, see the included COPYING file */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "lib.h"
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen#include "array.h"
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen#include "ioloop.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "sql-api-private.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen#include <time.h>
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
f69bd378b6454dc6498f7d35356ec651123e96a6Timo Sirainenstruct sql_db_module_register sql_db_module_register = { 0 };
8d80659e504ffb34bb0c6a633184fece35751b18Timo SirainenARRAY_TYPE(sql_drivers) sql_drivers;
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainenvoid sql_drivers_init(void)
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen{
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_array_init(&sql_drivers, 8);
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen}
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainenvoid sql_drivers_deinit(void)
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen{
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen array_free(&sql_drivers);
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen}
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainenstatic const struct sql_db *sql_driver_lookup(const char *name)
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen{
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen const struct sql_db *const *drivers;
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen unsigned int i, count;
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen drivers = array_get(&sql_drivers, &count);
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen for (i = 0; i < count; i++) {
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen if (strcmp(drivers[i]->name, name) == 0)
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen return drivers[i];
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen }
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen return NULL;
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen}
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainenvoid sql_driver_register(const struct sql_db *driver)
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen{
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen if (sql_driver_lookup(driver->name) != NULL) {
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen i_fatal("sql_driver_register(%s): Already registered",
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen driver->name);
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen }
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen array_append(&sql_drivers, &driver, 1);
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen}
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainenvoid sql_driver_unregister(const struct sql_db *driver)
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen{
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen const struct sql_db *const *drivers;
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen unsigned int i, count;
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen drivers = array_get(&sql_drivers, &count);
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen for (i = 0; i < count; i++) {
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen if (drivers[i] == driver) {
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen array_delete(&sql_drivers, i, 1);
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen break;
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen }
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen }
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstruct sql_db *sql_init(const char *db_driver, const char *connect_string)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sql_db *driver;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_db *db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert(connect_string != NULL);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
903507ced4fed650d36782a897e5a56a1978367aTimo Sirainen driver = sql_driver_lookup(db_driver);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (driver == NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_fatal("Unknown database driver '%s'", db_driver);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if ((driver->flags & SQL_DB_FLAG_POOLED) == 0)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db = driver->v.init(connect_string);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen else
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db = driver_sqlpool_init(connect_string, driver);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_array_init(&db->module_contexts, 5);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainenvoid sql_deinit(struct sql_db **_db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen struct sql_db *db = *_db;
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen *_db = NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->to_reconnect != NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen timeout_remove(&db->to_reconnect);
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen db->v.deinit(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainenenum sql_db_flags sql_get_flags(struct sql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return db->flags;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainenint sql_connect(struct sql_db *db)
a488bbb7e5d7cc537e7af21d1f651762a2b8bf56Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen time_t now;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen switch (db->state) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen case SQL_DB_STATE_DISCONNECTED:
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen break;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen case SQL_DB_STATE_CONNECTING:
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return 0;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen default:
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return 1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* don't try reconnecting more than once a second */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen now = time(NULL);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->last_connect_try + (time_t)db->connect_delay > now)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return -1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->last_connect_try = now;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen return db->v.connect(db);
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen}
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenvoid sql_disconnect(struct sql_db *db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->to_reconnect != NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen timeout_remove(&db->to_reconnect);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->v.disconnect(db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
13a8c553f293349248b161ff851743498916e26eTimo Sirainenconst char *sql_escape_string(struct sql_db *db, const char *string)
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen{
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen return db->v.escape_string(db, string);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen}
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainenconst char *sql_escape_blob(struct sql_db *db,
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen const unsigned char *data, size_t size)
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen{
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen return db->v.escape_blob(db, data, size);
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen}
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainenvoid sql_exec(struct sql_db *db, const char *query)
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen{
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen db->v.exec(db, query);
a488bbb7e5d7cc537e7af21d1f651762a2b8bf56Timo Sirainen}
a488bbb7e5d7cc537e7af21d1f651762a2b8bf56Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen#undef sql_query
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenvoid sql_query(struct sql_db *db, const char *query,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen sql_query_callback_t *callback, void *context)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen db->v.query(db, query, callback, context);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstruct sql_result *sql_query_s(struct sql_db *db, const char *query)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen return db->v.query_s(db, query);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainenvoid sql_result_ref(struct sql_result *result)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen result->refcount++;
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen}
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainenvoid sql_result_unref(struct sql_result *result)
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen{
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen i_assert(result->refcount > 0);
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen if (--result->refcount > 0)
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen return;
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen i_free(result->map);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen result->v.free(result);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen}
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainenstatic const struct sql_field_def *
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainensql_field_def_find(const struct sql_field_def *fields, const char *name)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen unsigned int i;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen for (i = 0; fields[i].name != NULL; i++) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (strcasecmp(fields[i].name, name) == 0)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return &fields[i];
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return NULL;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen}
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainenstatic void
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainensql_result_build_map(struct sql_result *result,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen const struct sql_field_def *fields, size_t dest_size)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen const struct sql_field_def *def;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen const char *name;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen unsigned int i, count, field_size = 0;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen count = sql_result_get_fields_count(result);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen result->map_size = count;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen result->map = i_new(struct sql_field_map, result->map_size);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen for (i = 0; i < count; i++) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen name = sql_result_get_field_name(result, i);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen def = sql_field_def_find(fields, name);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (def != NULL) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen result->map[i].type = def->type;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen result->map[i].offset = def->offset;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen switch (def->type) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen case SQL_TYPE_STR:
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen field_size = sizeof(const char *);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen break;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen case SQL_TYPE_UINT:
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen field_size = sizeof(unsigned int);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen break;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen case SQL_TYPE_ULLONG:
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen field_size = sizeof(unsigned long long);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen break;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen case SQL_TYPE_BOOL:
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen field_size = sizeof(bool);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen break;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen i_assert(def->offset + field_size <= dest_size);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen } else {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen result->map[i].offset = (size_t)-1;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen}
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainenvoid sql_result_setup_fetch(struct sql_result *result,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen const struct sql_field_def *fields,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen void *dest, size_t dest_size)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (result->map == NULL)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen sql_result_build_map(result, fields, dest_size);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen result->fetch_dest = dest;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen result->fetch_dest_size = dest_size;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen}
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainenstatic void sql_result_fetch(struct sql_result *result)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen unsigned int i, count;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen const char *value;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen void *ptr;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen memset(result->fetch_dest, 0, result->fetch_dest_size);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen count = result->map_size;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen for (i = 0; i < count; i++) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (result->map[i].offset == (size_t)-1)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen continue;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen value = sql_result_get_field_value(result, i);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen ptr = STRUCT_MEMBER_P(result->fetch_dest,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen result->map[i].offset);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen switch (result->map[i].type) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen case SQL_TYPE_STR: {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen *((const char **)ptr) = value;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen break;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen case SQL_TYPE_UINT: {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (value != NULL &&
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen str_to_uint(value, (unsigned int *)ptr) < 0)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_error("sql: Value not uint: %s", value);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen break;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen case SQL_TYPE_ULLONG: {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (value != NULL &&
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen str_to_ullong(value, (unsigned long long *)ptr) < 0)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_error("sql: Value not ullong: %s", value);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen break;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen case SQL_TYPE_BOOL: {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (value != NULL && (*value == 't' || *value == '1'))
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen *((bool *)ptr) = TRUE;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen break;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenint sql_result_next_row(struct sql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen int ret;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if ((ret = result->v.next_row(result)) <= 0)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return ret;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (result->fetch_dest != NULL)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen sql_result_fetch(result);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenunsigned int sql_result_get_fields_count(struct sql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return result->v.get_fields_count(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenconst char *sql_result_get_field_name(struct sql_result *result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int idx)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return result->v.get_field_name(result, idx);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenint sql_result_find_field(struct sql_result *result, const char *field_name)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return result->v.find_field(result, field_name);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenconst char *sql_result_get_field_value(struct sql_result *result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int idx)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return result->v.get_field_value(result, idx);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen}
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainenconst unsigned char *
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainensql_result_get_field_value_binary(struct sql_result *result,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen unsigned int idx, size_t *size_r)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return result->v.get_field_value_binary(result, idx, size_r);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenconst char *sql_result_find_field_value(struct sql_result *result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *field_name)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return result->v.find_field_value(result, field_name);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenconst char *const *sql_result_get_values(struct sql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return result->v.get_values(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenconst char *sql_result_get_error(struct sql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return result->v.get_error(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
1601169d6f6004e0656238ed7691c16f3aab61aaTimo Sirainenenum sql_result_error_type sql_result_get_error_type(struct sql_result *result)
1601169d6f6004e0656238ed7691c16f3aab61aaTimo Sirainen{
1601169d6f6004e0656238ed7691c16f3aab61aaTimo Sirainen return result->error_type;
1601169d6f6004e0656238ed7691c16f3aab61aaTimo Sirainen}
1601169d6f6004e0656238ed7691c16f3aab61aaTimo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainensql_result_not_connected_free(struct sql_result *result ATTR_UNUSED)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic int
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainensql_result_not_connected_next_row(struct sql_result *result ATTR_UNUSED)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return -1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainensql_result_not_connected_get_error(struct sql_result *result ATTR_UNUSED)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return SQL_ERRSTR_NOT_CONNECTED;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstruct sql_transaction_context *sql_transaction_begin(struct sql_db *db)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen return db->v.transaction_begin(db);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen#undef sql_transaction_commit
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid sql_transaction_commit(struct sql_transaction_context **_ctx,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen sql_commit_callback_t *callback, void *context)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct sql_transaction_context *ctx = *_ctx;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_ctx = NULL;
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen ctx->db->v.transaction_commit(ctx, callback, context);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenint sql_transaction_commit_s(struct sql_transaction_context **_ctx,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen const char **error_r)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct sql_transaction_context *ctx = *_ctx;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_ctx = NULL;
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen return ctx->db->v.transaction_commit_s(ctx, error_r);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid sql_transaction_rollback(struct sql_transaction_context **_ctx)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct sql_transaction_context *ctx = *_ctx;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_ctx = NULL;
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen ctx->db->v.transaction_rollback(ctx);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenvoid sql_update(struct sql_transaction_context *ctx, const char *query)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen ctx->db->v.update(ctx, query, NULL);
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen}
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainenvoid sql_update_get_rows(struct sql_transaction_context *ctx, const char *query,
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen unsigned int *affected_rows)
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen{
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen ctx->db->v.update(ctx, query, affected_rows);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenvoid sql_db_set_state(struct sql_db *db, enum sql_db_state state)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen enum sql_db_state old_state = db->state;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->state == state)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->state = state;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->state_change_callback != NULL) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->state_change_callback(db, old_state,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->state_change_context);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenvoid sql_transaction_add_query(struct sql_transaction_context *ctx, pool_t pool,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const char *query, unsigned int *affected_rows)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_transaction_query *tquery;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen tquery = p_new(pool, struct sql_transaction_query, 1);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen tquery->trans = ctx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen tquery->query = p_strdup(pool, query);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen tquery->affected_rows = affected_rows;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (ctx->head == NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ctx->head = tquery;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen else
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ctx->tail->next = tquery;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ctx->tail = tquery;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstruct sql_result sql_not_connected_result = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .v = {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen sql_result_not_connected_free,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen sql_result_not_connected_next_row,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen sql_result_not_connected_get_error
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen },
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen .failed_try_retry = TRUE
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen};