driver-cassandra.c revision b23a8d3514760899ac1094f2a8103a057ae6416d
/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "ioloop.h"
#include "write-full.h"
#include "sql-api-private.h"
#ifdef BUILD_CASSANDRA
#include <unistd.h>
#include <cassandra.h>
#define IS_CONNECTED(db) \
struct cassandra_callback {
unsigned int id;
struct cassandra_db *db;
void *context;
};
struct cassandra_db {
int fd_pipe[2];
unsigned int callback_ids;
struct cassandra_result *cur_result;
struct sql_result *sync_result;
char *error;
unsigned int set_consistency:1;
};
struct cassandra_result {
struct sql_result api;
const CassResult *result;
char *query;
char *error;
void *context;
unsigned int finished:1;
};
struct cassandra_transaction_context {
struct sql_transaction_context ctx;
int refcount;
void *context;
const char *error;
unsigned int begin_succeeded:1;
unsigned int begin_failed:1;
unsigned int failed:1;
};
extern const struct sql_db driver_cassandra_db;
extern const struct sql_result driver_cassandra_result;
static struct {
const char *name;
} cass_consistency_names[] = {
{ CASS_CONSISTENCY_ANY, "any" },
{ CASS_CONSISTENCY_ONE, "one" },
{ CASS_CONSISTENCY_TWO, "two" },
{ CASS_CONSISTENCY_THREE, "three" },
{ CASS_CONSISTENCY_QUORUM, "" },
{ CASS_CONSISTENCY_ALL, "all" },
{ CASS_CONSISTENCY_QUORUM, "" },
{ CASS_CONSISTENCY_ALL, "all" },
{ CASS_CONSISTENCY_LOCAL_QUORUM, "local-quorum" },
{ CASS_CONSISTENCY_EACH_QUORUM, "each-quorum" },
{ CASS_CONSISTENCY_SERIAL, "serial" },
{ CASS_CONSISTENCY_LOCAL_SERIAL, "local-serial" },
{ CASS_CONSISTENCY_LOCAL_ONE, "local-one" }
};
static struct {
const char *name;
} cass_log_level_names[] = {
{ CASS_LOG_CRITICAL, "critical" },
{ CASS_LOG_ERROR, "error" },
{ CASS_LOG_WARN, "warn" },
{ CASS_LOG_INFO, "info" },
{ CASS_LOG_DEBUG, "debug" },
{ CASS_LOG_TRACE, "trace" }
};
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(cass_consistency_names); i++) {
return 0;
}
}
return -1;
}
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(cass_log_level_names); i++) {
return 0;
}
}
return -1;
}
{
/* switch back to original ioloop in case the caller wants to
}
{
}
/* running a sync query, stop it */
}
}
{
const char *message;
}
void *context)
{
/* this isn't the main thread - communicate with main thread by
writing the callback id to the pipe */
i_error("cassandra: write(pipe) failed: %m");
}
{
}
{
/* usually there are only a few callbacks, so don't bother with using
a hash table */
return;
}
}
}
{
unsigned int ids[1024];
if (ret < 0)
i_error("cassandra: read(pipe) failed: %m");
else if (ret == 0)
i_error("cassandra: read(pipe) failed: EOF");
i_error("cassandra: read(pipe) returned wrong amount of data");
else {
/* success */
return;
}
}
static void
void *context)
{
struct cassandra_callback *cb;
}
{
"Couldn't connect to Cassandra");
return;
}
/* driver_cassandra_sync_init() waiting for connection to
finish */
}
}
{
i_error("pipe() failed: %m");
return -1;
}
return 0;
}
{
}
}
static const char *
const char *string)
{
unsigned int i;
return string;
for (i = 0; string[i] != '\0'; i++) {
if (string[i] == '\'')
}
}
const char *connect_string)
{
i_fatal("cassandra: Missing value in connect string: %s",
*args);
}
} else {
}
}
i_fatal("cassandra: No hosts given in connect string");
i_fatal("cassandra: No dbname given in connect string");
}
{
struct cassandra_db *db;
T_BEGIN {
} T_END;
}
{
}
}
{
}
{
/* we're coming here from a user's sql_result_free() that's
being called from a callback. we'll do this later,
so ignore. */
return;
}
}
{
bool free_result = TRUE;
}
T_BEGIN {
} T_END;
if (free_result)
}
{
const char *errmsg;
return;
}
}
{
if (db->set_consistency)
}
void *context ATTR_UNUSED)
{
}
{
struct cassandra_result *result;
}
{
struct cassandra_result *result;
}
{
}
{
return;
if (IS_CONNECTED(db))
return;
/* wait for connecting to finish */
}
{
return;
}
}
static struct sql_result *
{
struct sql_result *result;
case SQL_DB_STATE_CONNECTING:
case SQL_DB_STATE_BUSY:
i_unreached();
return &sql_not_connected_result;
case SQL_DB_STATE_IDLE:
break;
}
}
if (result == &sql_not_connected_result) {
/* we don't end up in cassandra's free function, so sync_result
won't be set to NULL if we don't do it here. */
}
return result;
}
static struct sql_result *
{
struct sql_result *result;
return result;
}
static int
{
const char *output;
if (cass_value_is_null(value)) {
return 0;
}
return -1;
}
return 0;
}
{
const char *str;
unsigned int i;
int ret = 1;
return -1;
return 0;
ret = -1;
break;
}
}
return ret;
}
static unsigned int
{
}
static const char *
unsigned int idx ATTR_UNUSED)
{
i_unreached();
}
static int
const char *field_name ATTR_UNUSED)
{
i_unreached();
}
static const char *
unsigned int idx)
{
const char *const *strp;
return *strp;
}
static const unsigned char *
unsigned int idx ATTR_UNUSED,
{
i_unreached();
}
static const char *
const char *field_name ATTR_UNUSED)
{
i_unreached();
}
static const char *const *
{
}
{
return "FIXME";
}
static struct sql_transaction_context *
{
struct cassandra_transaction_context *ctx;
/* we need to be able to handle multiple open transactions, so at least
for now just keep them in memory until commit time. */
}
static void
{
return;
}
static void
struct cassandra_transaction_context *ctx)
{
if (sql_result_next_row(result) < 0) {
} else {
}
}
static void
struct cassandra_transaction_context *ctx)
{
if (sql_result_next_row(result) < 0)
else
}
static void
struct sql_transaction_query *query)
{
struct cassandra_transaction_context *ctx =
if (sql_result_next_row(result) < 0) {
}
}
static void
{
struct cassandra_transaction_context *ctx =
(struct cassandra_transaction_context *)_ctx;
/* just a single query, send it */
} else {
/* multiple queries, use a transaction */
}
}
}
static void
{
}
static int
struct sql_result **result_r)
{
struct sql_result *result;
struct sql_transaction_query *query;
int ret = 0;
if (sql_result_next_row(result) < 0) {
return -1;
}
/* send queries */
if (sql_result_next_row(result) < 0) {
ret = -1;
break;
}
}
"ROLLBACK" : "COMMIT");
return ret;
}
static void
const char **error_r)
{
int ret = 0;
/* just a single query, send it */
} else {
/* multiple queries, use a transaction */
}
} else {
if (sql_result_next_row(result) < 0) {
}
}
}
static int
const char **error_r)
{
struct cassandra_transaction_context *ctx =
(struct cassandra_transaction_context *)_ctx;
}
static void
{
struct cassandra_transaction_context *ctx =
(struct cassandra_transaction_context *)_ctx;
}
static void
unsigned int *affected_rows)
{
struct cassandra_transaction_context *ctx =
(struct cassandra_transaction_context *)_ctx;
}
const struct sql_db driver_cassandra_db = {
.name = "cassandra",
.flags = 0,
.v = {
}
};
const struct sql_result driver_cassandra_result = {
.v = {
}
};
const char *driver_cassandra_version = DOVECOT_ABI_VERSION;
void driver_cassandra_init(void);
void driver_cassandra_deinit(void);
void driver_cassandra_init(void)
{
}
void driver_cassandra_deinit(void)
{
}
#endif