driver-pgsql.c revision 7cb128dc4cae2a03a742f63ba7afee23c78e3af0
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2004-2015 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned char *value;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char **fields;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char **values;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ARRAY(struct pgsql_binary_value) binary_values;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainenextern const struct sql_result driver_pgsql_result;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void result_finish(struct pgsql_result *result);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic const char *pgsql_prefix(struct pgsql_db *db)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainenstatic void driver_pgsql_set_state(struct pgsql_db *db, enum sql_db_state state)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(state == SQL_DB_STATE_BUSY || db->cur_result == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* switch back to original ioloop in case the caller wants to
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstatic void driver_pgsql_stop_io(struct pgsql_db *db)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstatic void driver_pgsql_close(struct pgsql_db *db)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_DISCONNECTED);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* running a sync query, stop it */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic const char *last_error(struct pgsql_db *db)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen const char *msg;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen return "(no error set)";
96c253a039f102fa78a313ee05200ab3970112dcTimo Sirainen /* Error message should contain trailing \n, we don't want it */
c3412ddeb9abc13f99d3caf50faf76cd99f7e9d2Timo Sirainenstatic void connect_callback(struct pgsql_db *db)
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen while ((ret = PQconnectPoll(db->pg)) == PGRES_POLLING_ACTIVE)
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen i_error("%s: Connect failed to database %s: %s",
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen pgsql_prefix(db), PQdb(db->pg), last_error(db));
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen db->io = io_add(PQsocket(db->pg), io_dir, connect_callback, db);
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_IDLE);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* driver_pgsql_sync_init() waiting for connection to
3f190f4cbb9233a3a6830956cb5c7ae56a577b79Timo Sirainenstatic void driver_pgsql_connect_timeout(struct pgsql_db *db)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen unsigned int secs = ioloop_time - db->api.last_connect_try;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen i_error("%s: Connect failed: Timeout after %u seconds",
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int driver_pgsql_connect(struct sql_db *_db)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_fatal("%s: PQconnectStart() failed (out of memory)",
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_error("%s: Connect failed to database %s: %s",
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen pgsql_prefix(db), PQdb(db->pg), last_error(db));
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* nonblocking connecting begins. */
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen i_error("%s: PQsetnonblocking() failed", pgsql_prefix(db));
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen db->to_connect = timeout_add(SQL_CONNECT_TIMEOUT_SECS * 1000,
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen db->io = io_add(PQsocket(db->pg), IO_WRITE, connect_callback, db);
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_CONNECTING);
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainenstatic void driver_pgsql_disconnect(struct sql_db *_db)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (db->cur_result != NULL && db->cur_result->to != NULL)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainenstatic struct sql_db *driver_pgsql_init_v(const char *connect_string)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen db->connect_string = i_strdup(connect_string);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const char *const *arg = t_strsplit(connect_string, " ");
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenstatic void driver_pgsql_deinit_v(struct sql_db *_db)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (db->cur_result != NULL && db->cur_result->to != NULL)
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainenstatic void driver_pgsql_set_idle(struct pgsql_db *db)
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_IDLE);
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainenstatic void consume_results(struct pgsql_db *db)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenstatic void driver_pgsql_result_free(struct sql_result *_result)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen /* we're coming here from a user's sql_result_free() that's
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen being called from a callback. we'll do this later,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen so ignore. */
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen success = result->pgres != NULL && !db->fatal_error;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* we'll have to read the rest of the results as well */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (array_is_created(&result->binary_values)) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen array_foreach_modifiable(&result->binary_values, value)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void result_finish(struct pgsql_result *result)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* if connection to server was lost, we don't yet see that the
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen connection is bad. we only see the fatal error, so assume it also
8af07808ba203f8709e2ff9eaf2291e1c4a4d53dTimo Sirainen means disconnection. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (PQstatus(db->pg) == CONNECTION_BAD || result->pgres == NULL ||
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen PQresultStatus(result->pgres) == PGRES_FATAL_ERROR)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen result->callback(&result->api, result->context);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen free_result = db->sync_result != &result->api;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenstatic void get_result(struct pgsql_result *result)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainenstatic void flush_callback(struct pgsql_result *result)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* all flushed */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void query_timeout(struct pgsql_result *result)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen i_error("%s: Query timed out, aborting", pgsql_prefix(db));
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic void do_query(struct pgsql_result *result, const char *query)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen driver_pgsql_set_state(db, SQL_DB_STATE_BUSY);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen result->to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen /* failed to send query */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen /* write blocks */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic const char *
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainendriver_pgsql_escape_string(struct sql_db *_db, const char *string)
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen if (db->api.state == SQL_DB_STATE_DISCONNECTED) {
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen /* try connecting again */
99be58a447b69d62cbd9e764000a06226b9c9c89Timo Sirainen if (db->api.state != SQL_DB_STATE_DISCONNECTED) {
bbc92cfb17eb71d2ee9463c9cfd70dfea9a36bb6Timo Sirainen len = PQescapeStringConn(db->pg, to, string, len, &error);
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainenstatic void exec_callback(struct sql_result *_result,
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen i_error("%s: sql_exec() failed: %s", pgsql_prefix(db), last_error(db));
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void driver_pgsql_exec(struct sql_db *db, const char *query)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void driver_pgsql_query(struct sql_db *db, const char *query,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen sql_query_callback_t *callback, void *context)
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainenstatic void pgsql_query_s_callback(struct sql_result *result, void *context)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void driver_pgsql_sync_init(struct pgsql_db *db)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(db->api.state == SQL_DB_STATE_CONNECTING);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* have to move our existing I/O and timeout handlers to new I/O loop */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen db->to_connect = timeout_add(SQL_CONNECT_TIMEOUT_SECS * 1000,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen db->io = io_add(PQsocket(db->pg), db->io_dir, connect_callback, db);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* wait for connecting to finish */
ff640b54224881abbc21141f217c881d6ba5cd28Timo Sirainenstatic void driver_pgsql_sync_deinit(struct pgsql_db *db)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic struct sql_result *
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainendriver_pgsql_sync_query(struct pgsql_db *db, const char *query)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen driver_pgsql_query(&db->api, query, pgsql_query_s_callback, db);
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen /* we don't end up in pgsql's free function, so sync_result
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen won't be set to NULL if we don't do it here. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic struct sql_result *
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainendriver_pgsql_query_s(struct sql_db *_db, const char *query)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int driver_pgsql_result_next_row(struct sql_result *_result)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* second time we're here */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* end of this packet. see if there's more. FIXME: this may
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen block, but the current API doesn't provide a non-blocking
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen way to do this.. */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* no rows returned */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* nonfatal error */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* treat as fatal error */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenstatic void driver_pgsql_result_fetch_fields(struct pgsql_result *result)
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen unsigned int i;
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen /* @UNSAFE */
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen result->fields_count = PQnfields(result->pgres);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen result->fields = i_new(const char *, result->fields_count);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen result->fields[i] = PQfname(result->pgres, i);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenstatic unsigned int
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainendriver_pgsql_result_get_fields_count(struct sql_result *_result)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenstatic const char *
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainendriver_pgsql_result_get_field_name(struct sql_result *_result, unsigned int idx)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int driver_pgsql_result_find_field(struct sql_result *_result,
d252f81a2ff1bdd5439f9d2b3df715b70a4bcd3dTimo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
3343a61404603b21c246783a7963b77833095f31Timo Sirainen unsigned int i;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (strcmp(result->fields[i], field_name) == 0)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic const char *
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainendriver_pgsql_result_get_field_value(struct sql_result *_result,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen unsigned int idx)
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
f1b7a02a05fbca580934c7312aae63ea9542aa79Timo Sirainen if (PQgetisnull(result->pgres, result->rownum, idx))
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return PQgetvalue(result->pgres, result->rownum, idx);
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainenstatic const unsigned char *
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainendriver_pgsql_result_get_field_value_binary(struct sql_result *_result,
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen if (PQgetisnull(result->pgres, result->rownum, idx)) {
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen value = PQgetvalue(result->pgres, result->rownum, idx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!array_is_created(&result->binary_values))
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_array_init(&result->binary_values, idx + 1);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen binary_value = array_idx_modifiable(&result->binary_values, idx);
6fd7c571326c61949ffc0f3ea565c3df04104235Timo Sirainenstatic const char *
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainendriver_pgsql_result_find_field_value(struct sql_result *result,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen idx = driver_pgsql_result_find_field(result, field_name);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return driver_pgsql_result_get_field_value(result, idx);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenstatic const char *const *
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainendriver_pgsql_result_get_values(struct sql_result *_result)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen unsigned int i;
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen result->values = i_new(const char *, result->fields_count);
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen /* @UNSAFE */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen driver_pgsql_result_get_field_value(_result, i);
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainenstatic const char *driver_pgsql_result_get_error(struct sql_result *_result)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen const char *msg;
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen /* connection error */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return "(no error set)";
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* Error message should contain trailing \n, we don't want it */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainendriver_pgsql_transaction_begin(struct sql_db *db)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen ctx = i_new(struct pgsql_transaction_context, 1);
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen /* we need to be able to handle multiple open transactions, so at least
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen for now just keep them in memory until commit time. */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen ctx->query_pool = pool_alloconly_create("pgsql transaction", 1024);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainendriver_pgsql_transaction_unref(struct pgsql_transaction_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainentransaction_begin_callback(struct sql_result *result,
3cfff0ca01961d885bdbd6ef08d761880116af07Timo Sirainentransaction_commit_callback(struct sql_result *result,
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen ctx->callback(sql_result_get_error(result), ctx->context);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainentransaction_update_callback(struct sql_result *result,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (struct pgsql_transaction_context *)query->trans;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen struct pgsql_result *pg_result = (struct pgsql_result *)result;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen *query->affected_rows = atoi(PQcmdTuples(pg_result->pgres));
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainendriver_pgsql_transaction_commit(struct sql_transaction_context *_ctx,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen sql_commit_callback_t *callback, void *context)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen callback(ctx->failed ? ctx->error : NULL, context);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* just a single query, send it */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* multiple queries, use a transaction */
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen sql_query(_ctx->db, "BEGIN", transaction_begin_callback, ctx);
99be58a447b69d62cbd9e764000a06226b9c9c89Timo Sirainen sql_query(_ctx->db, "COMMIT", transaction_commit_callback, ctx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainencommit_multi_fail(struct pgsql_transaction_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->error = t_strdup_printf("%s (query: %s)",
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic struct sql_result *
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainendriver_pgsql_transaction_commit_multi(struct pgsql_transaction_context *ctx)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)ctx->ctx.db;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen result = driver_pgsql_sync_query(db, "BEGIN");
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* send queries */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen for (query = ctx->ctx.head; query != NULL; query = query->next) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen result = driver_pgsql_sync_query(db, query->query);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return driver_pgsql_sync_query(db, ctx->failed ?
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainendriver_pgsql_try_commit_s(struct pgsql_transaction_context *ctx,
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen const char **error_r)
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen struct sql_transaction_context *_ctx = &ctx->ctx;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_ctx->db;
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen struct sql_transaction_query *single_query = NULL;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* just a single query, send it */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen result = sql_query_s(_ctx->db, single_query->query);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* multiple queries, use a transaction */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen result = driver_pgsql_transaction_commit_multi(ctx);
325f4573edfa5b751832ac01023f3e81be992bf0Timo Sirainendriver_pgsql_transaction_commit_s(struct sql_transaction_context *_ctx,
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen const char **error_r)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_ctx->db;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (_ctx->db->state == SQL_DB_STATE_DISCONNECTED) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainendriver_pgsql_transaction_rollback(struct sql_transaction_context *_ctx)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainendriver_pgsql_update(struct sql_transaction_context *_ctx, const char *query,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sql_transaction_add_query(_ctx, ctx->query_pool, query, affected_rows);
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainenconst struct sql_result driver_pgsql_result = {