driver-pgsql.c revision b87761f9bbef949f31dae297e619ac3f5e9c2b2e
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2004-2015 Dovecot authors, see the included COPYING file */
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen unsigned char *value;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char **fields;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char **values;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct pgsql_binary_value) binary_values;
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainenextern const struct sql_result driver_pgsql_result;
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainenstatic void result_finish(struct pgsql_result *result);
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainenstatic const char *pgsql_prefix(struct pgsql_db *db)
ab1b9a793d57a60c230a41f65f1a25d52c026233Timo Sirainenstatic void driver_pgsql_set_state(struct pgsql_db *db, enum sql_db_state state)
6df2db16b3920346ed07cefb86e8bdcb7e1faec5Timo Sirainen i_assert(state == SQL_DB_STATE_BUSY || db->cur_result == NULL);
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)
1d132fe27d010b73aacc605b4c6257b0079f9e97Timo Sirainen i_error("%s: Connect failed to database %s: %s (state: %s)",
1d132fe27d010b73aacc605b4c6257b0079f9e97Timo Sirainen pgsql_prefix(db), PQdb(db->pg), last_error(db), db->connect_state);
f6e301cb2060c4367d8145e2bf5d553ba87ceb34Timo Sirainen db->io = io_add(PQsocket(db->pg), io_dir, connect_callback, db);
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;
1d132fe27d010b73aacc605b4c6257b0079f9e97Timo Sirainen i_error("%s: Connect failed: Timeout after %u seconds (state: %s)",
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainenstatic int driver_pgsql_connect(struct sql_db *_db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED);
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen i_fatal("%s: PQconnectStart() failed (out of memory)",
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen i_error("%s: Connect failed to database %s: %s",
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen pgsql_prefix(db), PQdb(db->pg), last_error(db));
a99b64f7d63812806ee40c2e8a347343fa3b84a7Timo Sirainen /* PQconnectStart() blocks on host name resolving. Log a warning if
a99b64f7d63812806ee40c2e8a347343fa3b84a7Timo Sirainen it takes too long. Also don't include time spent on that in the
a99b64f7d63812806ee40c2e8a347343fa3b84a7Timo Sirainen connect timeout (by refreshing ioloop time). */
a99b64f7d63812806ee40c2e8a347343fa3b84a7Timo Sirainen msecs = timeval_diff_msecs(&ioloop_timeval, &tv_start);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* nonblocking connecting begins. */
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen i_error("%s: PQsetnonblocking() failed", pgsql_prefix(db));
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)
af98c413eebe0c8c49fbe785fc34915c92ebe8c1Timo 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 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 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;
1856c361aad526948d56d8aafd576bca94516b92Timo Sirainen i_assert(!free_result || result->api.refcount > 0);
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)
f119596e34bc4a7ce374f4aa5f4f1eb12061a372Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen i_error("%s: Query timed out, aborting", pgsql_prefix(db));
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void do_query(struct pgsql_result *result, const char *query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
294c71436de227178c709e4d498e7be9b5d8d7feTimo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_BUSY);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen result->to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* failed to send query */
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) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen len = PQescapeStringConn(db->pg, to, string, len, &error);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void exec_callback(struct sql_result *_result,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen i_error("%s: sql_exec() failed: %s", pgsql_prefix(db), 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 */
36c4702131e5a04984ad5d07cf5d8d5c633d43c3Timo 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;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (str_to_uint(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);
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (str_to_uint(PQcmdTuples(pg_result->pgres),
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return driver_pgsql_sync_query(db, ctx->failed ?
a343811459d1d2259e668f369646a20f02301c2cTimo Sirainendriver_pgsql_try_commit_s(struct pgsql_transaction_context *ctx,
a343811459d1d2259e668f369646a20f02301c2cTimo Sirainen const char **error_r)
a343811459d1d2259e668f369646a20f02301c2cTimo Sirainen struct sql_transaction_context *_ctx = &ctx->ctx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_ctx->db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_transaction_query *single_query = NULL;
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);
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (str_to_uint(PQcmdTuples(pg_result->pgres),
a343811459d1d2259e668f369646a20f02301c2cTimo Sirainendriver_pgsql_transaction_commit_s(struct sql_transaction_context *_ctx,
a343811459d1d2259e668f369646a20f02301c2cTimo Sirainen const char **error_r)
a343811459d1d2259e668f369646a20f02301c2cTimo Sirainen struct pgsql_db *db = (struct pgsql_db *)_ctx->db;
a343811459d1d2259e668f369646a20f02301c2cTimo Sirainen if (_ctx->db->state == SQL_DB_STATE_DISCONNECTED) {
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);
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainenstatic const char *
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainendriver_pgsql_escape_blob(struct sql_db *_db ATTR_UNUSED,
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainenconst struct sql_result driver_pgsql_result = {