Commit adfe2c3a authored by unknown's avatar unknown

merge


sql/item.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/mysqld.cc:
  Auto merged
sql/protocol.cc:
  Auto merged
parents 55cb8679 5f64e3e8
...@@ -1719,9 +1719,16 @@ The field description result set contains the meta info for a result set. ...@@ -1719,9 +1719,16 @@ The field description result set contains the meta info for a result set.
@item string @tab Table name alias (or table name if no alias) @item string @tab Table name alias (or table name if no alias)
@item string @tab Real table name @item string @tab Real table name
@item string @tab Alias for column name (or column name if not used) @item string @tab Alias for column name (or column name if not used)
@item 11 byte @tab Fixed length fields in one field part:
@itemize
@item 2 byte int @tab Character set number
@item 3 byte int @tab Length of column definition @item 3 byte int @tab Length of column definition
@item 1 byte int @tab Enum value for field type @item 1 byte int @tab Enum value for field type
@item 3 byte int @tab 2 byte column flags (NOT_NULL_FLAG etc..) + 1 byte number of decimals. @item 3 byte int @tab 2 byte column flags (NOT_NULL_FLAG etc..) + 1 byte number of decimals.
@item 2 byte int @tab zero (reserved for future use)
@end itemize
@item string int @tab Default value, only set when using mysql_list_fields(). @item string int @tab Default value, only set when using mysql_list_fields().
@end multitable @end multitable
......
...@@ -84,6 +84,7 @@ typedef struct st_mysql_field { ...@@ -84,6 +84,7 @@ typedef struct st_mysql_field {
unsigned long max_length; /* Max width of selected set */ unsigned long max_length; /* Max width of selected set */
unsigned int flags; /* Div flags */ unsigned int flags; /* Div flags */
unsigned int decimals; /* Number of decimals in field */ unsigned int decimals; /* Number of decimals in field */
unsigned int charsetnr; /* Character set */
enum enum_field_types type; /* Type of field. Se mysql_com.h for types */ enum enum_field_types type; /* Type of field. Se mysql_com.h for types */
} MYSQL_FIELD; } MYSQL_FIELD;
......
...@@ -1150,25 +1150,29 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, ...@@ -1150,25 +1150,29 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
free_rows(data); /* Free old data */ free_rows(data); /* Free old data */
DBUG_RETURN(0); DBUG_RETURN(0);
} }
bzero((char*) field, (uint) sizeof(MYSQL_FIELD)*fields);
if (server_capabilities & CLIENT_PROTOCOL_41) if (server_capabilities & CLIENT_PROTOCOL_41)
{ {
/* server is 4.1, and returns the new field result format */ /* server is 4.1, and returns the new field result format */
for (row=data->data; row ; row = row->next,field++) for (row=data->data; row ; row = row->next,field++)
{ {
uchar *pos;
field->db = strdup_root(alloc,(char*) row->data[0]); field->db = strdup_root(alloc,(char*) row->data[0]);
field->table = strdup_root(alloc,(char*) row->data[1]); field->table = strdup_root(alloc,(char*) row->data[1]);
field->org_table= strdup_root(alloc,(char*) row->data[2]); field->org_table= strdup_root(alloc,(char*) row->data[2]);
field->name = strdup_root(alloc,(char*) row->data[3]); field->name = strdup_root(alloc,(char*) row->data[3]);
field->org_name = strdup_root(alloc,(char*) row->data[4]); field->org_name = strdup_root(alloc,(char*) row->data[4]);
field->length = (uint) uint3korr(row->data[5]); /* Unpack fixed length parts */
field->type = (enum enum_field_types) (uchar) row->data[6][0]; pos= (uchar*) row->data[5];
field->charsetnr= uint2korr(pos);
field->flags= uint2korr(row->data[7]); field->length= (uint) uint3korr(pos+2);
field->decimals=(uint) (uchar) row->data[7][2]; field->type= (enum enum_field_types) pos[5];
field->flags= uint2korr(pos+6);
field->decimals= (uint) pos[8];
if (INTERNAL_NUM_FIELD(field)) if (INTERNAL_NUM_FIELD(field))
field->flags|= NUM_FLAG; field->flags|= NUM_FLAG;
if (default_value && row->data[8]) if (default_value && row->data[6])
field->def=strdup_root(alloc,(char*) row->data[8]); field->def=strdup_root(alloc,(char*) row->data[8]);
else else
field->def=0; field->def=0;
...@@ -2841,7 +2845,7 @@ my_bool STDCALL mysql_read_query_result(MYSQL *mysql) ...@@ -2841,7 +2845,7 @@ my_bool STDCALL mysql_read_query_result(MYSQL *mysql)
mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */ mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
if (!(fields=read_rows(mysql,(MYSQL_FIELD*)0, (protocol_41(mysql) ? 8 : 5)))) if (!(fields=read_rows(mysql,(MYSQL_FIELD*)0, 5)))
DBUG_RETURN(1); DBUG_RETURN(1);
if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
(uint) field_count,0, (uint) field_count,0,
...@@ -3212,8 +3216,7 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild) ...@@ -3212,8 +3216,7 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128); end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
if (simple_command(mysql,COM_FIELD_LIST,buff,(ulong) (end-buff),1) || if (simple_command(mysql,COM_FIELD_LIST,buff,(ulong) (end-buff),1) ||
!(query = read_rows(mysql,(MYSQL_FIELD*) 0, !(query = read_rows(mysql,(MYSQL_FIELD*) 0, 6)))
(protocol_41(mysql) ? 9 : 6))))
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
free_old_query(mysql); free_old_query(mysql);
...@@ -3250,7 +3253,7 @@ mysql_list_processes(MYSQL *mysql) ...@@ -3250,7 +3253,7 @@ mysql_list_processes(MYSQL *mysql)
free_old_query(mysql); free_old_query(mysql);
pos=(uchar*) mysql->net.read_pos; pos=(uchar*) mysql->net.read_pos;
field_count=(uint) net_field_length(&pos); field_count=(uint) net_field_length(&pos);
if (!(fields = read_rows(mysql,(MYSQL_FIELD*)0,protocol_41(mysql) ? 8: 5))) if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0, 5)))
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0, if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
mysql->server_capabilities))) mysql->server_capabilities)))
......
...@@ -223,6 +223,7 @@ void Field_num::make_field(Send_field *field) ...@@ -223,6 +223,7 @@ void Field_num::make_field(Send_field *field)
field->org_table_name=table->real_name; field->org_table_name=table->real_name;
field->table_name=table_name; field->table_name=table_name;
field->col_name=field->org_col_name=field_name; field->col_name=field->org_col_name=field_name;
field->charsetnr= charset()->number;
field->length=field_length; field->length=field_length;
field->type=type(); field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags; field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
...@@ -237,6 +238,7 @@ void Field_str::make_field(Send_field *field) ...@@ -237,6 +238,7 @@ void Field_str::make_field(Send_field *field)
field->org_table_name=table->real_name; field->org_table_name=table->real_name;
field->table_name=table_name; field->table_name=table_name;
field->col_name=field->org_col_name=field_name; field->col_name=field->org_col_name=field_name;
field->charsetnr= charset()->number;
field->length=field_length; field->length=field_length;
field->type=type(); field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags; field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
......
...@@ -1056,7 +1056,8 @@ class Send_field { ...@@ -1056,7 +1056,8 @@ class Send_field {
const char *db_name; const char *db_name;
const char *table_name,*org_table_name; const char *table_name,*org_table_name;
const char *col_name,*org_col_name; const char *col_name,*org_col_name;
uint length,flags,decimals; ulong length;
uint charsetnr, flags, decimals;
enum_field_types type; enum_field_types type;
Send_field() {} Send_field() {}
}; };
......
...@@ -721,11 +721,13 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -721,11 +721,13 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
void Item::init_make_field(Send_field *tmp_field, void Item::init_make_field(Send_field *tmp_field,
enum enum_field_types field_type) enum enum_field_types field_type)
{ {
tmp_field->db_name=(char*) ""; char *empty_name= (char*) "";
tmp_field->org_table_name=(char*) ""; tmp_field->db_name= empty_name;
tmp_field->org_col_name=(char*) ""; tmp_field->org_table_name= empty_name;
tmp_field->table_name=(char*) ""; tmp_field->org_col_name= empty_name;
tmp_field->col_name=name; tmp_field->table_name= empty_name;
tmp_field->col_name= name;
tmp_field->charsetnr= charset()->number;
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG; tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
tmp_field->type=field_type; tmp_field->type=field_type;
tmp_field->length=max_length; tmp_field->length=max_length;
......
...@@ -662,8 +662,6 @@ bool open_log(MYSQL_LOG *log, const char *hostname, ...@@ -662,8 +662,6 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
const char *index_file_name, const char *index_file_name,
enum_log_type type, bool read_append = 0, enum_log_type type, bool read_append = 0,
bool no_auto_events = 0); bool no_auto_events = 0);
/* mysqld.cc */
void clear_error_message(THD *thd);
/* /*
External variables External variables
......
...@@ -1736,17 +1736,6 @@ extern "C" int my_message_sql(uint error, const char *str, ...@@ -1736,17 +1736,6 @@ extern "C" int my_message_sql(uint error, const char *str,
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/*
Forget last error message (if we got one)
*/
void clear_error_message(THD *thd)
{
thd->clear_error();
}
#ifdef __WIN__ #ifdef __WIN__
struct utsname struct utsname
......
...@@ -132,6 +132,7 @@ void net_send_error(NET *net, uint sql_errno, const char *err) ...@@ -132,6 +132,7 @@ void net_send_error(NET *net, uint sql_errno, const char *err)
} }
#endif #endif
/* /*
Send a warning to the end user Send a warning to the end user
...@@ -284,8 +285,8 @@ void my_net_local_init(NET *net __attribute__(unused)) ...@@ -284,8 +285,8 @@ void my_net_local_init(NET *net __attribute__(unused))
If net->no_send_ok return without sending packet If net->no_send_ok return without sending packet
*/ */
#ifndef EMBEDDED_LIBRARY
#ifndef EMBEDDED_LIBRARY
void void
send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
{ {
...@@ -375,7 +376,6 @@ send_eof(THD *thd, bool no_flush) ...@@ -375,7 +376,6 @@ send_eof(THD *thd, bool no_flush)
/**************************************************************************** /****************************************************************************
Store a field length in logical packet Store a field length in logical packet
This is used to code the string length for normal protocol This is used to code the string length for normal protocol
****************************************************************************/ ****************************************************************************/
...@@ -457,9 +457,6 @@ char *net_store_data(char *to,longlong from) ...@@ -457,9 +457,6 @@ char *net_store_data(char *to,longlong from)
return to+length; return to+length;
} }
/*
Function called by my_net_init() to set some check variables
*/
/***************************************************************************** /*****************************************************************************
Default Protocol functions Default Protocol functions
...@@ -475,6 +472,7 @@ void Protocol::init(THD *thd_arg) ...@@ -475,6 +472,7 @@ void Protocol::init(THD *thd_arg)
#endif #endif
} }
/* /*
Send name and type of result to client. Send name and type of result to client.
...@@ -534,35 +532,55 @@ bool Protocol::send_fields(List<Item> *list, uint flag) ...@@ -534,35 +532,55 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
prot.store(field.org_table_name, prot.store(field.org_table_name,
(uint) strlen(field.org_table_name)) || (uint) strlen(field.org_table_name)) ||
prot.store(field.col_name, (uint) strlen(field.col_name)) || prot.store(field.col_name, (uint) strlen(field.col_name)) ||
prot.store(field.org_col_name, (uint) strlen(field.org_col_name))) prot.store(field.org_col_name, (uint) strlen(field.org_col_name)) ||
packet->realloc(packet->length()+12))
goto err; goto err;
/* Store fixed length fields */
pos= (char*) packet->ptr()+packet->length();
*pos++= 11; // Length of packed fields
int2store(pos, field.charsetnr);
int3store(pos+2, field.length);
pos[5]= field.type;
int2store(pos+6,field.flags);
pos[8]= (char) field.decimals;
pos[9]= 0; // For the future
pos[10]= 0; // For the future
pos+= 11;
} }
else else
{ {
if (prot.store(field.table_name, (uint) strlen(field.table_name)) || if (prot.store(field.table_name, (uint) strlen(field.table_name)) ||
prot.store(field.col_name, (uint) strlen(field.col_name))) prot.store(field.col_name, (uint) strlen(field.col_name)) ||
packet->realloc(packet->length()+10))
goto err; goto err;
} pos= (char*) packet->ptr()+packet->length();
if (packet->realloc(packet->length()+10))
goto err;
pos= (char*) packet->ptr()+packet->length();
#ifdef TO_BE_DELETED_IN_6 #ifdef TO_BE_DELETED_IN_6
if (!(thd->client_capabilities & CLIENT_LONG_FLAG)) if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
{ {
packet->length(packet->length()+9); pos[0]=3;
pos[0]=3; int3store(pos+1,field.length); int3store(pos+1,field.length);
pos[4]=1; pos[5]=field.type; pos[4]=1;
pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals; pos[5]=field.type;
} pos[6]=2;
else pos[7]= (char) field.flags;
pos[8]= (char) field.decimals;
pos+= 9;
}
else
#endif #endif
{ {
packet->length(packet->length()+10); pos[0]=3;
pos[0]=3; int3store(pos+1,field.length); int3store(pos+1,field.length);
pos[4]=1; pos[5]=field.type; pos[4]=1;
pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals; pos[5]=field.type;
pos[6]=3;
int2store(pos+7,field.flags);
pos[9]= (char) field.decimals;
pos+= 10;
}
} }
packet->length((uint) (pos - packet->ptr()));
if (flag & 2) if (flag & 2)
item->send(&prot, &tmp); // Send default value item->send(&prot, &tmp); // Send default value
if (prot.write()) if (prot.write())
...@@ -580,6 +598,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag) ...@@ -580,6 +598,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
} }
bool Protocol::send_records_num(List<Item> *list, ulonglong records) bool Protocol::send_records_num(List<Item> *list, ulonglong records)
{ {
char *pos; char *pos;
...@@ -589,13 +608,12 @@ bool Protocol::send_records_num(List<Item> *list, ulonglong records) ...@@ -589,13 +608,12 @@ bool Protocol::send_records_num(List<Item> *list, ulonglong records)
return my_net_write(&thd->net, buff,(uint) (pos-buff)); return my_net_write(&thd->net, buff,(uint) (pos-buff));
} }
bool Protocol::write() bool Protocol::write()
{ {
DBUG_ENTER("Protocol::write"); DBUG_ENTER("Protocol::write");
DBUG_RETURN(my_net_write(&thd->net, packet->ptr(), packet->length())); DBUG_RETURN(my_net_write(&thd->net, packet->ptr(), packet->length()));
} }
#endif /* EMBEDDED_LIBRARY */ #endif /* EMBEDDED_LIBRARY */
...@@ -653,7 +671,6 @@ bool Protocol::store(I_List<i_string>* str_list) ...@@ -653,7 +671,6 @@ bool Protocol::store(I_List<i_string>* str_list)
and client when you are not using prepared statements. and client when you are not using prepared statements.
All data are sent as 'packed-string-length' followed by 'string-data' All data are sent as 'packed-string-length' followed by 'string-data'
****************************************************************************/ ****************************************************************************/
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
...@@ -676,6 +693,7 @@ bool Protocol_simple::store_null() ...@@ -676,6 +693,7 @@ bool Protocol_simple::store_null()
} }
#endif #endif
bool Protocol_simple::store(const char *from, uint length) bool Protocol_simple::store(const char *from, uint length)
{ {
#ifndef DEBUG_OFF #ifndef DEBUG_OFF
...@@ -701,6 +719,7 @@ bool Protocol_simple::store_tiny(longlong from) ...@@ -701,6 +719,7 @@ bool Protocol_simple::store_tiny(longlong from)
(uint) (int10_to_str((int) from,buff, -10)-buff)); (uint) (int10_to_str((int) from,buff, -10)-buff));
} }
bool Protocol_simple::store_short(longlong from) bool Protocol_simple::store_short(longlong from)
{ {
#ifndef DEBUG_OFF #ifndef DEBUG_OFF
...@@ -712,6 +731,7 @@ bool Protocol_simple::store_short(longlong from) ...@@ -712,6 +731,7 @@ bool Protocol_simple::store_short(longlong from)
(uint) (int10_to_str((int) from,buff, -10)-buff)); (uint) (int10_to_str((int) from,buff, -10)-buff));
} }
bool Protocol_simple::store_long(longlong from) bool Protocol_simple::store_long(longlong from)
{ {
#ifndef DEBUG_OFF #ifndef DEBUG_OFF
...@@ -747,6 +767,7 @@ bool Protocol_simple::store(float from, uint32 decimals, String *buffer) ...@@ -747,6 +767,7 @@ bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
return net_store_data((char*) buffer->ptr(), buffer->length()); return net_store_data((char*) buffer->ptr(), buffer->length());
} }
bool Protocol_simple::store(double from, uint32 decimals, String *buffer) bool Protocol_simple::store(double from, uint32 decimals, String *buffer)
{ {
#ifndef DEBUG_OFF #ifndef DEBUG_OFF
...@@ -833,17 +854,18 @@ bool Protocol_simple::store_time(TIME *tm) ...@@ -833,17 +854,18 @@ bool Protocol_simple::store_time(TIME *tm)
Data format: Data format:
[ok:1] <-- reserved ok packet [ok:1] reserved ok packet
[null_field:(field_count+7+2)/8] <-- reserved to send null data. The size is [null_field:(field_count+7+2)/8] reserved to send null data. The size is
calculated using: calculated using:
bit_fields= (field_count+7+2)/8; bit_fields= (field_count+7+2)/8;
2 bits are reserved 2 bits are reserved for identifying type
[[length]data] <-- data field (the length applies only for of package.
string/binary/time/timestamp fields and [[length]data] data field (the length applies only for
rest of them are not sent as they have string/binary/time/timestamp fields and
the default length that client understands rest of them are not sent as they have
based on the field type the default length that client understands
[..]..[[length]data] <-- data based on the field type
[..]..[[length]data] data
****************************************************************************/ ****************************************************************************/
bool Protocol_prep::prepare_for_send(List<Item> *item_list) bool Protocol_prep::prepare_for_send(List<Item> *item_list)
...@@ -983,7 +1005,7 @@ bool Protocol_prep::store(double from, uint32 decimals, String *buffer) ...@@ -983,7 +1005,7 @@ bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
bool Protocol_prep::store(Field *field) bool Protocol_prep::store(Field *field)
{ {
/* /*
We should not count up field_pos here as send_binary() will call another We should not increment field_pos here as send_binary() will call another
protocol function to do this for us protocol function to do this for us
*/ */
if (field->is_null()) if (field->is_null())
...@@ -1057,10 +1079,3 @@ bool Protocol_prep::store_time(TIME *tm) ...@@ -1057,10 +1079,3 @@ bool Protocol_prep::store_time(TIME *tm)
buff[0]=(char) length; // Length is stored first buff[0]=(char) length; // Length is stored first
return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC); return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC);
} }
#if 0
bool Protocol_prep::send_fields(List<Item> *list, uint flag)
{
return prepare_for_send(list);
};
#endif
...@@ -1069,7 +1069,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1069,7 +1069,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_CHANGE_USER: case COM_CHANGE_USER:
{ {
thd->change_user(); thd->change_user();
clear_error_message(thd); // If errors from rollback thd->clear_error(); // If errors from rollback
statistic_increment(com_other,&LOCK_status); statistic_increment(com_other,&LOCK_status);
char *user= (char*) packet; char *user= (char*) packet;
...@@ -1210,7 +1210,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1210,7 +1210,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_PRINT("query",("%-.4096s",thd->query)); DBUG_PRINT("query",("%-.4096s",thd->query));
mysql_parse(thd,thd->query, thd->query_length); mysql_parse(thd,thd->query, thd->query_length);
while (!thd->is_fatal_error && thd->lex.found_colon) while (!thd->killed && !thd->fatal_error && thd->lex.found_colon)
{ {
char *packet= thd->lex.found_colon; char *packet= thd->lex.found_colon;
/* /*
...@@ -1229,7 +1229,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1229,7 +1229,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
} }
thd->query_length= length; thd->query_length= length;
thd->query= packet; thd->query= packet;
thd->net.last_error[0]= '\0';
VOID(pthread_mutex_lock(&LOCK_thread_count)); VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id= query_id++; thd->query_id= query_id++;
VOID(pthread_mutex_unlock(&LOCK_thread_count)); VOID(pthread_mutex_unlock(&LOCK_thread_count));
...@@ -3263,8 +3262,7 @@ mysql_parse(THD *thd, char *inBuf, uint length) ...@@ -3263,8 +3262,7 @@ mysql_parse(THD *thd, char *inBuf, uint length)
DBUG_ENTER("mysql_parse"); DBUG_ENTER("mysql_parse");
mysql_init_query(thd); mysql_init_query(thd);
thd->query_length = length; thd->clear_error();
thd->net.report_error= 0;
if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment