driver-pgsql.c revision 9fcf7b79236b0045f7709718f7b65ada516565e7
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/* Copyright (C) 2004 Timo Sirainen */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "lib.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "ioloop.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "ioloop-internal.h" /* kind of dirty, but it should be fine.. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "sql-api-private.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#ifdef BUILD_PGSQL
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <stdlib.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <time.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <libpq-fe.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct pgsql_db {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct sql_db api;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher pool_t pool;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char *connect_string;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PGconn *pg;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct io *io;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher enum io_condition io_dir;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_queue *queue, **queue_tail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct timeout *queue_to;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct ioloop *ioloop;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct sql_result *sync_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher char *error;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher time_t last_connect;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int connecting:1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int connected:1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int querying:1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int query_finished:1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct pgsql_result {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct sql_result api;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PGresult *pgres;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int rownum, rows;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int fields_count;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char **fields;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char **values;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher sql_query_callback_t *callback;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher void *context;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct pgsql_queue {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_queue *next;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher time_t created;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher char *query;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct pgsql_transaction_context {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct sql_transaction_context ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher sql_commit_callback_t *callback;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher void *context;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char *error;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int opened:1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int failed:1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherextern struct sql_db driver_pgsql_db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherextern struct sql_result driver_pgsql_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void queue_send_next(struct pgsql_db *db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void result_finish(struct pgsql_result *result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void driver_pgsql_close(struct pgsql_db *db)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->io != NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher io_remove(&db->io);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->io_dir = 0;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PQfinish(db->pg);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->pg = NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->connecting = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->connected = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->querying = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic const char *last_error(struct pgsql_db *db)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char *msg;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher size_t len;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher msg = PQerrorMessage(db->pg);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (msg == NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return "(no error set)";
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Error message should contain trailing \n, we don't want it */
e4c29d1f8e3b2c2b268105f169e5156a0a36aebfOndrej Kos len = strlen(msg);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return len == 0 || msg[len-1] != '\n' ? msg :
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher t_strndup(msg, len-1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void connect_callback(struct pgsql_db *db)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher enum io_condition io_dir = 0;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher while ((ret = PQconnectPoll(db->pg)) == PGRES_POLLING_ACTIVE)
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher ;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher switch (ret) {
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher case PGRES_POLLING_READING:
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher io_dir = IO_READ;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher break;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher case PGRES_POLLING_WRITING:
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher io_dir = IO_WRITE;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher break;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher case PGRES_POLLING_OK:
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher i_info("pgsql: Connected to %s", PQdb(db->pg));
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher db->connecting = FALSE;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher db->connected = TRUE;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher break;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher case PGRES_POLLING_FAILED:
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher i_error("pgsql: Connect failed to %s: %s",
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher PQdb(db->pg), last_error(db));
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher driver_pgsql_close(db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->io_dir != io_dir) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->io != NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher io_remove(&db->io);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->io = io_dir == 0 ? NULL :
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher io_add(PQsocket(db->pg), io_dir, connect_callback, db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->io_dir = io_dir;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->connected && db->queue != NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue_send_next(db);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny}
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenystatic int driver_pgsql_connect(struct sql_db *_db)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny{
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny struct pgsql_db *db = (struct pgsql_db *)_db;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny time_t now;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny /* don't try reconnecting more than once a second */
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek now = time(NULL);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (db->connecting || db->last_connect == now)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny return db->connected ? 1 : (db->connecting ? 0 : -1);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db->last_connect = now;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db->pg = PQconnectStart(db->connect_string);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (db->pg == NULL)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny i_fatal("pgsql: PQconnectStart() failed (out of memory)");
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (PQstatus(db->pg) == CONNECTION_BAD) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny i_error("pgsql: Connect failed to %s: %s",
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny PQdb(db->pg), last_error(db));
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny driver_pgsql_close(db);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny return -1;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny } else {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny /* nonblocking connecting begins. */
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db->io = io_add(PQsocket(db->pg), IO_WRITE,
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny connect_callback, db);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db->io_dir = IO_WRITE;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db->connecting = TRUE;
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek return 0;
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek }
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek}
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidekstatic struct sql_db *_driver_pgsql_init(const char *connect_string)
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek{
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek struct pgsql_db *db;
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny i_assert(connect_string != NULL);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db = i_new(struct pgsql_db, 1);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db->connect_string = i_strdup(connect_string);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db->api = driver_pgsql_db;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db->queue_tail = &db->queue;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny return &db->api;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny}
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenystatic void _driver_pgsql_deinit(struct sql_db *_db)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny{
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny struct pgsql_db *db = (struct pgsql_db *)_db;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny while (db->queue != NULL) {
b096321a5a02dda0b6b71ba0f9c4d8feacd979e4Michal Zidek struct pgsql_queue *next = db->queue->next;
b096321a5a02dda0b6b71ba0f9c4d8feacd979e4Michal Zidek
b096321a5a02dda0b6b71ba0f9c4d8feacd979e4Michal Zidek result_finish(db->queue->result);
b096321a5a02dda0b6b71ba0f9c4d8feacd979e4Michal Zidek i_free(db->queue->query);
b096321a5a02dda0b6b71ba0f9c4d8feacd979e4Michal Zidek i_free(db->queue);
b096321a5a02dda0b6b71ba0f9c4d8feacd979e4Michal Zidek
b096321a5a02dda0b6b71ba0f9c4d8feacd979e4Michal Zidek db->queue = next;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny }
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (db->queue_to != 0)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny timeout_remove(&db->queue_to);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny driver_pgsql_close(db);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny i_free(db->error);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny i_free(db);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny}
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenystatic enum sql_db_flags
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenydriver_pgsql_get_flags(struct sql_db *db __attr_unused__)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny{
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny return 0;
9ab243b369ba317cc964080786dbcdebaf23d6beMichal Zidek}
9ab243b369ba317cc964080786dbcdebaf23d6beMichal Zidek
9ab243b369ba317cc964080786dbcdebaf23d6beMichal Zidekstatic void consume_results(struct pgsql_db *db)
9ab243b369ba317cc964080786dbcdebaf23d6beMichal Zidek{
9ab243b369ba317cc964080786dbcdebaf23d6beMichal Zidek do {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!PQconsumeInput(db->pg))
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher break;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (PQisBusy(db->pg))
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher } while (PQgetResult(db->pg) != NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher io_remove(&db->io);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->querying = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->queue != NULL && db->connected)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue_send_next(db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void driver_pgsql_result_free(struct sql_result *_result)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)_result->db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result = (struct pgsql_result *)_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (result->api.callback)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (result->pgres != NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PQclear(result->pgres);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* we'll have to read the rest of the results as well */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_assert(db->io == NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->io = io_add(PQsocket(db->pg), IO_READ,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher consume_results, db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->io_dir = IO_READ;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher consume_results(db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher } else {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->querying = FALSE;
9ab243b369ba317cc964080786dbcdebaf23d6beMichal Zidek }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_free(result->fields);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_free(result->values);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_free(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->queue != NULL && !db->querying && db->connected)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue_send_next(db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void result_finish(struct pgsql_result *result)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)result->api.db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher bool free_result = TRUE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (result->callback != NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->api.callback = TRUE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher t_push();
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->callback(&result->api, result->context);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher t_pop();
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->api.callback = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher free_result = db->sync_result != &result->api;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (free_result)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_result_free(&result->api);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (PQstatus(db->pg) == CONNECTION_BAD) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* disconnected */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_close(db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenystatic void get_result(struct pgsql_result *result)
b1caacb098ae99ad65144120fdec4d0fd98ad9d5Pavel Březina{
b1caacb098ae99ad65144120fdec4d0fd98ad9d5Pavel Březina struct pgsql_db *db = (struct pgsql_db *)result->api.db;
b1caacb098ae99ad65144120fdec4d0fd98ad9d5Pavel Březina
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!PQconsumeInput(db->pg)) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->connected = FALSE;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny result_finish(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (PQisBusy(db->pg)) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (db->io == NULL) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny db->io = io_add(PQsocket(db->pg), IO_READ,
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny get_result, result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->io_dir = IO_READ;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->io != NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher io_remove(&db->io);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->pgres = PQgetResult(db->pg);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result_finish(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void flush_callback(struct pgsql_result *result)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)result->api.db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret = PQflush(db->pg);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret > 0)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher io_remove(&db->io);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret < 0) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->connected = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result_finish(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher } else {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* all flushed */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher get_result(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void send_query(struct pgsql_result *result, const char *query)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)result->api.db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_assert(db->io == NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_assert(!db->querying);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_assert(db->connected);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!PQsendQuery(db->pg, query)) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->connected = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result_finish(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret = PQflush(db->pg);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret < 0) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->connected = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result_finish(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->querying = TRUE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret > 0) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* write blocks */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->io = io_add(PQsocket(db->pg), IO_WRITE,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher flush_callback, result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->io_dir = IO_WRITE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher } else {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher get_result(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void queue_send_next(struct pgsql_db *db)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_queue *queue;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue = db->queue;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->queue = queue->next;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->queue == NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->queue_tail = &db->queue;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher send_query(queue->result, queue->query);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_free(queue->query);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_free(queue);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void queue_timeout(struct pgsql_db *db)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->querying)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!db->connected) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_connect(&db->api);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->queue != NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue_send_next(db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->queue == NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher timeout_remove(&db->queue_to);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherdriver_pgsql_queue_query(struct pgsql_result *result, const char *query)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)result->api.db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_queue *queue;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue = i_new(struct pgsql_queue, 1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue->created = time(NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue->query = i_strdup(query);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue->result = result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher *db->queue_tail = queue;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->queue_tail = &queue->next;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->queue_to == NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->queue_to = timeout_add(5000, queue_timeout, db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void do_query(struct pgsql_result *result, const char *query)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)result->api.db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->querying) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* only one query at a time */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_queue_query(result, query);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!db->connected) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* try connecting again */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_connect(&db->api);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_queue_query(result, query);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->queue == NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher send_query(result, query);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher else {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* there's already queries queued, send them first */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_queue_query(result, query);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher queue_send_next(db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void exec_callback(struct sql_result *result,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher void *context __attr_unused__)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)result->db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_error("pgsql: sql_exec() failed: %s", last_error(db));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic const char *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherdriver_pgsql_escape_string(struct sql_db *_db, const char *string)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)_db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher size_t len = strlen(string);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher char *to;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher to = t_buffer_get(len * 2 + 1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#ifdef HAVE_PQESCAPE_STRING_CONN
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!db->connected) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* try connecting again */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher (void)driver_pgsql_connect(&db->api);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher len = PQescapeStringConn(db->pg, to, string, len, NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#else
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher len = PQescapeString(to, string, len);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#endif
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher t_buffer_alloc(len + 1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return to;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void driver_pgsql_exec(struct sql_db *db, const char *query)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result = i_new(struct pgsql_result, 1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->api = driver_pgsql_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->api.db = db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->callback = exec_callback;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher do_query(result, query);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void driver_pgsql_query(struct sql_db *db, const char *query,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher sql_query_callback_t *callback, void *context)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result = i_new(struct pgsql_result, 1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->api = driver_pgsql_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->api.db = db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->callback = callback;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->context = context;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher do_query(result, query);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void pgsql_query_s_callback(struct sql_result *result, void *context)
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher{
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher struct pgsql_db *db = context;
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher db->query_finished = TRUE;
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher db->sync_result = result;
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher io_loop_stop(db->ioloop);
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher}
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagherstatic struct sql_result *
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagherdriver_pgsql_query_s(struct sql_db *_db, const char *query)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)_db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct io old_io;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (db->io == NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->ioloop = io_loop_create();
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher else {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* have to move our existing I/O handler to new I/O loop */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher old_io = *db->io;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher io_remove(&db->io);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->ioloop = io_loop_create();
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->io = io_add(PQsocket(db->pg), old_io.condition,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher old_io.callback, old_io.context);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->query_finished = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_query(_db, query, pgsql_query_s_callback, db);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!db->query_finished)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher io_loop_run(db->ioloop);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher io_loop_destroy(&db->ioloop);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_assert(db->io == NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return db->sync_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic int driver_pgsql_result_next_row(struct sql_result *_result)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result = (struct pgsql_result *)_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)_result->db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (result->rows != 0) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* second time we're here */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return ++result->rownum < result->rows;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (result->pgres == NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return -1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher switch (PQresultStatus(result->pgres)) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case PGRES_COMMAND_OK:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* no rows returned */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return 0;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case PGRES_TUPLES_OK:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->rows = PQntuples(result->pgres);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return result->rows > 0;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case PGRES_EMPTY_QUERY:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case PGRES_NONFATAL_ERROR:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* nonfatal error */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return -1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher default:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* treat as fatal error */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->connected = FALSE;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return -1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void driver_pgsql_result_fetch_fields(struct pgsql_result *result)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int i;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (result->fields != NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* @UNSAFE */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->fields_count = PQnfields(result->pgres);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->fields = i_new(const char *, result->fields_count);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < result->fields_count; i++)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->fields[i] = PQfname(result->pgres, i);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic unsigned int
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherdriver_pgsql_result_get_fields_count(struct sql_result *_result)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result = (struct pgsql_result *)_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_result_fetch_fields(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return result->fields_count;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic const char *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherdriver_pgsql_result_get_field_name(struct sql_result *_result, unsigned int idx)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result = (struct pgsql_result *)_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_result_fetch_fields(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_assert(idx < result->fields_count);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return result->fields[idx];
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic int driver_pgsql_result_find_field(struct sql_result *_result,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char *field_name)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result = (struct pgsql_result *)_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int i;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_result_fetch_fields(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < result->fields_count; i++) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (strcmp(result->fields[i], field_name) == 0)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return i;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return -1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic const char *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherdriver_pgsql_result_get_field_value(struct sql_result *_result,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int idx)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result = (struct pgsql_result *)_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (PQgetisnull(result->pgres, result->rownum, idx))
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return PQgetvalue(result->pgres, result->rownum, idx);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic const char *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherdriver_pgsql_result_find_field_value(struct sql_result *result,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char *field_name)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int idx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher idx = driver_pgsql_result_find_field(result, field_name);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (idx < 0)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return driver_pgsql_result_get_field_value(result, idx);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic const char *const *
0051296f67bd7d8e2e3094638ddff4e641324d04Michal Zidekdriver_pgsql_result_get_values(struct sql_result *_result)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result = (struct pgsql_result *)_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher unsigned int i;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (result->values == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_result_fetch_fields(result);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->values = i_new(const char *, result->fields_count);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* @UNSAFE */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < result->fields_count; i++) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result->values[i] =
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher driver_pgsql_result_get_field_value(_result, i);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return result->values;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic const char *driver_pgsql_result_get_error(struct sql_result *_result)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_result *result = (struct pgsql_result *)_result;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct pgsql_db *db = (struct pgsql_db *)_result->db;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char *msg;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher size_t len;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher msg = PQresultErrorMessage(result->pgres);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (msg == NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return "(no error set)";
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Error message should contain trailing \n, we don't want it */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher len = strlen(msg);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_free(db->error);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher db->error = len == 0 || msg[len-1] != '\n' ?
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_strdup(msg) : i_strndup(msg, len-1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return db->error;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherstatic struct sql_transaction_context *
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherdriver_pgsql_transaction_begin(struct sql_db *db)
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher{
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct pgsql_transaction_context *ctx;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher ctx = i_new(struct pgsql_transaction_context, 1);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher ctx->ctx.db = db;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher return &ctx->ctx;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher}
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherstatic void
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallaghertransaction_commit_callback(struct sql_result *result, void *context)
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher{
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct pgsql_transaction_context *ctx =
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher (struct pgsql_transaction_context *)context;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (sql_result_next_row(result) < 0)
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher ctx->callback(sql_result_get_error(result), ctx->context);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher else
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher ctx->callback(NULL, ctx->context);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher}
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherstatic void
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherdriver_pgsql_transaction_commit(struct sql_transaction_context *_ctx,
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher sql_commit_callback_t *callback, void *context)
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher{
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct pgsql_transaction_context *ctx =
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher (struct pgsql_transaction_context *)_ctx;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (ctx->failed) {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher callback(ctx->error, context);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (ctx->opened)
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher sql_exec(_ctx->db, "ROLLBACK");
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher i_free(ctx);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher return;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher }
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (!ctx->opened) {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher /* nothing done */
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher ctx->callback(NULL, ctx->context);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher return;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher }
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher ctx->callback = callback;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher ctx->context = context;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher sql_query(_ctx->db, "COMMIT", transaction_commit_callback, ctx);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher}
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherstatic int
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherdriver_pgsql_transaction_commit_s(struct sql_transaction_context *_ctx,
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher const char **error_r)
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher{
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct pgsql_transaction_context *ctx =
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher (struct pgsql_transaction_context *)_ctx;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct sql_result *result;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (ctx->failed) {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher *error_r = ctx->error;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (!ctx->opened)
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher sql_exec(_ctx->db, "ROLLBACK");
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher } else if (!ctx->opened)
*error_r = NULL;
else {
result = sql_query_s(_ctx->db, "COMMIT");
if (sql_result_next_row(result) < 0)
*error_r = sql_result_get_error(result);
else
*error_r = NULL;
sql_result_free(result);
}
i_free(ctx);
return *error_r == NULL ? 0 : -1;
}
static void
driver_pgsql_transaction_rollback(struct sql_transaction_context *_ctx)
{
struct pgsql_transaction_context *ctx =
(struct pgsql_transaction_context *)_ctx;
if (ctx->opened)
sql_exec(_ctx->db, "ROLLBACK");
i_free(ctx);
}
static void
transaction_update_callback(struct sql_result *result,
struct pgsql_transaction_context *ctx)
{
if (sql_result_next_row(result) < 0) {
ctx->failed = TRUE;
ctx->error = sql_result_get_error(result);
}
}
static void
driver_pgsql_update(struct sql_transaction_context *_ctx, const char *query)
{
struct pgsql_transaction_context *ctx =
(struct pgsql_transaction_context *)_ctx;
if (ctx->failed)
return;
if (!ctx->opened) {
ctx->opened = TRUE;
sql_query(_ctx->db, "BEGIN", transaction_update_callback, ctx);
}
sql_query(_ctx->db, query, transaction_update_callback, ctx);
}
struct sql_db driver_pgsql_db = {
"pgsql",
_driver_pgsql_init,
_driver_pgsql_deinit,
driver_pgsql_get_flags,
driver_pgsql_connect,
driver_pgsql_escape_string,
driver_pgsql_exec,
driver_pgsql_query,
driver_pgsql_query_s,
driver_pgsql_transaction_begin,
driver_pgsql_transaction_commit,
driver_pgsql_transaction_commit_s,
driver_pgsql_transaction_rollback,
driver_pgsql_update
};
struct sql_result driver_pgsql_result = {
NULL,
driver_pgsql_result_free,
driver_pgsql_result_next_row,
driver_pgsql_result_get_fields_count,
driver_pgsql_result_get_field_name,
driver_pgsql_result_find_field,
driver_pgsql_result_get_field_value,
driver_pgsql_result_find_field_value,
driver_pgsql_result_get_values,
driver_pgsql_result_get_error,
FALSE
};
void driver_pgsql_init(void);
void driver_pgsql_deinit(void);
void driver_pgsql_init(void)
{
sql_driver_register(&driver_pgsql_db);
}
void driver_pgsql_deinit(void)
{
sql_driver_unregister(&driver_pgsql_db);
}
#endif