Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
cd5ff630
Commit
cd5ff630
authored
Oct 16, 2002
by
Sinisa@sinisa.nasamreza.org
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
some fixes for SELECT INTO @vars ..
parent
51e98da2
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
118 additions
and
105 deletions
+118
-105
sql/sql_class.cc
sql/sql_class.cc
+24
-14
sql/sql_class.h
sql/sql_class.h
+5
-15
sql/sql_lex.h
sql/sql_lex.h
+1
-1
sql/sql_parse.cc
sql/sql_parse.cc
+12
-39
sql/sql_yacc.yy
sql/sql_yacc.yy
+76
-36
No files found.
sql/sql_class.cc
View file @
cd5ff630
...
@@ -916,31 +916,41 @@ bool select_exists_subselect::send_data(List<Item> &items)
...
@@ -916,31 +916,41 @@ bool select_exists_subselect::send_data(List<Item> &items)
/***************************************************************************
/***************************************************************************
** Dump of select to variables
** Dump of select to variables
***************************************************************************/
***************************************************************************/
int
select_dumpvar
::
prepare
(
List
<
Item
>
&
list
,
SELECT_LEX_UNIT
*
u
)
bool
select_dumpvar
::
send_data
(
List
<
Item
>
&
items
)
{
{
List_iterator_fast
<
Item
>
li
(
items
);
List_iterator_fast
<
Item
>
li
(
list
);
List_iterator_fast
<
LEX_STRING
>
gl
(
current_thd
->
lex
.
select_into_
var_list
);
List_iterator_fast
<
LEX_STRING
>
gl
(
var_list
);
Item
*
item
;
Item
*
item
;
LEX_STRING
*
ls
;
LEX_STRING
*
ls
;
DBUG_ENTER
(
"send_data"
);
if
(
var_list
.
elements
!=
list
.
elements
)
if
(
row_count
++
>
1
)
{
{
my_error
(
ER_
TOO_MANY_ROWS
,
MYF
(
0
));
my_error
(
ER_
WRONG_NUMBER_OF_COLUMNS_IN_SELECT
,
MYF
(
0
));
goto
err
;
return
1
;
}
}
while
((
item
=
li
++
)
&&
(
ls
=
gl
++
)
)
while
((
item
=
li
++
))
{
{
ls
=
gl
++
;
Item_func_set_user_var
*
xx
=
new
Item_func_set_user_var
(
*
ls
,
item
);
Item_func_set_user_var
*
xx
=
new
Item_func_set_user_var
(
*
ls
,
item
);
xx
->
fix_fields
(
current_thd
,(
TABLE_LIST
*
)
current_thd
->
lex
.
select_lex
.
table_list
.
first
,
&
item
);
xx
->
fix_fields
(
current_thd
,(
TABLE_LIST
*
)
current_thd
->
lex
.
select_lex
.
table_list
.
first
,
&
item
);
xx
->
fix_length_and_dec
();
xx
->
fix_length_and_dec
();
xx
->
update
(
);
vars
.
push_back
(
xx
);
}
}
return
0
;
}
bool
select_dumpvar
::
send_data
(
List
<
Item
>
&
items
)
{
List_iterator_fast
<
Item_func_set_user_var
>
li
(
vars
);
Item_func_set_user_var
*
xx
;
DBUG_ENTER
(
"send_data"
);
if
(
row_count
++
)
{
my_error
(
ER_TOO_MANY_ROWS
,
MYF
(
0
));
DBUG_RETURN
(
1
);
}
while
((
xx
=
li
++
))
xx
->
update
();
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
err:
DBUG_RETURN
(
1
);
}
}
bool
select_dumpvar
::
send_eof
()
bool
select_dumpvar
::
send_eof
()
...
...
sql/sql_class.h
View file @
cd5ff630
...
@@ -969,22 +969,12 @@ public:
...
@@ -969,22 +969,12 @@ public:
class
select_dumpvar
:
public
select_result
{
class
select_dumpvar
:
public
select_result
{
ha_rows
row_count
;
ha_rows
row_count
;
public:
public:
select_dumpvar
(
void
)
{
row_count
=
0
;}
List
<
LEX_STRING
>
var_list
;
List
<
Item_func_set_user_var
>
vars
;
select_dumpvar
(
void
)
{
var_list
.
empty
();
vars
.
empty
();
row_count
=
0
;}
~
select_dumpvar
()
{}
~
select_dumpvar
()
{}
int
prepare
(
List
<
Item
>
&
list
,
SELECT_LEX_UNIT
*
u
)
{
return
0
;}
int
prepare
(
List
<
Item
>
&
list
,
SELECT_LEX_UNIT
*
u
);
bool
send_fields
(
List
<
Item
>
&
list
,
uint
flag
)
bool
send_fields
(
List
<
Item
>
&
list
,
uint
flag
)
{
return
0
;}
{
if
(
current_thd
->
lex
.
select_into_var_list
.
elements
!=
list
.
elements
)
{
my_error
(
ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT
,
MYF
(
0
));
return
1
;
}
return
0
;
}
bool
send_data
(
List
<
Item
>
&
items
);
bool
send_data
(
List
<
Item
>
&
items
);
void
send_error
(
uint
errcode
,
const
char
*
err
)
{
my_message
(
errcode
,
err
,
MYF
(
0
));
}
bool
send_eof
();
bool
send_eof
();
};
};
sql/sql_lex.h
View file @
cd5ff630
...
@@ -334,6 +334,7 @@ typedef struct st_lex
...
@@ -334,6 +334,7 @@ typedef struct st_lex
enum
SSL_type
ssl_type
;
/* defined in violite.h */
enum
SSL_type
ssl_type
;
/* defined in violite.h */
String
*
wild
;
String
*
wild
;
sql_exchange
*
exchange
;
sql_exchange
*
exchange
;
select_result
*
result
;
List
<
key_part_spec
>
col_list
;
List
<
key_part_spec
>
col_list
;
List
<
key_part_spec
>
ref_list
;
List
<
key_part_spec
>
ref_list
;
...
@@ -348,7 +349,6 @@ typedef struct st_lex
...
@@ -348,7 +349,6 @@ typedef struct st_lex
List
<
List_item
>
many_values
;
List
<
List_item
>
many_values
;
List
<
set_var_base
>
var_list
;
List
<
set_var_base
>
var_list
;
List
<
Item
>
param_list
;
List
<
Item
>
param_list
;
List
<
LEX_STRING
>
select_into_var_list
;
SQL_LIST
proc_list
,
auxilliary_table_list
;
SQL_LIST
proc_list
,
auxilliary_table_list
;
TYPELIB
*
interval
;
TYPELIB
*
interval
;
create_field
*
last_field
;
create_field
*
last_field
;
...
...
sql/sql_parse.cc
View file @
cd5ff630
...
@@ -1403,7 +1403,7 @@ mysql_execute_command(THD *thd)
...
@@ -1403,7 +1403,7 @@ mysql_execute_command(THD *thd)
switch
(
lex
->
sql_command
)
{
switch
(
lex
->
sql_command
)
{
case
SQLCOM_SELECT
:
case
SQLCOM_SELECT
:
{
{
select_result
*
result
;
select_result
*
result
=
lex
->
result
;
if
(
select_lex
->
options
&
SELECT_DESCRIBE
)
if
(
select_lex
->
options
&
SELECT_DESCRIBE
)
lex
->
exchange
=
0
;
lex
->
exchange
=
0
;
if
(
tables
)
if
(
tables
)
...
@@ -1430,36 +1430,20 @@ mysql_execute_command(THD *thd)
...
@@ -1430,36 +1430,20 @@ mysql_execute_command(THD *thd)
if
(
unit
->
select_limit_cnt
==
HA_POS_ERROR
)
if
(
unit
->
select_limit_cnt
==
HA_POS_ERROR
)
select_lex
->
options
&=
~
OPTION_FOUND_ROWS
;
select_lex
->
options
&=
~
OPTION_FOUND_ROWS
;
if
(
lex
->
exchange
)
if
(
!
result
)
{
{
if
(
lex
->
exchange
->
dumpfile
)
if
(
(
result
=
new
select_send
())
)
{
{
if
(
!
(
result
=
new
select_dump
(
lex
->
exchange
)))
/*
{
Normal select:
res
=
-
1
;
Change lock if we are using SELECT HIGH PRIORITY,
break
;
FOR UPDATE or IN SHARE MODE
}
*/
TABLE_LIST
*
table
;
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
table
->
lock_type
=
lex
->
lock_option
;
}
}
else
else
{
if
(
!
(
result
=
new
select_export
(
lex
->
exchange
)))
{
res
=
-
1
;
break
;
}
}
}
else
if
(
lex
->
select_into_var_list
.
elements
)
{
if
(
!
(
result
=
new
select_dumpvar
()))
{
res
=
-
1
;
break
;
}
}
else
{
if
(
!
(
result
=
new
select_send
()))
{
{
res
=
-
1
;
res
=
-
1
;
#ifdef DELETE_ITEMS
#ifdef DELETE_ITEMS
...
@@ -1468,17 +1452,6 @@ mysql_execute_command(THD *thd)
...
@@ -1468,17 +1452,6 @@ mysql_execute_command(THD *thd)
#endif
#endif
break
;
break
;
}
}
else
{
/*
Normal select:
Change lock if we are using SELECT HIGH PRIORITY,
FOR UPDATE or IN SHARE MODE
*/
TABLE_LIST
*
table
;
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
table
->
lock_type
=
lex
->
lock_option
;
}
}
}
if
(
!
(
res
=
open_and_lock_tables
(
thd
,
tables
)))
if
(
!
(
res
=
open_and_lock_tables
(
thd
,
tables
)))
...
@@ -2976,8 +2949,8 @@ mysql_init_select(LEX *lex)
...
@@ -2976,8 +2949,8 @@ mysql_init_select(LEX *lex)
lex
->
thd
->
variables
.
select_limit
;
lex
->
thd
->
variables
.
select_limit
;
select_lex
->
olap
=
UNSPECIFIED_OLAP_TYPE
;
select_lex
->
olap
=
UNSPECIFIED_OLAP_TYPE
;
lex
->
exchange
=
0
;
lex
->
exchange
=
0
;
lex
->
result
=
0
;
lex
->
proc_list
.
first
=
0
;
lex
->
proc_list
.
first
=
0
;
lex
->
select_into_var_list
.
empty
();
}
}
...
...
sql/sql_yacc.yy
View file @
cd5ff630
...
@@ -632,7 +632,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
...
@@ -632,7 +632,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
handler_rkey_function handler_read_or_scan
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild union union_list
single_multi table_wild_list table_wild_one opt_wild union union_list
precision union_option opt_on_delete_item subselect_start opt_and
precision union_option opt_on_delete_item subselect_start opt_and
subselect_end select_var_list
subselect_end select_var_list
select_var_list_init
END_OF_INPUT
END_OF_INPUT
%type <NONE>
%type <NONE>
...
@@ -754,7 +754,8 @@ master_def:
...
@@ -754,7 +754,8 @@ master_def:
RELAY_LOG_POS_SYM EQ ULONG_NUM
RELAY_LOG_POS_SYM EQ ULONG_NUM
{
{
Lex->mi.relay_log_pos = $3;
Lex->mi.relay_log_pos = $3;
};
}
;
/* create a table */
/* create a table */
...
@@ -819,11 +820,13 @@ create:
...
@@ -819,11 +820,13 @@ create:
LEX *lex=Lex;
LEX *lex=Lex;
lex->udf.returns=(Item_result) $7;
lex->udf.returns=(Item_result) $7;
lex->udf.dl=$9.str;
lex->udf.dl=$9.str;
};
}
;
create2:
create2:
'(' field_list ')' opt_create_table_options create3 {}
'(' field_list ')' opt_create_table_options create3 {}
| opt_create_table_options create3 {};
| opt_create_table_options create3 {}
;
create3:
create3:
/* empty */ {}
/* empty */ {}
...
@@ -833,7 +836,8 @@ create3:
...
@@ -833,7 +836,8 @@ create3:
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
mysql_init_select(lex);
mysql_init_select(lex);
}
}
select_options select_item_list opt_select_from union {};
select_options select_item_list opt_select_from union {}
;
opt_as:
opt_as:
/* empty */ {}
/* empty */ {}
...
@@ -2543,36 +2547,53 @@ procedure_item:
...
@@ -2543,36 +2547,53 @@ procedure_item:
YYABORT;
YYABORT;
if (!$2->name)
if (!$2->name)
$2->set_name($1,(uint) ((char*) Lex->tok_end - $1));
$2->set_name($1,(uint) ((char*) Lex->tok_end - $1));
};
}
;
select_var_list_init:
{
if (!(Lex->result= new select_dumpvar()))
YYABORT;
}
select_var_list
;
select_var_list:
select_var_list:
select_var_list ',' '@' ident_or_text
select_var_list ',' select_var_ident
| select_var_ident {}
;
select_var_ident: '@' ident_or_text
{
{
if (Lex->select_into_var_list.push_back((LEX_STRING*) sql_memdup(&$4,sizeof(LEX_STRING))))
LEX *lex=Lex;
if ( ((select_dumpvar *)lex->result)->var_list.push_back((LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING))))
YYABORT;
YYABORT;
}
}
| '@' ident_or_text
{
if (Lex->select_into_var_list.push_back((LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING))))
YYABORT;
};
opt_into:
opt_into:
INTO OUTFILE TEXT_STRING
INTO OUTFILE TEXT_STRING
{
{
if (!(Lex->exchange= new sql_exchange($3.str,0)))
LEX *lex=Lex;
if (!(lex->exchange= new sql_exchange($3.str,0)))
YYABORT;
YYABORT;
if (!(lex->result= new select_export(lex->exchange)))
YYABORT;
}
}
opt_field_term opt_line_term
opt_field_term opt_line_term
| INTO DUMPFILE TEXT_STRING
| INTO DUMPFILE TEXT_STRING
{
{
if (!(Lex->exchange= new sql_exchange($3.str,1)))
LEX *lex=Lex;
if (!(lex->exchange= new sql_exchange($3.str,1)))
YYABORT;
YYABORT;
if (!(lex->result= new select_dump(lex->exchange)))
YYABORT;
}
}
| INTO select_var_list
| INTO select_var_list
_init
{
{
current_thd->safe_to_cache_query=0;
current_thd->safe_to_cache_query=0;
};
}
;
/*
/*
DO statement
DO statement
...
@@ -3582,7 +3603,8 @@ option_value:
...
@@ -3582,7 +3603,8 @@ option_value:
| PASSWORD FOR_SYM user equal text_or_password
| PASSWORD FOR_SYM user equal text_or_password
{
{
Lex->var_list.push_back(new set_var_password($3,$5));
Lex->var_list.push_back(new set_var_password($3,$5));
};
}
;
internal_variable_name:
internal_variable_name:
ident
ident
...
@@ -3591,7 +3613,8 @@ internal_variable_name:
...
@@ -3591,7 +3613,8 @@ internal_variable_name:
if (!tmp)
if (!tmp)
YYABORT;
YYABORT;
$$=tmp;
$$=tmp;
};
}
;
isolation_types:
isolation_types:
READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; }
READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; }
...
@@ -3612,7 +3635,8 @@ text_or_password:
...
@@ -3612,7 +3635,8 @@ text_or_password:
make_scrambled_password(buff,$3.str);
make_scrambled_password(buff,$3.str);
$$=buff;
$$=buff;
}
}
};
}
;
set_expr_or_default:
set_expr_or_default:
...
@@ -3642,16 +3666,19 @@ table_lock_list:
...
@@ -3642,16 +3666,19 @@ table_lock_list:
table_lock:
table_lock:
table_ident opt_table_alias lock_option
table_ident opt_table_alias lock_option
{ if (!add_table_to_list($1,$2,0,(thr_lock_type) $3)) YYABORT; };
{ if (!add_table_to_list($1,$2,0,(thr_lock_type) $3)) YYABORT; }
;
lock_option:
lock_option:
READ_SYM { $$=TL_READ_NO_INSERT; }
READ_SYM { $$=TL_READ_NO_INSERT; }
| WRITE_SYM { $$=current_thd->update_lock_default; }
| WRITE_SYM { $$=current_thd->update_lock_default; }
| LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
| LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
| READ_SYM LOCAL_SYM { $$= TL_READ; };
| READ_SYM LOCAL_SYM { $$= TL_READ; }
;
unlock:
unlock:
UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; };
UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }
;
/*
/*
...
@@ -3681,15 +3708,18 @@ handler:
...
@@ -3681,15 +3708,18 @@ handler:
if (!add_table_to_list($2,0,0))
if (!add_table_to_list($2,0,0))
YYABORT;
YYABORT;
}
}
handler_read_or_scan where_clause limit_clause { };
handler_read_or_scan where_clause limit_clause { }
;
handler_read_or_scan:
handler_read_or_scan:
handler_scan_function { Lex->backup_dir= 0; }
handler_scan_function { Lex->backup_dir= 0; }
| ident handler_rkey_function { Lex->backup_dir= $1.str; };
| ident handler_rkey_function { Lex->backup_dir= $1.str; }
;
handler_scan_function:
handler_scan_function:
FIRST_SYM { Lex->ha_read_mode = RFIRST; }
FIRST_SYM { Lex->ha_read_mode = RFIRST; }
| NEXT_SYM { Lex->ha_read_mode = RNEXT; };
| NEXT_SYM { Lex->ha_read_mode = RNEXT; }
;
handler_rkey_function:
handler_rkey_function:
FIRST_SYM { Lex->ha_read_mode = RFIRST; }
FIRST_SYM { Lex->ha_read_mode = RFIRST; }
...
@@ -3703,14 +3733,16 @@ handler_rkey_function:
...
@@ -3703,14 +3733,16 @@ handler_rkey_function:
lex->ha_rkey_mode=$1;
lex->ha_rkey_mode=$1;
if (!(lex->insert_list = new List_item))
if (!(lex->insert_list = new List_item))
YYABORT;
YYABORT;
} '(' values ')' { };
} '(' values ')' { }
;
handler_rkey_mode:
handler_rkey_mode:
EQ { $$=HA_READ_KEY_EXACT; }
EQ { $$=HA_READ_KEY_EXACT; }
| GE { $$=HA_READ_KEY_OR_NEXT; }
| GE { $$=HA_READ_KEY_OR_NEXT; }
| LE { $$=HA_READ_KEY_OR_PREV; }
| LE { $$=HA_READ_KEY_OR_PREV; }
| GT_SYM { $$=HA_READ_AFTER_KEY; }
| GT_SYM { $$=HA_READ_AFTER_KEY; }
| LT { $$=HA_READ_BEFORE_KEY; };
| LT { $$=HA_READ_BEFORE_KEY; }
;
/* GRANT / REVOKE */
/* GRANT / REVOKE */
...
@@ -3748,7 +3780,8 @@ grant:
...
@@ -3748,7 +3780,8 @@ grant:
grant_privileges:
grant_privileges:
grant_privilege_list {}
grant_privilege_list {}
| ALL PRIVILEGES { Lex->grant = GLOBAL_ACLS;}
| ALL PRIVILEGES { Lex->grant = GLOBAL_ACLS;}
| ALL { Lex->grant = GLOBAL_ACLS;};
| ALL { Lex->grant = GLOBAL_ACLS;}
;
grant_privilege_list:
grant_privilege_list:
grant_privilege
grant_privilege
...
@@ -3867,7 +3900,8 @@ opt_table:
...
@@ -3867,7 +3900,8 @@ opt_table:
YYABORT;
YYABORT;
if (lex->grant == GLOBAL_ACLS)
if (lex->grant == GLOBAL_ACLS)
lex->grant = TABLE_ACLS & ~GRANT_ACL;
lex->grant = TABLE_ACLS & ~GRANT_ACL;
};
}
;
user_list:
user_list:
...
@@ -3898,7 +3932,8 @@ grant_user:
...
@@ -3898,7 +3932,8 @@ grant_user:
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
{ $$=$1; $1->password=$5 ; }
{ $$=$1; $1->password=$5 ; }
| user
| user
{ $$=$1; $1->password.str=NullS; };
{ $$=$1; $1->password.str=NullS; }
;
opt_column_list:
opt_column_list:
...
@@ -3931,7 +3966,8 @@ column_list_id:
...
@@ -3931,7 +3966,8 @@ column_list_id:
point->rights |= lex->which_columns;
point->rights |= lex->which_columns;
else
else
lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns));
lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns));
};
}
;
require_clause: /* empty */
require_clause: /* empty */
...
@@ -3950,7 +3986,8 @@ require_clause: /* empty */
...
@@ -3950,7 +3986,8 @@ require_clause: /* empty */
| REQUIRE_SYM NONE_SYM
| REQUIRE_SYM NONE_SYM
{
{
Lex->ssl_type=SSL_TYPE_NONE;
Lex->ssl_type=SSL_TYPE_NONE;
};
}
;
grant_options:
grant_options:
/* empty */ {}
/* empty */ {}
...
@@ -3958,7 +3995,8 @@ grant_options:
...
@@ -3958,7 +3995,8 @@ grant_options:
grant_option_list:
grant_option_list:
grant_option_list grant_option {}
grant_option_list grant_option {}
| grant_option {};
| grant_option {}
;
grant_option:
grant_option:
GRANT OPTION { Lex->grant |= GRANT_ACL;}
GRANT OPTION { Lex->grant |= GRANT_ACL;}
...
@@ -3976,14 +4014,16 @@ grant_option:
...
@@ -3976,14 +4014,16 @@ grant_option:
{
{
Lex->mqh.connections=$2;
Lex->mqh.connections=$2;
Lex->mqh.bits |= 4;
Lex->mqh.bits |= 4;
};
}
;
begin:
begin:
BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work;
BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work;
opt_work:
opt_work:
/* empty */ {}
/* empty */ {}
| WORK_SYM {;};
| WORK_SYM {;}
;
commit:
commit:
COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;};
COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment