"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/lib-sql/driver-pgsql.c" between
dovecot-2.3.16.tar.gz and dovecot-2.3.17.tar.gz

About: Dovecot is an IMAP and POP3 server, written with security primarily in mind.

driver-pgsql.c  (dovecot-2.3.16):driver-pgsql.c  (dovecot-2.3.17)
/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */ /* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
#include "lib.h" #include "lib.h"
#include "array.h" #include "array.h"
#include "ioloop.h" #include "ioloop.h"
#include "hex-binary.h" #include "hex-binary.h"
#include "str.h" #include "str.h"
#include "time-util.h" #include "time-util.h"
#include "sql-api-private.h" #include "sql-api-private.h"
#include "llist.h"
#ifdef BUILD_PGSQL #ifdef BUILD_PGSQL
#include <libpq-fe.h> #include <libpq-fe.h>
#define PGSQL_DNS_WARN_MSECS 500 #define PGSQL_DNS_WARN_MSECS 500
struct pgsql_db { struct pgsql_db {
struct sql_db api; struct sql_db api;
pool_t pool; pool_t pool;
char *connect_string; char *connect_string;
char *host; char *host;
PGconn *pg; PGconn *pg;
struct io *io; struct io *io;
struct timeout *to_connect; struct timeout *to_connect;
enum io_condition io_dir; enum io_condition io_dir;
struct pgsql_result *pending_results;
struct pgsql_result *cur_result; struct pgsql_result *cur_result;
struct ioloop *ioloop, *orig_ioloop; struct ioloop *ioloop, *orig_ioloop;
struct sql_result *sync_result; struct sql_result *sync_result;
bool (*next_callback)(void *); bool (*next_callback)(void *);
void *next_context; void *next_context;
char *error; char *error;
const char *connect_state; const char *connect_state;
bool fatal_error:1; bool fatal_error:1;
}; };
struct pgsql_binary_value { struct pgsql_binary_value {
unsigned char *value; unsigned char *value;
size_t size; size_t size;
}; };
struct pgsql_result { struct pgsql_result {
struct sql_result api; struct sql_result api;
struct pgsql_result *prev, *next;
PGresult *pgres; PGresult *pgres;
struct timeout *to; struct timeout *to;
unsigned int rownum, rows; unsigned int rownum, rows;
unsigned int fields_count; unsigned int fields_count;
const char **fields; const char **fields;
const char **values; const char **values;
char *query; char *query;
ARRAY(struct pgsql_binary_value) binary_values; ARRAY(struct pgsql_binary_value) binary_values;
skipping to change at line 286 skipping to change at line 291
} }
static void driver_pgsql_free(struct pgsql_db **_db) static void driver_pgsql_free(struct pgsql_db **_db)
{ {
struct pgsql_db *db = *_db; struct pgsql_db *db = *_db;
*_db = NULL; *_db = NULL;
event_unref(&db->api.event); event_unref(&db->api.event);
i_free(db->connect_string); i_free(db->connect_string);
i_free(db->host); i_free(db->host);
i_free(db->error);
array_free(&db->api.module_contexts); array_free(&db->api.module_contexts);
i_free(db); i_free(db);
} }
static enum sql_db_flags driver_pgsql_get_flags(struct sql_db *db)
{
switch (db->state) {
case SQL_DB_STATE_DISCONNECTED:
if (sql_connect(db) < 0)
break;
/* fall through */
case SQL_DB_STATE_CONNECTING:
/* Wait for connection to finish, so we can get the flags
reliably. */
sql_wait(db);
break;
case SQL_DB_STATE_IDLE:
case SQL_DB_STATE_BUSY:
break;
}
return db->flags;
}
static int driver_pgsql_init_full_v(const struct sql_settings *set, static int driver_pgsql_init_full_v(const struct sql_settings *set,
struct sql_db **db_r, const char **error_r AT TR_UNUSED) struct sql_db **db_r, const char **error_r AT TR_UNUSED)
{ {
struct pgsql_db *db; struct pgsql_db *db;
db = i_new(struct pgsql_db, 1); db = i_new(struct pgsql_db, 1);
db->connect_string = i_strdup(set->connect_string); db->connect_string = i_strdup(set->connect_string);
db->api = driver_pgsql_db; db->api = driver_pgsql_db;
db->api.event = event_create(set->event_parent); db->api.event = event_create(set->event_parent);
event_add_category(db->api.event, &event_category_pgsql); event_add_category(db->api.event, &event_category_pgsql);
skipping to change at line 414 skipping to change at line 439
} }
static void result_finish(struct pgsql_result *result) static void result_finish(struct pgsql_result *result)
{ {
struct pgsql_db *db = (struct pgsql_db *)result->api.db; struct pgsql_db *db = (struct pgsql_db *)result->api.db;
bool free_result = TRUE; bool free_result = TRUE;
int duration; int duration;
i_assert(db->io == NULL); i_assert(db->io == NULL);
timeout_remove(&result->to); timeout_remove(&result->to);
DLLIST_REMOVE(&db->pending_results, result);
/* if connection to server was lost, we don't yet see that the /* if connection to server was lost, we don't yet see that the
connection is bad. we only see the fatal error, so assume it also connection is bad. we only see the fatal error, so assume it also
means disconnection. */ means disconnection. */
if (PQstatus(db->pg) == CONNECTION_BAD || result->pgres == NULL || if (PQstatus(db->pg) == CONNECTION_BAD || result->pgres == NULL ||
PQresultStatus(result->pgres) == PGRES_FATAL_ERROR) PQresultStatus(result->pgres) == PGRES_FATAL_ERROR)
db->fatal_error = TRUE; db->fatal_error = TRUE;
if (db->fatal_error) { if (db->fatal_error) {
result->api.failed = TRUE; result->api.failed = TRUE;
skipping to change at line 525 skipping to change at line 551
{ {
struct pgsql_db *db = (struct pgsql_db *)result->api.db; struct pgsql_db *db = (struct pgsql_db *)result->api.db;
int ret; int ret;
i_assert(SQL_DB_IS_READY(&db->api)); i_assert(SQL_DB_IS_READY(&db->api));
i_assert(db->cur_result == NULL); i_assert(db->cur_result == NULL);
i_assert(db->io == NULL); i_assert(db->io == NULL);
driver_pgsql_set_state(db, SQL_DB_STATE_BUSY); driver_pgsql_set_state(db, SQL_DB_STATE_BUSY);
db->cur_result = result; db->cur_result = result;
DLLIST_PREPEND(&db->pending_results, result);
result->to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000, result->to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
query_timeout, result); query_timeout, result);
result->query = i_strdup(query); result->query = i_strdup(query);
if (PQsendQuery(db->pg, query) == 0 || if (PQsendQuery(db->pg, query) == 0 ||
(ret = PQflush(db->pg)) < 0) { (ret = PQflush(db->pg)) < 0) {
/* failed to send query */ /* failed to send query */
result_finish(result); result_finish(result);
return; return;
} }
skipping to change at line 819 skipping to change at line 846
if (PQgetisnull(result->pgres, result->rownum, idx) != 0) { if (PQgetisnull(result->pgres, result->rownum, idx) != 0) {
*size_r = 0; *size_r = 0;
return NULL; return NULL;
} }
value = PQgetvalue(result->pgres, result->rownum, idx); value = PQgetvalue(result->pgres, result->rownum, idx);
if (!array_is_created(&result->binary_values)) if (!array_is_created(&result->binary_values))
i_array_init(&result->binary_values, idx + 1); i_array_init(&result->binary_values, idx + 1);
binary_value = array_idx_modifiable(&result->binary_values, idx); binary_value = array_idx_get_space(&result->binary_values, idx);
if (binary_value->value == NULL) { if (binary_value->value == NULL) {
binary_value->value = binary_value->value =
PQunescapeBytea((const unsigned char *)value, PQunescapeBytea((const unsigned char *)value,
&binary_value->size); &binary_value->size);
} }
*size_r = binary_value->size; *size_r = binary_value->size;
return binary_value->value; return binary_value->value;
} }
skipping to change at line 1229 skipping to change at line 1256
sql_transaction_add_query(_ctx, ctx->query_pool, query, affected_rows); sql_transaction_add_query(_ctx, ctx->query_pool, query, affected_rows);
} }
static const char * static const char *
driver_pgsql_escape_blob(struct sql_db *_db ATTR_UNUSED, driver_pgsql_escape_blob(struct sql_db *_db ATTR_UNUSED,
const unsigned char *data, size_t size) const unsigned char *data, size_t size)
{ {
string_t *str = t_str_new(128); string_t *str = t_str_new(128);
str_append(str, "E'\\x"); str_append(str, "E'\\\\x");
binary_to_hex_append(str, data, size); binary_to_hex_append(str, data, size);
str_append_c(str, '\''); str_append_c(str, '\'');
return str_c(str); return str_c(str);
} }
static bool driver_pgsql_have_work(struct pgsql_db *db)
{
return db->next_callback != NULL || db->pending_results != NULL ||
db->api.state == SQL_DB_STATE_CONNECTING;
}
static void driver_pgsql_wait(struct sql_db *_db)
{
struct pgsql_db *db = (struct pgsql_db *)_db;
if (!driver_pgsql_have_work(db))
return;
struct ioloop *prev_ioloop = current_ioloop;
db->ioloop = io_loop_create();
db->io = io_loop_move_io(&db->io);
while (driver_pgsql_have_work(db))
io_loop_run(db->ioloop);
io_loop_set_current(prev_ioloop);
db->io = io_loop_move_io(&db->io);
io_loop_set_current(db->ioloop);
io_loop_destroy(&db->ioloop);
}
const struct sql_db driver_pgsql_db = { const struct sql_db driver_pgsql_db = {
.name = "pgsql", .name = "pgsql",
.flags = SQL_DB_FLAG_POOLED, .flags = SQL_DB_FLAG_POOLED,
.v = { .v = {
.get_flags = driver_pgsql_get_flags,
.init_full = driver_pgsql_init_full_v, .init_full = driver_pgsql_init_full_v,
.deinit = driver_pgsql_deinit_v, .deinit = driver_pgsql_deinit_v,
.connect = driver_pgsql_connect, .connect = driver_pgsql_connect,
.disconnect = driver_pgsql_disconnect, .disconnect = driver_pgsql_disconnect,
.escape_string = driver_pgsql_escape_string, .escape_string = driver_pgsql_escape_string,
.exec = driver_pgsql_exec, .exec = driver_pgsql_exec,
.query = driver_pgsql_query, .query = driver_pgsql_query,
.query_s = driver_pgsql_query_s, .query_s = driver_pgsql_query_s,
.wait = driver_pgsql_wait,
.transaction_begin = driver_pgsql_transaction_begin, .transaction_begin = driver_pgsql_transaction_begin,
.transaction_commit = driver_pgsql_transaction_commit, .transaction_commit = driver_pgsql_transaction_commit,
.transaction_commit_s = driver_pgsql_transaction_commit_s, .transaction_commit_s = driver_pgsql_transaction_commit_s,
.transaction_rollback = driver_pgsql_transaction_rollback, .transaction_rollback = driver_pgsql_transaction_rollback,
.update = driver_pgsql_update, .update = driver_pgsql_update,
.escape_blob = driver_pgsql_escape_blob, .escape_blob = driver_pgsql_escape_blob,
} }
 End of changes. 12 change blocks. 
2 lines changed or deleted 56 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)