From a349f0ad0dc6f840a315b1e605c30292053a73f4 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Wed, 17 Oct 2018 17:38:06 +0300 Subject: [PATCH] MXS-1779 Implement the classify REST-API --- include/maxscale/config.h | 7 ++ include/maxscale/query_classifier.h | 9 +++ server/core/config.cc | 7 ++ server/core/query_classifier.cc | 109 +++++++++++++++++++++++++++- 4 files changed, 131 insertions(+), 1 deletion(-) diff --git a/include/maxscale/config.h b/include/maxscale/config.h index a18785363..e3392cb49 100644 --- a/include/maxscale/config.h +++ b/include/maxscale/config.h @@ -100,6 +100,7 @@ extern const char CN_ADMIN_PORT[]; extern const char CN_ADMIN_SSL_KEY[]; extern const char CN_ADMIN_SSL_CERT[]; extern const char CN_ADMIN_SSL_CA_CERT[]; +extern const char CN_ARGUMENTS[]; extern const char CN_ATTRIBUTES[]; extern const char CN_AUTHENTICATOR[]; extern const char CN_AUTHENTICATOR_DIAGNOSTICS[]; @@ -118,10 +119,13 @@ extern const char CN_DEFAULT[]; extern const char CN_DESCRIPTION[]; extern const char CN_DISK_SPACE_THRESHOLD[]; extern const char CN_ENABLE_ROOT_USER[]; +extern const char CN_FIELDS[]; extern const char CN_FILTERS[]; extern const char CN_FILTER[]; extern const char CN_FILTER_DIAGNOSTICS[]; +extern const char CN_FUNCTIONS[]; extern const char CN_GATEWAY[]; +extern const char CN_HAS_WHERE_CLAUSE[]; extern const char CN_ID[]; extern const char CN_INET[]; extern const char CN_LISTENER[]; @@ -143,8 +147,10 @@ extern const char CN_MONITOR_DIAGNOSTICS[]; extern const char CN_MS_TIMESTAMP[]; extern const char CN_NAME[]; extern const char CN_NON_BLOCKING_POLLS[]; +extern const char CN_OPERATION[]; extern const char CN_OPTIONS[]; extern const char CN_PARAMETERS[]; +extern const char CN_PARSE_RESULT[]; extern const char CN_PASSIVE[]; extern const char CN_PASSWORD[]; extern const char CN_PEER_HOSTS[]; @@ -189,6 +195,7 @@ extern const char CN_THREADS[]; extern const char CN_THREAD_STACK_SIZE[]; extern const char CN_TICKS[]; extern const char CN_TYPE[]; +extern const char CN_TYPE_MASK[]; extern const char CN_UNIX[]; extern const char CN_USER[]; extern const char CN_USERS[]; diff --git a/include/maxscale/query_classifier.h b/include/maxscale/query_classifier.h index 0b16b98cf..f24326845 100644 --- a/include/maxscale/query_classifier.h +++ b/include/maxscale/query_classifier.h @@ -933,4 +933,13 @@ bool qc_get_cache_stats(QC_CACHE_STATS* stats); */ json_t* qc_get_cache_stats_as_json(); +/** + * String represenation for the parse result. + * + * @param result A parsing result. + * + * @return The corresponding string. + */ +const char* qc_result_to_string(qc_parse_result_t result); + MXS_END_DECLS diff --git a/server/core/config.cc b/server/core/config.cc index b467fc3fe..22cfc6e6c 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -81,6 +81,7 @@ const char CN_ADMIN_PORT[] = "admin_port"; const char CN_ADMIN_SSL_KEY[] = "admin_ssl_key"; const char CN_ADMIN_SSL_CERT[] = "admin_ssl_cert"; const char CN_ADMIN_SSL_CA_CERT[] = "admin_ssl_ca_cert"; +const char CN_ARGUMENTS[] = "arguments"; const char CN_ATTRIBUTES[] = "attributes"; const char CN_AUTHENTICATOR[] = "authenticator"; const char CN_AUTHENTICATOR_DIAGNOSTICS[] = "authenticator_diagnostics"; @@ -99,10 +100,13 @@ const char CN_DESCRIPTION[] = "description"; const char CN_DISK_SPACE_THRESHOLD[] = "disk_space_threshold"; const char CN_DUMP_LAST_STATEMENTS[] = "dump_last_statements"; const char CN_ENABLE_ROOT_USER[] = "enable_root_user"; +const char CN_FIELDS[] = "fields"; const char CN_FILTERS[] = "filters"; const char CN_FILTER[] = "filter"; const char CN_FILTER_DIAGNOSTICS[] = "filter_diagnostics"; +const char CN_FUNCTIONS[] = "functions"; const char CN_GATEWAY[] = "gateway"; +const char CN_HAS_WHERE_CLAUSE[] = "has_where_clause"; const char CN_ID[] = "id"; const char CN_INET[] = "inet"; const char CN_LISTENER[] = "listener"; @@ -124,8 +128,10 @@ const char CN_MONITOR_DIAGNOSTICS[] = "monitor_diagnostics"; const char CN_MS_TIMESTAMP[] = "ms_timestamp"; const char CN_NAME[] = "name"; const char CN_NON_BLOCKING_POLLS[] = "non_blocking_polls"; +const char CN_OPERATION[] = "operation"; const char CN_OPTIONS[] = "options"; const char CN_PARAMETERS[] = "parameters"; +const char CN_PARSE_RESULT[] = "parse_result"; const char CN_PASSIVE[] = "passive"; const char CN_PASSWORD[] = "password"; const char CN_PEER_HOSTS[] = "peer_hosts"; @@ -172,6 +178,7 @@ const char CN_THREADS[] = "threads"; const char CN_THREAD_STACK_SIZE[] = "thread_stack_size"; const char CN_TICKS[] = "ticks"; const char CN_TYPE[] = "type"; +const char CN_TYPE_MASK[] = "type_mask"; const char CN_UNIX[] = "unix"; const char CN_USER[] = "user"; const char CN_USERS[] = "users"; diff --git a/server/core/query_classifier.cc b/server/core/query_classifier.cc index ae79a23d8..956f70823 100644 --- a/server/core/query_classifier.cc +++ b/server/core/query_classifier.cc @@ -775,6 +775,28 @@ GWBUF* qc_get_preparable_stmt(GWBUF* stmt) return preparable_stmt; } +const char* qc_result_to_string(qc_parse_result_t result) +{ + switch (result) + { + case QC_QUERY_INVALID: + return "QC_QUERY_INVALID"; + + case QC_QUERY_TOKENIZED: + return "QC_QUERY_TOKENIZED"; + + case QC_QUERY_PARTIALLY_PARSED: + return "QC_QUERY_PARTIALLY_PARSED"; + + case QC_QUERY_PARSED: + return "QC_QUERY_PARSED"; + + default: + mxb_assert(!true); + return "Unknown"; + } +} + const char* qc_op_to_string(qc_query_op_t op) { switch (op) @@ -1377,12 +1399,97 @@ bool qc_alter_from_json(json_t* pJson) return rv; } +namespace +{ + +void append_field_info(json_t* pParent, + const char* zName, + const QC_FIELD_INFO* begin, const QC_FIELD_INFO* end) +{ + json_t* pFields = json_array(); + + std::for_each(begin, end, [pFields](const QC_FIELD_INFO& info) { + std::string name; + + if (info.database) + { + name += info.database; + name += '.'; + mxb_assert(info.table); + } + + if (info.table) + { + name += info.table; + name += '.'; + } + + mxb_assert(info.column); + + name += info.column; + + json_array_append_new(pFields, json_string(name.c_str())); + }); + + json_object_set_new(pParent, zName, pFields); +} + +void append_field_info(json_t* pParams, GWBUF* pBuffer) +{ + const QC_FIELD_INFO* begin; + size_t n; + qc_get_field_info(pBuffer, &begin, &n); + + append_field_info(pParams, CN_FIELDS, begin, begin + n); +} + +void append_function_info(json_t* pParams, GWBUF* pBuffer) +{ + json_t* pFunctions = json_array(); + + const QC_FUNCTION_INFO* begin; + size_t n; + qc_get_function_info(pBuffer, &begin, &n); + + std::for_each(begin, begin + n, [pFunctions](const QC_FUNCTION_INFO& info) { + json_t* pFunction = json_object(); + + json_object_set_new(pFunction, CN_NAME, json_string(info.name)); + + append_field_info(pFunction, CN_ARGUMENTS, info.fields, info.fields + info.n_fields); + + json_array_append_new(pFunctions, pFunction); + }); + + json_object_set_new(pParams, CN_FUNCTIONS, pFunctions); +} + +} std::unique_ptr qc_classify_as_json(const char* zHost, const std::string& statement) { json_t* pParams = json_object(); - // TODO: Fill object with classification information. + std::unique_ptr sBuffer(modutil_create_query(statement.c_str())); + GWBUF* pBuffer = sBuffer.get(); + + qc_parse_result result = qc_parse(pBuffer, QC_COLLECT_ALL); + + json_object_set_new(pParams, CN_PARSE_RESULT, json_string(qc_result_to_string(result))); + + if (result != QC_QUERY_INVALID) + { + char* zType_mask = qc_typemask_to_string(qc_get_type_mask(pBuffer)); + json_object_set_new(pParams, CN_TYPE_MASK, json_string(zType_mask)); + MXS_FREE(zType_mask); + + json_object_set_new(pParams, CN_OPERATION, json_string(qc_op_to_string(qc_get_operation(pBuffer)))); + bool has_clause = qc_query_has_clause(pBuffer); + json_object_set_new(pParams, CN_HAS_WHERE_CLAUSE, json_boolean(has_clause)); + + append_field_info(pParams, pBuffer); + append_function_info(pParams, pBuffer); + } json_t* pAttributes = json_object(); json_object_set_new(pAttributes, CN_PARAMETERS, pParams);