dict-sql.c revision 4073f0dbf3277f981a8fcee3b89ea15aaf380a7f
/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "str.h"
#include "sql-api-private.h"
#include "sql-pool.h"
#include "dict-private.h"
#include "dict-sql-settings.h"
#include "dict-sql.h"
#include <unistd.h>
#include <fcntl.h>
#define DICT_SQL_MAX_UNUSED_CONNECTIONS 10
enum sql_recurse_type {
};
struct sql_dict {
const char *username;
const struct dict_sql_settings *set;
unsigned int prev_map_match_idx;
unsigned int has_on_duplicate_key:1;
};
struct sql_dict_iterate_context {
struct dict_iterate_context ctx;
enum dict_iterate_flags flags;
char *path;
struct sql_result *result;
const struct dict_sql_map *map;
};
struct sql_dict_transaction_context {
struct dict_transaction_context ctx;
struct sql_transaction_context *sql_ctx;
const struct dict_sql_map *prev_inc_map;
char *prev_inc_key;
long long prev_inc_diff;
unsigned int failed:1;
unsigned int changed:1;
};
static struct sql_pool *dict_sql_pool;
static struct dict *
{
pool_unref(&pool);
return NULL;
}
/* currently pgsql and sqlite don't support "ON DUPLICATE KEY" */
}
{
}
static bool
unsigned int *path_len_r, bool partial_ok)
{
const char *path_start = path;
unsigned int len;
if (*pat == '$') {
/* variable */
pat++;
if (*pat == '\0') {
/* pattern ended with this variable,
it'll match the rest of the path */
if (partial_ok) {
/* iterating - the last field never
matches fully. if there's a trailing
'/', drop it. */
pat--;
} else {
}
} else {
}
return TRUE;
}
/* pattern matches until the next '/' in path */
if (p != NULL) {
path = p;
} else {
/* no '/' anymore, but it'll still match a
partial */
pat++;
}
pat++;
path++;
} else {
return FALSE;
}
}
if (*pat == '\0')
return *path == '\0';
else if (!partial_ok)
return FALSE;
else {
/* partial matches must end with '/' */
}
}
static const struct dict_sql_map *
{
const struct dict_sql_map *maps;
for (i = 0; i < count; i++) {
/* start matching from the previously successful match */
}
}
return NULL;
}
static void
{
const char *const *sql_fields, *const *values;
/* if we came here from iteration code there may be less values */
/* we want everything */
return;
}
for (i = 0; i < exact_count; i++) {
if (i > 0)
}
switch (recurse_type) {
case SQL_DICT_RECURSE_NONE:
break;
case SQL_DICT_RECURSE_ONE:
if (i > 0)
if (i < count2) {
"%s NOT LIKE '%s/%%/%%'",
sql_fields[i],
sql_fields[i],
} else {
"%s NOT LIKE '%%/%%'",
sql_fields[i], sql_fields[i]);
}
break;
case SQL_DICT_RECURSE_FULL:
if (i < count2) {
if (i > 0)
}
break;
}
if (priv) {
if (count2 > 0)
}
}
{
const struct dict_sql_map *map;
struct sql_result *result;
int ret;
return 0;
}
T_BEGIN {
} T_END;
if (ret <= 0) {
if (ret < 0) {
i_error("dict sql lookup failed: %s",
}
} else {
*value_r =
}
return ret;
}
static const struct dict_sql_map *
{
const struct dict_sql_map *maps;
return &maps[i];
}
}
return NULL;
}
{
const struct dict_sql_map *map;
const char *const *sql_fields;
enum sql_recurse_type recurse_type;
unsigned int i, count;
return FALSE;
T_BEGIN {
/* get all missing fields */
i = array_count(&values);
if (i == count) {
/* we always want to know the last field since we're
iterating its children */
i_assert(i > 0);
i--;
}
for (; i < count; i++)
for (i = 0; i < count; i++) {
if (i < count-1)
}
} T_END;
return TRUE;
}
static struct dict_iterate_context *
enum dict_iterate_flags flags)
{
struct sql_dict_iterate_context *ctx;
if (!sql_dict_iterate_next_query(ctx)) {
}
}
{
struct sql_dict_iterate_context *ctx =
(struct sql_dict_iterate_context *)_ctx;
const char *p, *value;
unsigned int i, count;
int ret;
return -1;
/* see if there are more results in the next map */
if (!sql_dict_iterate_next_query(ctx))
return 0;
}
if (ret < 0) {
i_error("dict sql iterate failed: %s",
return ret;
}
/* convert fetched row to dict key */
if (ctx->key_prefix_len > 0 &&
i = 1;
if (*p != '$')
else {
i++;
}
}
return 1;
}
{
struct sql_dict_iterate_context *ctx =
(struct sql_dict_iterate_context *)_ctx;
}
static struct dict_transaction_context *
{
struct sql_dict_transaction_context *ctx;
}
bool async ATTR_UNUSED)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
const char *error;
int ret;
ret = -1;
if (ret < 0)
} else {
/* nothing to be done */
ret = 0;
}
return ret;
}
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
}
struct dict_sql_build_query_field {
const struct dict_sql_map *map;
const char *value;
};
struct dict_sql_build_query {
char key1;
bool inc;
};
{
const struct dict_sql_build_query_field *fields;
const char *const *sql_fields, *const *extra_values;
i_assert(field_count > 0);
for (i = 0; i < field_count; i++) {
if (i > 0) {
}
else {
}
}
}
/* add the other fields from the key */
for (i = 0; i < count; i++) {
}
if (!dict->has_on_duplicate_key)
for (i = 0; i < field_count; i++) {
if (i > 0)
} else {
}
}
}
static const char *
{
const struct dict_sql_build_query_field *fields;
unsigned int i, field_count;
i_assert(field_count > 0);
for (i = 0; i < field_count; i++) {
if (i > 0)
else
}
}
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
const struct dict_sql_map *map;
return;
}
T_BEGIN {
struct dict_sql_build_query build;
struct dict_sql_build_query_field field;
const char *query;
} T_END;
}
const char *key)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
const struct dict_sql_map *map;
return;
}
T_BEGIN {
} T_END;
}
{
const struct dict_sql_map *map;
T_BEGIN {
struct dict_sql_build_query build;
struct dict_sql_build_query_field field;
const char *query;
if (diff >= 0)
else {
/* negative changes can't never be initial values,
use UPDATE directly. */
}
} T_END;
}
{
}
static bool
const struct dict_sql_map *map1,
const struct dict_sql_map *map2,
{
const struct dict_sql_map *map3;
return FALSE;
return FALSE;
if (map1_key[0] == DICT_PATH_PRIVATE[0]) {
return FALSE;
}
return FALSE;
for (i = 0; i < count1; i++) {
return FALSE;
}
return TRUE;
}
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
const struct dict_sql_map *map;
return;
}
/* see if we can merge this increment SQL query with the
next one */
return;
}
} else T_BEGIN {
struct dict_sql_build_query build;
struct dict_sql_build_query_field *field;
const char *query;
if (diff >= 0)
else {
/* negative changes can't never be initial values,
use UPDATE directly. */
}
} T_END;
}
{
}
};
static struct dict *dict_sql_drivers;
void dict_sql_register(void)
{
unsigned int i, count;
/* @UNSAFE */
for (i = 0; i < count; i++) {
dict_sql_drivers[i] = sql_dict;
}
}
void dict_sql_unregister(void)
{
int i;
}