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
355c15b8
Commit
355c15b8
authored
May 20, 2009
by
Matthias Leich
Browse files
Options
Browse Files
Download
Plain Diff
Merge of latest modfications into GCA tree, no conflicts
parents
fc77e47d
9e530c0f
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
259 additions
and
138 deletions
+259
-138
mysql-test/r/func_in.result
mysql-test/r/func_in.result
+0
-5
mysql-test/suite/binlog/r/binlog_stm_ps.result
mysql-test/suite/binlog/r/binlog_stm_ps.result
+1
-1
mysql-test/suite/binlog/r/binlog_unsafe.result
mysql-test/suite/binlog/r/binlog_unsafe.result
+61
-61
mysql-test/suite/binlog/t/binlog_unsafe.test
mysql-test/suite/binlog/t/binlog_unsafe.test
+2
-2
mysql-test/suite/rpl/r/rpl_stm_loadfile.result
mysql-test/suite/rpl/r/rpl_stm_loadfile.result
+2
-2
mysql-test/suite/rpl/r/rpl_udf.result
mysql-test/suite/rpl/r/rpl_udf.result
+4
-4
mysql-test/t/func_in.test
mysql-test/t/func_in.test
+0
-10
sql-common/client.c
sql-common/client.c
+45
-24
sql/item_cmpfunc.cc
sql/item_cmpfunc.cc
+14
-14
sql/sql_prepare.cc
sql/sql_prepare.cc
+3
-0
tests/mysql_client_test.c
tests/mysql_client_test.c
+127
-15
No files found.
mysql-test/r/func_in.result
View file @
355c15b8
...
...
@@ -587,9 +587,4 @@ SELECT CASE c1 WHEN c1 + 1 THEN 1 END, ABS(AVG(c0)) FROM t1;
CASE c1 WHEN c1 + 1 THEN 1 END ABS(AVG(c0))
NULL 1.0000
DROP TABLE t1;
CREATE TABLE t1(a TEXT);
INSERT INTO t1 VALUES('iynfj');
SELECT SUM( DISTINCT a ) FROM t1 GROUP BY a HAVING a IN ( AVG( 1 ), 1 + a );
SUM( DISTINCT a )
DROP TABLE t1;
End of 5.1 tests
mysql-test/suite/binlog/r/binlog_stm_ps.result
View file @
355c15b8
...
...
@@ -11,7 +11,7 @@ prepare s from "insert into t1 select 100 limit ?";
set @a=100;
execute s using @a;
Warnings:
Note 1592 Statement
is not
safe to log in statement format.
Note 1592 Statement
may not be
safe to log in statement format.
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1 (a int)
...
...
mysql-test/suite/binlog/r/binlog_unsafe.result
View file @
355c15b8
This diff is collapsed.
Click to expand it.
mysql-test/suite/binlog/t/binlog_unsafe.test
View file @
355c15b8
...
...
@@ -289,7 +289,7 @@ CREATE TABLE t1(i INT PRIMARY KEY);
CREATE
TABLE
t2
(
i
INT
PRIMARY
KEY
);
CREATE
TABLE
t3
(
i
INT
,
ch
CHAR
(
50
));
--
echo
"Should issue message Statement
is not
safe to log in statement format."
--
echo
"Should issue message Statement
may not be
safe to log in statement format."
INSERT
INTO
t1
SELECT
*
FROM
t2
LIMIT
1
;
DELIMITER
|
;
...
...
@@ -302,7 +302,7 @@ BEGIN
RETURN
0
;
END
|
DELIMITER
;
|
--
echo
"Should issue message Statement
is not
safe to log in statement format only once"
--
echo
"Should issue message Statement
may not be
safe to log in statement format only once"
INSERT
INTO
t3
VALUES
(
func6
(),
UUID
());
--
echo
"Check whether SET @@SQL_LOG_BIN = 0/1 doesn't work in substatements"
...
...
mysql-test/suite/rpl/r/rpl_stm_loadfile.result
View file @
355c15b8
...
...
@@ -10,7 +10,7 @@ CREATE TABLE test.t1 (a INT, blob_column LONGBLOB, PRIMARY KEY(a));
INSERT INTO test.t1 VALUES(1,'test');
UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=1;
Warnings:
Note 1592 Statement
is not
safe to log in statement format.
Note 1592 Statement
may not be
safe to log in statement format.
create procedure test.p1()
begin
INSERT INTO test.t1 VALUES(2,'test');
...
...
@@ -18,7 +18,7 @@ UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=2;
end|
CALL test.p1();
Warnings:
Note 1592 Statement
is not
safe to log in statement format.
Note 1592 Statement
may not be
safe to log in statement format.
SELECT * FROM test.t1 ORDER BY blob_column;
a blob_column
1 abase
...
...
mysql-test/suite/rpl/r/rpl_udf.result
View file @
355c15b8
...
...
@@ -182,19 +182,19 @@ CREATE TABLE t1(sum INT, price FLOAT(24)) ENGINE=MyISAM;
affected rows: 0
INSERT INTO t1 VALUES(myfunc_int(100), myfunc_double(50.00));
Warnings:
Note 1592 Statement
is not
safe to log in statement format.
Note 1592 Statement
may not be
safe to log in statement format.
affected rows: 1
INSERT INTO t1 VALUES(myfunc_int(10), myfunc_double(5.00));
Warnings:
Note 1592 Statement
is not
safe to log in statement format.
Note 1592 Statement
may not be
safe to log in statement format.
affected rows: 1
INSERT INTO t1 VALUES(myfunc_int(200), myfunc_double(25.00));
Warnings:
Note 1592 Statement
is not
safe to log in statement format.
Note 1592 Statement
may not be
safe to log in statement format.
affected rows: 1
INSERT INTO t1 VALUES(myfunc_int(1), myfunc_double(500.00));
Warnings:
Note 1592 Statement
is not
safe to log in statement format.
Note 1592 Statement
may not be
safe to log in statement format.
affected rows: 1
SELECT * FROM t1 ORDER BY sum;
sum price
...
...
mysql-test/t/func_in.test
View file @
355c15b8
...
...
@@ -439,14 +439,4 @@ SELECT CASE c1 WHEN c1 + 1 THEN 1 END, ABS(AVG(c0)) FROM t1;
DROP
TABLE
t1
;
#
# Bug #44399: crash with statement using TEXT columns, aggregates, GROUP BY,
# and HAVING
#
CREATE
TABLE
t1
(
a
TEXT
);
INSERT
INTO
t1
VALUES
(
'iynfj'
);
SELECT
SUM
(
DISTINCT
a
)
FROM
t1
GROUP
BY
a
HAVING
a
IN
(
AVG
(
1
),
1
+
a
);
DROP
TABLE
t1
;
--
echo
End
of
5.1
tests
sql-common/client.c
View file @
355c15b8
...
...
@@ -120,6 +120,7 @@ const char *def_shared_memory_base_name= default_shared_memory_base_name;
static
void
mysql_close_free_options
(
MYSQL
*
mysql
);
static
void
mysql_close_free
(
MYSQL
*
mysql
);
static
void
mysql_prune_stmt_list
(
MYSQL
*
mysql
);
#if !(defined(__WIN__) || defined(__NETWARE__))
static
int
wait_for_data
(
my_socket
fd
,
uint
timeout
);
...
...
@@ -924,6 +925,7 @@ void end_server(MYSQL *mysql)
vio_delete
(
mysql
->
net
.
vio
);
reset_sigpipe
(
mysql
);
mysql
->
net
.
vio
=
0
;
/* Marker */
mysql_prune_stmt_list
(
mysql
);
}
net_end
(
&
mysql
->
net
);
free_old_query
(
mysql
);
...
...
@@ -2526,30 +2528,9 @@ my_bool mysql_reconnect(MYSQL *mysql)
tmp_mysql
.
reconnect
=
1
;
tmp_mysql
.
free_me
=
mysql
->
free_me
;
/*
For each stmt in mysql->stmts, move it to tmp_mysql if it is
in state MYSQL_STMT_INIT_DONE, otherwise close it.
*/
{
LIST
*
element
=
mysql
->
stmts
;
for
(;
element
;
element
=
element
->
next
)
{
MYSQL_STMT
*
stmt
=
(
MYSQL_STMT
*
)
element
->
data
;
if
(
stmt
->
state
!=
MYSQL_STMT_INIT_DONE
)
{
stmt
->
mysql
=
0
;
stmt
->
last_errno
=
CR_SERVER_LOST
;
strmov
(
stmt
->
last_error
,
ER
(
CR_SERVER_LOST
));
strmov
(
stmt
->
sqlstate
,
unknown_sqlstate
);
}
else
{
tmp_mysql
.
stmts
=
list_add
(
tmp_mysql
.
stmts
,
&
stmt
->
list
);
}
/* No need to call list_delete for statement here */
}
mysql
->
stmts
=
NULL
;
}
/* Move prepared statements (if any) over to the new mysql object */
tmp_mysql
.
stmts
=
mysql
->
stmts
;
mysql
->
stmts
=
0
;
/* Don't free options as these are now used in tmp_mysql */
bzero
((
char
*
)
&
mysql
->
options
,
sizeof
(
mysql
->
options
));
...
...
@@ -2639,6 +2620,46 @@ static void mysql_close_free(MYSQL *mysql)
}
/**
For use when the connection to the server has been lost (in which case
the server has discarded all information about prepared statements
associated with the connection).
Mark all statements in mysql->stmts by setting stmt->mysql= 0 if the
statement has transitioned beyond the MYSQL_STMT_INIT_DONE state, and
unlink the statement from the mysql->stmts list.
The remaining pruned list of statements (if any) is kept in mysql->stmts.
@param mysql pointer to the MYSQL object
@return none
*/
static
void
mysql_prune_stmt_list
(
MYSQL
*
mysql
)
{
LIST
*
element
=
mysql
->
stmts
;
LIST
*
pruned_list
=
0
;
for
(;
element
;
element
=
element
->
next
)
{
MYSQL_STMT
*
stmt
=
(
MYSQL_STMT
*
)
element
->
data
;
if
(
stmt
->
state
!=
MYSQL_STMT_INIT_DONE
)
{
stmt
->
mysql
=
0
;
stmt
->
last_errno
=
CR_SERVER_LOST
;
strmov
(
stmt
->
last_error
,
ER
(
CR_SERVER_LOST
));
strmov
(
stmt
->
sqlstate
,
unknown_sqlstate
);
}
else
{
pruned_list
=
list_add
(
pruned_list
,
element
);
}
}
mysql
->
stmts
=
pruned_list
;
}
/*
Clear connection pointer of every statement: this is necessary
to give error on attempt to use a prepared statement of closed
...
...
sql/item_cmpfunc.cc
View file @
355c15b8
...
...
@@ -189,7 +189,6 @@ enum_field_types agg_field_type(Item **items, uint nitems)
collect_cmp_types()
items Array of items to collect types from
nitems Number of items in the array
with_sum_func a sum function is referenced
DESCRIPTION
This function collects different result types for comparison of the first
...
...
@@ -200,7 +199,7 @@ enum_field_types agg_field_type(Item **items, uint nitems)
Bitmap of collected types - otherwise
*/
static
uint
collect_cmp_types
(
Item
**
items
,
uint
nitems
,
my_bool
with_sum_func
)
static
uint
collect_cmp_types
(
Item
**
items
,
uint
nitems
)
{
uint
i
;
uint
found_types
;
...
...
@@ -216,16 +215,6 @@ static uint collect_cmp_types(Item **items, uint nitems, my_bool with_sum_func)
found_types
|=
1
<<
(
uint
)
item_cmp_type
(
left_result
,
items
[
i
]
->
result_type
());
}
if
(
with_sum_func
||
current_thd
->
lex
->
current_select
->
group_list
.
elements
)
{
/*
See TODO commentary in the setup_copy_fields function:
item in a group may be wrapped with an Item_copy_string item.
That item has a STRING_RESULT result type, so we need
to take this type into account.
*/
found_types
|=
(
1
<<
item_cmp_type
(
left_result
,
STRING_RESULT
));
}
return
found_types
;
}
...
...
@@ -2733,8 +2722,19 @@ void Item_func_case::fix_length_and_dec()
for
(
nagg
=
0
;
nagg
<
ncases
/
2
;
nagg
++
)
agg
[
nagg
+
1
]
=
args
[
nagg
*
2
];
nagg
++
;
if
(
!
(
found_types
=
collect_cmp_types
(
agg
,
nagg
,
with_sum_func
)))
if
(
!
(
found_types
=
collect_cmp_types
(
agg
,
nagg
)))
return
;
if
(
with_sum_func
||
current_thd
->
lex
->
current_select
->
group_list
.
elements
)
{
/*
See TODO commentary in the setup_copy_fields function:
item in a group may be wrapped with an Item_copy_string item.
That item has a STRING_RESULT result type, so we need
to take this type into account.
*/
found_types
|=
(
1
<<
item_cmp_type
(
left_result_type
,
STRING_RESULT
));
}
for
(
i
=
0
;
i
<=
(
uint
)
DECIMAL_RESULT
;
i
++
)
{
if
(
found_types
&
(
1
<<
i
)
&&
!
cmp_items
[
i
])
...
...
@@ -3525,7 +3525,7 @@ void Item_func_in::fix_length_and_dec()
uint
type_cnt
=
0
,
i
;
Item_result
cmp_type
=
STRING_RESULT
;
left_result_type
=
args
[
0
]
->
result_type
();
if
(
!
(
found_types
=
collect_cmp_types
(
args
,
arg_count
,
with_sum_func
)))
if
(
!
(
found_types
=
collect_cmp_types
(
args
,
arg_count
)))
return
;
for
(
arg
=
args
+
1
,
arg_end
=
args
+
arg_count
;
arg
!=
arg_end
;
arg
++
)
...
...
sql/sql_prepare.cc
View file @
355c15b8
...
...
@@ -2461,6 +2461,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
stmt
->
execute_loop
(
&
expanded_query
,
open_cursor
,
packet
,
packet_end
);
/* Close connection socket; for use with client testing (Bug#43560). */
DBUG_EXECUTE_IF
(
"close_conn_after_stmt_execute"
,
vio_close
(
thd
->
net
.
vio
););
DBUG_VOID_RETURN
;
}
...
...
tests/mysql_client_test.c
View file @
355c15b8
...
...
@@ -103,7 +103,7 @@ if (!opt_silent) \
static
void
print_error
(
const
char
*
msg
);
static
void
print_st_error
(
MYSQL_STMT
*
stmt
,
const
char
*
msg
);
static
void
client_disconnect
(
void
);
static
void
client_disconnect
(
MYSQL
*
mysql
,
my_bool
drop_db
);
/*
...
...
@@ -271,10 +271,20 @@ mysql_simple_prepare(MYSQL *mysql_arg, const char *query)
}
/* Connect to the server */
static
void
client_connect
(
ulong
flag
)
/**
Connect to the server with options given by arguments to this application,
stored in global variables opt_host, opt_user, opt_password, opt_db,
opt_port and opt_unix_socket.
@param flag[in] client_flag passed on to mysql_real_connect
@param protocol[in] MYSQL_PROTOCOL_* to use for this connection
@param auto_reconnect[in] set to 1 for auto reconnect
@return pointer to initialized and connected MYSQL object
*/
static
MYSQL
*
client_connect
(
ulong
flag
,
uint
protocol
,
my_bool
auto_reconnect
)
{
MYSQL
*
mysql
;
int
rc
;
static
char
query
[
MAX_TEST_QUERY_LENGTH
];
myheader_r
(
"client_connect"
);
...
...
@@ -291,6 +301,7 @@ static void client_connect(ulong flag)
}
/* enable local infile, in non-binary builds often disabled by default */
mysql_options
(
mysql
,
MYSQL_OPT_LOCAL_INFILE
,
0
);
mysql_options
(
mysql
,
MYSQL_OPT_PROTOCOL
,
&
protocol
);
if
(
!
(
mysql_real_connect
(
mysql
,
opt_host
,
opt_user
,
opt_password
,
opt_db
?
opt_db
:
"test"
,
opt_port
,
...
...
@@ -302,7 +313,7 @@ static void client_connect(ulong flag)
fprintf
(
stdout
,
"
\n
Check the connection options using --help or -?
\n
"
);
exit
(
1
);
}
mysql
->
reconnect
=
1
;
mysql
->
reconnect
=
auto_reconnect
;
if
(
!
opt_silent
)
fprintf
(
stdout
,
"OK"
);
...
...
@@ -329,12 +340,14 @@ static void client_connect(ulong flag)
if
(
!
opt_silent
)
fprintf
(
stdout
,
"OK"
);
return
mysql
;
}
/* Close the connection */
static
void
client_disconnect
()
static
void
client_disconnect
(
MYSQL
*
mysql
,
my_bool
drop_db
)
{
static
char
query
[
MAX_TEST_QUERY_LENGTH
];
...
...
@@ -342,13 +355,16 @@ static void client_disconnect()
if
(
mysql
)
{
if
(
!
opt_silent
)
fprintf
(
stdout
,
"
\n
dropping the test database '%s' ..."
,
current_db
);
strxmov
(
query
,
"DROP DATABASE IF EXISTS "
,
current_db
,
NullS
);
if
(
drop_db
)
{
if
(
!
opt_silent
)
fprintf
(
stdout
,
"
\n
dropping the test database '%s' ..."
,
current_db
);
strxmov
(
query
,
"DROP DATABASE IF EXISTS "
,
current_db
,
NullS
);
mysql_query
(
mysql
,
query
);
if
(
!
opt_silent
)
fprintf
(
stdout
,
"OK"
);
mysql_query
(
mysql
,
query
);
if
(
!
opt_silent
)
fprintf
(
stdout
,
"OK"
);
}
if
(
!
opt_silent
)
fprintf
(
stdout
,
"
\n
closing the connection ..."
);
...
...
@@ -17712,6 +17728,100 @@ static void test_bug40365(void)
}
/**
Subtest for Bug#43560. Verifies that a loss of connection on the server side
is handled well by the mysql_stmt_execute() call, i.e., no SIGSEGV due to
a vio socket that is cleared upon closed connection.
Assumes the presence of the close_conn_after_stmt_execute debug feature in
the server. Verifies that it is connected to a debug server before proceeding
with the test.
*/
static
void
test_bug43560
(
void
)
{
MYSQL
*
conn
;
uint
rc
;
MYSQL_STMT
*
stmt
=
0
;
MYSQL_BIND
bind
;
my_bool
is_null
=
0
;
const
uint
BUFSIZE
=
256
;
char
buffer
[
BUFSIZE
];
const
char
*
values
[]
=
{
"eins"
,
"zwei"
,
"drei"
,
"viele"
,
NULL
};
const
char
insert_str
[]
=
"INSERT INTO t1 (c2) VALUES (?)"
;
unsigned
long
length
;
DBUG_ENTER
(
"test_bug43560"
);
myheader
(
"test_bug43560"
);
/* Make sure we only run against a debug server. */
if
(
!
strstr
(
mysql
->
server_version
,
"debug"
))
{
fprintf
(
stdout
,
"Skipping test_bug43560: server not DEBUG version
\n
"
);
DBUG_VOID_RETURN
;
}
/*
Set up a separate connection for this test to avoid messing up the
general MYSQL object used in other subtests. Use TCP protocol to avoid
problems with the buffer semantics of AF_UNIX, and turn off auto reconnect.
*/
conn
=
client_connect
(
0
,
MYSQL_PROTOCOL_TCP
,
0
);
rc
=
mysql_query
(
conn
,
"DROP TABLE IF EXISTS t1"
);
myquery
(
rc
);
rc
=
mysql_query
(
conn
,
"CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 CHAR(10))"
);
myquery
(
rc
);
stmt
=
mysql_stmt_init
(
conn
);
check_stmt
(
stmt
);
rc
=
mysql_stmt_prepare
(
stmt
,
insert_str
,
strlen
(
insert_str
));
check_execute
(
stmt
,
rc
);
bind
.
buffer_type
=
MYSQL_TYPE_STRING
;
bind
.
buffer_length
=
BUFSIZE
;
bind
.
buffer
=
buffer
;
bind
.
is_null
=
&
is_null
;
bind
.
length
=
&
length
;
rc
=
mysql_stmt_bind_param
(
stmt
,
&
bind
);
check_execute
(
stmt
,
rc
);
/* First execute; should succeed. */
strncpy
(
buffer
,
values
[
0
],
BUFSIZE
);
length
=
strlen
(
buffer
);
rc
=
mysql_stmt_execute
(
stmt
);
check_execute
(
stmt
,
rc
);
/*
Set up the server to close this session's server-side socket after
next execution of prep statement.
*/
rc
=
mysql_query
(
conn
,
"SET SESSION debug='+d,close_conn_after_stmt_execute'"
);
myquery
(
rc
);
/* Second execute; should fail due to socket closed during execution. */
strncpy
(
buffer
,
values
[
1
],
BUFSIZE
);
length
=
strlen
(
buffer
);
rc
=
mysql_stmt_execute
(
stmt
);
DIE_UNLESS
(
rc
&&
mysql_stmt_errno
(
stmt
)
==
CR_SERVER_LOST
);
/*
Third execute; should fail (connection already closed), or SIGSEGV in
case of a Bug#43560 type regression in which case the whole test fails.
*/
strncpy
(
buffer
,
values
[
2
],
BUFSIZE
);
length
=
strlen
(
buffer
);
rc
=
mysql_stmt_execute
(
stmt
);
DIE_UNLESS
(
rc
&&
mysql_stmt_errno
(
stmt
)
==
CR_SERVER_LOST
);
client_disconnect
(
conn
,
0
);
rc
=
mysql_query
(
mysql
,
"DROP TABLE t1"
);
myquery
(
rc
);
DBUG_VOID_RETURN
;
}
/**
Bug#36326: nested transaction and select
*/
...
...
@@ -18140,6 +18250,7 @@ static struct my_tests_st my_tests[]= {
{
"test_wl4166_2"
,
test_wl4166_2
},
{
"test_bug38486"
,
test_bug38486
},
{
"test_bug40365"
,
test_bug40365
},
{
"test_bug43560"
,
test_bug43560
},
#ifdef HAVE_QUERY_CACHE
{
"test_bug36326"
,
test_bug36326
},
#endif
...
...
@@ -18268,7 +18379,8 @@ int main(int argc, char **argv)
(
char
**
)
embedded_server_groups
))
DIE
(
"Can't initialize MySQL server"
);
client_connect
(
0
);
/* connect to server */
/* connect to server with no flags, default protocol, auto reconnect true */
mysql
=
client_connect
(
0
,
MYSQL_PROTOCOL_DEFAULT
,
1
);
total_time
=
0
;
for
(
iter_count
=
1
;
iter_count
<=
opt_count
;
iter_count
++
)
...
...
@@ -18298,7 +18410,7 @@ int main(int argc, char **argv)
fprintf
(
stderr
,
"
\n\n
Given test not found: '%s'
\n
"
,
*
argv
);
fprintf
(
stderr
,
"See legal test names with %s -T
\n\n
Aborting!
\n
"
,
my_progname
);
client_disconnect
();
client_disconnect
(
mysql
,
1
);
free_defaults
(
defaults_argv
);
exit
(
1
);
}
...
...
@@ -18311,7 +18423,7 @@ int main(int argc, char **argv)
/* End of tests */
}
client_disconnect
();
/* disconnect from server */
client_disconnect
(
mysql
,
1
);
/* disconnect from server */
free_defaults
(
defaults_argv
);
print_test_output
();
...
...
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