434 lines
15 KiB
C++
434 lines
15 KiB
C++
/* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License, version 2.0,
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is also distributed with certain software (including
|
|
but not limited to OpenSSL) that is licensed under separate terms,
|
|
as designated in a particular file or component or in included license
|
|
documentation. The authors of MySQL hereby grant you an additional
|
|
permission to link the program and your derivative works with the
|
|
separately licensed software that they have included with MySQL.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License, version 2.0, for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
#ifndef COMPONENT_SYS_VAR_SERVICE_H
|
|
#define COMPONENT_SYS_VAR_SERVICE_H
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <mysql/components/service.h>
|
|
|
|
/**
|
|
A utility class for the ENUM variables
|
|
*/
|
|
|
|
struct TYPE_LIB {
|
|
size_t count{0}; /* How many types */
|
|
const char *name{nullptr}; /* Name of typelib */
|
|
const char **type_names{nullptr};
|
|
unsigned int *type_lengths{nullptr};
|
|
};
|
|
|
|
/**
|
|
@addtogroup group_components_services_sys_var_service_types Variable types
|
|
|
|
Possible system variable types. Use at most one of these.
|
|
|
|
@sa mysql_service_component_sys_variable_register service.
|
|
|
|
@{
|
|
*/
|
|
|
|
/** bool variable. Use @ref BOOL_CHECK_ARG */
|
|
#define PLUGIN_VAR_BOOL 0x0001
|
|
/** int variable. Use @ref INTEGRAL_CHECK_ARG */
|
|
#define PLUGIN_VAR_INT 0x0002
|
|
/** long variable Use @ref INTEGRAL_CHECK_ARG */
|
|
#define PLUGIN_VAR_LONG 0x0003
|
|
/** longlong variable. Use @ref INTEGRAL_CHECK_ARG */
|
|
#define PLUGIN_VAR_LONGLONG 0x0004
|
|
/** char * variable. Use @ref STR_CHECK_ARG */
|
|
#define PLUGIN_VAR_STR 0x0005
|
|
/** Enum variable. Use @ref ENUM_CHECK_ARG */
|
|
#define PLUGIN_VAR_ENUM 0x0006
|
|
/** A set variable. Use @ref ENUM_CHECK_ARG */
|
|
#define PLUGIN_VAR_SET 0x0007
|
|
/** double variable. Use @ref INTEGRAL_CHECK_ARG */
|
|
#define PLUGIN_VAR_DOUBLE 0x0008
|
|
/** @} */
|
|
/**
|
|
@addtogroup group_components_services_sys_var_service_flags Variable flags
|
|
|
|
Flags to specify the behavior of system variables. Use multiple as needed.
|
|
|
|
@sa mysql_service_component_sys_variable_register service.
|
|
|
|
@{
|
|
*/
|
|
#define PLUGIN_VAR_UNSIGNED 0x0080 /**< The variable is unsigned */
|
|
#define PLUGIN_VAR_THDLOCAL 0x0100 /**< Variable is per-connection */
|
|
#define PLUGIN_VAR_READONLY 0x0200 /**< Server variable is read only */
|
|
#define PLUGIN_VAR_NOSYSVAR 0x0400 /**< Not a server variable */
|
|
#define PLUGIN_VAR_NOCMDOPT 0x0800 /**< Not a command line option */
|
|
#define PLUGIN_VAR_NOCMDARG 0x1000 /**< No argument for cmd line */
|
|
#define PLUGIN_VAR_RQCMDARG 0x0000 /**< Argument required for cmd line */
|
|
#define PLUGIN_VAR_OPCMDARG 0x2000 /**< Argument optional for cmd line */
|
|
#define PLUGIN_VAR_NODEFAULT 0x4000 /**< SET DEFAULT is prohibited */
|
|
#define PLUGIN_VAR_MEMALLOC 0x8000 /**< String needs memory allocated */
|
|
#define PLUGIN_VAR_NOPERSIST \
|
|
0x10000 /**< SET PERSIST_ONLY is prohibited for read only variables */
|
|
/** @} */
|
|
|
|
class THD;
|
|
struct SYS_VAR;
|
|
#define MYSQL_THD THD *
|
|
|
|
/**
|
|
Signature for the check function
|
|
|
|
This is called to check if the value supplied is valid and can be set
|
|
as a new variable value at that time.
|
|
It needs to extract the value supplied from the value API pointer.
|
|
Note that extracting this value can be expensive (e.g. a scalar subquery)
|
|
hence it should be done only once. This is why the result of this should
|
|
be stored into the save output parameter so that it can be futher reused by
|
|
update() etc.
|
|
For a multi-variable SET statement the server will first call all of the
|
|
check functions and only if they all return success it will start calling the
|
|
update functions.
|
|
So the idea is that the update function should succeed no matter what.
|
|
And all the necessary checks should be done in the check function.
|
|
If you do not supply a check or update function the server will use the basic
|
|
ones to check e.g. min and max values for the integer types etc.
|
|
|
|
@param thd The thread handle to the current thread
|
|
@param var handle to the system variable definition
|
|
@param[out] save placeholder for the value. This should be cast according to
|
|
the type
|
|
@param value Interface to extract the actual parameter value.
|
|
@return status
|
|
@retval 0 success
|
|
@retval 1 failure
|
|
|
|
@sa mysql_sys_var_update_func, mysql_service_component_sys_variable_register_t
|
|
*/
|
|
typedef int (*mysql_sys_var_check_func)(MYSQL_THD thd, SYS_VAR *var, void *save,
|
|
struct st_mysql_value *value);
|
|
|
|
/**
|
|
Signature for the update function
|
|
|
|
This is called to set the updated value into the var_ptr placeholder and
|
|
invoke any side effects that may stem from setting this system variable.
|
|
|
|
It receives the pre-calculated value (usually from
|
|
@ref mysql_sys_var_check_func) in the save pointer.
|
|
It needs to set it into the var_ptr pointer and invoke any side effects.
|
|
|
|
For a multi-variable SET statement the server will first call all of the
|
|
check functions and only if they all return success it will start calling the
|
|
update functions.
|
|
So the idea is that the update function should succeed no matter what.
|
|
And all the necessary checks should be done in the check function.
|
|
If you do not supply an update function the server will use the basic
|
|
one to set the value according to the variable's type.
|
|
|
|
@param thd The thread handle to the current thread
|
|
@param var handle to the system variable definition
|
|
@param[out] val_ptr placeholder for the value. Store save in here.
|
|
@param save The pre-calculated value from check.
|
|
|
|
@sa mysql_sys_var_check_func, mysql_service_component_sys_variable_register_t
|
|
*/
|
|
typedef void (*mysql_sys_var_update_func)(MYSQL_THD thd, SYS_VAR *var,
|
|
void *var_ptr, const void *save);
|
|
|
|
#define COPY_MYSQL_PLUGIN_VAR_HEADER(sys_var_type, type, sys_var_check, \
|
|
sys_var_update) \
|
|
sys_var_type->flags = flags; \
|
|
sys_var_type->name = var_name; \
|
|
sys_var_type->comment = comment; \
|
|
sys_var_type->check = check_func ? check_func : sys_var_check; \
|
|
sys_var_type->update = update_func ? update_func : sys_var_update; \
|
|
sys_var_type->value = (type *)variable_value;
|
|
|
|
#define COPY_MYSQL_PLUGIN_VAR_REMAINING(sys_var_type, check_arg_type) \
|
|
sys_var_type->def_val = check_arg_type->def_val; \
|
|
sys_var_type->min_val = check_arg_type->min_val; \
|
|
sys_var_type->max_val = check_arg_type->max_val; \
|
|
sys_var_type->blk_sz = check_arg_type->blk_sz;
|
|
|
|
#define SYSVAR_INTEGRAL_TYPE(type) \
|
|
struct sysvar_##type##_type { \
|
|
MYSQL_PLUGIN_VAR_HEADER; \
|
|
type *value; \
|
|
type def_val; \
|
|
type min_val; \
|
|
type max_val; \
|
|
type blk_sz; \
|
|
}
|
|
|
|
#define SYSVAR_ENUM_TYPE(type) \
|
|
struct sysvar_##type##_type { \
|
|
MYSQL_PLUGIN_VAR_HEADER; \
|
|
unsigned long *value; \
|
|
unsigned long def_val; \
|
|
TYPE_LIB *typelib; \
|
|
}
|
|
|
|
#define SYSVAR_BOOL_TYPE(type) \
|
|
struct sysvar_##type##_type { \
|
|
MYSQL_PLUGIN_VAR_HEADER; \
|
|
bool *value; \
|
|
bool def_val; \
|
|
}
|
|
|
|
#define SYSVAR_STR_TYPE(type) \
|
|
struct sysvar_##type##_type { \
|
|
MYSQL_PLUGIN_VAR_HEADER; \
|
|
char **value; \
|
|
char *def_val; \
|
|
}
|
|
|
|
/**
|
|
@addtogroup group_components_services_sys_var_service_args Variable
|
|
definitions
|
|
|
|
You need to fill one of these in an pass it to the registration function.
|
|
The values are copied so this doesn't have to survive once the registration
|
|
call is done.
|
|
So usually it's done as an automatic variable in the stack.
|
|
|
|
Make sure to use the right one for your variable type.
|
|
See @ref group_components_services_sys_var_service_types for what to use
|
|
for the individual types.
|
|
|
|
@sa mysql_service_component_sys_variable_register service.
|
|
|
|
@{
|
|
*/
|
|
|
|
/**
|
|
Defines an integral placeholder to fill in with values and
|
|
pass to the registration function.
|
|
|
|
Make sure to fill in def_val, min_val, max_val and blk_sz.
|
|
*/
|
|
#define INTEGRAL_CHECK_ARG(type) \
|
|
struct type##_check_arg_s { \
|
|
type def_val; \
|
|
type min_val; \
|
|
type max_val; \
|
|
type blk_sz; \
|
|
}
|
|
|
|
/**
|
|
Defines an @ref TYPE_LIB placeholder to fill in with values and
|
|
pass to the registration function.
|
|
|
|
Make sure to fill in def_val and typelib.
|
|
*/
|
|
#define ENUM_CHECK_ARG(type) \
|
|
struct type##_check_arg_s { \
|
|
unsigned long def_val; \
|
|
TYPE_LIB *typelib; \
|
|
}
|
|
|
|
/**
|
|
Defines a bool placeholder to fill in with values and
|
|
pass to the registration function.
|
|
|
|
Make sure to fill in def_val.
|
|
*/
|
|
#define BOOL_CHECK_ARG(type) \
|
|
struct type##_check_arg_s { \
|
|
bool def_val; \
|
|
}
|
|
|
|
/**
|
|
Defines a char * placeholder to fill in with values and
|
|
pass to the registration function.
|
|
|
|
Make sure to fill in def_val.
|
|
*/
|
|
#define STR_CHECK_ARG(type) \
|
|
struct type##_check_arg_s { \
|
|
char *def_val; \
|
|
}
|
|
/** @} */
|
|
|
|
/**
|
|
@ingroup group_components_services_inventory
|
|
|
|
Service to register variable and get variable value
|
|
|
|
@sa mysql_component_sys_variable_imp
|
|
*/
|
|
BEGIN_SERVICE_DEFINITION(component_sys_variable_register)
|
|
|
|
/**
|
|
Register a new system variable.
|
|
|
|
The variable registered is then accessible in SQL as "SELECT
|
|
component_name.name" The variable registration needs a global of the relevant
|
|
type that stores the value.
|
|
|
|
To define a new variable you need to:
|
|
1. Decide on a variable type among one of the
|
|
@ref group_components_services_sys_var_service_types
|
|
2. Decide on attributes of the type among one of the
|
|
@ref group_components_services_sys_var_service_flags
|
|
3. Declare a local variable placeholder matching the type using one of the
|
|
@ref group_components_services_sys_var_service_args macros.
|
|
4. Fill in the placeholder values (min, max, default etc) as appropriate for
|
|
the selected type.
|
|
5. Provide storage for the variable value: usually a global variable of the
|
|
relevant type.
|
|
6. Call the function with all of the above to register the system variable.
|
|
|
|
@warning: Make sure to unregister the system variable when you no longer
|
|
intend to have it or when your component deinitializes. Failure to do so will
|
|
lead to resource leaks and crashes.
|
|
|
|
Typical use
|
|
@code
|
|
static int int_variable_value;
|
|
static char *str_variable_value;
|
|
static ulong enum_variable_value;
|
|
|
|
static const char *enums[] = {"LOW", "MEDIUM", "STRONG", NullS};
|
|
|
|
static TYPE_LIB enums_typelib_t = {array_elements(enums) - 1,
|
|
"enums_typelib_t",
|
|
enums, NULL};
|
|
|
|
...
|
|
|
|
INTEGRAL_CHECK_ARG(int) int_arg;
|
|
int_arg.def_val = 8;
|
|
int_arg.min_val = 0;
|
|
int_arg.max_val = 1024;
|
|
int_arg.blk_sz = 0;
|
|
if (mysql_service_component_sys_variable_register->register_variable(
|
|
"foo", "int_sys_var", PLUGIN_VAR_INT,
|
|
"Registering int sys_variable", NULL, NULL, (void *)&int_arg,
|
|
(void *)&int_variable_value)) {
|
|
deal_with_error();
|
|
}
|
|
|
|
STR_CHECK_ARG(str) str_arg;
|
|
str_arg.def_val = NULL;
|
|
if (mysql_service_component_sys_variable_register->register_variable(
|
|
"foo", "str_sys_var", PLUGIN_VAR_STR | PLUGIN_VAR_MEMALLOC,
|
|
"Registering string sys_variable", NULL, NULL, (void *)&str_arg,
|
|
(void *)&str_variable_value)) {
|
|
deal_with_error();
|
|
}
|
|
|
|
ENUM_CHECK_ARG(enum) enum_arg;
|
|
enum_arg.def_val = 1; // medium
|
|
enum_arg.typelib = &enum_typelib_t;
|
|
if (mysql_service_component_sys_variable_register->register_variable(
|
|
"foo", "enum_sys_var", PLUGIN_VAR_ENUM,
|
|
"Registering enum sys_variable", NULL, NULL, (void *)&enum_arg,
|
|
(void *)&enum_variable_value)) {
|
|
deal_with_error();
|
|
}
|
|
@endcode
|
|
|
|
|
|
@sa mysql_service_component_sys_variable_unregister_t
|
|
|
|
@param component_name The name of the component the system variable belongs
|
|
to.
|
|
@param name The name of the variable.
|
|
@param flags one of @ref group_components_services_sys_var_service_types plus
|
|
zero or more of group_components_services_sys_var_service_flags
|
|
@param comment explanation of what the variable is to be shown in metadata
|
|
tables
|
|
@param check A function to be called to check for validity of the new value.
|
|
@param update A function to be called when the variable value is updated
|
|
@param check_arg The variable declared through one of
|
|
@ref group_components_services_sys_var_service_args
|
|
@param variable_value A pointer to a storage location of the relevant type.
|
|
@retval true operation failed
|
|
@retval false operation succeeded
|
|
*/
|
|
DECLARE_BOOL_METHOD(register_variable,
|
|
(const char *component_name, const char *name, int flags,
|
|
const char *comment, mysql_sys_var_check_func check,
|
|
mysql_sys_var_update_func update, void *check_arg,
|
|
void *variable_value));
|
|
/**
|
|
Fetches the global value of a system variable
|
|
|
|
Call this to get the global value of a variable. You can access both the
|
|
component variables (SELECT @@global.component_name.variable_name) and the
|
|
"legacy" system variables (SELECT @@global.variable_name) that are registered
|
|
by the server component.
|
|
To access the latter you need to pass "mysql_server" (lowercase) as a
|
|
component name.
|
|
|
|
A pointer to the value is returned into the val input/output argument. And the
|
|
length of the value (as applicable) is returned into the out_length_of_val
|
|
argument.
|
|
|
|
In case when the user buffer was too small to copy the value, the call fails
|
|
and needed buffer size is returned by 'out_length_of_val'.
|
|
|
|
Typical use (char * variable):
|
|
@code
|
|
|
|
char *value, buffer_for_value[160];
|
|
size_t value_length;
|
|
|
|
value= &buffer_for_value[0];
|
|
value_length= sizeof(buffer_for_value) - 1;
|
|
get_variable("foo", "bar", &value, &value_length);
|
|
|
|
printf("%.*s", (int) value_length, value);
|
|
@endcode
|
|
|
|
@param component_name Name of the component or "mysql_server" for the legacy
|
|
ones.
|
|
@param name name of the variable
|
|
@param[in,out] val On input: a buffer to hold the value. On output a pointer
|
|
to the value.
|
|
@param[in,out] out_length_of_val On input: the buffer size. On output the
|
|
length of the data copied.
|
|
|
|
@retval true failure
|
|
@retval false success
|
|
*/
|
|
DECLARE_BOOL_METHOD(get_variable, (const char *component_name, const char *name,
|
|
void **val, size_t *out_length_of_val));
|
|
|
|
END_SERVICE_DEFINITION(component_sys_variable_register)
|
|
|
|
/**
|
|
@ingroup group_components_services_inventory
|
|
|
|
Service to unregister variable
|
|
|
|
Make sure to call this for each variable registered.
|
|
|
|
@sa mysql_service_component_sys_variable_unregister_t
|
|
*/
|
|
BEGIN_SERVICE_DEFINITION(component_sys_variable_unregister)
|
|
|
|
DECLARE_BOOL_METHOD(unregister_variable,
|
|
(const char *component_name, const char *name));
|
|
|
|
END_SERVICE_DEFINITION(component_sys_variable_unregister)
|
|
|
|
#endif /* COMPONENT_SYS_VAR_SERVICE_H */
|