diff options
Diffstat (limited to 'server-tools/instance-manager/parse.cc')
-rw-r--r-- | server-tools/instance-manager/parse.cc | 351 |
1 files changed, 265 insertions, 86 deletions
diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc index 14b3db16b45..4e931488fce 100644 --- a/server-tools/instance-manager/parse.cc +++ b/server-tools/instance-manager/parse.cc @@ -17,12 +17,12 @@ #include "parse.h" #include "commands.h" -#include <string.h> - enum Token { - TOK_ERROR= 0, /* Encodes the "ERROR" word, it doesn't indicate error. */ + TOK_CREATE= 0, + TOK_DROP, + TOK_ERROR, /* Encodes the "ERROR" word, it doesn't indicate error. */ TOK_FILES, TOK_FLUSH, TOK_GENERAL, @@ -50,6 +50,8 @@ struct tokens_st static struct tokens_st tokens[]= { + {6, "CREATE"}, + {4, "DROP"}, {5, "ERROR"}, {5, "FILES"}, {5, "FLUSH"}, @@ -67,6 +69,37 @@ static struct tokens_st tokens[]= { {5, "UNSET"} }; +/************************************************************************/ + +Named_value_arr::Named_value_arr() : + initialized(FALSE) +{ +} + + +bool Named_value_arr::init() +{ + if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32)) + return TRUE; + + initialized= TRUE; + + return FALSE; +} + + +Named_value_arr::~Named_value_arr() +{ + if (!initialized) + return; + + for (int i= 0; i < get_size(); ++i) + get_element(i).free(); + + delete_dynamic(&arr); +} + +/************************************************************************/ /* Returns token no if word corresponds to some token, otherwise returns @@ -104,53 +137,200 @@ Token shift_token(const char **text, uint *word_len) } -int get_text_id(const char **text, uint *word_len, const char **id) +int get_text_id(const char **text, LEX_STRING *token) { - get_word(text, word_len); - if (*word_len == 0) + get_word(text, &token->length); + if (token->length == 0) return 1; - *id= *text; + token->str= (char *) *text; return 0; } +static bool parse_long(const LEX_STRING *token, long *value) +{ + int err_code; + char *end_ptr= token->str + token->length; + + *value= my_strtoll10(token->str, &end_ptr, &err_code); + + return err_code != 0; +} + + +bool parse_option_value(const char *text, uint *text_len, char **value) +{ + char beginning_quote; + const char *text_start_ptr; + char *v; + bool escape_mode= FALSE; + + if (!*text || (*text != '\'' && *text != '"')) + return TRUE; /* syntax error: string expected. */ + + beginning_quote= *text; + + ++text; /* skip the beginning quote. */ + + text_start_ptr= text; + + if (!(v= Named_value::alloc_str(text))) + return TRUE; + + *value= v; + + while (TRUE) + { + if (!*text) + { + Named_value::free_str(value); + return TRUE; /* syntax error: missing terminating ' character. */ + } + + if (*text == '\n' || *text == '\r') + { + Named_value::free_str(value); + return TRUE; /* syntax error: option value should be a single line. */ + } + + if (!escape_mode && *text == beginning_quote) + break; + + if (escape_mode) + { + switch (*text) + { + case 'b': /* \b -- backspace */ + if (v > *value) + --v; + break; + + case 't': /* \t -- tab */ + *v= '\t'; + ++v; + break; + + case 'n': /* \n -- newline */ + *v= '\n'; + ++v; + break; + + case 'r': /* \r -- carriage return */ + *v= '\r'; + ++v; + break; + + case '\\': /* \\ -- back slash */ + *v= '\\'; + ++v; + break; + + case 's': /* \s -- space */ + *v= ' '; + ++v; + break; + + default: /* Unknown escape sequence. Treat as error. */ + Named_value::free_str(value); + return TRUE; + } + + escape_mode= FALSE; + } + else + { + if (*text == '\\') + { + escape_mode= TRUE; + } + else + { + *v= *text; + ++v; + } + } + + ++text; + } + + *v= 0; + + /* "2" below stands for beginning and ending quotes. */ + *text_len= text - text_start_ptr + 2; + + return FALSE; +} + + +void skip_spaces(const char **text) +{ + while (**text && my_isspace(default_charset_info, **text)) + ++(*text); +} + + Command *parse_command(Instance_map *map, const char *text) { uint word_len; - const char *instance_name; - uint instance_name_len; - const char *option; - uint option_len; - const char *option_value; - uint option_value_len; - const char *log_size; + LEX_STRING instance_name; Command *command; const char *saved_text= text; - bool skip= false; - const char *tmp; Token tok1= shift_token(&text, &word_len); switch (tok1) { case TOK_START: // fallthrough case TOK_STOP: + case TOK_CREATE: + case TOK_DROP: if (shift_token(&text, &word_len) != TOK_INSTANCE) goto syntax_error; get_word(&text, &word_len); if (word_len == 0) goto syntax_error; - instance_name= text; - instance_name_len= word_len; + instance_name.str= (char *) text; + instance_name.length= word_len; text+= word_len; - /* it should be the end of command */ - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - if (tok1 == TOK_START) - command= new Start_instance(map, instance_name, instance_name_len); + if (tok1 == TOK_CREATE) + { + Create_instance *cmd= new Create_instance(map, &instance_name); + + if (!cmd) + return NULL; /* Report ER_OUT_OF_RESOURCES. */ + + if (cmd->init(&text)) + { + delete cmd; + goto syntax_error; + } + + command= cmd; + } else - command= new Stop_instance(map, instance_name, instance_name_len); + { + /* it should be the end of command */ + get_word(&text, &word_len, NONSPACE); + if (word_len) + goto syntax_error; + } + + switch (tok1) { + case TOK_START: + command= new Start_instance(map, &instance_name); + break; + case TOK_STOP: + command= new Stop_instance(map, &instance_name); + break; + case TOK_CREATE: + ; /* command already initialized. */ + break; + case TOK_DROP: + command= new Drop_instance(map, &instance_name); + break; + default: /* this is impossible, but nevertheless... */ + DBUG_ASSERT(0); + } break; case TOK_FLUSH: if (shift_token(&text, &word_len) != TOK_INSTANCES) @@ -163,53 +343,28 @@ Command *parse_command(Instance_map *map, const char *text) command= new Flush_instances(map); break; case TOK_UNSET: - skip= true; case TOK_SET: + { + Abstract_option_cmd *cmd; - if (get_text_id(&text, &instance_name_len, &instance_name)) - goto syntax_error; - text+= instance_name_len; - - /* the next token should be a dot */ - get_word(&text, &word_len); - if (*text != '.') - goto syntax_error; - text++; + if (tok1 == TOK_SET) + cmd= new Set_option(map); + else + cmd= new Unset_option(map); - get_word(&text, &option_len, NONSPACE); - option= text; - if ((tmp= strchr(text, '=')) != NULL) - option_len= tmp - text; - text+= option_len; + if (!cmd) + return NULL; /* Report ER_OUT_OF_RESOURCES. */ - get_word(&text, &word_len); - if (*text == '=') - { - text++; /* skip '=' */ - get_word(&text, &option_value_len, NONSPACE); - option_value= text; - text+= option_value_len; - } - else - { - option_value= ""; - option_value_len= 0; - } + if (cmd->init(&text)) + { + delete cmd; + goto syntax_error; + } - /* should be empty */ - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; + command= cmd; - if (skip) - command= new Unset_option(map, instance_name, instance_name_len, - option, option_len, option_value, - option_value_len); - else - command= new Set_option(map, instance_name, instance_name_len, - option, option_len, option_value, - option_value_len); - break; + break; + } case TOK_SHOW: switch (shift_token(&text, &word_len)) { case TOK_INSTANCES: @@ -222,30 +377,35 @@ Command *parse_command(Instance_map *map, const char *text) switch (Token tok2= shift_token(&text, &word_len)) { case TOK_OPTIONS: case TOK_STATUS: - if (get_text_id(&text, &instance_name_len, &instance_name)) + if (get_text_id(&text, &instance_name)) goto syntax_error; - text+= instance_name_len; + text+= instance_name.length; /* check that this is the end of the command */ get_word(&text, &word_len, NONSPACE); if (word_len) goto syntax_error; if (tok2 == TOK_STATUS) - command= new Show_instance_status(map, instance_name, - instance_name_len); + command= new Show_instance_status(map, &instance_name); else - command= new Show_instance_options(map, instance_name, - instance_name_len); + command= new Show_instance_options(map, &instance_name); break; default: goto syntax_error; } break; default: - instance_name= text - word_len; - instance_name_len= word_len; - if (instance_name_len) + instance_name.str= (char *) text - word_len; + instance_name.length= word_len; + if (instance_name.length) { Log_type log_type; + + long log_size; + LEX_STRING log_size_str; + + long log_offset= 0; + LEX_STRING log_offset_str= { NULL, 0 }; + switch (shift_token(&text, &word_len)) { case TOK_LOG: switch (Token tok3= shift_token(&text, &word_len)) { @@ -254,8 +414,7 @@ Command *parse_command(Instance_map *map, const char *text) /* check that this is the end of the command */ if (word_len) goto syntax_error; - command= new Show_instance_log_files(map, instance_name, - instance_name_len); + command= new Show_instance_log_files(map, &instance_name); break; case TOK_ERROR: case TOK_GENERAL: @@ -275,12 +434,14 @@ Command *parse_command(Instance_map *map, const char *text) goto syntax_error; } /* get the size of the log we want to retrieve */ - if (get_text_id(&text, &word_len, &log_size)) + if (get_text_id(&text, &log_size_str)) goto syntax_error; - text+= word_len; + text+= log_size_str.length; + /* this parameter is required */ - if (!word_len) + if (!log_size_str.length) goto syntax_error; + /* the next token should be comma, or nothing */ get_word(&text, &word_len); switch (*text) { @@ -290,23 +451,41 @@ Command *parse_command(Instance_map *map, const char *text) get_word(&text, &word_len); if (!word_len) goto syntax_error; + log_offset_str.str= (char *) text; + log_offset_str.length= word_len; text+= word_len; - command= new Show_instance_log(map, instance_name, - instance_name_len, log_type, - log_size, text); get_word(&text, &word_len, NONSPACE); /* check that this is the end of the command */ if (word_len) goto syntax_error; break; case '\0': - command= new Show_instance_log(map, instance_name, - instance_name_len, log_type, - log_size, NULL); break; /* this is ok */ default: + goto syntax_error; + } + + /* Parse size parameter. */ + + if (parse_long(&log_size_str, &log_size)) + goto syntax_error; + + if (log_size <= 0) goto syntax_error; + + /* Parse offset parameter (if specified). */ + + if (log_offset_str.length) + { + if (parse_long(&log_offset_str, &log_offset)) + goto syntax_error; + + if (log_offset <= 0) + goto syntax_error; } + + command= new Show_instance_log(map, &instance_name, + log_type, log_size, log_offset); break; default: goto syntax_error; |