driver-pgsql.c revision 7bafda1813454621e03615e83d55bccfa7cc56bd
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen#include "ioloop-internal.h" /* kind of dirty, but it should be fine.. */
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen unsigned char *value;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char **fields;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char **values;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen ARRAY_DEFINE(binary_values, struct pgsql_binary_value);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainendriver_pgsql_query_full(struct sql_db *db, const char *query,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen sql_query_callback_t *callback, void *context,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void queue_send_next(struct pgsql_db *db);
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainenstatic void result_finish(struct pgsql_result *result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_pgsql_close(struct pgsql_db *db)
a54fa00087ba926a3d966a8449d8d7579e89911cTimo Sirainen /* The fd may be closed before call to PQfinish() already,
a54fa00087ba926a3d966a8449d8d7579e89911cTimo Sirainen so use io_remove_closed(). */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *last_error(struct pgsql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *msg;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return "(no error set)";
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* Error message should contain trailing \n, we don't want it */
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void connect_callback(struct pgsql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen while ((ret = PQconnectPoll(db->pg)) == PGRES_POLLING_ACTIVE)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_info("pgsql: Connected to %s", PQdb(db->pg));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen io_add(PQsocket(db->pg), io_dir, connect_callback, db);
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainenstatic int driver_pgsql_connect(struct sql_db *_db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* don't try reconnecting more than once a second */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->connecting || db->last_connect == now)
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen return db->connected ? 1 : (db->connecting ? 0 : -1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_fatal("pgsql: PQconnectStart() failed (out of memory)");
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* nonblocking connecting begins. */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic struct sql_db *driver_pgsql_init_v(const char *connect_string)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connect_string = i_strdup(connect_string);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void driver_pgsql_deinit_v(struct sql_db *_db)
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainendriver_pgsql_get_flags(struct sql_db *db ATTR_UNUSED)
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void consume_results(struct pgsql_db *db)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void driver_pgsql_result_free(struct sql_result *_result)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* we'll have to read the rest of the results as well */
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (array_is_created(&result->binary_values)) {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen array_foreach_modifiable(&result->binary_values, value)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->queue != NULL && !db->querying && db->connected)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void result_finish(struct pgsql_result *result)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen /* if connection to server was lost, we don't yet see that the
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen connection is bad. we only see the fatal error, so assume it also
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen means disconnection. */
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen disconnected = PQstatus(db->pg) == CONNECTION_BAD ||
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen PQresultStatus(result->pgres) == PGRES_FATAL_ERROR;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen /* retry the query */
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen i_error("pgsql: Query failed, retrying: %s", last_error(db));
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen result->callback(&result->api, result->context);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen free_result = db->sync_result != &result->api;
b221779c191d1fb5fa7eb03907e62d39d1edeb08Timo Sirainen /* disconnected */
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen /* retry the query */
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen driver_pgsql_query_full(&db->api, result->query,
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void get_result(struct pgsql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void flush_callback(struct pgsql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* all flushed */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void send_query(struct pgsql_result *result, const char *query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* write blocks */
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainenstatic struct pgsql_queue *queue_unlink_first(struct pgsql_db *db)
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainenstatic void queue_send_next(struct pgsql_db *db)
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainenstatic void queue_abort_next(struct pgsql_db *db)
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen queue->result->callback(&sql_not_connected_result,
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainenstatic void queue_drop_timed_out_queries(struct pgsql_db *db)
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen db->queue->created + QUERY_TIMEOUT_SECS < ioloop_time)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_queue_query(struct pgsql_result *result, const char *query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->queue_to = timeout_add(5000, queue_timeout, db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void do_query(struct pgsql_result *result, const char *query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* only one query at a time */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* try connecting again */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* there's already queries queued, send them first */
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void exec_callback(struct sql_result *_result,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_error("pgsql: sql_exec() failed: %s", last_error(db));
13a8c553f293349248b161ff851743498916e26eTimo Sirainenstatic const char *
13a8c553f293349248b161ff851743498916e26eTimo Sirainendriver_pgsql_escape_string(struct sql_db *_db, const char *string)
9fcf7b79236b0045f7709718f7b65ada516565e7Timo Sirainen /* try connecting again */
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen len = PQescapeStringConn(db->pg, to, string, len, NULL);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void driver_pgsql_exec_full(struct sql_db *db, const char *query,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void driver_pgsql_exec(struct sql_db *db, const char *query)
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainendriver_pgsql_query_full(struct sql_db *db, const char *query,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen sql_query_callback_t *callback, void *context,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void driver_pgsql_query(struct sql_db *db, const char *query,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen sql_query_callback_t *callback, void *context)
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen driver_pgsql_query_full(db, query, callback, context, TRUE);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void pgsql_query_s_callback(struct sql_result *result, void *context)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic struct sql_result *
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_query_s(struct sql_db *_db, const char *query)
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen /* we're creating a new ioloop, make sure the timeout gets
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen added there. */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen /* have to move our existing I/O handler to new I/O loop */
510a871e2187891d538bf2ebb3cfd2056003af88Timo Sirainen db->io = io_add(PQsocket(db->pg), old_io.condition,
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen driver_pgsql_query(_db, query, pgsql_query_s_callback, db);
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen if ((db->connected || db->connecting) && db->io != NULL)
840a3701b7a0f7fadd17738998c33790a8dfad2dTimo Sirainen i_assert(db->sync_result == &sql_not_connected_result);
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen /* we don't end up in pgsql's free function, so sync_result
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen won't be set to NULL if we don't do it here. */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic int driver_pgsql_result_next_row(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* second time we're here */
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen /* end of this packet. see if there's more. FIXME: this may
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen block, but the current API doesn't provide a non-blocking
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen way to do this.. */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* no rows returned */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* nonfatal error */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* treat as fatal error */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_pgsql_result_fetch_fields(struct pgsql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int i;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* @UNSAFE */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->fields_count = PQnfields(result->pgres);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->fields = i_new(const char *, result->fields_count);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->fields[i] = PQfname(result->pgres, i);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic unsigned int
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_get_fields_count(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_get_field_name(struct sql_result *_result, unsigned int idx)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic int driver_pgsql_result_find_field(struct sql_result *_result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int i;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (strcmp(result->fields[i], field_name) == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_get_field_value(struct sql_result *_result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int idx)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (PQgetisnull(result->pgres, result->rownum, idx))
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return PQgetvalue(result->pgres, result->rownum, idx);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainenstatic const unsigned char *
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainendriver_pgsql_result_get_field_value_binary(struct sql_result *_result,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (PQgetisnull(result->pgres, result->rownum, idx)) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen value = PQgetvalue(result->pgres, result->rownum, idx);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (!array_is_created(&result->binary_values))
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen i_array_init(&result->binary_values, idx + 1);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen binary_value = array_idx_modifiable(&result->binary_values, idx);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_find_field_value(struct sql_result *result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen idx = driver_pgsql_result_find_field(result, field_name);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return driver_pgsql_result_get_field_value(result, idx);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *const *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_get_values(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int i;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->values = i_new(const char *, result->fields_count);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* @UNSAFE */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_result_get_field_value(_result, i);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *driver_pgsql_result_get_error(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *msg;
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen /* connection error */
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen return "(no error set)";
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen /* Error message should contain trailing \n, we don't want it */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_begin(struct sql_db *db)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen ctx = i_new(struct pgsql_transaction_context, 1);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* we need to be able to handle multiple open transactions, so at least
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen for now just keep them in memory until commit time. */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->query_pool = pool_alloconly_create("pgsql transaction", 1024);
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainendriver_pgsql_transaction_unref(struct pgsql_transaction_context *ctx)
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainentransaction_begin_callback(struct sql_result *result,
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainentransaction_commit_callback(struct sql_result *result,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen ctx->callback(sql_result_get_error(result), ctx->context);
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainentransaction_update_callback(struct sql_result *result,
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_transaction_context *ctx = list->ctx;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_result *pg_result = (struct pgsql_result *)result;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen *list->affected_rows = atoi(PQcmdTuples(pg_result->pgres));
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_commit(struct sql_transaction_context *_ctx,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen sql_commit_callback_t *callback, void *context)
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen callback(ctx->failed ? ctx->error : NULL, context);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* just a single query, send it */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* multiple queries, use a transaction */
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen sql_query(_ctx->db, "BEGIN", transaction_begin_callback, ctx);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen sql_query(_ctx->db, "COMMIT", transaction_commit_callback, ctx);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_commit_s(struct sql_transaction_context *_ctx,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen const char **error_r)
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* nothing to be done */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* just a single query, send it */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen result = sql_query_s(_ctx->db, ctx->head->query);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* multiple queries, use a transaction */
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen sql_query(_ctx->db, "BEGIN", transaction_begin_callback, ctx);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* flush the previous queries */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_rollback(struct sql_transaction_context *_ctx)
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainendriver_pgsql_update(struct sql_transaction_context *_ctx, const char *query,
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen list = p_new(ctx->query_pool, struct pgsql_query_list, 1);