Merge branch 'binlog_server_wait_data' into binlog_server_waitdata_encryption
This commit is contained in:
@ -290,8 +290,29 @@ where,
|
||||
* the _op_ can be `=`, `!=`, `like` or `unlike`, and
|
||||
* the _value_ a string.
|
||||
|
||||
If _op_ is `=` or `!=` then _value_ is used verbatim; if it is `like`
|
||||
or `unlike`, then _value_ is interpreted as a _pcre2_ regular expression.
|
||||
If _op_ is `=` or `!=` then _value_ is interpreted as a MariaDB account
|
||||
string, that is, `%` means indicates wildcard, but if _op_ is `like` or
|
||||
`unlike` it is simply assumed _value_ is a pcre2 regular expression.
|
||||
|
||||
For instance, the following are equivalent:
|
||||
|
||||
```
|
||||
{
|
||||
"attribute": "user",
|
||||
"op": "=",
|
||||
"value": "'bob'@'%'"
|
||||
}
|
||||
|
||||
{
|
||||
"attribute": "user",
|
||||
"op": "like",
|
||||
"value": "bob@.*"
|
||||
}
|
||||
|
||||
Note that if _op_ is `=` or `!=` then the usual assumptions apply,
|
||||
that is, a value of `bob` is equivalent with `'bob'@'%'`. If _like_
|
||||
or _unlike_ is used, then no assumptions apply, but the string is
|
||||
used verbatim as a regular expression.
|
||||
|
||||
The objects in the `use` array are processed in order. If the result
|
||||
of a comparison is _true_, no further processing will be made and the
|
||||
@ -307,7 +328,8 @@ rule in the `store` array.
|
||||
|
||||
### Examples
|
||||
|
||||
Use data from the cache for all users except `admin`.
|
||||
Use data from the cache for all users except `admin` (actually `'admin'@'%'`),
|
||||
regardless of what host the `admin` user comes from.
|
||||
```
|
||||
{
|
||||
"use": [
|
||||
@ -319,6 +341,7 @@ Use data from the cache for all users except `admin`.
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
# Storage
|
||||
|
||||
## Storage RocksDB
|
||||
|
@ -1,6 +1,19 @@
|
||||
#ifndef _HK_HEARTBEAT_H
|
||||
#define _HK_HEARTBEAT_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The global housekeeper heartbeat value. This value is incremented
|
||||
* every 100 milliseconds and may be used for crude timing etc.
|
||||
|
@ -1,5 +1,19 @@
|
||||
#ifndef TEST_UTILS_H
|
||||
#define TEST_UTILS_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#include <maxscale/poll.h>
|
||||
#include <dcb.h>
|
||||
#include <housekeeper.h>
|
||||
|
4
server/modules/filter/cache/CMakeLists.txt
vendored
4
server/modules/filter/cache/CMakeLists.txt
vendored
@ -5,3 +5,7 @@ set_target_properties(cache PROPERTIES LINK_FLAGS -Wl,-z,defs)
|
||||
install_module(cache experimental)
|
||||
|
||||
add_subdirectory(storage)
|
||||
|
||||
if(BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
514
server/modules/filter/cache/rules.c
vendored
514
server/modules/filter/cache/rules.c
vendored
@ -63,10 +63,8 @@ static struct cache_attribute_mapping cache_use_attributes[] =
|
||||
static bool cache_rule_attribute_get(struct cache_attribute_mapping *mapping,
|
||||
const char *s,
|
||||
cache_rule_attribute_t *attribute);
|
||||
static const char *cache_rule_attribute_to_string(cache_rule_attribute_t attribute);
|
||||
|
||||
static bool cache_rule_op_get(const char *s, cache_rule_op_t *op);
|
||||
static const char *cache_rule_op_to_string(cache_rule_op_t op);
|
||||
|
||||
static bool cache_rule_compare(CACHE_RULE *rule, const char *value);
|
||||
static bool cache_rule_compare_n(CACHE_RULE *rule, const char *value, size_t length);
|
||||
@ -104,6 +102,7 @@ static bool cache_rule_matches(CACHE_RULE *rule, const char *default_db, const G
|
||||
|
||||
static void cache_rules_add_store_rule(CACHE_RULES* self, CACHE_RULE* rule);
|
||||
static void cache_rules_add_use_rule(CACHE_RULES* self, CACHE_RULE* rule);
|
||||
static CACHE_RULES* cache_rules_create_from_json(json_t* root, uint32_t debug);
|
||||
static bool cache_rules_parse_json(CACHE_RULES* self, json_t* root);
|
||||
|
||||
typedef bool (*cache_rules_parse_element_t)(CACHE_RULES *self, json_t *object, size_t index);
|
||||
@ -113,10 +112,86 @@ static bool cache_rules_parse_array(CACHE_RULES *self, json_t *store, const char
|
||||
static bool cache_rules_parse_store_element(CACHE_RULES *self, json_t *object, size_t index);
|
||||
static bool cache_rules_parse_use_element(CACHE_RULES *self, json_t *object, size_t index);
|
||||
|
||||
static bool dequote_mysql(char *s);
|
||||
|
||||
typedef enum pcre_quote_approach
|
||||
{
|
||||
PCRE_QUOTE_VERBATIM,
|
||||
PCRE_QUOTE_QUERY
|
||||
} pcre_quote_approach_t;
|
||||
|
||||
typedef enum mysql_account_kind
|
||||
{
|
||||
MYSQL_ACCOUNT_WITH_WILDCARD,
|
||||
MYSQL_ACCOUNT_WITHOUT_WILDCARD
|
||||
} mysql_account_kind_t;
|
||||
|
||||
static mysql_account_kind_t mysql_to_pcre(char *pcre, const char *mysql, pcre_quote_approach_t approach);
|
||||
|
||||
/*
|
||||
* API begin
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a string representation of a attribute.
|
||||
*
|
||||
* @param attribute An attribute type.
|
||||
*
|
||||
* @return Corresponding string, not to be freed.
|
||||
*/
|
||||
const char *cache_rule_attribute_to_string(cache_rule_attribute_t attribute)
|
||||
{
|
||||
switch (attribute)
|
||||
{
|
||||
case CACHE_ATTRIBUTE_COLUMN:
|
||||
return "column";
|
||||
|
||||
case CACHE_ATTRIBUTE_DATABASE:
|
||||
return "database";
|
||||
|
||||
case CACHE_ATTRIBUTE_QUERY:
|
||||
return "query";
|
||||
|
||||
case CACHE_ATTRIBUTE_TABLE:
|
||||
return "table";
|
||||
|
||||
case CACHE_ATTRIBUTE_USER:
|
||||
return "user";
|
||||
|
||||
default:
|
||||
ss_dassert(!true);
|
||||
return "<invalid>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of an operator.
|
||||
*
|
||||
* @param op An operator.
|
||||
*
|
||||
* @return Corresponding string, not to be freed.
|
||||
*/
|
||||
const char *cache_rule_op_to_string(cache_rule_op_t op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case CACHE_OP_EQ:
|
||||
return "=";
|
||||
|
||||
case CACHE_OP_NEQ:
|
||||
return "!=";
|
||||
|
||||
case CACHE_OP_LIKE:
|
||||
return "like";
|
||||
|
||||
case CACHE_OP_UNLIKE:
|
||||
return "unlike";
|
||||
|
||||
default:
|
||||
ss_dassert(!true);
|
||||
return "<invalid>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default cache rules object.
|
||||
@ -158,17 +233,7 @@ CACHE_RULES *cache_rules_load(const char *path, uint32_t debug)
|
||||
|
||||
if (root)
|
||||
{
|
||||
rules = cache_rules_create(debug);
|
||||
|
||||
if (rules)
|
||||
{
|
||||
if (!cache_rules_parse_json(rules, root))
|
||||
{
|
||||
cache_rules_free(rules);
|
||||
rules = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
rules = cache_rules_create_from_json(root, debug);
|
||||
json_decref(root);
|
||||
}
|
||||
else
|
||||
@ -190,6 +255,35 @@ CACHE_RULES *cache_rules_load(const char *path, uint32_t debug)
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the caching rules from a string and returns corresponding object.
|
||||
*
|
||||
* @param json String containing json.
|
||||
* @param debug The debug level.
|
||||
*
|
||||
* @return The corresponding rules object, or NULL in case of error.
|
||||
*/
|
||||
CACHE_RULES *cache_rules_parse(const char *json, uint32_t debug)
|
||||
{
|
||||
CACHE_RULES *rules = NULL;
|
||||
|
||||
json_error_t error;
|
||||
json_t *root = json_loads(json, JSON_DISABLE_EOF_CHECK, &error);
|
||||
|
||||
if (root)
|
||||
{
|
||||
rules = cache_rules_create_from_json(root, debug);
|
||||
json_decref(root);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Parsing rules failed: (%d:%d): %s",
|
||||
error.line, error.column, error.text);
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the rules object.
|
||||
*
|
||||
@ -252,12 +346,27 @@ bool cache_rules_should_use(CACHE_RULES *self, const SESSION *session)
|
||||
|
||||
CACHE_RULE *rule = self->use_rules;
|
||||
const char *user = session_getUser((SESSION*)session);
|
||||
const char *host = session_get_remote((SESSION*)session);
|
||||
|
||||
if (rule && user)
|
||||
if (!user)
|
||||
{
|
||||
user = "";
|
||||
}
|
||||
|
||||
if (!host)
|
||||
{
|
||||
host = "";
|
||||
}
|
||||
|
||||
if (rule)
|
||||
{
|
||||
char account[strlen(user) + 1 + strlen(host) + 1];
|
||||
sprintf(account, "%s@%s", user, host);
|
||||
|
||||
while (rule && !should_use)
|
||||
{
|
||||
should_use = cache_rule_matches_user(rule, user);
|
||||
should_use = cache_rule_matches_user(rule, account);
|
||||
|
||||
rule = rule->next;
|
||||
}
|
||||
}
|
||||
@ -301,35 +410,6 @@ static bool cache_rule_attribute_get(struct cache_attribute_mapping *mapping,
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of a attribute.
|
||||
*
|
||||
* @param attribute An attribute type.
|
||||
*
|
||||
* @return Corresponding string, not to be freed.
|
||||
*/
|
||||
static const char *cache_rule_attribute_to_string(cache_rule_attribute_t attribute)
|
||||
{
|
||||
switch (attribute)
|
||||
{
|
||||
case CACHE_ATTRIBUTE_COLUMN:
|
||||
return "column";
|
||||
|
||||
case CACHE_ATTRIBUTE_DATABASE:
|
||||
return "database";
|
||||
|
||||
case CACHE_ATTRIBUTE_QUERY:
|
||||
return "query";
|
||||
|
||||
case CACHE_ATTRIBUTE_TABLE:
|
||||
return "table";
|
||||
|
||||
default:
|
||||
ss_dassert(!true);
|
||||
return "<invalid>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to an operator
|
||||
*
|
||||
@ -367,35 +447,6 @@ static bool cache_rule_op_get(const char *s, cache_rule_op_t *op)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of an operator.
|
||||
*
|
||||
* @param op An operator.
|
||||
*
|
||||
* @return Corresponding string, not to be freed.
|
||||
*/
|
||||
static const char *cache_rule_op_to_string(cache_rule_op_t op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case CACHE_OP_EQ:
|
||||
return "=";
|
||||
|
||||
case CACHE_OP_NEQ:
|
||||
return "!=";
|
||||
|
||||
case CACHE_OP_LIKE:
|
||||
return "like";
|
||||
|
||||
case CACHE_OP_UNLIKE:
|
||||
return "unlike";
|
||||
|
||||
default:
|
||||
ss_dassert(!true);
|
||||
return "<invalid>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CACHE_RULE object doing regexp matching.
|
||||
*
|
||||
@ -464,6 +515,99 @@ static CACHE_RULE *cache_rule_create_regexp(cache_rule_attribute_t attribute,
|
||||
return rule;
|
||||
}
|
||||
|
||||
static CACHE_RULE *cache_rule_create_user(cache_rule_attribute_t attribute,
|
||||
cache_rule_op_t op,
|
||||
const char *cvalue,
|
||||
uint32_t debug)
|
||||
{
|
||||
ss_dassert((op == CACHE_OP_EQ) || (op == CACHE_OP_NEQ));
|
||||
|
||||
CACHE_RULE *rule = NULL;
|
||||
|
||||
bool error = false;
|
||||
size_t len = strlen(cvalue);
|
||||
|
||||
char value[strlen(cvalue) + 1];
|
||||
strcpy(value, cvalue);
|
||||
|
||||
char *at = strchr(value, '@');
|
||||
char *user = value;
|
||||
char *host;
|
||||
|
||||
if (at)
|
||||
{
|
||||
*at = 0;
|
||||
host = at + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
host = "%";
|
||||
}
|
||||
|
||||
if (dequote_mysql(user))
|
||||
{
|
||||
char pcre_user[2 * len + 1]; // Surely enough
|
||||
|
||||
if (*user == 0)
|
||||
{
|
||||
strcpy(pcre_user, ".*");
|
||||
}
|
||||
else
|
||||
{
|
||||
mysql_to_pcre(pcre_user, user, PCRE_QUOTE_VERBATIM);
|
||||
}
|
||||
|
||||
if (dequote_mysql(host))
|
||||
{
|
||||
char pcre_host[2 * len + 1]; // Surely enough
|
||||
|
||||
if (mysql_to_pcre(pcre_host, host, PCRE_QUOTE_QUERY) == MYSQL_ACCOUNT_WITH_WILDCARD)
|
||||
{
|
||||
op = (op == CACHE_OP_EQ ? CACHE_OP_LIKE : CACHE_OP_UNLIKE);
|
||||
|
||||
char regexp[strlen(pcre_user) + 1 + strlen(pcre_host) + 1];
|
||||
|
||||
sprintf(regexp, "%s@%s", pcre_user, pcre_host);
|
||||
|
||||
rule = cache_rule_create_regexp(attribute, op, regexp, debug);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No wildcard, no need to use regexp.
|
||||
|
||||
rule = (CACHE_RULE*)MXS_CALLOC(1, sizeof(CACHE_RULE));
|
||||
char *value = MXS_MALLOC(strlen(user) + 1 + strlen(host) + 1);
|
||||
|
||||
if (rule && value)
|
||||
{
|
||||
sprintf(value, "%s@%s", user, host);
|
||||
|
||||
rule->attribute = attribute;
|
||||
rule->op = op;
|
||||
rule->debug = debug;
|
||||
rule->value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(rule);
|
||||
MXS_FREE(value);
|
||||
rule = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Could not dequote host %s.", cvalue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Could not dequote user %s.", cvalue);
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CACHE_RULE object doing simple matching.
|
||||
*
|
||||
@ -481,21 +625,30 @@ static CACHE_RULE *cache_rule_create_simple(cache_rule_attribute_t attribute,
|
||||
{
|
||||
ss_dassert((op == CACHE_OP_EQ) || (op == CACHE_OP_NEQ));
|
||||
|
||||
CACHE_RULE *rule = (CACHE_RULE*)MXS_CALLOC(1, sizeof(CACHE_RULE));
|
||||
CACHE_RULE *rule;
|
||||
|
||||
char *value = MXS_STRDUP(cvalue);
|
||||
|
||||
if (rule && value)
|
||||
if (attribute == CACHE_ATTRIBUTE_USER)
|
||||
{
|
||||
rule->attribute = attribute;
|
||||
rule->op = op;
|
||||
rule->value = value;
|
||||
rule->debug = debug;
|
||||
rule = cache_rule_create_user(attribute, op, cvalue, debug);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(value);
|
||||
MXS_FREE(rule);
|
||||
rule = (CACHE_RULE*)MXS_CALLOC(1, sizeof(CACHE_RULE));
|
||||
char *value = MXS_STRDUP(cvalue);
|
||||
|
||||
if (rule && value)
|
||||
{
|
||||
rule->attribute = attribute;
|
||||
rule->op = op;
|
||||
rule->debug = debug;
|
||||
rule->value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(rule);
|
||||
MXS_FREE(value);
|
||||
rule = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return rule;
|
||||
@ -787,18 +940,42 @@ static bool cache_rule_matches_table(CACHE_RULE *self, const char *default_db, c
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns boolean indicating whether the user rule matches the user or not.
|
||||
* Returns boolean indicating whether the user rule matches the account or not.
|
||||
*
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param user The current default db.
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param account The account.
|
||||
*
|
||||
* @return True, if the rule matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_matches_user(CACHE_RULE *self, const char *user)
|
||||
static bool cache_rule_matches_user(CACHE_RULE *self, const char *account)
|
||||
{
|
||||
ss_dassert(self->attribute == CACHE_ATTRIBUTE_USER);
|
||||
|
||||
return cache_rule_compare(self, user);
|
||||
bool matches = cache_rule_compare(self, account);
|
||||
|
||||
|
||||
if ((matches && (self->debug & CACHE_DEBUG_MATCHING)) ||
|
||||
(!matches && (self->debug & CACHE_DEBUG_NON_MATCHING)))
|
||||
{
|
||||
const char *text;
|
||||
if (matches)
|
||||
{
|
||||
text = "MATCHES";
|
||||
}
|
||||
else
|
||||
{
|
||||
text = "does NOT match";
|
||||
}
|
||||
|
||||
MXS_NOTICE("Rule { \"attribute\": \"%s\", \"op\": \"%s\", \"value\": \"%s\" } %s \"%s\".",
|
||||
cache_rule_attribute_to_string(self->attribute),
|
||||
cache_rule_op_to_string(self->op),
|
||||
self->value,
|
||||
text,
|
||||
account);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -921,6 +1098,32 @@ static void cache_rules_add_use_rule(CACHE_RULES* self, CACHE_RULE* rule)
|
||||
self->use_rules = cache_rule_append(self->use_rules, rule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rules object from a JSON object.
|
||||
*
|
||||
* @param root The root JSON object in the rules file.
|
||||
* @param debug The debug level.
|
||||
*
|
||||
* @return A rules object if the json object could be parsed, NULL otherwise.
|
||||
*/
|
||||
static CACHE_RULES* cache_rules_create_from_json(json_t* root, uint32_t debug)
|
||||
{
|
||||
ss_dassert(root);
|
||||
|
||||
CACHE_RULES *rules = cache_rules_create(debug);
|
||||
|
||||
if (rules)
|
||||
{
|
||||
if (!cache_rules_parse_json(rules, root))
|
||||
{
|
||||
cache_rules_free(rules);
|
||||
rules = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the JSON object used for configuring the rules.
|
||||
*
|
||||
@ -1106,3 +1309,138 @@ static bool cache_rules_parse_use_element(CACHE_RULES *self, json_t *object, siz
|
||||
|
||||
return rule != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove quote characters surrounding a string.
|
||||
* 'abcd' => abcd
|
||||
* "abcd" => abcd
|
||||
* `abcd` => abcd
|
||||
*
|
||||
* @param s The string to be dequoted.
|
||||
*
|
||||
* @note The string is modified in place.
|
||||
*/
|
||||
static bool dequote_mysql(char *s)
|
||||
{
|
||||
bool dequoted = true;
|
||||
|
||||
char *i = s;
|
||||
char *end = s + strlen(s);
|
||||
|
||||
// Remove space from the beginning
|
||||
while (*i && isspace(*i))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
if (*i)
|
||||
{
|
||||
// Remove space from the end
|
||||
while (isspace(*(end - 1)))
|
||||
{
|
||||
*(end - 1) = 0;
|
||||
--end;
|
||||
}
|
||||
|
||||
ss_dassert(end > i);
|
||||
|
||||
char quote;
|
||||
|
||||
switch (*i)
|
||||
{
|
||||
case '\'':
|
||||
case '"':
|
||||
case '`':
|
||||
quote = *i;
|
||||
++i;
|
||||
break;
|
||||
|
||||
default:
|
||||
quote = 0;
|
||||
}
|
||||
|
||||
if (quote)
|
||||
{
|
||||
--end;
|
||||
|
||||
if (*end == quote)
|
||||
{
|
||||
*end = 0;
|
||||
|
||||
memmove(s, i, end - i + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dequoted = false;
|
||||
}
|
||||
}
|
||||
else if (i != s)
|
||||
{
|
||||
memmove(s, i, end - i + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
return dequoted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert MySQL/MariaDB account string to a pcre compatible one.
|
||||
*
|
||||
* @param pcre The string to which the conversion should be copied.
|
||||
* To be on the safe size, the buffer should be twice the
|
||||
* size of 'mysql'.
|
||||
* @param mysql The mysql account string.
|
||||
* @param approach Whether % should be converted or not.
|
||||
*
|
||||
* @return Whether or not the account contains a wildcard.
|
||||
*/
|
||||
static mysql_account_kind_t mysql_to_pcre(char *pcre, const char *mysql, pcre_quote_approach_t approach)
|
||||
{
|
||||
mysql_account_kind_t rv = MYSQL_ACCOUNT_WITHOUT_WILDCARD;
|
||||
|
||||
while (*mysql)
|
||||
{
|
||||
switch (*mysql)
|
||||
{
|
||||
case '%':
|
||||
if (approach == PCRE_QUOTE_QUERY)
|
||||
{
|
||||
*pcre = '.';
|
||||
pcre++;
|
||||
*pcre = '*';
|
||||
}
|
||||
rv = MYSQL_ACCOUNT_WITH_WILDCARD;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
case '^':
|
||||
case '.':
|
||||
case '$':
|
||||
case '|':
|
||||
case '(':
|
||||
case ')':
|
||||
case '[':
|
||||
case ']':
|
||||
case '*':
|
||||
case '+':
|
||||
case '?':
|
||||
case '{':
|
||||
case '}':
|
||||
*pcre++ = '\\';
|
||||
// Flowthrough
|
||||
default:
|
||||
*pcre = *mysql;
|
||||
}
|
||||
|
||||
++pcre;
|
||||
++mysql;
|
||||
}
|
||||
|
||||
*pcre = 0;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
3
server/modules/filter/cache/rules.h
vendored
3
server/modules/filter/cache/rules.h
vendored
@ -59,11 +59,14 @@ typedef struct cache_rules
|
||||
CACHE_RULE *use_rules; // The rules for when to use data from the cache.
|
||||
} CACHE_RULES;
|
||||
|
||||
const char *cache_rule_attribute_to_string(cache_rule_attribute_t attribute);
|
||||
const char *cache_rule_op_to_string(cache_rule_op_t op);
|
||||
|
||||
CACHE_RULES *cache_rules_create(uint32_t debug);
|
||||
void cache_rules_free(CACHE_RULES *rules);
|
||||
|
||||
CACHE_RULES *cache_rules_load(const char *path, uint32_t debug);
|
||||
CACHE_RULES *cache_rules_parse(const char *json, uint32_t debug);
|
||||
|
||||
bool cache_rules_should_store(CACHE_RULES *rules, const char *default_db, const GWBUF* query);
|
||||
bool cache_rules_should_use(CACHE_RULES *rules, const SESSION *session);
|
||||
|
5
server/modules/filter/cache/test/CMakeLists.txt
vendored
Normal file
5
server/modules/filter/cache/test/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
add_executable(testrules testrules.c ../rules.c)
|
||||
include_directories(..)
|
||||
target_link_libraries(testrules maxscale-common jansson)
|
||||
|
||||
add_test(TestCache_rules testrules)
|
102
server/modules/filter/cache/test/testrules.c
vendored
Normal file
102
server/modules/filter/cache/test/testrules.c
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "rules.h"
|
||||
#include <log_manager.h>
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#include <skygw_debug.h>
|
||||
|
||||
struct test_case
|
||||
{
|
||||
const char* json;
|
||||
struct
|
||||
{
|
||||
cache_rule_op_t op;
|
||||
const char *value;
|
||||
} expect;
|
||||
};
|
||||
|
||||
#define TEST_CASE(op_from, from, op_to, to) \
|
||||
{ "{ \"use\": [ { \"attribute\": \"user\", \"op\": \"" #op_from "\", \"value\": \"" #from "\" } ] }",\
|
||||
{ op_to, #to } }
|
||||
|
||||
const struct test_case test_cases[] =
|
||||
{
|
||||
TEST_CASE(=, bob, CACHE_OP_LIKE, bob@.*),
|
||||
TEST_CASE(=, 'bob', CACHE_OP_LIKE, bob@.*),
|
||||
TEST_CASE(=, bob@%, CACHE_OP_LIKE, bob@.*),
|
||||
TEST_CASE(=, 'bob'@'%.52', CACHE_OP_LIKE, bob@.*\\.52),
|
||||
TEST_CASE(=, bob@127.0.0.1, CACHE_OP_EQ, bob@127.0.0.1),
|
||||
TEST_CASE(=, b*b@127.0.0.1, CACHE_OP_EQ, b*b@127.0.0.1),
|
||||
TEST_CASE(=, b*b@%.0.0.1, CACHE_OP_LIKE, b\\*b@.*\\.0\\.0\\.1),
|
||||
TEST_CASE(=, b*b@%.0.%.1, CACHE_OP_LIKE, b\\*b@.*\\.0\\..*\\.1),
|
||||
};
|
||||
|
||||
const size_t n_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
|
||||
|
||||
int test()
|
||||
{
|
||||
int errors = 0;
|
||||
|
||||
for (int i = 0; i < n_test_cases; ++i)
|
||||
{
|
||||
const struct test_case *test_case = &test_cases[i];
|
||||
|
||||
CACHE_RULES *rules = cache_rules_parse(test_case->json, 0);
|
||||
ss_dassert(rules);
|
||||
|
||||
CACHE_RULE *rule = rules->use_rules;
|
||||
ss_dassert(rule);
|
||||
|
||||
if (rule->op != test_case->expect.op)
|
||||
{
|
||||
printf("%s\nExpected: %s,\nGot : %s\n",
|
||||
test_case->json,
|
||||
cache_rule_op_to_string(test_case->expect.op),
|
||||
cache_rule_op_to_string(rule->op));
|
||||
++errors;
|
||||
}
|
||||
|
||||
if (strcmp(rule->value, test_case->expect.value) != 0)
|
||||
{
|
||||
printf("%s\nExpected: %s,\nGot : %s\n",
|
||||
test_case->json,
|
||||
test_case->expect.value,
|
||||
rule->value);
|
||||
++errors;
|
||||
}
|
||||
}
|
||||
|
||||
return errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int rc = EXIT_FAILURE;
|
||||
|
||||
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
||||
{
|
||||
rc = test();
|
||||
|
||||
mxs_log_finish();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("error: Could not initialize log.");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
@ -1657,7 +1657,9 @@ static char* create_parse_error(FW_INSTANCE* my_instance,
|
||||
{
|
||||
char *msg = NULL;
|
||||
|
||||
char format[] = "dbfwfilter: Query could not be %s and will hence be rejected";
|
||||
char format[] =
|
||||
"dbfwfilter: Query could not be %s and will hence be rejected. "
|
||||
"Please ensure that the SQL syntax is correct";
|
||||
size_t len = sizeof(format) + strlen(reason); // sizeof includes the trailing NULL as well.
|
||||
char message[len];
|
||||
sprintf(message, format, reason);
|
||||
|
@ -1,3 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* MaxScale AVRO router
|
||||
*
|
||||
|
@ -1,7 +1,14 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -1,3 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#ifndef _SHARDING_COMMON_HG
|
||||
#define _SHARDING_COMMON_HG
|
||||
|
||||
|
@ -77,6 +77,7 @@ typedef struct
|
||||
bool failover; /**< If simple failover is enabled */
|
||||
int failcount; /**< How many monitoring cycles servers must be
|
||||
down before failover is initiated */
|
||||
bool warn_failover; /**< Log a warning when failover happens */
|
||||
} MYSQL_MONITOR;
|
||||
|
||||
#endif
|
||||
|
@ -275,6 +275,7 @@ startMonitor(MONITOR *monitor, const CONFIG_PARAMETER* params)
|
||||
handle->mysql51_replication = false;
|
||||
handle->failover = false;
|
||||
handle->failcount = MYSQLMON_DEFAULT_FAILCOUNT;
|
||||
handle->warn_failover = true;
|
||||
memset(handle->events, false, sizeof(handle->events));
|
||||
spinlock_init(&handle->lock);
|
||||
}
|
||||
@ -1093,18 +1094,21 @@ void do_failover(MYSQL_MONITOR *handle, MONITOR_SERVERS *db)
|
||||
{
|
||||
if (SERVER_IS_RUNNING(db->server))
|
||||
{
|
||||
if (!SERVER_IS_MASTER(db->server))
|
||||
if (!SERVER_IS_MASTER(db->server) && handle->warn_failover)
|
||||
{
|
||||
MXS_WARNING("Failover initiated, server '%s' is now the master. "
|
||||
"All other servers are set into maintenance mode.",
|
||||
db->server->unique_name);
|
||||
handle->warn_failover = false;
|
||||
}
|
||||
|
||||
server_clear_set_status(db->server, SERVER_SLAVE, SERVER_MASTER);
|
||||
monitor_set_pending_status(db, SERVER_MASTER);
|
||||
monitor_clear_pending_status(db, SERVER_SLAVE);
|
||||
}
|
||||
else
|
||||
{
|
||||
server_set_status(db->server, SERVER_MAINT);
|
||||
monitor_set_pending_status(db, SERVER_MAINT);
|
||||
}
|
||||
db = db->next;
|
||||
@ -1395,6 +1399,10 @@ monitorMain(void *arg)
|
||||
/** Other servers have died, initiate a failover to the last remaining server */
|
||||
do_failover(handle, mon->databases);
|
||||
}
|
||||
else
|
||||
{
|
||||
handle->warn_failover = true;
|
||||
}
|
||||
}
|
||||
|
||||
ptr = mon->databases;
|
||||
|
@ -1,5 +1,19 @@
|
||||
#ifndef MAXSCALE_TEST_H
|
||||
#define MAXSCALE_TEST_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#define TEST_DIR "@CMAKE_BINARY_DIR@"
|
||||
#define TEST_LOG_DIR "@CMAKE_BINARY_DIR@/log"
|
||||
#define TEST_BIN_DIR "@CMAKE_BINARY_DIR@/bin"
|
||||
|
Reference in New Issue
Block a user