mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
This is an implementation of two WL items:
- WL#3158: IM: Instance configuration extensions; - WL#3159: IM: --bootstrap and --start-default-instance modes The following new statements have been added: - CREATE INSTANCE; - DROP INSTANCE; The behaviour of the following statements have been changed: - SET; - UNSET; - FLUSH INSTANCES; - SHOW INSTANCES; - SHOW INSTANCE OPTIONS;
This commit is contained in:
@ -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:
|
||||
|
||||
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++;
|
||||
|
||||
get_word(&text, &option_len, NONSPACE);
|
||||
option= text;
|
||||
if ((tmp= strchr(text, '=')) != NULL)
|
||||
option_len= tmp - text;
|
||||
text+= option_len;
|
||||
|
||||
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;
|
||||
}
|
||||
Abstract_option_cmd *cmd;
|
||||
|
||||
/* should be empty */
|
||||
get_word(&text, &word_len, NONSPACE);
|
||||
if (word_len)
|
||||
goto syntax_error;
|
||||
if (tok1 == TOK_SET)
|
||||
cmd= new Set_option(map);
|
||||
else
|
||||
cmd= new Unset_option(map);
|
||||
|
||||
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;
|
||||
if (!cmd)
|
||||
return NULL; /* Report ER_OUT_OF_RESOURCES. */
|
||||
|
||||
if (cmd->init(&text))
|
||||
{
|
||||
delete cmd;
|
||||
goto syntax_error;
|
||||
}
|
||||
|
||||
command= cmd;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
Reference in New Issue
Block a user