mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
merge
This commit is contained in:
commit
0584756fb4
15 changed files with 1043 additions and 42 deletions
|
@ -27,6 +27,19 @@
|
|||
#include <mysql.h>
|
||||
|
||||
|
||||
/* some useful functions */
|
||||
|
||||
static int put_to_buff(Buffer *buff, const char *str, uint *position)
|
||||
{
|
||||
uint len= strlen(str);
|
||||
if (buff->append(*position, str, len))
|
||||
return 1;
|
||||
|
||||
*position+= len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* implementation for Show_instances: */
|
||||
|
||||
|
||||
|
@ -106,7 +119,7 @@ int Flush_instances::execute(struct st_net *net, ulong connection_id)
|
|||
if (instance_map->flush_instances())
|
||||
return ER_OUT_OF_RESOURCES;
|
||||
|
||||
net_send_ok(net, connection_id);
|
||||
net_send_ok(net, connection_id, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -119,7 +132,7 @@ Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
|
|||
{
|
||||
Instance *instance;
|
||||
|
||||
/* we make a search here, since we don't want t store the name */
|
||||
/* 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;
|
||||
|
@ -225,7 +238,7 @@ Show_instance_options::Show_instance_options(Instance_map *instance_map_arg,
|
|||
{
|
||||
Instance *instance;
|
||||
|
||||
/* we make a search here, since we don't want t store the name */
|
||||
/* 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;
|
||||
|
@ -344,7 +357,7 @@ Start_instance::Start_instance(Instance_map *instance_map_arg,
|
|||
const char *name, uint len)
|
||||
:Command(instance_map_arg)
|
||||
{
|
||||
/* we make a search here, since we don't want t store the name */
|
||||
/* 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;
|
||||
}
|
||||
|
@ -365,19 +378,470 @@ int Start_instance::execute(struct st_net *net, ulong connection_id)
|
|||
if (!(instance->options.nonguarded))
|
||||
instance_map->guardian->guard(instance);
|
||||
|
||||
net_send_ok(net, connection_id);
|
||||
net_send_ok(net, connection_id, "Instance started");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* implementation for Show_instance_log: */
|
||||
|
||||
Show_instance_log::Show_instance_log(Instance_map *instance_map_arg,
|
||||
const char *name, uint len,
|
||||
Log_type log_type_arg,
|
||||
const char *size_arg,
|
||||
const char *offset_arg)
|
||||
:Command(instance_map_arg)
|
||||
{
|
||||
Instance *instance;
|
||||
|
||||
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::do_command(struct st_net *net,
|
||||
const char *instance_name)
|
||||
{
|
||||
enum { MAX_VERSION_LENGTH= 40 };
|
||||
Buffer send_buff; /* buffer for packets */
|
||||
LIST name;
|
||||
LIST *field_list;
|
||||
NAME_WITH_LENGTH name_field;
|
||||
uint position=0;
|
||||
|
||||
/* create list of the fileds to be passed to send_fields */
|
||||
name_field.name= (char *) "Log";
|
||||
name_field.length= 20;
|
||||
name.data= &name_field;
|
||||
field_list= list_add(NULL, &name);
|
||||
|
||||
/* cannot read negative number of bytes */
|
||||
if (offset > size)
|
||||
return ER_SYNTAX_ERROR;
|
||||
|
||||
send_fields(net, field_list);
|
||||
|
||||
{
|
||||
Instance *instance;
|
||||
const char *logpath;
|
||||
File fd;
|
||||
|
||||
if ((instance= instance_map->find(instance_name, strlen(instance_name))) == NULL)
|
||||
goto err;
|
||||
|
||||
switch (log_type)
|
||||
{
|
||||
case LOG_ERROR:
|
||||
logpath= instance->options.error_log;
|
||||
break;
|
||||
case LOG_GENERAL:
|
||||
logpath= instance->options.query_log;
|
||||
break;
|
||||
case LOG_SLOW:
|
||||
logpath= instance->options.slow_log;
|
||||
break;
|
||||
default:
|
||||
logpath= NULL;
|
||||
}
|
||||
|
||||
/* Instance has no such log */
|
||||
if (logpath == NULL)
|
||||
{
|
||||
return ER_NO_SUCH_LOG;
|
||||
}
|
||||
else if (*logpath == '\0')
|
||||
{
|
||||
return ER_GUESS_LOGFILE;
|
||||
}
|
||||
|
||||
|
||||
if ((fd= open(logpath, O_RDONLY)))
|
||||
{
|
||||
size_t buff_size;
|
||||
int read_len;
|
||||
/* calculate buffer size */
|
||||
struct stat file_stat;
|
||||
|
||||
if(fstat(fd, &file_stat))
|
||||
goto err;
|
||||
|
||||
buff_size= (size - offset);
|
||||
|
||||
/* read in one chunk */
|
||||
read_len= my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0));
|
||||
|
||||
char *bf= (char *) malloc(sizeof(char)*buff_size);
|
||||
read_len= my_read(fd, bf, buff_size, MYF(0));
|
||||
store_to_string(&send_buff, (char *) bf, &position, read_len);
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ER_OPEN_LOGFILE;
|
||||
}
|
||||
|
||||
if (my_net_write(net, send_buff.buffer, (uint) position))
|
||||
goto err;
|
||||
}
|
||||
|
||||
send_eof(net);
|
||||
net_flush(net);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return ER_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
|
||||
int Show_instance_log::execute(struct st_net *net, ulong connection_id)
|
||||
{
|
||||
if (instance_name != NULL)
|
||||
{
|
||||
return do_command(net, instance_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ER_BAD_INSTANCE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* implementation for 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 *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 the list of the log files
|
||||
used by the instance.
|
||||
|
||||
SYNOPSYS
|
||||
Show_instance_log_files::do_command()
|
||||
net The network connection to the client.
|
||||
instance_name The name of the instance.
|
||||
|
||||
RETURN
|
||||
0 - ok
|
||||
1 - error occured
|
||||
*/
|
||||
|
||||
|
||||
int Show_instance_log_files::do_command(struct st_net *net,
|
||||
const char *instance_name)
|
||||
{
|
||||
enum { MAX_VERSION_LENGTH= 40 };
|
||||
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;
|
||||
|
||||
/* create list of the fileds to be passed to send_fields */
|
||||
name_field.name= (char *) "Logfile";
|
||||
name_field.length= 20;
|
||||
name.data= &name_field;
|
||||
path_field.name= (char *) "Path";
|
||||
path_field.length= 20;
|
||||
path.data= &path_field;
|
||||
size_field.name= (char *) "Filesize";
|
||||
size_field.length= 20;
|
||||
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);
|
||||
|
||||
Instance *instance;
|
||||
|
||||
if ((instance= instance_map->
|
||||
find(instance_name, strlen(instance_name))) == NULL)
|
||||
goto err;
|
||||
{
|
||||
/*
|
||||
We have alike structure in instance_options.cc. We use such to be able
|
||||
to loop througt 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.error_log},
|
||||
{"GENERAL LOG", instance->options.query_log},
|
||||
{"SLOW LOG", instance->options.slow_log},
|
||||
{NULL, NULL}
|
||||
};
|
||||
struct log_files_st *log_files;
|
||||
|
||||
|
||||
instance->options.print_argv();
|
||||
for (log_files= logs; log_files->name; log_files++)
|
||||
{
|
||||
if (log_files->value != NULL)
|
||||
{
|
||||
struct stat file_stat;
|
||||
char buff[20];
|
||||
|
||||
position= 0;
|
||||
/* store the type of the log in the send buffer */
|
||||
store_to_string(&send_buff, log_files->name, &position);
|
||||
switch (stat(log_files->value, &file_stat)) {
|
||||
case 0:
|
||||
if (S_ISREG(file_stat.st_mode))
|
||||
{
|
||||
store_to_string(&send_buff,
|
||||
(char *) log_files->value,
|
||||
&position);
|
||||
int10_to_str(file_stat.st_size, buff, 10);
|
||||
store_to_string(&send_buff, (char *) buff, &position);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
store_to_string(&send_buff,
|
||||
"",
|
||||
&position);
|
||||
store_to_string(&send_buff, (char *) "0", &position);
|
||||
}
|
||||
if (my_net_write(net, send_buff.buffer, (uint) position))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_eof(net);
|
||||
net_flush(net);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return 1;
|
||||
}
|
||||
int Show_instance_log_files::execute(struct st_net *net, ulong connection_id)
|
||||
{
|
||||
if (instance_name != NULL)
|
||||
{
|
||||
if (do_command(net, instance_name))
|
||||
return ER_OUT_OF_RESOURCES;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ER_BAD_INSTANCE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* implementation for SET nstance_name.option=option_value: */
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
/* add prefix for add_option */
|
||||
if ((option_len_arg < MAX_OPTION_LEN - 1) ||
|
||||
(option_value_len_arg < MAX_OPTION_LEN - 1))
|
||||
{
|
||||
strncpy(option, option_arg, option_len_arg);
|
||||
option[option_len_arg]= 0;
|
||||
strncpy(option_value, option_value_arg, option_value_len_arg);
|
||||
option_value[option_value_len_arg]= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
option[0]= 0;
|
||||
option_value[0]= 0;
|
||||
}
|
||||
instance_name_len= len;
|
||||
}
|
||||
else
|
||||
{
|
||||
instance_name= NULL;
|
||||
instance_name_len= 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Correct the file. skip option could be used in future if we don't want to
|
||||
let user change the options file (E.g. he lacks permissions to do that)
|
||||
*/
|
||||
int Set_option::correct_file(bool skip)
|
||||
{
|
||||
FILE *cnf_file;
|
||||
const char *default_location="/etc/my.cnf";
|
||||
char linebuff[4096], *ptr;
|
||||
uint optlen;
|
||||
Buffer file_buffer;
|
||||
uint position= 0;
|
||||
bool isfound= false;
|
||||
|
||||
optlen= strlen(option);
|
||||
|
||||
if (!(cnf_file= my_fopen(default_location, O_RDONLY, MYF(0))))
|
||||
goto err_fopen;
|
||||
|
||||
while (fgets(linebuff, sizeof(linebuff), cnf_file))
|
||||
{
|
||||
/* if the section is found traverse it */
|
||||
if (isfound)
|
||||
{
|
||||
/* skip the old value of the option we are changing */
|
||||
if (strncmp(linebuff, option, optlen))
|
||||
{
|
||||
/* copy all other lines line */
|
||||
put_to_buff(&file_buffer, linebuff, &position);
|
||||
}
|
||||
}
|
||||
else
|
||||
put_to_buff(&file_buffer, linebuff, &position);
|
||||
|
||||
/* looking for appropriate instance section */
|
||||
for (ptr= linebuff ; my_isspace(&my_charset_latin1,*ptr) ; ptr++);
|
||||
if (*ptr == '[')
|
||||
{
|
||||
/* copy the line to the buffer */
|
||||
if (!strncmp(++ptr, instance_name, instance_name_len))
|
||||
{
|
||||
isfound= true;
|
||||
/* add option */
|
||||
if (!skip)
|
||||
{
|
||||
put_to_buff(&file_buffer, option, &position);
|
||||
if (option_value[0] != 0)
|
||||
{
|
||||
put_to_buff(&file_buffer, "=", &position);
|
||||
put_to_buff(&file_buffer, option_value, &position);
|
||||
}
|
||||
/* add a newline */
|
||||
put_to_buff(&file_buffer, "\n", &position);
|
||||
}
|
||||
}
|
||||
else
|
||||
isfound= false; /* mark that this section is of no interest to us */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (my_fclose(cnf_file, MYF(0)))
|
||||
goto err;
|
||||
|
||||
/* we must hold an instance_map mutex while changing config file */
|
||||
instance_map->lock();
|
||||
|
||||
if (!(cnf_file= my_fopen(default_location, O_WRONLY|O_TRUNC, MYF(0))))
|
||||
goto err;
|
||||
if (my_fwrite(cnf_file, file_buffer.buffer, position, MYF(MY_NABP)))
|
||||
goto err;
|
||||
|
||||
if (my_fclose(cnf_file, MYF(0)))
|
||||
goto err;
|
||||
|
||||
instance_map->unlock();
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
my_fclose(cnf_file, MYF(0));
|
||||
return ER_OUT_OF_RESOURCES;
|
||||
err_fopen:
|
||||
return ER_ACCESS_OPTION_FILE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The method sets an option in the the default config file (/etc/my.cnf).
|
||||
|
||||
SYNOPSYS
|
||||
Set_option::do_command()
|
||||
net The network connection to the client.
|
||||
|
||||
RETURN
|
||||
0 - ok
|
||||
1 - error occured
|
||||
*/
|
||||
|
||||
|
||||
int Set_option::do_command(struct st_net *net)
|
||||
{
|
||||
return correct_file(false);
|
||||
}
|
||||
|
||||
|
||||
int Set_option::execute(struct st_net *net, ulong connection_id)
|
||||
{
|
||||
if (instance_name != NULL)
|
||||
{
|
||||
int val;
|
||||
|
||||
val= do_command(net);
|
||||
if (val == 0)
|
||||
{
|
||||
net_send_ok(net, connection_id, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ER_BAD_INSTANCE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* the only function from Unset_option we need to Implement */
|
||||
|
||||
int Unset_option::do_command(struct st_net *net)
|
||||
{
|
||||
return correct_file(true);
|
||||
}
|
||||
|
||||
|
||||
/* Implementation for Stop_instance: */
|
||||
|
||||
Stop_instance::Stop_instance(Instance_map *instance_map_arg,
|
||||
const char *name, uint len)
|
||||
:Command(instance_map_arg)
|
||||
{
|
||||
/* we make a search here, since we don't want t store the name */
|
||||
/* 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;
|
||||
}
|
||||
|
@ -398,7 +862,7 @@ int Stop_instance::execute(struct st_net *net, ulong connection_id)
|
|||
stop_guard(instance);
|
||||
if ((err_code= instance->stop()))
|
||||
return err_code;
|
||||
net_send_ok(net, connection_id);
|
||||
net_send_ok(net, connection_id, NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "command.h"
|
||||
#include "instance.h"
|
||||
#include "parse.h"
|
||||
|
||||
/*
|
||||
Print all instances of this instance manager.
|
||||
|
@ -115,6 +116,45 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/*
|
||||
Print requested part of the log
|
||||
Grammar:
|
||||
SHOW <instance_name> log {ERROR | SLOW | GENERAL} size[, offset_from_end]
|
||||
*/
|
||||
|
||||
class Show_instance_log : public Command
|
||||
{
|
||||
public:
|
||||
|
||||
Show_instance_log(Instance_map *instance_map_arg, const char *name,
|
||||
uint len, Log_type log_type_arg, const char *size_arg,
|
||||
const char *offset_arg);
|
||||
int do_command(struct st_net *net, const char *instance_name);
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
Log_type log_type;
|
||||
const char *instance_name;
|
||||
uint size;
|
||||
uint offset;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Shows the list of the log files, used by an instance.
|
||||
Grammar: SHOW <instance_name> LOG FILES
|
||||
*/
|
||||
|
||||
class Show_instance_log_files : public Command
|
||||
{
|
||||
public:
|
||||
|
||||
Show_instance_log_files(Instance_map *instance_map_arg, const char *name, uint len);
|
||||
int do_command(struct st_net *net, const char *instance_name);
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
const char *instance_name;
|
||||
const char *option;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Syntax error command. This command is issued if parser reported a syntax error.
|
||||
We need it to distinguish the parse error and the situation when parser internal
|
||||
|
@ -128,4 +168,50 @@ public:
|
|||
int execute(struct st_net *net, ulong connection_id);
|
||||
};
|
||||
|
||||
/*
|
||||
Set an option for the instance.
|
||||
Grammar: SET instance_name.option=option_value
|
||||
*/
|
||||
|
||||
class Set_option : public Command
|
||||
{
|
||||
public:
|
||||
Set_option(Instance_map *instance_map_arg, const char *name, uint len,
|
||||
const char *option_arg, uint option_len,
|
||||
const char *option_value_arg, uint option_value_len);
|
||||
/*
|
||||
the following function is virtual to let Unset_option to use
|
||||
*/
|
||||
virtual int do_command(struct st_net *net);
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
protected:
|
||||
int correct_file(bool skip);
|
||||
public:
|
||||
const char *instance_name;
|
||||
uint instance_name_len;
|
||||
/* buffer for the option */
|
||||
enum { MAX_OPTION_LEN= 1024 };
|
||||
char option[MAX_OPTION_LEN];
|
||||
char option_value[MAX_OPTION_LEN];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Remove option of the instance from config file
|
||||
Grammar: UNSET instance_name.option
|
||||
*/
|
||||
|
||||
class Unset_option: public Set_option
|
||||
{
|
||||
public:
|
||||
Unset_option(Instance_map *instance_map_arg, const char *name, uint len,
|
||||
const char *option_arg, uint option_len,
|
||||
const char *option_value_arg, uint option_value_len):
|
||||
Set_option(instance_map_arg, name, len, option_arg, option_len,
|
||||
option_value_arg, option_value_len)
|
||||
{}
|
||||
int do_command(struct st_net *net);
|
||||
};
|
||||
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */
|
||||
|
|
|
@ -16,40 +16,85 @@
|
|||
|
||||
#include "factory.h"
|
||||
|
||||
|
||||
Show_instances *Command_factory::new_Show_instances()
|
||||
{
|
||||
return new Show_instances(&instance_map);
|
||||
}
|
||||
|
||||
|
||||
Flush_instances *Command_factory::new_Flush_instances()
|
||||
{
|
||||
return new Flush_instances(&instance_map);
|
||||
}
|
||||
|
||||
|
||||
Show_instance_status *Command_factory::
|
||||
new_Show_instance_status(const char *name, uint len)
|
||||
{
|
||||
return new Show_instance_status(&instance_map, name, len);
|
||||
}
|
||||
|
||||
|
||||
Show_instance_options *Command_factory::
|
||||
new_Show_instance_options(const char *name, uint len)
|
||||
{
|
||||
return new Show_instance_options(&instance_map, name, len);
|
||||
}
|
||||
|
||||
|
||||
Start_instance *Command_factory::
|
||||
new_Start_instance(const char *name, uint len)
|
||||
{
|
||||
return new Start_instance(&instance_map, name, len);
|
||||
}
|
||||
|
||||
|
||||
Stop_instance *Command_factory::new_Stop_instance(const char *name, uint len)
|
||||
{
|
||||
return new Stop_instance(&instance_map, name, len);
|
||||
}
|
||||
|
||||
|
||||
Syntax_error *Command_factory::new_Syntax_error()
|
||||
{
|
||||
return new Syntax_error();
|
||||
}
|
||||
|
||||
|
||||
Set_option *Command_factory::
|
||||
new_Set_option(const char* name, uint len,
|
||||
const char *option_arg, uint option_len,
|
||||
const char *option_value_arg, uint option_value_len)
|
||||
{
|
||||
return new Set_option(&instance_map, name, len, option_arg,
|
||||
option_len, option_value_arg, option_value_len);
|
||||
}
|
||||
|
||||
|
||||
Unset_option *Command_factory::
|
||||
new_Unset_option(const char* name, uint len,
|
||||
const char *option_arg, uint option_len,
|
||||
const char *option_value_arg, uint option_value_len)
|
||||
{
|
||||
return new Unset_option(&instance_map, name, len, option_arg,
|
||||
option_len, option_value_arg, option_value_len);
|
||||
}
|
||||
|
||||
|
||||
Show_instance_log *Command_factory::
|
||||
new_Show_instance_log(const char *name, uint len,
|
||||
Log_type log_type_arg,
|
||||
const char *size, const char *offset)
|
||||
{
|
||||
return new Show_instance_log(&instance_map, name, len,
|
||||
log_type_arg, size, offset);
|
||||
}
|
||||
|
||||
|
||||
Show_instance_log_files *Command_factory::
|
||||
new_Show_instance_log_files(const char *name, uint len)
|
||||
{
|
||||
return new Show_instance_log_files(&instance_map, name, len);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
Http_command_factory e.t.c. Also see comment in the instance_map.cc
|
||||
*/
|
||||
|
||||
class Show_instances;
|
||||
|
||||
class Command_factory
|
||||
{
|
||||
public:
|
||||
|
@ -33,12 +35,26 @@ public:
|
|||
{}
|
||||
|
||||
Show_instances *new_Show_instances ();
|
||||
Flush_instances *new_Flush_instances ();
|
||||
Syntax_error *new_Syntax_error ();
|
||||
Show_instance_status *new_Show_instance_status (const char *name, uint len);
|
||||
Show_instance_options *new_Show_instance_options (const char *name, uint len);
|
||||
Start_instance *new_Start_instance (const char *name, uint len);
|
||||
Stop_instance *new_Stop_instance (const char *name, uint len);
|
||||
Flush_instances *new_Flush_instances ();
|
||||
Syntax_error *new_Syntax_error ();
|
||||
Show_instance_log *new_Show_instance_log (const char *name, uint len,
|
||||
Log_type log_type_arg,
|
||||
const char *size,
|
||||
const char *offset);
|
||||
Set_option *new_Set_option (const char *name, uint len,
|
||||
const char *option_arg, uint option_len,
|
||||
const char *option_value_arg,
|
||||
uint option_value_len);
|
||||
Unset_option *new_Unset_option (const char *name, uint len,
|
||||
const char *option_arg, uint option_len,
|
||||
const char *option_value_arg,
|
||||
uint option_value_len);
|
||||
Show_instance_log_files *new_Show_instance_log_files (const char *name,
|
||||
uint len);
|
||||
|
||||
Instance_map &instance_map;
|
||||
};
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
#include "instance_options.h"
|
||||
|
||||
#include "parse_output.h"
|
||||
#include "parse.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include <my_sys.h>
|
||||
#include <mysql.h>
|
||||
#include <signal.h>
|
||||
#include <m_string.h>
|
||||
|
||||
|
@ -54,7 +54,7 @@ int Instance_options::get_default_option(char *result, size_t result_len,
|
|||
int rc= 1;
|
||||
char verbose_option[]= " --no-defaults --verbose --help";
|
||||
|
||||
Buffer cmd(strlen(mysqld_path)+sizeof(verbose_option)+1);
|
||||
Buffer cmd(strlen(mysqld_path) + sizeof(verbose_option) + 1);
|
||||
if (cmd.get_size()) /* malloc succeeded */
|
||||
{
|
||||
cmd.append(position, mysqld_path, strlen(mysqld_path));
|
||||
|
@ -76,6 +76,135 @@ err:
|
|||
}
|
||||
|
||||
|
||||
int Instance_options::fill_log_options()
|
||||
{
|
||||
/* array for the log option for mysqld */
|
||||
enum { MAX_LOG_OPTIONS= 8 };
|
||||
enum { MAX_LOG_OPTION_LENGTH= 256 };
|
||||
/* the last option must be '\0', so we reserve space for it */
|
||||
char log_options[MAX_LOG_OPTIONS + 1][MAX_LOG_OPTION_LENGTH];
|
||||
Buffer buff;
|
||||
uint position= 0;
|
||||
char **tmp_argv= argv;
|
||||
char datadir[MAX_LOG_OPTION_LENGTH];
|
||||
char hostname[MAX_LOG_OPTION_LENGTH];
|
||||
uint hostname_length;
|
||||
struct log_files_st
|
||||
{
|
||||
const char *name;
|
||||
uint length;
|
||||
const char **value;
|
||||
const char *default_suffix;
|
||||
} logs[]=
|
||||
{
|
||||
{"--log-error", 11, &error_log, ".err"},
|
||||
{"--log", 5, &query_log, ".log"},
|
||||
{"--log-slow-queries", 18, &slow_log, "-slow.log"},
|
||||
{NULL, 0, NULL, NULL}
|
||||
};
|
||||
struct log_files_st *log_files;
|
||||
|
||||
/* clean the buffer before usage */
|
||||
bzero(log_options, sizeof(log_options));
|
||||
|
||||
/* create a "mysqld <argv_options>" command in the buffer */
|
||||
buff.append(position, mysqld_path, strlen(mysqld_path));
|
||||
position= strlen(mysqld_path);
|
||||
|
||||
/* skip the first option */
|
||||
tmp_argv++;
|
||||
|
||||
while (*tmp_argv != 0)
|
||||
{
|
||||
buff.append(position, " ", 1);
|
||||
position++;
|
||||
buff.append(position, *tmp_argv, strlen(*tmp_argv));
|
||||
position+= strlen(*tmp_argv);
|
||||
tmp_argv++;
|
||||
}
|
||||
|
||||
buff.append(position, "\0", 1);
|
||||
position++;
|
||||
|
||||
/* get options and parse them */
|
||||
if (parse_arguments(buff.buffer, "--log", (char *) log_options,
|
||||
MAX_LOG_OPTIONS + 1, MAX_LOG_OPTION_LENGTH))
|
||||
goto err;
|
||||
/* compute hostname and datadir for the instance */
|
||||
if (mysqld_datadir == NULL)
|
||||
{
|
||||
if (get_default_option(datadir,
|
||||
MAX_LOG_OPTION_LENGTH, "--datadir"))
|
||||
goto err;
|
||||
}
|
||||
else /* below is safe, as --datadir always has a value */
|
||||
strncpy(datadir, strchr(mysqld_datadir, '=') + 1,
|
||||
MAX_LOG_OPTION_LENGTH);
|
||||
|
||||
if (gethostname(hostname,sizeof(hostname)-1) < 0)
|
||||
strmov(hostname, "mysql");
|
||||
|
||||
hostname[MAX_LOG_OPTION_LENGTH - 1]= 0; /* Safety */
|
||||
hostname_length= strlen(hostname);
|
||||
|
||||
|
||||
for (log_files= logs; log_files->name; log_files++)
|
||||
{
|
||||
for (int i=0; (i < MAX_LOG_OPTIONS) && (log_options[i][0] != '\0'); i++)
|
||||
{
|
||||
if (!strncmp(log_options[i], log_files->name, log_files->length))
|
||||
{
|
||||
/*
|
||||
This is really log_files->name option if and only if it is followed
|
||||
by '=', '\0' or space character. This way we can distinguish such
|
||||
options as '--log' and '--log-bin'. This is checked in the following
|
||||
two statements.
|
||||
*/
|
||||
if (log_options[i][log_files->length] == '\0' ||
|
||||
my_isspace(default_charset_info, log_options[i][log_files->length]))
|
||||
{
|
||||
char full_name[MAX_LOG_OPTION_LENGTH];
|
||||
|
||||
fn_format(full_name, hostname, datadir, "",
|
||||
MY_UNPACK_FILENAME | MY_SAFE_PATH);
|
||||
|
||||
|
||||
if ((MAX_LOG_OPTION_LENGTH - strlen(full_name)) >
|
||||
strlen(log_files->default_suffix))
|
||||
{
|
||||
strcpy(full_name + strlen(full_name),
|
||||
log_files->default_suffix);
|
||||
}
|
||||
else
|
||||
goto err;
|
||||
|
||||
*(log_files->value)= strdup_root(&alloc, datadir);
|
||||
}
|
||||
|
||||
if (log_options[i][log_files->length] == '=')
|
||||
{
|
||||
char full_name[MAX_LOG_OPTION_LENGTH];
|
||||
|
||||
fn_format(full_name, log_options[i] +log_files->length + 1,
|
||||
datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH);
|
||||
|
||||
if (!(*(log_files->value)=
|
||||
strdup_root(&alloc, full_name)))
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int Instance_options::get_pid_filename(char *result)
|
||||
{
|
||||
const char *pid_file= mysqld_pid_file;
|
||||
|
@ -190,6 +319,8 @@ int Instance_options::complete_initialization(const char *default_path,
|
|||
options_array.elements*sizeof(char*));
|
||||
argv[filled_default_options + options_array.elements]= 0;
|
||||
|
||||
fill_log_options();
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
|
|
@ -40,7 +40,8 @@ public:
|
|||
mysqld_socket(0), mysqld_datadir(0),
|
||||
mysqld_bind_address(0), mysqld_pid_file(0), mysqld_port(0),
|
||||
mysqld_port_val(0), mysqld_path(0), nonguarded(0), shutdown_delay(0),
|
||||
shutdown_delay_val(0), filled_default_options(0)
|
||||
shutdown_delay_val(0), error_log(0), query_log(0), slow_log(0),
|
||||
filled_default_options(0)
|
||||
{}
|
||||
~Instance_options();
|
||||
/* fills in argv */
|
||||
|
@ -76,9 +77,14 @@ public:
|
|||
const char *nonguarded;
|
||||
const char *shutdown_delay;
|
||||
uint shutdown_delay_val;
|
||||
const char *error_log;
|
||||
const char *query_log;
|
||||
const char *slow_log;
|
||||
|
||||
/* this value is computed and cashed here */
|
||||
DYNAMIC_ARRAY options_array;
|
||||
private:
|
||||
int fill_log_options();
|
||||
int add_to_argv(const char *option);
|
||||
int get_default_option(char *result, size_t result_len,
|
||||
const char *option_name);
|
||||
|
|
|
@ -57,6 +57,15 @@ static const char *mysqld_error_message(unsigned sql_errno)
|
|||
" or resources shortage";
|
||||
case ER_STOP_INSTANCE:
|
||||
return "Cannot stop instance";
|
||||
case ER_NO_SUCH_LOG:
|
||||
return "The instance has no such log enabled";
|
||||
case ER_OPEN_LOGFILE:
|
||||
return "Cannot open log file";
|
||||
case ER_GUESS_LOGFILE:
|
||||
return "Cannot guess the log filename. Try specifying full log name"
|
||||
"in the instance options";
|
||||
case ER_ACCESS_OPTION_FILE:
|
||||
return "Cannot open the option file to edit. Check permissions";
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
return 0;
|
||||
|
|
|
@ -284,7 +284,7 @@ int Mysql_connection_thread::check_connection()
|
|||
net_send_error(&net, ER_ACCESS_DENIED_ERROR);
|
||||
return 1;
|
||||
}
|
||||
net_send_ok(&net, connection_id);
|
||||
net_send_ok(&net, connection_id, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -332,7 +332,7 @@ int Mysql_connection_thread::dispatch_command(enum enum_server_command command,
|
|||
return 1;
|
||||
case COM_PING:
|
||||
log_info("query for connection %d received ping command", connection_id);
|
||||
net_send_ok(&net, connection_id);
|
||||
net_send_ok(&net, connection_id, NULL);
|
||||
break;
|
||||
case COM_QUERY:
|
||||
{
|
||||
|
|
|
@ -23,5 +23,9 @@
|
|||
#define ER_INSTANCE_ALREADY_STARTED 3002
|
||||
#define ER_CANNOT_START_INSTANCE 3003
|
||||
#define ER_STOP_INSTANCE 3004
|
||||
#define ER_NO_SUCH_LOG 3005
|
||||
#define ER_OPEN_LOGFILE 3006
|
||||
#define ER_GUESS_LOGFILE 3007
|
||||
#define ER_ACCESS_OPTION_FILE 3008
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */
|
||||
|
|
|
@ -15,38 +15,56 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "parse.h"
|
||||
#include "factory.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
enum Token
|
||||
{
|
||||
TOK_FLUSH = 0,
|
||||
TOK_ERROR= 0, /* Encodes the "ERROR" word, it doesn't indicate error. */
|
||||
TOK_FILES,
|
||||
TOK_FLUSH,
|
||||
TOK_GENERAL,
|
||||
TOK_INSTANCE,
|
||||
TOK_INSTANCES,
|
||||
TOK_LOG,
|
||||
TOK_OPTIONS,
|
||||
TOK_SET,
|
||||
TOK_SLOW,
|
||||
TOK_START,
|
||||
TOK_STATUS,
|
||||
TOK_STOP,
|
||||
TOK_SHOW,
|
||||
TOK_UNSET,
|
||||
TOK_NOT_FOUND, // must be after all tokens
|
||||
TOK_END
|
||||
};
|
||||
|
||||
|
||||
struct tokens_st
|
||||
{
|
||||
uint length;
|
||||
const char *tok_name;
|
||||
};
|
||||
|
||||
|
||||
static struct tokens_st tokens[]= {
|
||||
{5, "ERROR"},
|
||||
{5, "FILES"},
|
||||
{5, "FLUSH"},
|
||||
{7, "GENERAL"},
|
||||
{8, "INSTANCE"},
|
||||
{9, "INSTANCES"},
|
||||
{3, "LOG"},
|
||||
{7, "OPTIONS"},
|
||||
{3, "SET"},
|
||||
{4, "SLOW"},
|
||||
{5, "START"},
|
||||
{6, "STATUS"},
|
||||
{4, "STOP"},
|
||||
{4, "SHOW"}
|
||||
{4, "SHOW"},
|
||||
{5, "UNSET"}
|
||||
};
|
||||
|
||||
|
||||
|
@ -86,13 +104,6 @@ Token shift_token(const char **text, uint *word_len)
|
|||
}
|
||||
|
||||
|
||||
void print_token(const char *token, uint tok_len)
|
||||
{
|
||||
for (uint i= 0; i < tok_len; ++i)
|
||||
printf("%c", token[i]);
|
||||
}
|
||||
|
||||
|
||||
int get_text_id(const char **text, uint *word_len, const char **id)
|
||||
{
|
||||
get_word(text, word_len);
|
||||
|
@ -108,7 +119,15 @@ Command *parse_command(Command_factory *factory, 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;
|
||||
Command *command;
|
||||
const char *saved_text= text;
|
||||
bool skip= false;
|
||||
const char *tmp;
|
||||
|
||||
Token tok1= shift_token(&text, &word_len);
|
||||
|
||||
|
@ -143,6 +162,55 @@ Command *parse_command(Command_factory *factory, const char *text)
|
|||
|
||||
command= factory->new_Flush_instances();
|
||||
break;
|
||||
case TOK_UNSET:
|
||||
skip= true;
|
||||
case TOK_SET:
|
||||
|
||||
get_text_id(&text, &instance_name_len, &instance_name);
|
||||
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;
|
||||
}
|
||||
|
||||
/* should be empty */
|
||||
get_word(&text, &word_len);
|
||||
if (word_len)
|
||||
{
|
||||
goto syntax_error;
|
||||
}
|
||||
|
||||
if (skip)
|
||||
command= factory->new_Unset_option(instance_name, instance_name_len,
|
||||
option, option_len, option_value,
|
||||
option_value_len);
|
||||
else
|
||||
command= factory->new_Set_option(instance_name, instance_name_len,
|
||||
option, option_len, option_value,
|
||||
option_value_len);
|
||||
break;
|
||||
case TOK_SHOW:
|
||||
switch (shift_token(&text, &word_len)) {
|
||||
case TOK_INSTANCES:
|
||||
|
@ -157,6 +225,7 @@ Command *parse_command(Command_factory *factory, const char *text)
|
|||
case TOK_STATUS:
|
||||
get_text_id(&text, &instance_name_len, &instance_name);
|
||||
text+= instance_name_len;
|
||||
/* check that this is the end of the command */
|
||||
get_word(&text, &word_len);
|
||||
if (word_len)
|
||||
goto syntax_error;
|
||||
|
@ -172,7 +241,87 @@ Command *parse_command(Command_factory *factory, const char *text)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
goto syntax_error;
|
||||
instance_name= text - word_len;
|
||||
instance_name_len= word_len;
|
||||
if (instance_name_len)
|
||||
{
|
||||
Log_type log_type;
|
||||
switch (shift_token(&text, &word_len)) {
|
||||
case TOK_LOG:
|
||||
switch (Token tok3= shift_token(&text, &word_len)) {
|
||||
case TOK_FILES:
|
||||
get_word(&text, &word_len);
|
||||
/* check that this is the end of the command */
|
||||
if (word_len)
|
||||
goto syntax_error;
|
||||
command= (Command *)
|
||||
factory->new_Show_instance_log_files(instance_name,
|
||||
instance_name_len);
|
||||
break;
|
||||
case TOK_ERROR:
|
||||
case TOK_GENERAL:
|
||||
case TOK_SLOW:
|
||||
/* define a log type */
|
||||
switch (tok3) {
|
||||
case TOK_ERROR:
|
||||
log_type= LOG_ERROR;
|
||||
break;
|
||||
case TOK_GENERAL:
|
||||
log_type= LOG_GENERAL;
|
||||
break;
|
||||
case TOK_SLOW:
|
||||
log_type= LOG_SLOW;
|
||||
break;
|
||||
default:
|
||||
goto syntax_error;
|
||||
}
|
||||
/* get the size of the log we want to retrieve */
|
||||
get_text_id(&text, &word_len, &log_size);
|
||||
text+= word_len;
|
||||
/* this parameter is required */
|
||||
if (!word_len)
|
||||
goto syntax_error;
|
||||
/* the next token should be comma, or nothing */
|
||||
get_word(&text, &word_len);
|
||||
switch (*text) {
|
||||
case ',':
|
||||
text++; /* swallow the comma */
|
||||
/* read the next word */
|
||||
get_word(&text, &word_len);
|
||||
if (!word_len)
|
||||
goto syntax_error;
|
||||
command= (Command *)
|
||||
factory->new_Show_instance_log(instance_name,
|
||||
instance_name_len,
|
||||
log_type,
|
||||
log_size,
|
||||
text);
|
||||
|
||||
//get_text_id(&text, &log_size_len, &log_size);
|
||||
break;
|
||||
case '\0':
|
||||
command= (Command *)
|
||||
factory->new_Show_instance_log(instance_name,
|
||||
instance_name_len,
|
||||
log_type,
|
||||
log_size,
|
||||
NULL);
|
||||
break; /* this is ok */
|
||||
default:
|
||||
goto syntax_error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto syntax_error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto syntax_error;
|
||||
}
|
||||
}
|
||||
else
|
||||
goto syntax_error;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -182,3 +331,43 @@ syntax_error:
|
|||
return command;
|
||||
}
|
||||
|
||||
/* additional parse function, needed to parse */
|
||||
|
||||
/* create an array of strings from the output, starting from "word" */
|
||||
int parse_arguments(const char *command, const char *word, char *result,
|
||||
int max_result_cardinality, size_t option_len)
|
||||
{
|
||||
int wordlen;
|
||||
int i= 0; /* result array index */
|
||||
/* should be enough to store the string from the output */
|
||||
enum { MAX_LINE_LEN= 4096 };
|
||||
char linebuf[MAX_LINE_LEN];
|
||||
|
||||
wordlen= strlen(word);
|
||||
|
||||
uint lineword_len= 0;
|
||||
const char *linep= command;
|
||||
get_word((const char **) &linep, &lineword_len, NONSPACE);
|
||||
while ((*linep != '\0') && (i < max_result_cardinality))
|
||||
{
|
||||
if (!strncmp(word, linep, wordlen))
|
||||
{
|
||||
strncpy(result + i*option_len, linep, lineword_len);
|
||||
*(result + i*option_len + lineword_len)= '\0';
|
||||
linep+= lineword_len;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
linep+= lineword_len;
|
||||
get_word((const char **) &linep, &lineword_len, NONSPACE);
|
||||
|
||||
/* stop if we've filled the array */
|
||||
if (i >= max_result_cardinality)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,10 +16,24 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "factory.h"
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
class Command;
|
||||
class Command_factory;
|
||||
|
||||
enum Log_type
|
||||
{
|
||||
LOG_ERROR= 0,
|
||||
LOG_GENERAL,
|
||||
LOG_SLOW
|
||||
};
|
||||
|
||||
Command *parse_command(Command_factory *factory, const char *text);
|
||||
|
||||
int parse_arguments(const char *command, const char *word, char *result,
|
||||
int max_result_cardinality, size_t option_len);
|
||||
|
||||
/* define kinds of the word seek method */
|
||||
enum { ALPHANUM= 1, NONSPACE };
|
||||
|
||||
|
@ -44,10 +58,12 @@ inline void get_word(const char **text, uint *word_len,
|
|||
while (my_isalnum(default_charset_info, *word_end))
|
||||
++word_end;
|
||||
else
|
||||
while (!my_isspace(default_charset_info, *word_end))
|
||||
while (!my_isspace(default_charset_info, *word_end) &&
|
||||
(*word_end != '\0'))
|
||||
++word_end;
|
||||
|
||||
*word_len= word_end - *text;
|
||||
}
|
||||
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */
|
||||
|
|
|
@ -47,7 +47,7 @@ int parse_output_and_get_value(const char *command, const char *word,
|
|||
{
|
||||
FILE *output;
|
||||
uint wordlen;
|
||||
/* should be enought to store the string from the output */
|
||||
/* should be enough to store the string from the output */
|
||||
enum { MAX_LINE_LEN= 512 };
|
||||
char linebuf[MAX_LINE_LEN];
|
||||
|
||||
|
@ -99,3 +99,4 @@ pclose:
|
|||
err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H
|
||||
#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H
|
||||
/* Copyright (C) 2004 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -17,3 +19,4 @@
|
|||
int parse_output_and_get_value(const char *command, const char *word,
|
||||
char *result, size_t result_len);
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H */
|
||||
|
|
|
@ -24,15 +24,25 @@
|
|||
|
||||
static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */
|
||||
|
||||
int net_send_ok(struct st_net *net, unsigned long connection_id)
|
||||
{
|
||||
char buff[1 + // packet type code
|
||||
9 + // affected rows count
|
||||
9 + // connection id
|
||||
2 + // thread return status
|
||||
2]; // warning count
|
||||
|
||||
char *pos= buff;
|
||||
int net_send_ok(struct st_net *net, unsigned long connection_id,
|
||||
const char *message)
|
||||
{
|
||||
/*
|
||||
The format of a packet
|
||||
1 packet type code
|
||||
1-9 affected rows count
|
||||
1-9 connection id
|
||||
2 thread return status
|
||||
2 warning count
|
||||
1-9 + message length message to send (isn't stored if no message)
|
||||
*/
|
||||
Buffer buff;
|
||||
char *pos= buff.buffer;
|
||||
|
||||
/* check that we have space to hold mandatory fields */
|
||||
buff.reserve(0, 23);
|
||||
|
||||
enum { OK_PACKET_CODE= 0 };
|
||||
*pos++= OK_PACKET_CODE;
|
||||
pos= net_store_length(pos, (ulonglong) 0);
|
||||
|
@ -43,7 +53,15 @@ int net_send_ok(struct st_net *net, unsigned long connection_id)
|
|||
int2store(pos, 0);
|
||||
pos+= 2;
|
||||
|
||||
return my_net_write(net, buff, pos - buff) || net_flush(net);
|
||||
uint position= pos - buff.buffer; /* we might need it for message */
|
||||
|
||||
if (message != NULL)
|
||||
{
|
||||
buff.reserve(position, 9 + strlen(message));
|
||||
store_to_string(&buff, message, &position);
|
||||
}
|
||||
|
||||
return my_net_write(net, buff.buffer, position) || net_flush(net);
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,15 +117,15 @@ char *net_store_length(char *pkg, uint length)
|
|||
}
|
||||
|
||||
|
||||
int store_to_string(Buffer *buf, const char *string, uint *position)
|
||||
int store_to_string(Buffer *buf, const char *string, uint *position,
|
||||
uint string_len)
|
||||
{
|
||||
uint currpos;
|
||||
uint string_len;
|
||||
|
||||
string_len= strlen(string);
|
||||
if (buf->reserve(*position, 2))
|
||||
if (buf->reserve(*position, 9))
|
||||
goto err;
|
||||
currpos= (net_store_length(buf->buffer + *position, string_len) - buf->buffer);
|
||||
currpos= (net_store_length(buf->buffer + *position,
|
||||
(ulonglong) string_len) - buf->buffer);
|
||||
if (buf->append(currpos, string, string_len))
|
||||
goto err;
|
||||
*position= *position + string_len + (currpos - *position);
|
||||
|
@ -118,6 +136,15 @@ err:
|
|||
}
|
||||
|
||||
|
||||
int store_to_string(Buffer *buf, const char *string, uint *position)
|
||||
{
|
||||
uint string_len;
|
||||
|
||||
string_len= strlen(string);
|
||||
return store_to_string(buf, string, position, string_len);
|
||||
}
|
||||
|
||||
|
||||
int send_eof(struct st_net *net)
|
||||
{
|
||||
char buff[1 + /* eof packet code */
|
||||
|
|
|
@ -27,7 +27,8 @@ typedef struct field {
|
|||
|
||||
struct st_net;
|
||||
|
||||
int net_send_ok(struct st_net *net, unsigned long connection_id);
|
||||
int net_send_ok(struct st_net *net, unsigned long connection_id,
|
||||
const char *message);
|
||||
|
||||
int net_send_error(struct st_net *net, unsigned sql_errno);
|
||||
|
||||
|
@ -39,6 +40,9 @@ char *net_store_length(char *pkg, uint length);
|
|||
|
||||
int store_to_string(Buffer *buf, const char *string, uint *position);
|
||||
|
||||
int store_to_string(Buffer *buf, const char *string, uint *position,
|
||||
uint string_len);
|
||||
|
||||
int send_eof(struct st_net *net);
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H */
|
||||
|
|
Loading…
Reference in a new issue