driver-pgsql.c revision 9349a0afffad990e45d3ad33081e1d2d9e68a753
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2004-2010 Dovecot authors, see the included COPYING file */
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);
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainenextern const struct sql_result driver_pgsql_result;
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainenstatic void result_finish(struct pgsql_result *result);
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainenstatic void driver_pgsql_set_state(struct pgsql_db *db, enum sql_db_state state)
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen /* switch back to original ioloop in case the caller wants to
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainenstatic void driver_pgsql_stop_io(struct pgsql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_pgsql_close(struct pgsql_db *db)
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_DISCONNECTED);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* running a sync query, stop it */
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)
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen db->io = io_add(PQsocket(db->pg), io_dir, connect_callback, db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_info("pgsql: Connected to %s", PQdb(db->pg));
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_IDLE);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* driver_pgsql_sync_init() waiting for connection to
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_pgsql_connect_timeout(struct pgsql_db *db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int secs = ioloop_time - db->api.last_connect_try;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_error("pgsql: Connect failed to %s: Timeout after %u seconds",
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainenstatic int driver_pgsql_connect(struct sql_db *_db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_fatal("pgsql: PQconnectStart() failed (out of memory)");
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* nonblocking connecting begins. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->to_connect = timeout_add(SQL_CONNECT_TIMEOUT_SECS * 1000,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->io = io_add(PQsocket(db->pg), IO_WRITE, connect_callback, db);
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_CONNECTING);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_pgsql_disconnect(struct sql_db *_db)
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen if (db->cur_result != NULL && db->cur_result->to != NULL)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic struct sql_db *driver_pgsql_init_v(const char *connect_string)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connect_string = i_strdup(connect_string);
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen const char *const *arg = t_strsplit(connect_string, " ");
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void driver_pgsql_deinit_v(struct sql_db *_db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->cur_result != NULL && db->cur_result->to != NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_pgsql_set_idle(struct pgsql_db *db)
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_IDLE);
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;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* we're coming here from a user's sql_result_free() that's
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen being called from a callback. we'll do this later,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen so ignore. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen success = result->pgres != NULL && !db->fatal_error;
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)
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. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (PQstatus(db->pg) == CONNECTION_BAD || result->pgres == NULL ||
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen PQresultStatus(result->pgres) == PGRES_FATAL_ERROR)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen result->callback(&result->api, result->context);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen free_result = db->sync_result != &result->api;
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 */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void query_timeout(struct pgsql_result *result)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void do_query(struct pgsql_result *result, const char *query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen result->to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* failed to send query */
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_BUSY);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* write blocks */
13a8c553f293349248b161ff851743498916e26eTimo Sirainenstatic const char *
13a8c553f293349248b161ff851743498916e26eTimo Sirainendriver_pgsql_escape_string(struct sql_db *_db, const char *string)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->api.state == SQL_DB_STATE_DISCONNECTED) {
9fcf7b79236b0045f7709718f7b65ada516565e7Timo Sirainen /* try connecting again */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->api.state != SQL_DB_STATE_DISCONNECTED) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen len = PQescapeStringConn(db->pg, to, string, len, NULL);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void exec_callback(struct sql_result *_result,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_error("pgsql: sql_exec() failed: %s", last_error(db));
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_pgsql_exec(struct sql_db *db, const char *query)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_pgsql_query(struct sql_db *db, const char *query,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_query_callback_t *callback, void *context)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void pgsql_query_s_callback(struct sql_result *result, void *context)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_pgsql_sync_init(struct pgsql_db *db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert(db->api.state == SQL_DB_STATE_CONNECTING);
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen /* have to move our existing I/O and timeout handlers to new I/O loop */
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainen db->to_connect = timeout_add(SQL_CONNECT_TIMEOUT_SECS * 1000,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->io = io_add(PQsocket(db->pg), db->io_dir, connect_callback, db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* wait for connecting to finish */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_pgsql_sync_deinit(struct pgsql_db *db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic struct sql_result *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_pgsql_sync_query(struct pgsql_db *db, const char *query)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_pgsql_query(&db->api, query, pgsql_query_s_callback, db);
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. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic struct sql_result *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_pgsql_query_s(struct sql_db *_db, const char *query)
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,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (struct pgsql_transaction_context *)query->trans;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_result *pg_result = (struct pgsql_result *)result;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *query->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);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainencommit_multi_fail(struct pgsql_transaction_context *ctx,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ctx->error = t_strdup_printf("%s (query: %s)",
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic struct sql_result *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_pgsql_transaction_commit_multi(struct pgsql_transaction_context *ctx)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)ctx->ctx.db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen result = driver_pgsql_sync_query(db, "BEGIN");
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* send queries */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen for (query = ctx->ctx.head; query != NULL; query = query->next) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen result = driver_pgsql_sync_query(db, query->query);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return driver_pgsql_sync_query(db, ctx->failed ?
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_commit_s(struct sql_transaction_context *_ctx,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen const char **error_r)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_ctx->db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_transaction_query *single_query = NULL;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* nothing to be done */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* just a single query, send it */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen result = sql_query_s(_ctx->db, single_query->query);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* multiple queries, use a transaction */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen result = driver_pgsql_transaction_commit_multi(ctx);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_rollback(struct sql_transaction_context *_ctx)
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainendriver_pgsql_update(struct sql_transaction_context *_ctx, const char *query,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_transaction_add_query(_ctx, ctx->query_pool, query, affected_rows);