driver-pgsql.c revision 7bafda1813454621e03615e83d55bccfa7cc56bd
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "lib.h"
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen#include "array.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "ioloop.h"
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen#include "ioloop-internal.h" /* kind of dirty, but it should be fine.. */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "sql-api-private.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen#ifdef BUILD_PGSQL
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include <stdlib.h>
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include <time.h>
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include <libpq-fe.h>
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen#define QUERY_TIMEOUT_SECS 6
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstruct pgsql_db {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct sql_db api;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen pool_t pool;
22627da0fb77c1d0d9a8e8bc485ef5540b6f2e69Timo Sirainen char *connect_string;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen PGconn *pg;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct io *io;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen enum io_condition io_dir;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_queue *queue, **queue_tail;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct timeout *queue_to;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct ioloop *ioloop;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct sql_result *sync_result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen char *error;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen time_t last_connect;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int connecting:1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int connected:1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int querying:1;
1285518f4f8905f22f5812d022a9f75b51752ed4Timo Sirainen unsigned int query_finished:1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen};
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainenstruct pgsql_binary_value {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen unsigned char *value;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen size_t size;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen};
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstruct pgsql_result {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct sql_result api;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen PGresult *pgres;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen char *query;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int rownum, rows;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int fields_count;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char **fields;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char **values;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen ARRAY_DEFINE(binary_values, struct pgsql_binary_value);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen sql_query_callback_t *callback;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen void *context;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen unsigned int retry_query:1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen};
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstruct pgsql_queue {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_queue *next;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen time_t created;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen char *query;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen};
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstruct pgsql_transaction_context {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct sql_transaction_context ctx;
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen int refcount;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen sql_commit_callback_t *callback;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen void *context;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen pool_t query_pool;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen struct pgsql_query_list *head, *tail;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen const char *error;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen unsigned int begin_succeeded:1;
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen unsigned int begin_failed:1;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen unsigned int failed:1;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen};
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainenstruct pgsql_query_list {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen struct pgsql_query_list *next;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_transaction_context *ctx;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen const char *query;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen unsigned int *affected_rows;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen};
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainenextern struct sql_db driver_pgsql_db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenextern struct sql_result driver_pgsql_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainendriver_pgsql_query_full(struct sql_db *db, const char *query,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen sql_query_callback_t *callback, void *context,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen bool retry_query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void queue_send_next(struct pgsql_db *db);
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainenstatic void result_finish(struct pgsql_result *result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_pgsql_close(struct pgsql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->io_dir = 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen PQfinish(db->pg);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->pg = NULL;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a54fa00087ba926a3d966a8449d8d7579e89911cTimo Sirainen if (db->io != NULL) {
a54fa00087ba926a3d966a8449d8d7579e89911cTimo Sirainen /* The fd may be closed before call to PQfinish() already,
a54fa00087ba926a3d966a8449d8d7579e89911cTimo Sirainen so use io_remove_closed(). */
a54fa00087ba926a3d966a8449d8d7579e89911cTimo Sirainen io_remove_closed(&db->io);
a54fa00087ba926a3d966a8449d8d7579e89911cTimo Sirainen }
a54fa00087ba926a3d966a8449d8d7579e89911cTimo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connecting = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connected = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->querying = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *last_error(struct pgsql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *msg;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen size_t len;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen msg = PQerrorMessage(db->pg);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (msg == NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return "(no error set)";
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* Error message should contain trailing \n, we don't want it */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen len = strlen(msg);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return len == 0 || msg[len-1] != '\n' ? msg :
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen t_strndup(msg, len-1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void connect_callback(struct pgsql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen enum io_condition io_dir = 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen int ret;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen while ((ret = PQconnectPoll(db->pg)) == PGRES_POLLING_ACTIVE)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen switch (ret) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen case PGRES_POLLING_READING:
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen io_dir = IO_READ;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen break;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen case PGRES_POLLING_WRITING:
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen io_dir = IO_WRITE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen break;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen case PGRES_POLLING_OK:
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_info("pgsql: Connected to %s", PQdb(db->pg));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connecting = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connected = TRUE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen break;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen case PGRES_POLLING_FAILED:
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_error("pgsql: Connect failed to %s: %s",
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen PQdb(db->pg), last_error(db));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_close(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->io_dir != io_dir) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->io != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io_remove(&db->io);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->io = io_dir == 0 ? NULL :
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen io_add(PQsocket(db->pg), io_dir, connect_callback, db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->io_dir = io_dir;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen if (db->connected && db->queue != NULL)
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen queue_send_next(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainenstatic int driver_pgsql_connect(struct sql_db *_db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen struct pgsql_db *db = (struct pgsql_db *)_db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen time_t now;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* don't try reconnecting more than once a second */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen now = time(NULL);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->connecting || db->last_connect == now)
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen return db->connected ? 1 : (db->connecting ? 0 : -1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->last_connect = now;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->pg = PQconnectStart(db->connect_string);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->pg == NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_fatal("pgsql: PQconnectStart() failed (out of memory)");
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (PQstatus(db->pg) == CONNECTION_BAD) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_error("pgsql: Connect failed to %s: %s",
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen PQdb(db->pg), last_error(db));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_close(db);
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen return -1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen } else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* nonblocking connecting begins. */
e9a0dc3e1e63f0f3affbcea7a0f5ffc112f34427Timo Sirainen if (PQsetnonblocking(db->pg, 1) < 0)
e9a0dc3e1e63f0f3affbcea7a0f5ffc112f34427Timo Sirainen i_error("pgsql: PQsetnonblocking() failed");
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->io = io_add(PQsocket(db->pg), IO_WRITE,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen connect_callback, db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->io_dir = IO_WRITE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connecting = TRUE;
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen return 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic struct sql_db *driver_pgsql_init_v(const char *connect_string)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
944a12ae4f453cc3f8a25f1e9047a5094fdfe828Timo Sirainen i_assert(connect_string != NULL);
944a12ae4f453cc3f8a25f1e9047a5094fdfe828Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db = i_new(struct pgsql_db, 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connect_string = i_strdup(connect_string);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->api = driver_pgsql_db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->queue_tail = &db->queue;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return &db->api;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void driver_pgsql_deinit_v(struct sql_db *_db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen while (db->queue != NULL) {
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen struct pgsql_queue *next = db->queue->next;
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen result_finish(db->queue->result);
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen i_free(db->queue->query);
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen i_free(db->queue);
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen db->queue = next;
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen }
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen if (db->queue_to != NULL)
d16b506f5540e3407d256bda35624b38a5ecf88fTimo Sirainen timeout_remove(&db->queue_to);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_close(db);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen i_free(db->error);
22627da0fb77c1d0d9a8e8bc485ef5540b6f2e69Timo Sirainen i_free(db->connect_string);
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen array_free(&_db->module_contexts);
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen i_free(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
ccffb125d94adff0ad776de5a96e22f864d6fb0aTimo Sirainenstatic enum sql_db_flags
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainendriver_pgsql_get_flags(struct sql_db *db ATTR_UNUSED)
ccffb125d94adff0ad776de5a96e22f864d6fb0aTimo Sirainen{
ccffb125d94adff0ad776de5a96e22f864d6fb0aTimo Sirainen return 0;
ccffb125d94adff0ad776de5a96e22f864d6fb0aTimo Sirainen}
ccffb125d94adff0ad776de5a96e22f864d6fb0aTimo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void consume_results(struct pgsql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen do {
b221779c191d1fb5fa7eb03907e62d39d1edeb08Timo Sirainen if (!PQconsumeInput(db->pg))
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen break;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (PQisBusy(db->pg))
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen } while (PQgetResult(db->pg) != NULL);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen if (PQstatus(db->pg) == CONNECTION_BAD)
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen io_remove_closed(&db->io);
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen else
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen io_remove(&db->io);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->querying = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->queue != NULL && db->connected)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen queue_send_next(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void driver_pgsql_result_free(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (result->api.callback)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a1aaf11831cab8346d6d0dc702e37b3f1d95eb43Timo Sirainen if (_result == db->sync_result)
a1aaf11831cab8346d6d0dc702e37b3f1d95eb43Timo Sirainen db->sync_result = NULL;
a1aaf11831cab8346d6d0dc702e37b3f1d95eb43Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (result->pgres != NULL) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen PQclear(result->pgres);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* we'll have to read the rest of the results as well */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(db->io == NULL);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->io = io_add(PQsocket(db->pg), IO_READ,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen consume_results, db);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen db->io_dir = IO_READ;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen consume_results(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen } else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->querying = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (array_is_created(&result->binary_values)) {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen struct pgsql_binary_value *value;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen array_foreach_modifiable(&result->binary_values, value)
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen PQfreemem(value->value);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen array_free(&result->binary_values);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_free(result->fields);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_free(result->values);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen i_free(result->query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_free(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->queue != NULL && !db->querying && db->connected)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen queue_send_next(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void result_finish(struct pgsql_result *result)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen bool free_result = TRUE, retry = FALSE;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen bool disconnected;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen
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;
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen if (disconnected && result->retry_query) {
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen /* retry the query */
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen i_error("pgsql: Query failed, retrying: %s", last_error(db));
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen retry = TRUE;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen } else if (result->callback != NULL) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen result->api.callback = TRUE;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen result->callback(&result->api, result->context);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
46744f1c9837f189e1c1b13e4d83231b3c9dfff6Timo Sirainen result->api.callback = FALSE;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen free_result = db->sync_result != &result->api;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (db->queue == NULL && db->ioloop != NULL)
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen io_loop_stop(db->ioloop);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen }
b221779c191d1fb5fa7eb03907e62d39d1edeb08Timo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen if (disconnected) {
b221779c191d1fb5fa7eb03907e62d39d1edeb08Timo Sirainen /* disconnected */
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen if (result->pgres != NULL) {
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen PQclear(result->pgres);
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen result->pgres = NULL;
e958a3c4573058f17999f0083a34080ca35e34d8Timo Sirainen }
b221779c191d1fb5fa7eb03907e62d39d1edeb08Timo Sirainen driver_pgsql_close(db);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen if (retry) {
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen /* retry the query */
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen driver_pgsql_query_full(&db->api, result->query,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen result->callback,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen result->context, FALSE);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen }
b221779c191d1fb5fa7eb03907e62d39d1edeb08Timo Sirainen }
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen if (free_result)
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen sql_result_unref(&result->api);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void get_result(struct pgsql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!PQconsumeInput(db->pg)) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connected = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result_finish(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (PQisBusy(db->pg)) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->io == NULL) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->io = io_add(PQsocket(db->pg), IO_READ,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen get_result, result);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen db->io_dir = IO_READ;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (db->io != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io_remove(&db->io);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->pgres = PQgetResult(db->pg);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result_finish(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void flush_callback(struct pgsql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen int ret;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ret = PQflush(db->pg);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (ret > 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io_remove(&db->io);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (ret < 0) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connected = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result_finish(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen } else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* all flushed */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen get_result(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void send_query(struct pgsql_result *result, const char *query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen int ret;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(db->io == NULL);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(!db->querying);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(db->connected);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!PQsendQuery(db->pg, query)) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connected = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result_finish(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ret = PQflush(db->pg);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (ret < 0) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connected = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result_finish(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->querying = TRUE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (ret > 0) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* write blocks */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->io = io_add(PQsocket(db->pg), IO_WRITE,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen flush_callback, result);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen db->io_dir = IO_WRITE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen } else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen get_result(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainenstatic struct pgsql_queue *queue_unlink_first(struct pgsql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_queue *queue;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen queue = db->queue;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->queue = queue->next;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
dd171dccbe98fc63ca737e6e4e8edbeb601e5cbdTimo Sirainen if (db->queue == NULL)
dd171dccbe98fc63ca737e6e4e8edbeb601e5cbdTimo Sirainen db->queue_tail = &db->queue;
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen return queue;
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen}
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainenstatic void queue_send_next(struct pgsql_db *db)
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen{
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen struct pgsql_queue *queue;
dd171dccbe98fc63ca737e6e4e8edbeb601e5cbdTimo Sirainen
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen queue = queue_unlink_first(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen send_query(queue->result, queue->query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_free(queue->query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_free(queue);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainenstatic void queue_abort_next(struct pgsql_db *db)
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen{
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen struct pgsql_queue *queue;
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen queue = queue_unlink_first(db);
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen queue->result->callback(&sql_not_connected_result,
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen queue->result->context);
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen i_free(queue->result);
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen i_free(queue->query);
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen i_free(queue);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (db->queue == NULL && db->ioloop != NULL)
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen io_loop_stop(db->ioloop);
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen}
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainenstatic void queue_drop_timed_out_queries(struct pgsql_db *db)
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen{
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen while (db->queue != NULL &&
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen db->queue->created + QUERY_TIMEOUT_SECS < ioloop_time)
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen queue_abort_next(db);
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen}
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void queue_timeout(struct pgsql_db *db)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->querying)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!db->connected) {
61dca057fe86fd5ae57f5106f8f049b7287d78cdTimo Sirainen queue_drop_timed_out_queries(db);
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen driver_pgsql_connect(&db->api);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->queue != NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen queue_send_next(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (db->queue == NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen timeout_remove(&db->queue_to);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_queue_query(struct pgsql_result *result, const char *query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_queue *queue;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen queue = i_new(struct pgsql_queue, 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen queue->created = time(NULL);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen queue->query = i_strdup(query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen queue->result = result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen *db->queue_tail = queue;
dd171dccbe98fc63ca737e6e4e8edbeb601e5cbdTimo Sirainen db->queue_tail = &queue->next;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->queue_to == NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->queue_to = timeout_add(5000, queue_timeout, db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void do_query(struct pgsql_result *result, const char *query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)result->api.db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a1aaf11831cab8346d6d0dc702e37b3f1d95eb43Timo Sirainen i_assert(db->sync_result == NULL);
a1aaf11831cab8346d6d0dc702e37b3f1d95eb43Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->querying) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* only one query at a time */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_queue_query(result, query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!db->connected) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* try connecting again */
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen driver_pgsql_connect(&db->api);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_queue_query(result, query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (db->queue == NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen send_query(result, query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* there's already queries queued, send them first */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_queue_query(result, query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen queue_send_next(db);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void exec_callback(struct sql_result *_result,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_error("pgsql: sql_exec() failed: %s", last_error(db));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
13a8c553f293349248b161ff851743498916e26eTimo Sirainenstatic const char *
13a8c553f293349248b161ff851743498916e26eTimo Sirainendriver_pgsql_escape_string(struct sql_db *_db, const char *string)
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen{
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_db;
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen size_t len = strlen(string);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen char *to;
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen#ifdef HAVE_PQESCAPE_STRING_CONN
9fcf7b79236b0045f7709718f7b65ada516565e7Timo Sirainen if (!db->connected) {
9fcf7b79236b0045f7709718f7b65ada516565e7Timo Sirainen /* try connecting again */
9fcf7b79236b0045f7709718f7b65ada516565e7Timo Sirainen (void)driver_pgsql_connect(&db->api);
9fcf7b79236b0045f7709718f7b65ada516565e7Timo Sirainen }
c9343c25215e98880db8f9e9c5f120f6311bc06dTimo Sirainen to = t_buffer_get(len * 2 + 1);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen len = PQescapeStringConn(db->pg, to, string, len, NULL);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen#else
c9343c25215e98880db8f9e9c5f120f6311bc06dTimo Sirainen to = t_buffer_get(len * 2 + 1);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen len = PQescapeString(to, string, len);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen#endif
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen t_buffer_alloc(len + 1);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen return to;
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen}
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void driver_pgsql_exec_full(struct sql_db *db, const char *query,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen bool retry_query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result = i_new(struct pgsql_result, 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->api = driver_pgsql_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->api.db = db;
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen result->api.refcount = 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->callback = exec_callback;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen if (retry_query) {
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen result->query = i_strdup(query);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen result->retry_query = TRUE;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen do_query(result, query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void driver_pgsql_exec(struct sql_db *db, const char *query)
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen{
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen driver_pgsql_exec_full(db, query, TRUE);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen}
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainendriver_pgsql_query_full(struct sql_db *db, const char *query,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen sql_query_callback_t *callback, void *context,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen bool retry_query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result = i_new(struct pgsql_result, 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->api = driver_pgsql_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->api.db = db;
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen result->api.refcount = 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->callback = callback;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->context = context;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen if (retry_query) {
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen result->query = i_strdup(query);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen result->retry_query = TRUE;
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen do_query(result, query);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainenstatic void driver_pgsql_query(struct sql_db *db, const char *query,
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen sql_query_callback_t *callback, void *context)
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen{
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen driver_pgsql_query_full(db, query, callback, context, TRUE);
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen}
68f0dfb4b2815ecbc1bd8d8a68adcfd577ec55aeTimo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void pgsql_query_s_callback(struct sql_result *result, void *context)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_db *db = context;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
1285518f4f8905f22f5812d022a9f75b51752ed4Timo Sirainen db->query_finished = TRUE;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen db->sync_result = result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic struct sql_result *
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_query_s(struct sql_db *_db, const char *query)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_db;
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen struct sql_result *result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct io old_io;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen if (db->queue_to != NULL) {
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen /* we're creating a new ioloop, make sure the timeout gets
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen added there. */
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen timeout_remove(&db->queue_to);
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen }
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (db->io == NULL)
510a871e2187891d538bf2ebb3cfd2056003af88Timo Sirainen db->ioloop = io_loop_create();
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen else {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen /* have to move our existing I/O handler to new I/O loop */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen old_io = *db->io;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io_remove(&db->io);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
510a871e2187891d538bf2ebb3cfd2056003af88Timo Sirainen db->ioloop = io_loop_create();
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
510a871e2187891d538bf2ebb3cfd2056003af88Timo Sirainen db->io = io_add(PQsocket(db->pg), old_io.condition,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen old_io.callback, old_io.context);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
1285518f4f8905f22f5812d022a9f75b51752ed4Timo Sirainen db->query_finished = FALSE;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (query != NULL)
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen driver_pgsql_query(_db, query, pgsql_query_s_callback, db);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen if (!db->query_finished) {
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen if ((db->connected || db->connecting) && db->io != NULL)
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen io_loop_run(db->ioloop);
840a3701b7a0f7fadd17738998c33790a8dfad2dTimo Sirainen else
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen queue_abort_next(db);
840a3701b7a0f7fadd17738998c33790a8dfad2dTimo Sirainen
840a3701b7a0f7fadd17738998c33790a8dfad2dTimo Sirainen if (db->io != NULL) {
840a3701b7a0f7fadd17738998c33790a8dfad2dTimo Sirainen i_assert(db->sync_result == &sql_not_connected_result);
840a3701b7a0f7fadd17738998c33790a8dfad2dTimo Sirainen io_remove(&db->io);
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen }
840a3701b7a0f7fadd17738998c33790a8dfad2dTimo Sirainen if (db->queue_to != NULL)
840a3701b7a0f7fadd17738998c33790a8dfad2dTimo Sirainen timeout_remove(&db->queue_to);
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen } else {
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen i_assert(db->io == NULL);
5fe06fea9fee0f5e4e9cb49f6866877223f78b85Timo Sirainen i_assert(db->queue_to == NULL);
1412a091183dc0e5d6ea4f403a5cd4f4cd5c7301Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io_loop_destroy(&db->ioloop);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen result = db->sync_result;
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen if (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. */
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen db->sync_result = NULL;
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen i_assert(db->io == NULL);
06f537a8e0b399222cc2a7755015ef3963525fd2Timo Sirainen return result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic int driver_pgsql_result_next_row(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_db *db = (struct pgsql_db *)_result->db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (result->rows != 0) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* second time we're here */
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen if (++result->rownum < result->rows)
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen return 1;
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen
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.. */
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen PQclear(result->pgres);
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen result->pgres = PQgetResult(db->pg);
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen if (result->pgres == NULL)
26cdaf7097427fa90343260fa236af12ab93cca3Timo Sirainen return 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (result->pgres == NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return -1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen switch (PQresultStatus(result->pgres)) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen case PGRES_COMMAND_OK:
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* no rows returned */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen case PGRES_TUPLES_OK:
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->rows = PQntuples(result->pgres);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return result->rows > 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen case PGRES_EMPTY_QUERY:
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen case PGRES_NONFATAL_ERROR:
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* nonfatal error */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return -1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen default:
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* treat as fatal error */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->connected = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return -1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_pgsql_result_fetch_fields(struct pgsql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int i;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (result->fields != NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* @UNSAFE */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->fields_count = PQnfields(result->pgres);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->fields = i_new(const char *, result->fields_count);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen for (i = 0; i < result->fields_count; i++)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->fields[i] = PQfname(result->pgres, i);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic unsigned int
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_get_fields_count(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_result_fetch_fields(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return result->fields_count;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_get_field_name(struct sql_result *_result, unsigned int idx)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_result_fetch_fields(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(idx < result->fields_count);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return result->fields[idx];
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic int driver_pgsql_result_find_field(struct sql_result *_result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *field_name)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int i;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_result_fetch_fields(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen for (i = 0; i < result->fields_count; i++) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (strcmp(result->fields[i], field_name) == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return i;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return -1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_get_field_value(struct sql_result *_result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int idx)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (PQgetisnull(result->pgres, result->rownum, idx))
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return NULL;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return PQgetvalue(result->pgres, result->rownum, idx);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainenstatic const unsigned char *
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainendriver_pgsql_result_get_field_value_binary(struct sql_result *_result,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen unsigned int idx, size_t *size_r)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen const char *value;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen struct pgsql_binary_value *binary_value;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (PQgetisnull(result->pgres, result->rownum, idx)) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen *size_r = 0;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return NULL;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen value = PQgetvalue(result->pgres, result->rownum, idx);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (!array_is_created(&result->binary_values))
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen i_array_init(&result->binary_values, idx + 1);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen binary_value = array_idx_modifiable(&result->binary_values, idx);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen if (binary_value->value == NULL) {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen binary_value->value =
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen PQunescapeBytea((const unsigned char *)value,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen &binary_value->size);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen *size_r = binary_value->size;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return binary_value->value;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen}
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_find_field_value(struct sql_result *result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *field_name)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen int idx;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen idx = driver_pgsql_result_find_field(result, field_name);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (idx < 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return NULL;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return driver_pgsql_result_get_field_value(result, idx);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *const *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_pgsql_result_get_values(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct pgsql_result *result = (struct pgsql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int i;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (result->values == NULL) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_result_fetch_fields(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->values = i_new(const char *, result->fields_count);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* @UNSAFE */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen for (i = 0; i < result->fields_count; i++) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->values[i] =
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_pgsql_result_get_field_value(_result, i);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return result->values;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *driver_pgsql_result_get_error(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
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;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen size_t len;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen i_free_and_null(db->error);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen if (result->pgres == NULL) {
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen /* connection error */
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen db->error = i_strdup(last_error(db));
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen } else {
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen msg = PQresultErrorMessage(result->pgres);
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen if (msg == NULL)
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen return "(no error set)";
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen /* Error message should contain trailing \n, we don't want it */
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen len = strlen(msg);
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen db->error = len == 0 || msg[len-1] != '\n' ?
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen i_strdup(msg) : i_strndup(msg, len-1);
9672bb2a11c37c275d695451accd824da5c9e485Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return db->error;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic struct sql_transaction_context *
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_begin(struct sql_db *db)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_transaction_context *ctx;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen ctx = i_new(struct pgsql_transaction_context, 1);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen ctx->ctx.db = db;
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen ctx->refcount = 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);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return &ctx->ctx;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainenstatic void
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainendriver_pgsql_transaction_unref(struct pgsql_transaction_context *ctx)
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen{
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen i_assert(ctx->refcount > 0);
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen if (--ctx->refcount > 0)
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen return;
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen pool_unref(&ctx->query_pool);
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen i_free(ctx);
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen}
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainentransaction_begin_callback(struct sql_result *result,
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_transaction_context *ctx)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen if (sql_result_next_row(result) < 0) {
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen ctx->begin_failed = TRUE;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen ctx->failed = TRUE;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen ctx->error = sql_result_get_error(result);
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen } else {
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen ctx->begin_succeeded = TRUE;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen }
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen driver_pgsql_transaction_unref(ctx);
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainenstatic void
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainentransaction_commit_callback(struct sql_result *result,
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_transaction_context *ctx)
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (sql_result_next_row(result) < 0)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen ctx->callback(sql_result_get_error(result), ctx->context);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen else
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen ctx->callback(NULL, ctx->context);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen driver_pgsql_transaction_unref(ctx);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen}
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainenstatic void
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainentransaction_update_callback(struct sql_result *result,
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_query_list *list)
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen{
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_transaction_context *ctx = list->ctx;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (sql_result_next_row(result) < 0) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->failed = TRUE;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->error = sql_result_get_error(result);
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen } else if (list->affected_rows != NULL) {
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_result *pg_result = (struct pgsql_result *)result;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen *list->affected_rows = atoi(PQcmdTuples(pg_result->pgres));
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen }
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen driver_pgsql_transaction_unref(ctx);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_commit(struct sql_transaction_context *_ctx,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen sql_commit_callback_t *callback, void *context)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_transaction_context *ctx =
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen (struct pgsql_transaction_context *)_ctx;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen ctx->callback = callback;
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen ctx->context = context;
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (ctx->failed || ctx->head == NULL) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen callback(ctx->failed ? ctx->error : NULL, context);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen driver_pgsql_transaction_unref(ctx);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen } else if (ctx->head->next == NULL) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* just a single query, send it */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen sql_query(_ctx->db, ctx->head->query,
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen transaction_commit_callback, ctx);
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen } else {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* multiple queries, use a transaction */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->refcount++;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen sql_query(_ctx->db, "BEGIN", transaction_begin_callback, ctx);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen while (ctx->head != NULL) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->refcount++;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen sql_query(_ctx->db, ctx->head->query,
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen transaction_update_callback, ctx->head);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->head = ctx->head->next;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen }
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen sql_query(_ctx->db, "COMMIT", transaction_commit_callback, ctx);
28cddf411c475eb8bb84b4023398bb12346ce5adTimo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic int
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_commit_s(struct sql_transaction_context *_ctx,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen const char **error_r)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_transaction_context *ctx =
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen (struct pgsql_transaction_context *)_ctx;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct sql_result *result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen *error_r = NULL;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (ctx->failed || ctx->head == NULL) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* nothing to be done */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen result = NULL;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen } else if (ctx->head->next == NULL) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* just a single query, send it */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen result = sql_query_s(_ctx->db, ctx->head->query);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen } else {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* multiple queries, use a transaction */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->refcount++;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen sql_query(_ctx->db, "BEGIN", transaction_begin_callback, ctx);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen while (ctx->head != NULL) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->refcount++;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen sql_query(_ctx->db, ctx->head->query,
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen transaction_update_callback, ctx->head);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->head = ctx->head->next;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen }
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (ctx->refcount > 1) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen /* flush the previous queries */
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen (void)driver_pgsql_query_s(_ctx->db, NULL);
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen }
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (ctx->begin_failed) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen result = NULL;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen } else if (ctx->failed) {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen result = sql_query_s(_ctx->db, "ROLLBACK");
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen } else {
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen result = sql_query_s(_ctx->db, "COMMIT");
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen }
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen }
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (ctx->failed)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen *error_r = ctx->error;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen else if (result != NULL) {
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen if (sql_result_next_row(result) < 0)
f4c0b1874b0533bcf2df1d28d584ff02cfdae3faTimo Sirainen *error_r = sql_result_get_error(result);
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen else if (ctx->head != NULL &&
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen ctx->head->affected_rows != NULL) {
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen struct pgsql_result *pg_result =
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen (struct pgsql_result *)result;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen *ctx->head->affected_rows =
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen atoi(PQcmdTuples(pg_result->pgres));
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen }
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (result != NULL)
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen sql_result_unref(result);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen i_assert(ctx->refcount == 1);
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen driver_pgsql_transaction_unref(ctx);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return *error_r == NULL ? 0 : -1;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_pgsql_transaction_rollback(struct sql_transaction_context *_ctx)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_transaction_context *ctx =
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen (struct pgsql_transaction_context *)_ctx;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen i_assert(ctx->refcount == 1);
9c2b0eb659540b9db8dd3a8a6a2515921fbe8eebTimo Sirainen driver_pgsql_transaction_unref(ctx);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainendriver_pgsql_update(struct sql_transaction_context *_ctx, const char *query,
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen unsigned int *affected_rows)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct pgsql_transaction_context *ctx =
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen (struct pgsql_transaction_context *)_ctx;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen struct pgsql_query_list *list;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen list = p_new(ctx->query_pool, struct pgsql_query_list, 1);
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen list->ctx = ctx;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen list->query = p_strdup(ctx->query_pool, query);
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen list->affected_rows = affected_rows;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen if (ctx->head == NULL)
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->head = list;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen else
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->tail->next = list;
892b3cbf0eba9ba455448adcf71864a409345c6dTimo Sirainen ctx->tail = list;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstruct sql_db driver_pgsql_db = {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen "pgsql",
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .v = {
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_init_v,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_deinit_v,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_get_flags,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_connect,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_escape_string,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_exec,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_query,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_query_s,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_transaction_begin,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_transaction_commit,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_transaction_commit_s,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_transaction_rollback,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen driver_pgsql_update
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen};
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstruct sql_result driver_pgsql_result = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .v = {
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_free,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_next_row,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_get_fields_count,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_get_field_name,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_find_field,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_get_field_value,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_get_field_value_binary,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_find_field_value,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_get_values,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_pgsql_result_get_error
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen};
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainenvoid driver_pgsql_init(void);
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainenvoid driver_pgsql_deinit(void);
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainenvoid driver_pgsql_init(void)
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen{
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen sql_driver_register(&driver_pgsql_db);
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen}
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainenvoid driver_pgsql_deinit(void)
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen{
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen sql_driver_unregister(&driver_pgsql_db);
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen}
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#endif