MXS-1475 Attempt to set unknown MXS user variable causes error

By causing an error if an unknown MaxScale user variable is set,
the user will become aware of typos etc.
This commit is contained in:
Johan Wikman
2018-02-26 21:53:09 +02:00
parent 872a51a376
commit 2434482dc6
3 changed files with 66 additions and 25 deletions

View File

@ -137,11 +137,14 @@ typedef struct mxs_upstream
* @param value_begin The beginning of the value as specified in the * @param value_begin The beginning of the value as specified in the
* "set @maxscale.x.y = VALUE" statement. * "set @maxscale.x.y = VALUE" statement.
* @param value_end One past the end of the VALUE. * @param value_end One past the end of the VALUE.
*
* @return NULL if successful, otherwise a dynamically allocated string
* containing an end-user friendly error message.
*/ */
typedef void (*session_variable_handler_t)(void* context, typedef char* (*session_variable_handler_t)(void* context,
const char* name, const char* name,
const char* value_begin, const char* value_begin,
const char* value_end); const char* value_end);
#ifdef __cplusplus #ifdef __cplusplus
typedef struct session_variable typedef struct session_variable
@ -572,13 +575,16 @@ bool session_remove_variable(MXS_SESSION* session,
* @param value_begin Should point to the beginning of the value. * @param value_begin Should point to the beginning of the value.
* @param value_end Should point one past the end of the value. * @param value_end Should point one past the end of the value.
* *
* @return NULL if successful, otherwise a dynamically allocated string
* containing an end-user friendly error message.
*
* @note Should only be called from the protocol module that scans * @note Should only be called from the protocol module that scans
* incoming statements. * incoming statements.
*/ */
void session_set_variable_value(MXS_SESSION* session, char* session_set_variable_value(MXS_SESSION* session,
const char* name_begin, const char* name_begin,
const char* name_end, const char* name_end,
const char* value_begin, const char* value_begin,
const char* value_end); const char* value_end);
MXS_END_DECLS MXS_END_DECLS

View File

@ -108,9 +108,8 @@ MXS_SESSION* session_alloc_with_id(SERVICE *service, DCB *client_dcb, uint64_t i
return NULL; return NULL;
} }
session->variables = session_variables;
session_initialize(session); session_initialize(session);
session->variables = session_variables;
session->ses_id = id; session->ses_id = id;
return session_alloc_body(service, client_dcb, session); return session_alloc_body(service, client_dcb, session);
} }
@ -1144,12 +1143,14 @@ bool session_add_variable(MXS_SESSION* session,
return added; return added;
} }
void session_set_variable_value(MXS_SESSION* session, char* session_set_variable_value(MXS_SESSION* session,
const char* name_begin, const char* name_begin,
const char* name_end, const char* name_end,
const char* value_begin, const char* value_begin,
const char* value_end) const char* value_end)
{ {
char* rv = NULL;
string key(name_begin, name_end - name_begin); string key(name_begin, name_end - name_begin);
transform(key.begin(), key.end(), key.begin(), toupper); transform(key.begin(), key.end(), key.begin(), toupper);
@ -1158,8 +1159,26 @@ void session_set_variable_value(MXS_SESSION* session,
if (i != session->variables->end()) if (i != session->variables->end())
{ {
i->second.handler(i->second.context, key.c_str(), value_begin, value_end); rv = i->second.handler(i->second.context, key.c_str(), value_begin, value_end);
} }
else
{
const char FORMAT[] = "Attempt to set unknown MaxScale user variable %.*s";
int name_length = name_end - name_begin;
int len = snprintf(NULL, 0, FORMAT, name_length, name_begin);
rv = static_cast<char*>(MXS_MALLOC(len + 1));
if (rv)
{
sprintf(rv, FORMAT, name_length, name_begin);
}
MXS_WARNING(FORMAT, name_length, name_begin);
}
return rv;
} }
bool session_remove_variable(MXS_SESSION* session, bool session_remove_variable(MXS_SESSION* session,

View File

@ -879,9 +879,13 @@ static bool process_client_commands(DCB* dcb, int bytes_available, GWBUF** buffe
* @param session The session for which the query classifier mode is adjusted. * @param session The session for which the query classifier mode is adjusted.
* @param read_buffer Pointer to a buffer, assumed to contain a statement. * @param read_buffer Pointer to a buffer, assumed to contain a statement.
* May be reallocated if not contiguous. * May be reallocated if not contiguous.
*
* @return NULL if successful, otherwise dynamically allocated error message.
*/ */
void handle_variables(MXS_SESSION* session, GWBUF** read_buffer) char* handle_variables(MXS_SESSION* session, GWBUF** read_buffer)
{ {
char* message = NULL;
SetParser set_parser; SetParser set_parser;
SetParser::Result result; SetParser::Result result;
@ -917,9 +921,9 @@ void handle_variables(MXS_SESSION* session, GWBUF** read_buffer)
break; break;
case SetParser::IS_SET_MAXSCALE: case SetParser::IS_SET_MAXSCALE:
session_set_variable_value(session, message = session_set_variable_value(session,
result.variable_begin(), result.variable_end(), result.variable_begin(), result.variable_end(),
result.value_begin(), result.value_end()); result.value_begin(), result.value_end());
break; break;
case SetParser::NOT_RELEVANT: case SetParser::NOT_RELEVANT:
@ -928,6 +932,8 @@ void handle_variables(MXS_SESSION* session, GWBUF** read_buffer)
default: default:
ss_dassert(!true); ss_dassert(!true);
} }
return message;
} }
/** /**
@ -985,10 +991,20 @@ gw_read_normal_data(DCB *dcb, GWBUF *read_buffer, int nbytes_read)
return 0; return 0;
} }
handle_variables(session, &read_buffer); char* message = handle_variables(session, &read_buffer);
// Must be done whether or not there were any changes, as the query classifier
// is thread and not session specific. if (message)
qc_set_sql_mode(static_cast<qc_sql_mode_t>(session->client_protocol_data)); {
int rv = dcb->func.write(dcb, modutil_create_mysql_err_msg(1, 0, 1193, "HY000", message));
MXS_FREE(message);
return rv;
}
else
{
// Must be done whether or not there were any changes, as the query classifier
// is thread and not session specific.
qc_set_sql_mode(static_cast<qc_sql_mode_t>(session->client_protocol_data));
}
} }
/** Update the current protocol command being executed */ /** Update the current protocol command being executed */
else if (!process_client_commands(dcb, nbytes_read, &read_buffer)) else if (!process_client_commands(dcb, nbytes_read, &read_buffer))