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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
a535342d
Commit
a535342d
authored
Apr 10, 2004
by
bell@sanja.is.com.ua
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
after review PS fixes
parent
e8137a13
Changes
13
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
527 additions
and
317 deletions
+527
-317
sql/item_cmpfunc.cc
sql/item_cmpfunc.cc
+2
-3
sql/mysql_priv.h
sql/mysql_priv.h
+15
-1
sql/set_var.cc
sql/set_var.cc
+25
-1
sql/sql_acl.cc
sql/sql_acl.cc
+3
-3
sql/sql_acl.h
sql/sql_acl.h
+2
-2
sql/sql_delete.cc
sql/sql_delete.cc
+36
-12
sql/sql_insert.cc
sql/sql_insert.cc
+40
-12
sql/sql_lex.cc
sql/sql_lex.cc
+13
-7
sql/sql_parse.cc
sql/sql_parse.cc
+188
-98
sql/sql_prepare.cc
sql/sql_prepare.cc
+142
-152
sql/sql_show.cc
sql/sql_show.cc
+1
-1
sql/sql_update.cc
sql/sql_update.cc
+58
-24
sql/table.h
sql/table.h
+2
-1
No files found.
sql/item_cmpfunc.cc
View file @
a535342d
...
...
@@ -477,10 +477,9 @@ bool Item_in_optimizer::fix_left(THD *thd,
struct
st_table_list
*
tables
,
Item
**
ref
)
{
if
((
!
args
[
0
]
->
fixed
&&
args
[
0
]
->
fix_fields
(
thd
,
tables
,
args
)))
if
(
!
args
[
0
]
->
fixed
&&
args
[
0
]
->
fix_fields
(
thd
,
tables
,
args
)
||
!
cache
&&
!
(
cache
=
Item_cache
::
get_cache
(
args
[
0
]
->
result_type
())))
return
1
;
if
(
!
cache
&&
!
(
cache
=
Item_cache
::
get_cache
(
args
[
0
]
->
result_type
())))
return
1
;
cache
->
setup
(
args
[
0
]);
cache
->
store
(
args
[
0
]);
...
...
sql/mysql_priv.h
View file @
a535342d
...
...
@@ -348,12 +348,17 @@ void cleanup_items(Item *item);
class
THD
;
void
close_thread_tables
(
THD
*
thd
,
bool
locked
=
0
,
bool
skip_derived
=
0
);
int
check_one_table_access
(
THD
*
thd
,
ulong
privilege
,
TABLE_LIST
*
tables
,
bool
no_errors
);
TABLE_LIST
*
tables
);
bool
check_merge_table_access
(
THD
*
thd
,
char
*
db
,
TABLE_LIST
*
table_list
);
int
multi_update_precheck
(
THD
*
thd
,
TABLE_LIST
*
tables
);
int
multi_delete_precheck
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
*
table_count
);
int
insert_select_precheck
(
THD
*
thd
,
TABLE_LIST
*
tables
);
int
update_precheck
(
THD
*
thd
,
TABLE_LIST
*
tables
);
int
delete_precheck
(
THD
*
thd
,
TABLE_LIST
*
tables
);
int
insert_precheck
(
THD
*
thd
,
TABLE_LIST
*
tables
,
bool
update
);
int
create_table_precheck
(
THD
*
thd
,
TABLE_LIST
*
tables
,
TABLE_LIST
*
create_table
);
#include "sql_class.h"
#include "opt_range.h"
...
...
@@ -532,6 +537,9 @@ bool mysql_rename_table(enum db_type base,
int
mysql_create_index
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
List
<
Key
>
&
keys
);
int
mysql_drop_index
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
List
<
Alter_drop
>
&
drop_list
);
int
mysql_prepare_update
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
TABLE_LIST
*
update_table_list
,
Item
**
conds
,
uint
order_num
,
ORDER
*
order
);
int
mysql_update
(
THD
*
thd
,
TABLE_LIST
*
tables
,
List
<
Item
>
&
fields
,
List
<
Item
>
&
values
,
COND
*
conds
,
uint
order_num
,
ORDER
*
order
,
ha_rows
limit
,
...
...
@@ -541,9 +549,15 @@ int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
COND
*
conds
,
ulong
options
,
enum
enum_duplicates
handle_duplicates
,
SELECT_LEX_UNIT
*
unit
,
SELECT_LEX
*
select_lex
);
int
mysql_prepare_insert
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
TABLE_LIST
*
insert_table_list
,
TABLE
*
table
,
List
<
Item
>
&
fields
,
List_item
*
values
,
List
<
Item
>
&
update_fields
,
List
<
Item
>
&
update_values
,
enum_duplicates
duplic
);
int
mysql_insert
(
THD
*
thd
,
TABLE_LIST
*
table
,
List
<
Item
>
&
fields
,
List
<
List_item
>
&
values
,
List
<
Item
>
&
update_fields
,
List
<
Item
>
&
update_values
,
enum_duplicates
flag
);
int
mysql_prepare_delete
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
Item
**
conds
);
int
mysql_delete
(
THD
*
thd
,
TABLE_LIST
*
table
,
COND
*
conds
,
SQL_LIST
*
order
,
ha_rows
rows
,
ulong
options
);
int
mysql_truncate
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
bool
dont_send_ok
=
0
);
...
...
sql/set_var.cc
View file @
a535342d
...
...
@@ -2529,6 +2529,18 @@ int set_var::check(THD *thd)
}
/*
Check variable, but without assigning value (used by PS)
SYNOPSIS
set_var::light_check()
thd thread handler
RETURN VALUE
0 ok
1 ERROR, message sent (normally no variables was updated)
-1 ERROR, message not sent
*/
int
set_var
::
light_check
(
THD
*
thd
)
{
if
(
var
->
check_type
(
type
))
...
...
@@ -2538,7 +2550,7 @@ int set_var::light_check(THD *thd)
var
->
name
);
return
-
1
;
}
if
(
(
type
==
OPT_GLOBAL
&&
check_global_access
(
thd
,
SUPER_ACL
)
))
if
(
type
==
OPT_GLOBAL
&&
check_global_access
(
thd
,
SUPER_ACL
))
return
1
;
if
(
value
&&
(
value
->
fix_fields
(
thd
,
0
,
&
value
)
||
value
->
check_cols
(
1
)))
...
...
@@ -2574,6 +2586,18 @@ int set_var_user::check(THD *thd)
}
/*
Check variable, but without assigning value (used by PS)
SYNOPSIS
set_var_user::light_check()
thd thread handler
RETURN VALUE
0 ok
1 ERROR, message sent (normally no variables was updated)
-1 ERROR, message not sent
*/
int
set_var_user
::
light_check
(
THD
*
thd
)
{
/*
...
...
sql/sql_acl.cc
View file @
a535342d
...
...
@@ -1388,7 +1388,7 @@ static bool test_if_create_new_users(THD *thd)
thd
->
priv_user
,
tl
.
db
,
0
);
if
(
!
(
db_access
&
INSERT_ACL
))
{
if
(
check_grant
(
thd
,
INSERT_ACL
,
&
tl
,
0
,
1
))
if
(
check_grant
(
thd
,
INSERT_ACL
,
&
tl
,
0
,
UINT_MAX
,
1
))
create_new_users
=
0
;
}
}
...
...
@@ -2650,7 +2650,7 @@ void grant_reload(THD *thd)
****************************************************************************/
bool
check_grant
(
THD
*
thd
,
ulong
want_access
,
TABLE_LIST
*
tables
,
uint
show_table
,
bool
no_errors
)
uint
show_table
,
uint
number
,
bool
no_errors
)
{
TABLE_LIST
*
table
;
char
*
user
=
thd
->
priv_user
;
...
...
@@ -2660,7 +2660,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
return
0
;
// ok
rw_rdlock
(
&
LOCK_grant
);
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
for
(
table
=
tables
;
table
&&
number
--
;
table
=
table
->
next
)
{
if
(
!
(
~
table
->
grant
.
privilege
&
want_access
)
||
table
->
derived
)
{
...
...
sql/sql_acl.h
View file @
a535342d
...
...
@@ -154,7 +154,7 @@ my_bool grant_init(THD *thd);
void
grant_free
(
void
);
void
grant_reload
(
THD
*
thd
);
bool
check_grant
(
THD
*
thd
,
ulong
want_access
,
TABLE_LIST
*
tables
,
uint
show_command
,
bool
dont_print_error
);
uint
show_command
,
uint
number
,
bool
dont_print_error
);
bool
check_grant_column
(
THD
*
thd
,
TABLE
*
table
,
const
char
*
name
,
uint
length
,
uint
show_command
=
0
);
bool
check_grant_all_columns
(
THD
*
thd
,
ulong
want_access
,
TABLE
*
table
);
...
...
@@ -168,6 +168,6 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list);
int
mysql_revoke_all
(
THD
*
thd
,
List
<
LEX_USER
>
&
list
);
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define check_grant(A,B,C,D,E) 0
#define check_grant(A,B,C,D,E
,F
) 0
#define check_grant_db(A,B) 0
#endif
sql/sql_delete.cc
View file @
a535342d
...
...
@@ -37,8 +37,6 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
bool
using_limit
=
limit
!=
HA_POS_ERROR
;
bool
transactional_table
,
log_delayed
,
safe_update
,
const_cond
;
ha_rows
deleted
;
TABLE_LIST
*
delete_table_list
=
(
TABLE_LIST
*
)
thd
->
lex
->
select_lex
.
table_list
.
first
;
DBUG_ENTER
(
"mysql_delete"
);
if
((
open_and_lock_tables
(
thd
,
table_list
)))
...
...
@@ -47,15 +45,9 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
table
->
file
->
info
(
HA_STATUS_VARIABLE
|
HA_STATUS_NO_LOCK
);
thd
->
proc_info
=
"init"
;
table
->
map
=
1
;
if
(
setup_conds
(
thd
,
delete_table_list
,
&
conds
)
||
setup_ftfuncs
(
&
thd
->
lex
->
select_lex
))
DBUG_RETURN
(
-
1
);
if
(
find_real_table_in_list
(
table_list
->
next
,
table_list
->
db
,
table_list
->
real_name
))
{
my_error
(
ER_UPDATE_TABLE_USED
,
MYF
(
0
),
table_list
->
real_name
);
DBUG_RETURN
(
-
1
);
}
if
((
error
=
mysql_prepare_delete
(
thd
,
table_list
,
&
conds
)))
DBUG_RETURN
(
error
);
const_cond
=
(
!
conds
||
conds
->
const_item
());
safe_update
=
test
(
thd
->
options
&
OPTION_SAFE_UPDATES
);
...
...
@@ -242,7 +234,39 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
send_ok
(
thd
,
deleted
);
DBUG_PRINT
(
"info"
,(
"%d records deleted"
,
deleted
));
}
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
}
/*
Prepare items in DELETE statement
SYNOPSIS
mysql_prepare_delete()
thd - thread handler
table_list - global table list
conds - conditions
RETURN VALUE
0 - OK
1 - error (message is sent to user)
-1 - error (message is not sent to user)
*/
int
mysql_prepare_delete
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
Item
**
conds
)
{
TABLE_LIST
*
delete_table_list
=
(
TABLE_LIST
*
)
thd
->
lex
->
select_lex
.
table_list
.
first
;
DBUG_ENTER
(
" mysql_prepare_delete"
);
if
(
setup_conds
(
thd
,
delete_table_list
,
conds
)
||
setup_ftfuncs
(
&
thd
->
lex
->
select_lex
))
DBUG_RETURN
(
-
1
);
if
(
find_real_table_in_list
(
table_list
->
next
,
table_list
->
db
,
table_list
->
real_name
))
{
my_error
(
ER_UPDATE_TABLE_USED
,
MYF
(
0
),
table_list
->
real_name
);
DBUG_RETURN
(
-
1
);
}
}
...
...
sql/sql_insert.cc
View file @
a535342d
...
...
@@ -207,19 +207,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
goto
abort
;
}
if
(
check_insert_fields
(
thd
,
table
,
fields
,
*
values
,
1
)
||
setup_tables
(
insert_table_list
)
||
setup_fields
(
thd
,
0
,
insert_table_list
,
*
values
,
0
,
0
,
0
)
||
(
duplic
==
DUP_UPDATE
&&
(
setup_fields
(
thd
,
0
,
insert_table_list
,
update_fields
,
0
,
0
,
0
)
||
setup_fields
(
thd
,
0
,
insert_table_list
,
update_values
,
0
,
0
,
0
))))
goto
abort
;
if
(
find_real_table_in_list
(
table_list
->
next
,
table_list
->
db
,
table_list
->
real_name
))
{
my_error
(
ER_UPDATE_TABLE_USED
,
MYF
(
0
),
table_list
->
real_name
);
if
(
mysql_prepare_insert
(
thd
,
table_list
,
insert_table_list
,
table
,
fields
,
values
,
update_fields
,
update_values
,
duplic
))
goto
abort
;
}
value_count
=
values
->
elements
;
while
((
values
=
its
++
))
...
...
@@ -438,6 +429,43 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
}
/*
Prepare items in INSERT statement
SYNOPSIS
mysql_prepare_update()
thd - thread handler
table_list - global table list
insert_table_list - local table list of INSERT SELECT_LEX
RETURN VALUE
0 - OK
-1 - error (message is not sent to user)
*/
int
mysql_prepare_insert
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
TABLE_LIST
*
insert_table_list
,
TABLE
*
table
,
List
<
Item
>
&
fields
,
List_item
*
values
,
List
<
Item
>
&
update_fields
,
List
<
Item
>
&
update_values
,
enum_duplicates
duplic
)
{
DBUG_ENTER
(
"mysql_prepare_insert"
);
if
(
check_insert_fields
(
thd
,
table
,
fields
,
*
values
,
1
)
||
setup_tables
(
insert_table_list
)
||
setup_fields
(
thd
,
0
,
insert_table_list
,
*
values
,
0
,
0
,
0
)
||
(
duplic
==
DUP_UPDATE
&&
(
setup_fields
(
thd
,
0
,
insert_table_list
,
update_fields
,
0
,
0
,
0
)
||
setup_fields
(
thd
,
0
,
insert_table_list
,
update_values
,
0
,
0
,
0
))))
DBUG_RETURN
(
-
1
);
if
(
find_real_table_in_list
(
table_list
->
next
,
table_list
->
db
,
table_list
->
real_name
))
{
my_error
(
ER_UPDATE_TABLE_USED
,
MYF
(
0
),
table_list
->
real_name
);
DBUG_RETURN
(
-
1
);
}
DBUG_RETURN
(
0
);
}
/* Check if there is more uniq keys after field */
static
int
last_uniq_key
(
TABLE
*
table
,
uint
keynr
)
...
...
sql/sql_lex.cc
View file @
a535342d
...
...
@@ -1634,8 +1634,10 @@ void st_select_lex::print_limit(THD *thd, String *str)
}
}
/*
unlink first table from table lists
Unlink first table from global table list and first must outer select list
(lex->select_lex)
SYNOPSIS
unlink_first_table()
...
...
@@ -1652,9 +1654,13 @@ TABLE_LIST *st_lex::unlink_first_table(TABLE_LIST *tables,
{
*
global_first
=
tables
;
*
local_first
=
(
TABLE_LIST
*
)
select_lex
.
table_list
.
first
;
// exclude from global table list
/*
exclude from global table list
*/
tables
=
tables
->
next
;
// and from local list if it is not the same
/*
and from local list if it is not the same
*/
if
(
&
select_lex
!=
all_selects_list
)
select_lex
.
table_list
.
first
=
(
gptr
)(
*
local_first
)
->
next
;
else
...
...
@@ -1663,8 +1669,9 @@ TABLE_LIST *st_lex::unlink_first_table(TABLE_LIST *tables,
return
tables
;
}
/*
link unlinked first table back
Link table back that was unlinked with unlink_first_table()
SYNOPSIS
link_first_table_back()
...
...
@@ -1680,7 +1687,6 @@ TABLE_LIST *st_lex::link_first_table_back(TABLE_LIST *tables,
TABLE_LIST
*
local_first
)
{
global_first
->
next
=
tables
;
tables
=
global_first
;
if
(
&
select_lex
!=
all_selects_list
)
{
/*
...
...
@@ -1690,8 +1696,8 @@ TABLE_LIST *st_lex::link_first_table_back(TABLE_LIST *tables,
select_lex
.
table_list
.
first
=
(
gptr
)
local_first
;
}
else
select_lex
.
table_list
.
first
=
(
gptr
)
tables
;
return
tables
;
select_lex
.
table_list
.
first
=
(
gptr
)
global_first
;
return
global_first
;
}
/*
...
...
sql/sql_parse.cc
View file @
a535342d
This diff is collapsed.
Click to expand it.
sql/sql_prepare.cc
View file @
a535342d
This diff is collapsed.
Click to expand it.
sql/sql_show.cc
View file @
a535342d
...
...
@@ -436,7 +436,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
table_list
.
db
=
(
char
*
)
db
;
table_list
.
real_name
=
file
->
name
;
table_list
.
grant
.
privilege
=
col_access
;
if
(
check_grant
(
thd
,
TABLE_ACLS
,
&
table_list
,
1
,
1
))
if
(
check_grant
(
thd
,
TABLE_ACLS
,
&
table_list
,
1
,
UINT_MAX
,
1
))
continue
;
}
#endif
...
...
sql/sql_update.cc
View file @
a535342d
...
...
@@ -70,8 +70,6 @@ int mysql_update(THD *thd,
READ_RECORD
info
;
TABLE_LIST
*
update_table_list
=
((
TABLE_LIST
*
)
thd
->
lex
->
select_lex
.
table_list
.
first
);
TABLE_LIST
tables
;
List
<
Item
>
all_fields
;
DBUG_ENTER
(
"mysql_update"
);
LINT_INIT
(
used_index
);
...
...
@@ -86,30 +84,13 @@ int mysql_update(THD *thd,
/* Calculate "table->used_keys" based on the WHERE */
table
->
used_keys
=
table
->
keys_in_use
;
table
->
quick_keys
.
clear_all
();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
want_privilege
=
table
->
grant
.
want_privilege
;
table
->
grant
.
want_privilege
=
(
SELECT_ACL
&
~
table
->
grant
.
privilege
);
want_privilege
=
table
->
grant
.
want_privilege
;
#endif
bzero
((
char
*
)
&
tables
,
sizeof
(
tables
));
// For ORDER BY
tables
.
table
=
table
;
tables
.
alias
=
table_list
->
alias
;
if
(
setup_tables
(
update_table_list
)
||
setup_conds
(
thd
,
update_table_list
,
&
conds
)
||
thd
->
lex
->
select_lex
.
setup_ref_array
(
thd
,
order_num
)
||
setup_order
(
thd
,
thd
->
lex
->
select_lex
.
ref_pointer_array
,
update_table_list
,
all_fields
,
all_fields
,
order
)
||
setup_ftfuncs
(
&
thd
->
lex
->
select_lex
))
DBUG_RETURN
(
-
1
);
/* purecov: inspected */
/* Check that we are not using table that we are updating in a sub select */
if
(
find_real_table_in_list
(
table_list
->
next
,
table_list
->
db
,
table_list
->
real_name
))
{
my_error
(
ER_UPDATE_TABLE_USED
,
MYF
(
0
),
table_list
->
real_name
);
DBUG_RETURN
(
-
1
);
}
if
((
error
=
mysql_prepare_update
(
thd
,
table_list
,
update_table_list
,
&
conds
,
order_num
,
order
)))
DBUG_RETURN
(
error
);
old_used_keys
=
table
->
used_keys
;
// Keys used in WHERE
/*
...
...
@@ -406,6 +387,59 @@ int mysql_update(THD *thd,
DBUG_RETURN
(
-
1
);
}
/*
Prepare items in UPDATE statement
SYNOPSIS
mysql_prepare_update()
thd - thread handler
table_list - global table list
update_table_list - local table list of UPDATE SELECT_LEX
conds - conditions
order_num - number of ORDER BY list entries
order - ORDER BY clause list
RETURN VALUE
0 - OK
1 - error (message is sent to user)
-1 - error (message is not sent to user)
*/
int
mysql_prepare_update
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
TABLE_LIST
*
update_table_list
,
Item
**
conds
,
uint
order_num
,
ORDER
*
order
)
{
TABLE
*
table
=
table_list
->
table
;
TABLE_LIST
tables
;
List
<
Item
>
all_fields
;
DBUG_ENTER
(
"mysql_prepare_update"
);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table
->
grant
.
want_privilege
=
(
SELECT_ACL
&
~
table
->
grant
.
privilege
);
#endif
bzero
((
char
*
)
&
tables
,
sizeof
(
tables
));
// For ORDER BY
tables
.
table
=
table
;
tables
.
alias
=
table_list
->
alias
;
if
(
setup_tables
(
update_table_list
)
||
setup_conds
(
thd
,
update_table_list
,
conds
)
||
thd
->
lex
->
select_lex
.
setup_ref_array
(
thd
,
order_num
)
||
setup_order
(
thd
,
thd
->
lex
->
select_lex
.
ref_pointer_array
,
update_table_list
,
all_fields
,
all_fields
,
order
)
||
setup_ftfuncs
(
&
thd
->
lex
->
select_lex
))
DBUG_RETURN
(
-
1
);
/* Check that we are not using table that we are updating in a sub select */
if
(
find_real_table_in_list
(
table_list
->
next
,
table_list
->
db
,
table_list
->
real_name
))
{
my_error
(
ER_UPDATE_TABLE_USED
,
MYF
(
0
),
table_list
->
real_name
);
DBUG_RETURN
(
-
1
);
}
DBUG_RETURN
(
0
);
}
/***************************************************************************
Update multiple tables from join
...
...
sql/table.h
View file @
a535342d
...
...
@@ -194,7 +194,8 @@ typedef struct st_table_list
bool
force_index
;
/* Prefer index over table scan */
bool
ignore_leaves
;
/* Preload only non-leaf nodes */
bool
cacheable_table
;
/* stop PS caching */
bool
checked
;
/* used in multi-upd privelege check */
/* used in multi-upd privelege check */
bool
table_in_update_from_clause
;
}
TABLE_LIST
;
typedef
struct
st_changed_table_list
...
...
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