summaryrefslogtreecommitdiff
path: root/server-tools/instance-manager/commands.cc
diff options
context:
space:
mode:
Diffstat (limited to 'server-tools/instance-manager/commands.cc')
-rw-r--r--server-tools/instance-manager/commands.cc1855
1 files changed, 1369 insertions, 486 deletions
diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc
index 7b999f61503..83ed9cf6536 100644
--- a/server-tools/instance-manager/commands.cc
+++ b/server-tools/instance-manager/commands.cc
@@ -14,36 +14,54 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
+#pragma implementation
+#endif
+
#include "commands.h"
+#include <my_global.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include <mysql.h>
+#include <my_dir.h>
+
+#include "buffer.h"
+#include "guardian.h"
#include "instance_map.h"
+#include "log.h"
+#include "manager.h"
#include "messages.h"
#include "mysqld_error.h"
#include "mysql_manager_error.h"
-#include "protocol.h"
-#include "buffer.h"
#include "options.h"
+#include "priv.h"
+#include "protocol.h"
-#include <m_string.h>
-#include <m_ctype.h>
-#include <mysql.h>
-#include <my_dir.h>
+
+/*
+ modify_defaults_to_im_error -- a map of error codes of
+ mysys::modify_defaults_file() into Instance Manager error codes.
+*/
+
+static const int modify_defaults_to_im_error[]= { 0, ER_OUT_OF_RESOURCES,
+ ER_ACCESS_OPTION_FILE };
/*
- Add a string to a buffer
+ Add a string to a buffer.
SYNOPSYS
put_to_buff()
buff buffer to add the string
str string to add
- uint offset in the buff to add a string
+ position offset in the buff to add a string
DESCRIPTION
Function to add a string to the buffer. It is different from
- store_to_protocol_packet, which is used in the protocol.cc. The last
- one also stores the length of the string in a special way.
+ store_to_protocol_packet, which is used in the protocol.cc.
+ The last one also stores the length of the string in a special way.
This is required for MySQL client/server protocol support only.
RETURN
@@ -51,7 +69,6 @@
1 - error occured
*/
-
static inline int put_to_buff(Buffer *buff, const char *str, uint *position)
{
uint len= strlen(str);
@@ -88,749 +105,1615 @@ static int parse_version_number(const char *version_str, char *version,
}
-/* implementation for Show_instances: */
+/**************************************************************************
+ Implementation of Instance_name.
+**************************************************************************/
+Instance_name::Instance_name(const LEX_STRING *name)
+{
+ str.str= str_buffer;
+ str.length= name->length;
-/*
- The method sends a list of instances in the instance map to the client.
+ if (str.length > MAX_INSTANCE_NAME_SIZE - 1)
+ str.length= MAX_INSTANCE_NAME_SIZE - 1;
- SYNOPSYS
- Show_instances::execute()
- net The network connection to the client.
- connection_id Client connection ID
+ strmake(str.str, name->str, str.length);
+}
- RETURN
- 0 - ok
- 1 - error occured
+/**************************************************************************
+ Implementation of Show_instances.
+**************************************************************************/
+
+/*
+ Implementation of SHOW INSTANCES statement.
+
+ Possible error codes:
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
-int Show_instances::execute(struct st_net *net, ulong connection_id)
+int Show_instances::execute(st_net *net, ulong connection_id)
{
- Buffer send_buff; /* buffer for packets */
- LIST name, status;
- NAME_WITH_LENGTH name_field, status_field;
+ int err_code;
+
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net)))
+ return err_code;
+
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+int Show_instances::write_header(st_net *net)
+{
+ LIST name, state;
+ LEX_STRING name_field, state_field;
LIST *field_list;
- uint position=0;
- name_field.name= (char*) "instance_name";
+ name_field.str= (char *) "instance_name";
name_field.length= DEFAULT_FIELD_LENGTH;
name.data= &name_field;
- status_field.name= (char*) "status";
- status_field.length= DEFAULT_FIELD_LENGTH;
- status.data= &status_field;
- field_list= list_add(NULL, &status);
+
+ state_field.str= (char *) "state";
+ state_field.length= DEFAULT_FIELD_LENGTH;
+ state.data= &state_field;
+
+ field_list= list_add(NULL, &state);
field_list= list_add(field_list, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
+
+
+int Show_instances::write_data(st_net *net)
+{
+ my_bool err_status= FALSE;
+
+ Instance *instance;
+ Instance_map::Iterator iterator(instance_map);
+ instance_map->guardian->lock();
+ instance_map->lock();
+
+ while ((instance= iterator.next()))
{
- Instance *instance;
- Instance_map::Iterator iterator(instance_map);
+ Buffer send_buf; /* buffer for packets */
+ uint pos= 0;
+
+ const char *instance_name= instance->options.instance_name.str;
+ const char *state_name= instance_map->get_instance_state_name(instance);
- instance_map->lock();
- while ((instance= iterator.next()))
+ if (store_to_protocol_packet(&send_buf, instance_name, &pos) ||
+ store_to_protocol_packet(&send_buf, state_name, &pos) ||
+ my_net_write(net, send_buf.buffer, pos))
{
- position= 0;
- store_to_protocol_packet(&send_buff, instance->options.instance_name,
- &position);
- if (instance->is_running())
- store_to_protocol_packet(&send_buff, (char*) "online", &position);
- else
- store_to_protocol_packet(&send_buff, (char*) "offline", &position);
- if (my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ err_status= TRUE;
+ break;
}
- instance_map->unlock();
}
- if (send_eof(net))
- goto err;
- if (net_flush(net))
- goto err;
- return 0;
-err:
- return ER_OUT_OF_RESOURCES;
+ instance_map->unlock();
+ instance_map->guardian->unlock();
+
+ return err_status ? ER_OUT_OF_RESOURCES : 0;
}
-/* implementation for Flush_instances: */
+/**************************************************************************
+ Implementation of Flush_instances.
+**************************************************************************/
+
+/*
+ Implementation of FLUSH INSTANCES statement.
+
+ Possible error codes:
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+ ER_THERE_IS_ACTIVE_INSTACE If there is an active instance
+*/
-int Flush_instances::execute(struct st_net *net, ulong connection_id)
+int Flush_instances::execute(st_net *net, ulong connection_id)
{
- if (instance_map->flush_instances() ||
- net_send_ok(net, connection_id, NULL))
+ instance_map->guardian->lock();
+ instance_map->lock();
+
+ if (instance_map->is_there_active_instance())
+ {
+ instance_map->unlock();
+ instance_map->guardian->unlock();
+ return ER_THERE_IS_ACTIVE_INSTACE;
+ }
+
+ if (instance_map->flush_instances())
+ {
+ instance_map->unlock();
+ instance_map->guardian->unlock();
return ER_OUT_OF_RESOURCES;
+ }
- return 0;
+ instance_map->unlock();
+ instance_map->guardian->unlock();
+
+ return net_send_ok(net, connection_id, NULL) ? ER_OUT_OF_RESOURCES : 0;
}
-/* implementation for Show_instance_status: */
+/**************************************************************************
+ Implementation of Abstract_instance_cmd.
+**************************************************************************/
-Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
- const char *name, uint len)
- :Command(instance_map_arg)
+Abstract_instance_cmd::Abstract_instance_cmd(
+ Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
+ :Command(instance_map_arg),
+ instance_name(instance_name_arg)
{
- Instance *instance;
+ /*
+ MT-NOTE: we can not make a search for Instance object here,
+ because it can dissappear after releasing the lock.
+ */
+}
+
+
+int Abstract_instance_cmd::execute(st_net *net, ulong connection_id)
+{
+ int err_code;
+
+ instance_map->lock();
+
+ {
+ Instance *instance= instance_map->find(get_instance_name());
+
+ if (!instance)
+ {
+ instance_map->unlock();
+ return ER_BAD_INSTANCE_NAME;
+ }
+
+ err_code= execute_impl(net, instance);
+ }
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
- else
- instance_name= NULL;
+ instance_map->unlock();
+
+ if (!err_code)
+ err_code= send_ok_response(net, connection_id);
+
+ return err_code;
}
-/*
- The method sends a table with a status of requested instance to the client.
+/**************************************************************************
+ Implementation of Show_instance_status.
+**************************************************************************/
- SYNOPSYS
- Show_instance_status::do_command()
- net The network connection to the client.
- instance_name The name of the instance.
+Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
+}
- RETURN
- 0 - ok
- 1 - error occured
+
+/*
+ Implementation of SHOW INSTANCE STATUS statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
+int Show_instance_status::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
+
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net, instance)))
+ return err_code;
-int Show_instance_status::execute(struct st_net *net,
- ulong connection_id)
+ return 0;
+}
+
+
+int Show_instance_status::send_ok_response(st_net *net, ulong connection_id)
{
- enum { MAX_VERSION_LENGTH= 40 };
- Buffer send_buff; /* buffer for packets */
- LIST name, status, version, version_number;
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+int Show_instance_status::write_header(st_net *net)
+{
+ LIST name, state, version, version_number, mysqld_compatible;
LIST *field_list;
- NAME_WITH_LENGTH name_field, status_field, version_field,
- version_number_field;
- uint position=0;
+ LEX_STRING name_field, state_field, version_field,
+ version_number_field, mysqld_compatible_field;
- if (!instance_name)
- return ER_BAD_INSTANCE_NAME;
+ /* Create list of the fileds to be passed to send_fields(). */
- /* create list of the fileds to be passed to send_fields */
- name_field.name= (char*) "instance_name";
+ name_field.str= (char *) "instance_name";
name_field.length= DEFAULT_FIELD_LENGTH;
name.data= &name_field;
- status_field.name= (char*) "status";
- status_field.length= DEFAULT_FIELD_LENGTH;
- status.data= &status_field;
- version_field.name= (char*) "version";
+
+ state_field.str= (char *) "state";
+ state_field.length= DEFAULT_FIELD_LENGTH;
+ state.data= &state_field;
+
+ version_field.str= (char *) "version";
version_field.length= MAX_VERSION_LENGTH;
version.data= &version_field;
- version_number_field.name= (char*) "version_number";
+
+ version_number_field.str= (char *) "version_number";
version_number_field.length= MAX_VERSION_LENGTH;
version_number.data= &version_number_field;
- field_list= list_add(NULL, &version);
+
+ mysqld_compatible_field.str= (char *) "mysqld_compatible";
+ mysqld_compatible_field.length= DEFAULT_FIELD_LENGTH;
+ mysqld_compatible.data= &mysqld_compatible_field;
+
+ field_list= list_add(NULL, &mysqld_compatible);
+ field_list= list_add(field_list, &version);
field_list= list_add(field_list, &version_number);
- field_list= list_add(field_list, &status);
+ field_list= list_add(field_list, &state);
field_list= list_add(field_list, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
- {
- Instance *instance;
- store_to_protocol_packet(&send_buff, (char*) instance_name, &position);
- if (!(instance= instance_map->find(instance_name, strlen(instance_name))))
- goto err;
- if (instance->is_running())
- store_to_protocol_packet(&send_buff, (char*) "online", &position);
- else
- store_to_protocol_packet(&send_buff, (char*) "offline", &position);
+int Show_instance_status::write_data(st_net *net, Instance *instance)
+{
+ Buffer send_buf; /* buffer for packets */
+ char version_num_buf[MAX_VERSION_LENGTH];
+ uint pos= 0;
- if (instance->options.mysqld_version)
- {
- char parsed_version[MAX_VERSION_LENGTH];
+ const char *state_name;
+ const char *version_tag= "unknown";
+ const char *version_num= "unknown";
+ const char *mysqld_compatible_status;
- parse_version_number(instance->options.mysqld_version, parsed_version,
- sizeof(parsed_version));
- store_to_protocol_packet(&send_buff, parsed_version, &position);
+ instance_map->guardian->lock();
+ state_name= instance_map->get_instance_state_name(instance);
+ mysqld_compatible_status= instance->is_mysqld_compatible() ? "yes" : "no";
+ instance_map->guardian->unlock();
- store_to_protocol_packet(&send_buff, instance->options.mysqld_version,
- &position);
- }
- else
- {
- store_to_protocol_packet(&send_buff, (char*) "unknown", &position);
- store_to_protocol_packet(&send_buff, (char*) "unknown", &position);
- }
+ if (instance->options.mysqld_version)
+ {
+ if (parse_version_number(instance->options.mysqld_version, version_num_buf,
+ sizeof(version_num_buf)))
+ return ER_OUT_OF_RESOURCES;
- if (send_buff.is_error() ||
- my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ version_num= version_num_buf;
+ version_tag= instance->options.mysqld_version;
}
- if (send_eof(net) || net_flush(net))
- goto err;
+ if (store_to_protocol_packet(&send_buf, get_instance_name()->str, &pos) ||
+ store_to_protocol_packet(&send_buf, state_name, &pos) ||
+ store_to_protocol_packet(&send_buf, version_num, &pos) ||
+ store_to_protocol_packet(&send_buf, version_tag, &pos) ||
+ store_to_protocol_packet(&send_buf, mysqld_compatible_status, &pos) ||
+ my_net_write(net, send_buf.buffer, (uint) pos))
+ {
+ return ER_OUT_OF_RESOURCES;
+ }
return 0;
+}
+
+
+/**************************************************************************
+ Implementation of Show_instance_options.
+**************************************************************************/
-err:
- return ER_OUT_OF_RESOURCES;
+Show_instance_options::Show_instance_options(
+ Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
}
-/* Implementation for Show_instance_options */
+/*
+ Implementation of SHOW INSTANCE OPTIONS statement.
-Show_instance_options::Show_instance_options(Instance_map *instance_map_arg,
- const char *name, uint len):
- Command(instance_map_arg)
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Show_instance_options::execute_impl(st_net *net, Instance *instance)
{
- Instance *instance;
+ int err_code;
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
- else
- instance_name= NULL;
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net, instance)))
+ return err_code;
+
+ return 0;
}
-int Show_instance_options::execute(struct st_net *net, ulong connection_id)
+int Show_instance_options::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+int Show_instance_options::write_header(st_net *net)
{
- Buffer send_buff; /* buffer for packets */
LIST name, option;
LIST *field_list;
- NAME_WITH_LENGTH name_field, option_field;
- uint position=0;
+ LEX_STRING name_field, option_field;
- if (!instance_name)
- return ER_BAD_INSTANCE_NAME;
+ /* Create list of the fileds to be passed to send_fields(). */
- /* create list of the fileds to be passed to send_fields */
- name_field.name= (char*) "option_name";
+ name_field.str= (char *) "option_name";
name_field.length= DEFAULT_FIELD_LENGTH;
name.data= &name_field;
- option_field.name= (char*) "value";
+
+ option_field.str= (char *) "value";
option_field.length= DEFAULT_FIELD_LENGTH;
option.data= &option_field;
+
field_list= list_add(NULL, &option);
field_list= list_add(field_list, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
+
+int Show_instance_options::write_data(st_net *net, Instance *instance)
+{
+ Buffer send_buff; /* buffer for packets */
+ uint pos= 0;
+
+ if (store_to_protocol_packet(&send_buff, "instance_name", &pos) ||
+ store_to_protocol_packet(&send_buff, get_instance_name()->str, &pos) ||
+ my_net_write(net, send_buff.buffer, pos))
{
- Instance *instance;
-
- if (!(instance= instance_map->find(instance_name, strlen(instance_name))))
- goto err;
- store_to_protocol_packet(&send_buff, (char*) "instance_name", &position);
- store_to_protocol_packet(&send_buff, (char*) instance_name, &position);
- if (my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
- if ((instance->options.mysqld_path))
- {
- position= 0;
- store_to_protocol_packet(&send_buff, (char*) "mysqld-path", &position);
- store_to_protocol_packet(&send_buff,
- (char*) instance->options.mysqld_path,
- &position);
- if (send_buff.is_error() ||
- my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
- }
+ return ER_OUT_OF_RESOURCES;
+ }
+
+ /* Loop through the options. */
+
+ for (int i= 0; i < instance->options.get_num_options(); i++)
+ {
+ Named_value option= instance->options.get_option(i);
+ const char *option_value= option.get_value()[0] ? option.get_value() : "";
+
+ pos= 0;
- if ((instance->options.nonguarded))
+ if (store_to_protocol_packet(&send_buff, option.get_name(), &pos) ||
+ store_to_protocol_packet(&send_buff, option_value, &pos) ||
+ my_net_write(net, send_buff.buffer, pos))
{
- position= 0;
- store_to_protocol_packet(&send_buff, (char*) "nonguarded", &position);
- store_to_protocol_packet(&send_buff, "", &position);
- if (send_buff.is_error() ||
- my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ return ER_OUT_OF_RESOURCES;
}
+ }
+
+ return 0;
+}
+
- /* loop through the options stored in DYNAMIC_ARRAY */
- for (uint i= 0; i < instance->options.options_array.elements; i++)
+/**************************************************************************
+ Implementation of Start_instance.
+**************************************************************************/
+
+Start_instance::Start_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
+}
+
+
+/*
+ Implementation of START INSTANCE statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Start_instance::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
+
+ if ((err_code= instance->start()))
+ return err_code;
+
+ if (!(instance->options.nonguarded))
+ instance_map->guardian->guard(instance);
+
+ return 0;
+}
+
+
+int Start_instance::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (net_send_ok(net, connection_id, "Instance started"))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+/**************************************************************************
+ Implementation of Stop_instance.
+**************************************************************************/
+
+Stop_instance::Stop_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
+}
+
+
+/*
+ Implementation of STOP INSTANCE statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Stop_instance::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
+
+ if (!(instance->options.nonguarded))
+ instance_map->guardian->stop_guard(instance);
+
+ if ((err_code= instance->stop()))
+ return err_code;
+
+ return 0;
+}
+
+
+int Stop_instance::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (net_send_ok(net, connection_id, NULL))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+/**************************************************************************
+ Implementation for Create_instance.
+**************************************************************************/
+
+Create_instance::Create_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Command(instance_map_arg),
+ instance_name(instance_name_arg)
+{
+}
+
+
+/*
+ This operation initializes Create_instance object.
+
+ SYNOPSYS
+ text [IN/OUT] a pointer to the text containing instance options.
+
+ RETURN
+ FALSE On success.
+ TRUE On error.
+*/
+
+bool Create_instance::init(const char **text)
+{
+ return options.init() || parse_args(text);
+}
+
+
+/*
+ This operation parses CREATE INSTANCE options.
+
+ SYNOPSYS
+ text [IN/OUT] a pointer to the text containing instance options.
+
+ RETURN
+ FALSE On success.
+ TRUE On syntax error.
+*/
+
+bool Create_instance::parse_args(const char **text)
+{
+ uint len;
+
+ /* Check if we have something (and trim leading spaces). */
+
+ get_word(text, &len, NONSPACE);
+
+ if (len == 0)
+ return FALSE; /* OK: no option. */
+
+ /* Main parsing loop. */
+
+ while (TRUE)
+ {
+ LEX_STRING option_name;
+ char *option_name_str;
+ char *option_value_str= NULL;
+
+ /* Looking for option name. */
+
+ get_word(text, &option_name.length, OPTION_NAME);
+
+ if (option_name.length == 0)
+ return TRUE; /* Syntax error: option name expected. */
+
+ option_name.str= (char *) *text;
+ *text+= option_name.length;
+
+ /* Looking for equal sign. */
+
+ skip_spaces(text);
+
+ if (**text == '=')
{
- char *tmp_option, *option_value;
- get_dynamic(&(instance->options.options_array), (gptr) &tmp_option, i);
- option_value= strchr(tmp_option, '=');
- /* split the option string into two parts if it has a value */
+ ++(*text); /* Skip an equal sign. */
- position= 0;
- if (option_value != NULL)
+ /* Looking for option value. */
+
+ skip_spaces(text);
+
+ if (!**text)
+ return TRUE; /* Syntax error: EOS when option value expected. */
+
+ if (**text != '\'' && **text != '"')
{
- *option_value= 0;
- store_to_protocol_packet(&send_buff, tmp_option + 2, &position);
- store_to_protocol_packet(&send_buff, option_value + 1, &position);
- /* join name and the value into the same option again */
- *option_value= '=';
+ /* Option value is a simple token. */
+
+ LEX_STRING option_value;
+
+ get_word(text, &option_value.length, ALPHANUM);
+
+ if (option_value.length == 0)
+ return TRUE; /* internal parser error. */
+
+ option_value.str= (char *) *text;
+ *text+= option_value.length;
+
+ if (!(option_value_str= Named_value::alloc_str(&option_value)))
+ return TRUE; /* out of memory during parsing. */
}
else
{
- store_to_protocol_packet(&send_buff, tmp_option + 2, &position);
- store_to_protocol_packet(&send_buff, "", &position);
+ /* Option value is a string. */
+
+ if (parse_option_value(*text, &len, &option_value_str))
+ return TRUE; /* Syntax error: invalid string specification. */
+
+ *text+= len;
}
+ }
+
+ if (!option_value_str)
+ {
+ LEX_STRING empty_str= { C_STRING_WITH_SIZE("") };
+
+ if (!(option_value_str= Named_value::alloc_str(&empty_str)))
+ return TRUE; /* out of memory during parsing. */
+ }
+
+ if (!(option_name_str= Named_value::alloc_str(&option_name)))
+ {
+ Named_value::free_str(&option_value_str);
+ return TRUE; /* out of memory during parsing. */
+ }
+
+ {
+ Named_value option(option_name_str, option_value_str);
- if (send_buff.is_error() ||
- my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ if (options.add_element(&option))
+ {
+ option.free();
+ return TRUE; /* out of memory during parsing. */
+ }
}
+
+ skip_spaces(text);
+
+ if (!**text)
+ return FALSE; /* OK: end of options. */
+
+ if (**text != ',')
+ return TRUE; /* Syntax error: comma expected. */
+
+ ++(*text);
}
+}
- if (send_eof(net) || net_flush(net))
- goto err;
- return 0;
+/*
+ Implementation of CREATE INSTANCE statement.
-err:
- return ER_OUT_OF_RESOURCES;
+ Possible error codes:
+ ER_MALFORMED_INSTANCE_NAME Instance name is malformed
+ ER_CREATE_EXISTING_INSTANCE There is an instance with the given name
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Create_instance::execute(st_net *net, ulong connection_id)
+{
+ int err_code;
+
+ /* Check that the name is valid and there is no instance with such name. */
+
+ if (!Instance::is_name_valid(get_instance_name()))
+ return ER_MALFORMED_INSTANCE_NAME;
+
+ /*
+ NOTE: In order to prevent race condition, we should perform all operations
+ on under acquired lock.
+ */
+
+ instance_map->lock();
+
+ if (instance_map->find(get_instance_name()))
+ {
+ instance_map->unlock();
+ return ER_CREATE_EXISTING_INSTANCE;
+ }
+
+ if ((err_code= instance_map->create_instance(get_instance_name(), &options)))
+ {
+ instance_map->unlock();
+ return err_code;
+ }
+
+ if ((err_code= create_instance_in_file(get_instance_name(), &options)))
+ {
+ Instance *instance= instance_map->find(get_instance_name());
+
+ if (instance)
+ instance_map->remove_instance(instance); /* instance is deleted here. */
+
+ instance_map->unlock();
+ return err_code;
+ }
+
+ /* That's all. */
+
+ instance_map->unlock();
+
+ /* Send the result. */
+
+ if (net_send_ok(net, connection_id, NULL))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
}
-/* Implementation for Start_instance */
+/**************************************************************************
+ Implementation for Drop_instance.
+**************************************************************************/
-Start_instance::Start_instance(Instance_map *instance_map_arg,
- const char *name, uint len)
- :Command(instance_map_arg)
+Drop_instance::Drop_instance(Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
{
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
}
-int Start_instance::execute(struct st_net *net, ulong connection_id)
+/*
+ Implementation of DROP INSTANCE statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_DROP_ACTIVE_INSTANCE The specified instance is active
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Drop_instance::execute_impl(st_net *net, Instance *instance)
{
- uint err_code;
- if (instance == 0)
- return ER_BAD_INSTANCE_NAME; /* haven't found an instance */
- else
- {
- if ((err_code= instance->start()))
- return err_code;
+ int err_code;
+
+ /* Check that the instance is offline. */
- if (!(instance->options.nonguarded))
- instance_map->guardian->guard(instance);
+ if (instance_map->guardian->is_active(instance))
+ return ER_DROP_ACTIVE_INSTANCE;
- net_send_ok(net, connection_id, "Instance started");
- return 0;
+ err_code= modify_defaults_file(Options::Main::config_file, NULL, NULL,
+ get_instance_name()->str, MY_REMOVE_SECTION);
+ DBUG_ASSERT(err_code >= 0 && err_code <= 2);
+
+ if (err_code)
+ {
+ log_error("Can not remove instance '%s' from defaults file (%s). "
+ "Original error code: %d.",
+ (const char *) get_instance_name()->str,
+ (const char *) Options::Main::config_file,
+ (int) err_code);
}
+
+ if (err_code)
+ return modify_defaults_to_im_error[err_code];
+
+ /* Remove instance from the instance map hash and Guardian's list. */
+
+ if (!instance->options.nonguarded)
+ instance_map->guardian->stop_guard(instance);
+
+ if ((err_code= instance->stop()))
+ return err_code;
+
+ instance_map->remove_instance(instance);
+
+ return 0;
}
-/* implementation for Show_instance_log: */
+int Drop_instance::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (net_send_ok(net, connection_id, "Instance dropped"))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+/**************************************************************************
+ Implementation for Show_instance_log.
+**************************************************************************/
Show_instance_log::Show_instance_log(Instance_map *instance_map_arg,
- const char *name, uint len,
+ const LEX_STRING *instance_name_arg,
Log_type log_type_arg,
- const char *size_arg,
- const char *offset_arg)
- :Command(instance_map_arg)
+ uint size_arg, uint offset_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg),
+ log_type(log_type_arg),
+ size(size_arg),
+ offset(offset_arg)
{
- Instance *instance;
+}
+
+
+/*
+ Implementation of SHOW INSTANCE LOG statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OFFSET_ERROR We were requested to read negative number of
+ bytes from the log
+ ER_NO_SUCH_LOG The specified type of log is not available for
+ the given instance
+ ER_GUESS_LOGFILE IM wasn't able to figure out the log
+ placement, while it is enabled. Probably user
+ should specify the path to the logfile
+ explicitly.
+ ER_OPEN_LOGFILE Cannot open the logfile
+ ER_READ_FILE Cannot read the logfile
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Show_instance_log::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
+
+ if ((err_code= check_params(instance)))
+ return err_code;
+
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net, instance)))
+ return err_code;
+
+ return 0;
+}
- if (offset_arg != NULL)
- offset= atoi(offset_arg);
- else
- offset= 0;
- size= atoi(size_arg);
- log_type= log_type_arg;
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
- else
- instance_name= NULL;
+int Show_instance_log::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
}
+int Show_instance_log::check_params(Instance *instance)
+{
+ const char *logpath= instance->options.logs[log_type];
-/*
- Open the logfile, read requested part of the log and send the info
- to the client.
+ /* Cannot read negative number of bytes. */
- SYNOPSYS
- Show_instance_log::execute()
- net The network connection to the client.
- connection_id Client connection ID
+ if (offset > size)
+ return ER_OFFSET_ERROR;
- DESCRIPTION
+ /* Instance has no such log. */
- Send a table with the content of the log requested. The function also
- deals with errro handling, to be verbose.
+ if (logpath == NULL)
+ return ER_NO_SUCH_LOG;
+
+ if (*logpath == '\0')
+ return ER_GUESS_LOGFILE;
+
+ return 0;
+}
- RETURN
- ER_OFFSET_ERROR We were requested to read negative number of bytes
- from the log
- ER_NO_SUCH_LOG The kind log being read is not enabled in the instance
- ER_GUESS_LOGFILE IM wasn't able to figure out the log placement, while
- it is enabled. Probably user should specify the path
- to the logfile explicitly.
- ER_OPEN_LOGFILE Cannot open the logfile
- ER_READ_FILE Cannot read the logfile
- ER_OUT_OF_RESOURCES We weren't able to allocate some resources
-*/
-int Show_instance_log::execute(struct st_net *net, ulong connection_id)
+int Show_instance_log::write_header(st_net *net)
{
- Buffer send_buff; /* buffer for packets */
LIST name;
LIST *field_list;
- NAME_WITH_LENGTH name_field;
- uint position= 0;
+ LEX_STRING name_field;
+
+ /* Create list of the fields to be passed to send_fields(). */
- /* create list of the fileds to be passed to send_fields */
- name_field.name= (char*) "Log";
+ name_field.str= (char *) "Log";
name_field.length= DEFAULT_FIELD_LENGTH;
- name.data= &name_field;
- field_list= list_add(NULL, &name);
- if (!instance_name)
- return ER_BAD_INSTANCE_NAME;
+ name.data= &name_field;
- /* cannot read negative number of bytes */
- if (offset > size)
- return ER_OFFSET_ERROR;
+ field_list= list_add(NULL, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
- {
- Instance *instance;
- const char *logpath;
- File fd;
- if ((instance= instance_map->find(instance_name,
- strlen(instance_name))) == NULL)
- goto err;
+int Show_instance_log::write_data(st_net *net, Instance *instance)
+{
+ Buffer send_buff; /* buffer for packets */
+ uint pos= 0;
- logpath= instance->options.logs[log_type];
+ const char *logpath= instance->options.logs[log_type];
+ File fd;
- /* Instance has no such log */
- if (logpath == NULL)
- return ER_NO_SUCH_LOG;
+ size_t buff_size;
+ int read_len;
- if (*logpath == '\0')
- return ER_GUESS_LOGFILE;
+ MY_STAT file_stat;
+ Buffer read_buff;
+ if ((fd= my_open(logpath, O_RDONLY | O_BINARY, MYF(MY_WME))) <= 0)
+ return ER_OPEN_LOGFILE;
- if ((fd= my_open(logpath, O_RDONLY | O_BINARY, MYF(MY_WME))) >= 0)
- {
- size_t buff_size;
- int read_len;
- /* calculate buffer size */
- MY_STAT file_stat;
- Buffer read_buff;
+ /* my_fstat doesn't use the flag parameter */
+ if (my_fstat(fd, &file_stat, MYF(0)))
+ {
+ close(fd);
+ return ER_OUT_OF_RESOURCES;
+ }
- /* my_fstat doesn't use the flag parameter */
- if (my_fstat(fd, &file_stat, MYF(0)))
- goto err;
+ /* calculate buffer size */
+ buff_size= (size - offset);
- buff_size= (size - offset);
+ read_buff.reserve(0, buff_size);
- read_buff.reserve(0, buff_size);
+ /* read in one chunk */
+ read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0));
- /* read in one chunk */
- read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0));
+ if ((read_len= my_read(fd, (byte*) read_buff.buffer,
+ buff_size, MYF(0))) < 0)
+ {
+ close(fd);
+ return ER_READ_FILE;
+ }
- if ((read_len= my_read(fd, (byte*) read_buff.buffer,
- buff_size, MYF(0))) < 0)
- return ER_READ_FILE;
- store_to_protocol_packet(&send_buff, read_buff.buffer,
- &position, read_len);
- close(fd);
- }
- else
- return ER_OPEN_LOGFILE;
+ close(fd);
- if (my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
+ if (store_to_protocol_packet(&send_buff, read_buff.buffer, &pos, read_len) ||
+ my_net_write(net, send_buff.buffer, pos))
+ {
+ return ER_OUT_OF_RESOURCES;
}
- if (send_eof(net) || net_flush(net))
- goto err;
-
return 0;
-
-err:
- return ER_OUT_OF_RESOURCES;
}
-/* implementation for Show_instance_log_files: */
+/**************************************************************************
+ Implementation of Show_instance_log_files.
+**************************************************************************/
Show_instance_log_files::Show_instance_log_files
- (Instance_map *instance_map_arg, const char *name, uint len)
- :Command(instance_map_arg)
+ (Instance_map *instance_map_arg,
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
{
- Instance *instance;
-
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
- else
- instance_name= NULL;
}
/*
- The method sends a table with a list of log files
- used by the instance.
-
- SYNOPSYS
- Show_instance_log_files::execute()
- net The network connection to the client.
- connection_id The ID of the client connection
+ Implementation of SHOW INSTANCE LOG FILES statement.
- RETURN
- ER_BAD_INSTANCE_NAME The instance name specified is not valid
- ER_OUT_OF_RESOURCES some error occured
- 0 - ok
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
-int Show_instance_log_files::execute(struct st_net *net, ulong connection_id)
+int Show_instance_log_files::execute_impl(st_net *net, Instance *instance)
+{
+ int err_code;
+
+ if ((err_code= write_header(net)) ||
+ (err_code= write_data(net, instance)))
+ return err_code;
+
+ return 0;
+}
+
+
+int Show_instance_log_files::send_ok_response(st_net *net, ulong connection_id)
+{
+ if (send_eof(net) || net_flush(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+int Show_instance_log_files::write_header(st_net *net)
{
- Buffer send_buff; /* buffer for packets */
LIST name, path, size;
LIST *field_list;
- NAME_WITH_LENGTH name_field, path_field, size_field;
- uint position= 0;
+ LEX_STRING name_field, path_field, size_field;
- if (!instance_name)
- return ER_BAD_INSTANCE_NAME;
+ /* Create list of the fileds to be passed to send_fields(). */
- /* create list of the fileds to be passed to send_fields */
- name_field.name= (char*) "Logfile";
+ name_field.str= (char *) "Logfile";
name_field.length= DEFAULT_FIELD_LENGTH;
name.data= &name_field;
- path_field.name= (char*) "Path";
+
+ path_field.str= (char *) "Path";
path_field.length= DEFAULT_FIELD_LENGTH;
path.data= &path_field;
- size_field.name= (char*) "File size";
+
+ size_field.str= (char *) "File size";
size_field.length= DEFAULT_FIELD_LENGTH;
size.data= &size_field;
+
field_list= list_add(NULL, &size);
field_list= list_add(field_list, &path);
field_list= list_add(field_list, &name);
- send_fields(net, field_list);
+ return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
- Instance *instance;
- if ((instance= instance_map->
- find(instance_name, strlen(instance_name))) == NULL)
- goto err;
+int Show_instance_log_files::write_data(st_net *net, Instance *instance)
+{
+ Buffer send_buff; /* buffer for packets */
+ /*
+ We have alike structure in instance_options.cc. We use such to be able
+ to loop through the options, which we need to handle in some common way.
+ */
+ struct log_files_st
+ {
+ const char *name;
+ const char *value;
+ } logs[]=
{
+ {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]},
+ {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]},
+ {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]},
+ {NULL, NULL}
+ };
+ struct log_files_st *log_files;
+
+ for (log_files= logs; log_files->name; log_files++)
+ {
+ if (!log_files->value)
+ continue;
+
+ struct stat file_stat;
/*
- We have alike structure in instance_options.cc. We use such to be able
- to loop through the options, which we need to handle in some common way.
+ Save some more space for the log file names. In fact all
+ we need is strlen("GENERAL_LOG") + 1
*/
- struct log_files_st
- {
- const char *name;
- const char *value;
- } logs[]=
- {
- {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]},
- {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]},
- {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]},
- {NULL, NULL}
- };
- struct log_files_st *log_files;
-
- for (log_files= logs; log_files->name; log_files++)
+ enum { LOG_NAME_BUFFER_SIZE= 20 };
+ char buff[LOG_NAME_BUFFER_SIZE];
+
+ uint pos= 0;
+
+ const char *log_path= "";
+ const char *log_size= "0";
+
+ if (!stat(log_files->value, &file_stat) &&
+ MY_S_ISREG(file_stat.st_mode))
{
- if (log_files->value != NULL)
- {
- struct stat file_stat;
- /*
- Save some more space for the log file names. In fact all
- we need is srtlen("GENERAL_LOG") + 1
- */
- enum { LOG_NAME_BUFFER_SIZE= 20 };
- char buff[LOG_NAME_BUFFER_SIZE];
-
- position= 0;
- /* store the type of the log in the send buffer */
- store_to_protocol_packet(&send_buff, log_files->name, &position);
- if (stat(log_files->value, &file_stat))
- {
- store_to_protocol_packet(&send_buff, "", &position);
- store_to_protocol_packet(&send_buff, (char*) "0", &position);
- }
- else if (MY_S_ISREG(file_stat.st_mode))
- {
- store_to_protocol_packet(&send_buff,
- (char*) log_files->value,
- &position);
- int10_to_str(file_stat.st_size, buff, 10);
- store_to_protocol_packet(&send_buff, (char*) buff, &position);
- }
-
- if (my_net_write(net, send_buff.buffer, (uint) position))
- goto err;
- }
+ int10_to_str(file_stat.st_size, buff, 10);
+
+ log_path= log_files->value;
+ log_size= buff;
}
- }
- if (send_eof(net) || net_flush(net))
- goto err;
+ if (store_to_protocol_packet(&send_buff, log_files->name, &pos) ||
+ store_to_protocol_packet(&send_buff, log_path, &pos) ||
+ store_to_protocol_packet(&send_buff, log_size, &pos) ||
+ my_net_write(net, send_buff.buffer, pos))
+ return ER_OUT_OF_RESOURCES;
+ }
return 0;
-
-err:
- return ER_OUT_OF_RESOURCES;
}
-/* implementation for SET instance_name.option=option_value: */
+/**************************************************************************
+ Implementation of Abstract_option_cmd.
+**************************************************************************/
+
+/*
+ Instance_options_list -- a data class representing a list of options for
+ some instance.
+*/
-Set_option::Set_option(Instance_map *instance_map_arg,
- const char *name, uint len,
- const char *option_arg, uint option_len_arg,
- const char *option_value_arg, uint option_value_len_arg)
- :Command(instance_map_arg)
+class Instance_options_list
{
- Instance *instance;
+public:
+ Instance_options_list(const LEX_STRING *instance_name_arg);
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- {
- instance_name= instance->options.instance_name;
+public:
+ bool init();
- /* add prefix for add_option */
- if ((option_len_arg < MAX_OPTION_LEN - 1) ||
- (option_value_len_arg < MAX_OPTION_LEN - 1))
- {
- strmake(option, option_arg, option_len_arg);
- strmake(option_value, option_value_arg, option_value_len_arg);
- }
- else
- {
- option[0]= 0;
- option_value[0]= 0;
- }
- instance_name_len= len;
- }
- else
+ const LEX_STRING *get_instance_name() const
{
- instance_name= NULL;
- instance_name_len= 0;
+ return instance_name.get_str();
}
+
+public:
+ /*
+ This member is set and used only in Abstract_option_cmd::execute_impl().
+ Normally it is not used (and should not).
+
+ The problem is that construction and execution of commands are made not
+ in one transaction (not under one lock session). So, we can not initialize
+ instance in constructor and use it in execution.
+ */
+ Instance *instance;
+
+ Named_value_arr options;
+
+private:
+ Instance_name instance_name;
+};
+
+
+/**************************************************************************/
+
+Instance_options_list::Instance_options_list(
+ const LEX_STRING *instance_name_arg)
+ :instance(NULL),
+ instance_name(instance_name_arg)
+{
}
-/*
- The method sends a table with a list of log files
- used by the instance.
+bool Instance_options_list::init()
+{
+ return options.init();
+}
- SYNOPSYS
- Set_option::correct_file()
- skip Skip the option, being searched while writing the result file.
- That is, to delete it.
- DESCRIPTION
+/**************************************************************************/
+
+C_MODE_START
+
+static byte* get_item_key(const byte* item, uint* len,
+ my_bool __attribute__((unused)) t)
+{
+ const Instance_options_list *lst= (const Instance_options_list *) item;
+ *len= lst->get_instance_name()->length;
+ return (byte *) lst->get_instance_name()->str;
+}
+
+static void delete_item(void *item)
+{
+ delete (Instance_options_list *) item;
+}
+
+C_MODE_END
+
+
+/**************************************************************************/
+
+Abstract_option_cmd::Abstract_option_cmd(Instance_map *instance_map_arg)
+ :Command(instance_map_arg),
+ initialized(FALSE)
+{
+}
+
+
+Abstract_option_cmd::~Abstract_option_cmd()
+{
+ if (initialized)
+ hash_free(&instance_options_map);
+}
+
+
+bool Abstract_option_cmd::add_option(const LEX_STRING *instance_name,
+ Named_value *option)
+{
+ Instance_options_list *lst= get_instance_options_list(instance_name);
+ if (!lst)
+ return TRUE;
+
+ lst->options.add_element(option);
+
+ return FALSE;
+}
+
+
+bool Abstract_option_cmd::init(const char **text)
+{
+ static const int INITIAL_HASH_SIZE= 16;
+
+ if (hash_init(&instance_options_map, default_charset_info,
+ INITIAL_HASH_SIZE, 0, 0, get_item_key, delete_item, 0))
+ return TRUE;
+
+ if (parse_args(text))
+ return TRUE;
+
+ initialized= TRUE;
+
+ return FALSE;
+}
+
+
+/*
Correct the option file. The "skip" option is used to remove the found
option.
+ SYNOPSYS
+ Abstract_option_cmd::correct_file()
+ skip Skip the option, being searched while writing the result file.
+ That is, to delete it.
+
RETURN
- ER_OUT_OF_RESOURCES out of resources
+ 0 Success
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
ER_ACCESS_OPTION_FILE Cannot access the option file
- 0 - ok
*/
-int Set_option::correct_file(int skip)
+int Abstract_option_cmd::correct_file(Instance *instance, Named_value *option,
+ bool skip)
+{
+ int err_code= modify_defaults_file(Options::Main::config_file,
+ option->get_name(),
+ option->get_value(),
+ instance->get_name()->str,
+ skip);
+
+ DBUG_ASSERT(err_code >= 0 && err_code <= 2);
+
+ if (err_code)
+ {
+ log_error("Can not modify option (%s) in defaults file (%s). "
+ "Original error code: %d.",
+ (const char *) option->get_name(),
+ (const char *) Options::Main::config_file,
+ (int) err_code);
+ }
+
+ return modify_defaults_to_im_error[err_code];
+}
+
+
+/*
+ Implementation of SET statement.
+
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance with the given name does not exist
+ ER_INCOMPATIBLE_OPTION The specified option can not be set for
+ mysqld-compatible instance
+ ER_INSTANCE_IS_ACTIVE The specified instance is active
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
+
+int Abstract_option_cmd::execute(st_net *net, ulong connection_id)
+{
+ int err_code;
+
+ instance_map->lock();
+
+ err_code= execute_impl(net, connection_id);
+
+ instance_map->unlock();
+
+ return err_code;
+}
+
+
+Instance_options_list *
+Abstract_option_cmd::get_instance_options_list(const LEX_STRING *instance_name)
{
- static const int mysys_to_im_error[]= { 0, ER_OUT_OF_RESOURCES,
- ER_ACCESS_OPTION_FILE };
- int error;
+ Instance_options_list *lst=
+ (Instance_options_list *) hash_search(&instance_options_map,
+ (byte *) instance_name->str,
+ instance_name->length);
+
+ if (!lst)
+ {
+ lst= new Instance_options_list(instance_name);
- error= modify_defaults_file(Options::config_file, option,
- option_value, instance_name, skip);
- DBUG_ASSERT(error >= 0 && error <= 2);
+ if (!lst)
+ return NULL;
- return mysys_to_im_error[error];
+ if (lst->init() || my_hash_insert(&instance_options_map, (byte *) lst))
+ {
+ delete lst;
+ return NULL;
+ }
+ }
+
+ return lst;
+}
+
+
+int Abstract_option_cmd::execute_impl(st_net *net, ulong connection_id)
+{
+ int err_code;
+
+ /* Check that all the specified instances exist and are offline. */
+
+ for (uint i= 0; i < instance_options_map.records; ++i)
+ {
+ Instance_options_list *lst=
+ (Instance_options_list *) hash_element(&instance_options_map, i);
+
+ lst->instance= instance_map->find(lst->get_instance_name());
+
+ if (!lst->instance)
+ return ER_BAD_INSTANCE_NAME;
+
+ if (instance_map->guardian->is_active(lst->instance))
+ return ER_INSTANCE_IS_ACTIVE;
+ }
+
+ /* Perform command-specific (SET/UNSET) actions. */
+
+ for (uint i= 0; i < instance_options_map.records; ++i)
+ {
+ Instance_options_list *lst=
+ (Instance_options_list *) hash_element(&instance_options_map, i);
+
+ for (int j= 0; j < lst->options.get_size(); ++j)
+ {
+ Named_value option= lst->options.get_element(j);
+ err_code= process_option(lst->instance, &option);
+
+ if (err_code)
+ break;
+ }
+
+ if (err_code)
+ break;
+ }
+
+ if (err_code == 0)
+ net_send_ok(net, connection_id, NULL);
+
+ return err_code;
+}
+
+
+/**************************************************************************
+ Implementation of Set_option.
+**************************************************************************/
+
+Set_option::Set_option(Instance_map *instance_map_arg)
+ :Abstract_option_cmd(instance_map_arg)
+{
}
/*
- The method sets an option in the the default config file (/etc/my.cnf).
+ This operation parses SET options.
SYNOPSYS
- Set_option::do_command()
- net The network connection to the client.
+ text [IN/OUT] a pointer to the text containing options.
RETURN
- 0 - ok
- 1 - error occured
+ FALSE On success.
+ TRUE On syntax error.
*/
-int Set_option::do_command(struct st_net *net)
+bool Set_option::parse_args(const char **text)
{
- int error;
+ uint len;
- /* we must hold the instance_map mutex while changing config file */
- instance_map->lock();
- error= correct_file(FALSE);
- instance_map->unlock();
+ /* Check if we have something (and trim leading spaces). */
+
+ get_word(text, &len, NONSPACE);
+
+ if (len == 0)
+ return TRUE; /* Syntax error: no option. */
+
+ /* Main parsing loop. */
+
+ while (TRUE)
+ {
+ LEX_STRING instance_name;
+ LEX_STRING option_name;
+ char *option_name_str;
+ char *option_value_str= NULL;
+
+ /* Looking for instance name. */
+
+ get_word(text, &instance_name.length, ALPHANUM);
+
+ if (instance_name.length == 0)
+ return TRUE; /* Syntax error: instance name expected. */
+
+ instance_name.str= (char *) *text;
+ *text+= instance_name.length;
+
+ skip_spaces(text);
+
+ /* Check the the delimiter is a dot. */
+
+ if (**text != '.')
+ return TRUE; /* Syntax error: dot expected. */
+
+ ++(*text);
+
+ /* Looking for option name. */
+
+ get_word(text, &option_name.length, OPTION_NAME);
+
+ if (option_name.length == 0)
+ return TRUE; /* Syntax error: option name expected. */
+
+ option_name.str= (char *) *text;
+ *text+= option_name.length;
+
+ /* Looking for equal sign. */
+
+ skip_spaces(text);
+
+ if (**text == '=')
+ {
+ ++(*text); /* Skip an equal sign. */
+
+ /* Looking for option value. */
+
+ skip_spaces(text);
+
+ if (!**text)
+ return TRUE; /* Syntax error: EOS when option value expected. */
+
+ if (**text != '\'' && **text != '"')
+ {
+ /* Option value is a simple token. */
+
+ LEX_STRING option_value;
+
+ get_word(text, &option_value.length, ALPHANUM);
+
+ if (option_value.length == 0)
+ return TRUE; /* internal parser error. */
+
+ option_value.str= (char *) *text;
+ *text+= option_value.length;
- return error;
+ if (!(option_value_str= Named_value::alloc_str(&option_value)))
+ return TRUE; /* out of memory during parsing. */
+ }
+ else
+ {
+ /* Option value is a string. */
+
+ if (parse_option_value(*text, &len, &option_value_str))
+ return TRUE; /* Syntax error: invalid string specification. */
+
+ *text+= len;
+ }
+ }
+
+ if (!option_value_str)
+ {
+ LEX_STRING empty_str= { C_STRING_WITH_SIZE("") };
+
+ if (!(option_value_str= Named_value::alloc_str(&empty_str)))
+ return TRUE; /* out of memory during parsing. */
+ }
+
+ if (!(option_name_str= Named_value::alloc_str(&option_name)))
+ {
+ Named_value::free_str(&option_name_str);
+ return TRUE; /* out of memory during parsing. */
+ }
+
+ {
+ Named_value option(option_name_str, option_value_str);
+
+ if (add_option(&instance_name, &option))
+ {
+ option.free();
+ return TRUE; /* out of memory during parsing. */
+ }
+ }
+
+ skip_spaces(text);
+
+ if (!**text)
+ return FALSE; /* OK: end of options. */
+
+ if (**text != ',')
+ return TRUE; /* Syntax error: comma expected. */
+
+ ++(*text); /* Skip a comma. */
+ }
}
-int Set_option::execute(struct st_net *net, ulong connection_id)
+int Set_option::process_option(Instance *instance, Named_value *option)
{
- if (instance_name != NULL)
+ /* Check that the option is valid. */
+
+ if (instance->is_mysqld_compatible() &&
+ Instance_options::is_option_im_specific(option->get_name()))
{
- int val;
+ log_error("Error: IM-option (%s) can not be used "
+ "in the configuration of mysqld-compatible instance (%s).",
+ (const char *) option->get_name(),
+ (const char *) instance->get_name()->str);
+ return ER_INCOMPATIBLE_OPTION;
+ }
- val= do_command(net);
+ /* Update the configuration file. */
- if (val == 0)
- net_send_ok(net, connection_id, NULL);
+ int err_code= correct_file(instance, option, FALSE);
- return val;
- }
+ if (err_code)
+ return err_code;
+
+ /* Update the internal cache. */
- return ER_BAD_INSTANCE_NAME;
+ if (instance->options.set_option(option))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
}
-/* the only function from Unset_option we need to Implement */
+/**************************************************************************
+ Implementation of Unset_option.
+**************************************************************************/
-int Unset_option::do_command(struct st_net *net)
+Unset_option::Unset_option(Instance_map *instance_map_arg)
+ :Abstract_option_cmd(instance_map_arg)
{
- return correct_file(TRUE);
}
-/* Implementation for Stop_instance: */
+/*
+ This operation parses UNSET options.
-Stop_instance::Stop_instance(Instance_map *instance_map_arg,
- const char *name, uint len)
- :Command(instance_map_arg)
+ SYNOPSYS
+ text [IN/OUT] a pointer to the text containing options.
+
+ RETURN
+ FALSE On success.
+ TRUE On syntax error.
+*/
+
+bool Unset_option::parse_args(const char **text)
{
- /* we make a search here, since we don't want to store the name */
- if ((instance= instance_map->find(name, len)))
- instance_name= instance->options.instance_name;
+ uint len;
+
+ /* Check if we have something (and trim leading spaces). */
+
+ get_word(text, &len, NONSPACE);
+
+ if (len == 0)
+ return TRUE; /* Syntax error: no option. */
+
+ /* Main parsing loop. */
+
+ while (TRUE)
+ {
+ LEX_STRING instance_name;
+ LEX_STRING option_name;
+ char *option_name_str;
+ char *option_value_str;
+
+ /* Looking for instance name. */
+
+ get_word(text, &instance_name.length, ALPHANUM);
+
+ if (instance_name.length == 0)
+ return TRUE; /* Syntax error: instance name expected. */
+
+ instance_name.str= (char *) *text;
+ *text+= instance_name.length;
+
+ skip_spaces(text);
+
+ /* Check the the delimiter is a dot. */
+
+ if (**text != '.')
+ return TRUE; /* Syntax error: dot expected. */
+
+ ++(*text); /* Skip a dot. */
+
+ /* Looking for option name. */
+
+ get_word(text, &option_name.length, OPTION_NAME);
+
+ if (option_name.length == 0)
+ return TRUE; /* Syntax error: option name expected. */
+
+ option_name.str= (char *) *text;
+ *text+= option_name.length;
+
+ if (!(option_name_str= Named_value::alloc_str(&option_name)))
+ return TRUE; /* out of memory during parsing. */
+
+ {
+ LEX_STRING empty_str= { C_STRING_WITH_SIZE("") };
+
+ if (!(option_value_str= Named_value::alloc_str(&empty_str)))
+ {
+ Named_value::free_str(&option_name_str);
+ return TRUE;
+ }
+ }
+
+ {
+ Named_value option(option_name_str, option_value_str);
+
+ if (add_option(&instance_name, &option))
+ {
+ option.free();
+ return TRUE; /* out of memory during parsing. */
+ }
+ }
+
+ skip_spaces(text);
+
+ if (!**text)
+ return FALSE; /* OK: end of options. */
+
+ if (**text != ',')
+ return TRUE; /* Syntax error: comma expected. */
+
+ ++(*text); /* Skip a comma. */
+ }
}
-int Stop_instance::execute(struct st_net *net, ulong connection_id)
-{
- uint err_code;
+/*
+ Implementation of UNSET statement.
- if (instance == 0)
- return ER_BAD_INSTANCE_NAME; /* haven't found an instance */
+ Possible error codes:
+ ER_BAD_INSTANCE_NAME The instance name specified is not valid
+ ER_INSTANCE_IS_ACTIVE The specified instance is active
+ ER_OUT_OF_RESOURCES Not enough resources to complete the operation
+*/
- if (!(instance->options.nonguarded))
- instance_map->guardian->stop_guard(instance);
+int Unset_option::process_option(Instance *instance, Named_value *option)
+{
+ /* Update the configuration file. */
- if ((err_code= instance->stop()))
+ int err_code= correct_file(instance, option, TRUE);
+
+ if (err_code)
return err_code;
- net_send_ok(net, connection_id, NULL);
+ /* Update the internal cache. */
+
+ instance->options.unset_option(option->get_name());
+
return 0;
}
-int Syntax_error::execute(struct st_net *net, ulong connection_id)
+/**************************************************************************
+ Implementation of Syntax_error.
+**************************************************************************/
+
+int Syntax_error::execute(st_net *net, ulong connection_id)
{
return ER_SYNTAX_ERROR;
}