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
04bf9996
Commit
04bf9996
authored
Dec 02, 2020
by
Varun Gupta
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More improvements to the encoder class
parent
7a1d56eb
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
152 additions
and
89 deletions
+152
-89
sql/field.cc
sql/field.cc
+3
-0
sql/filesort.cc
sql/filesort.cc
+1
-1
sql/item_sum.cc
sql/item_sum.cc
+10
-7
sql/sql_statistics.cc
sql/sql_statistics.cc
+4
-4
sql/uniques.cc
sql/uniques.cc
+113
-55
sql/uniques.h
sql/uniques.h
+21
-22
No files found.
sql/field.cc
View file @
04bf9996
...
@@ -1064,6 +1064,9 @@ Field::make_packed_sort_key_part(uchar *buff,
...
@@ -1064,6 +1064,9 @@ Field::make_packed_sort_key_part(uchar *buff,
}
}
/*
TODO varun: need to look what to do here
*/
uint
uint
Field
::
make_packed_key_part
(
uchar
*
buff
,
const
SORT_FIELD_ATTR
*
sort_field
)
Field
::
make_packed_key_part
(
uchar
*
buff
,
const
SORT_FIELD_ATTR
*
sort_field
)
{
{
...
...
sql/filesort.cc
View file @
04bf9996
...
@@ -2587,7 +2587,7 @@ uint32 Sort_param::get_record_length_for_unique(uchar *to,
...
@@ -2587,7 +2587,7 @@ uint32 Sort_param::get_record_length_for_unique(uchar *to,
{
{
if
(
!
using_packed_sortkeys
())
if
(
!
using_packed_sortkeys
())
return
rec_length
;
return
rec_length
;
return
Variable_size_
composite_key_desc
::
read_packed_length
(
to
)
+
return
Variable_size_
keys_descriptor
::
read_packed_length
(
to
)
+
size_of_dupl_count
;
size_of_dupl_count
;
}
}
...
...
sql/item_sum.cc
View file @
04bf9996
...
@@ -3921,7 +3921,7 @@ Item_func_group_concat::dump_leaf_variable_sized_key(void *key_arg,
...
@@ -3921,7 +3921,7 @@ Item_func_group_concat::dump_leaf_variable_sized_key(void *key_arg,
pos
=
item
->
unique_filter
->
get_descriptor
()
->
get_sortorder
();
pos
=
item
->
unique_filter
->
get_descriptor
()
->
get_sortorder
();
key_end
=
key
+
item
->
unique_filter
->
get_full_size
();
key_end
=
key
+
item
->
unique_filter
->
get_full_size
();
key
+=
Variable_size_
composite_key_desc
::
size_of_length_field
;
key
+=
Variable_size_
keys_descriptor
::
size_of_length_field
;
ulonglong
*
offset_limit
=
&
item
->
copy_offset_limit
;
ulonglong
*
offset_limit
=
&
item
->
copy_offset_limit
;
ulonglong
*
row_limit
=
&
item
->
copy_row_limit
;
ulonglong
*
row_limit
=
&
item
->
copy_row_limit
;
...
@@ -4794,7 +4794,7 @@ bool Item_sum::is_packing_allowed(TABLE *table, uint* total_length)
...
@@ -4794,7 +4794,7 @@ bool Item_sum::is_packing_allowed(TABLE *table, uint* total_length)
Unique::size_of_lengt_field is the length bytes to store the packed length
Unique::size_of_lengt_field is the length bytes to store the packed length
for each record inserted in the Unique tree
for each record inserted in the Unique tree
*/
*/
(
*
total_length
)
+=
Variable_size_
composite_key_desc
::
size_of_length_field
+
(
*
total_length
)
+=
Variable_size_
keys_descriptor
::
size_of_length_field
+
size_of_packable_fields
;
size_of_packable_fields
;
return
true
;
return
true
;
}
}
...
@@ -4818,6 +4818,8 @@ Item_sum::get_unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
...
@@ -4818,6 +4818,8 @@ Item_sum::get_unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
desc
=
new
Variable_size_keys_simple
(
size_arg
);
desc
=
new
Variable_size_keys_simple
(
size_arg
);
else
else
desc
=
new
Variable_size_composite_key_desc
(
size_arg
);
desc
=
new
Variable_size_composite_key_desc
(
size_arg
);
if
(
!
desc
||
desc
->
init
())
return
NULL
;
}
}
else
else
{
{
...
@@ -4825,10 +4827,9 @@ Item_sum::get_unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
...
@@ -4825,10 +4827,9 @@ Item_sum::get_unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
desc
=
new
Fixed_size_keys_descriptor
(
size_arg
);
desc
=
new
Fixed_size_keys_descriptor
(
size_arg
);
else
else
desc
=
new
Fixed_size_composite_keys_descriptor
(
size_arg
);
desc
=
new
Fixed_size_composite_keys_descriptor
(
size_arg
);
if
(
!
desc
||
desc
->
init
())
return
NULL
;
}
}
if
(
!
desc
)
return
NULL
;
return
new
Unique_impl
(
comp_func
,
comp_func_fixed_arg
,
size_arg
,
return
new
Unique_impl
(
comp_func
,
comp_func_fixed_arg
,
size_arg
,
max_in_memory_size_arg
,
min_dupl_count_arg
,
desc
);
max_in_memory_size_arg
,
min_dupl_count_arg
,
desc
);
}
}
...
@@ -4851,6 +4852,8 @@ Item_func_group_concat::get_unique(qsort_cmp2 comp_func,
...
@@ -4851,6 +4852,8 @@ Item_func_group_concat::get_unique(qsort_cmp2 comp_func,
desc
=
new
Variable_size_keys_simple
(
size_arg
);
desc
=
new
Variable_size_keys_simple
(
size_arg
);
else
else
desc
=
new
Variable_size_composite_key_desc
(
size_arg
);
desc
=
new
Variable_size_composite_key_desc
(
size_arg
);
if
(
!
desc
||
desc
->
init
())
return
NULL
;
}
}
else
else
{
{
...
@@ -4858,10 +4861,10 @@ Item_func_group_concat::get_unique(qsort_cmp2 comp_func,
...
@@ -4858,10 +4861,10 @@ Item_func_group_concat::get_unique(qsort_cmp2 comp_func,
desc
=
new
Fixed_size_keys_descriptor_with_nulls
(
size_arg
);
desc
=
new
Fixed_size_keys_descriptor_with_nulls
(
size_arg
);
else
else
desc
=
new
Fixed_size_keys_for_group_concat
(
size_arg
);
desc
=
new
Fixed_size_keys_for_group_concat
(
size_arg
);
if
(
!
desc
)
return
NULL
;
}
}
if
(
!
desc
)
return
NULL
;
return
new
Unique_impl
(
comp_func
,
comp_func_fixed_arg
,
size_arg
,
return
new
Unique_impl
(
comp_func
,
comp_func_fixed_arg
,
size_arg
,
max_in_memory_size_arg
,
min_dupl_count_arg
,
desc
);
max_in_memory_size_arg
,
min_dupl_count_arg
,
desc
);
}
}
...
...
sql/sql_statistics.cc
View file @
04bf9996
...
@@ -1527,7 +1527,7 @@ class Stat_table_write_iter
...
@@ -1527,7 +1527,7 @@ class Stat_table_write_iter
*/
*/
uint
get_offset_to_value
(
Field
*
field
)
uint
get_offset_to_value
(
Field
*
field
)
{
{
return
Variable_size_
composite_key_desc
::
size_of_length_field
+
return
Variable_size_
keys_descriptor
::
size_of_length_field
+
MY_TEST
(
field
->
maybe_null
());
MY_TEST
(
field
->
maybe_null
());
}
}
...
@@ -1538,7 +1538,7 @@ uint get_offset_to_value(Field *field)
...
@@ -1538,7 +1538,7 @@ uint get_offset_to_value(Field *field)
*/
*/
uchar
*
get_buffer_end
(
Field
*
field
,
uchar
*
to
)
uchar
*
get_buffer_end
(
Field
*
field
,
uchar
*
to
)
{
{
return
to
+
Variable_size_
composite_key_desc
::
read_packed_length
(
to
);
return
to
+
Variable_size_
keys_descriptor
::
read_packed_length
(
to
);
}
}
...
@@ -1719,11 +1719,11 @@ class Count_distinct_field: public Sql_alloc
...
@@ -1719,11 +1719,11 @@ class Count_distinct_field: public Sql_alloc
tree_key_length
=
table_field
->
tree_key_length
=
table_field
->
max_packed_col_length
(
table_field
->
pack_length
());
max_packed_col_length
(
table_field
->
pack_length
());
tree_key_length
+=
Variable_size_
composite_key_desc
::
size_of_length_field
;
tree_key_length
+=
Variable_size_
keys_descriptor
::
size_of_length_field
;
tree_key_length
+=
MY_TEST
(
table_field
->
maybe_null
());
tree_key_length
+=
MY_TEST
(
table_field
->
maybe_null
());
desc
=
new
Variable_size_keys_simple
(
tree_key_length
);
desc
=
new
Variable_size_keys_simple
(
tree_key_length
);
if
(
!
desc
)
if
(
!
desc
||
desc
->
init
()
)
return
true
;
// OOM
return
true
;
// OOM
tree
=
new
Unique_impl
((
qsort_cmp2
)
key_cmp
,
tree
=
new
Unique_impl
((
qsort_cmp2
)
key_cmp
,
(
void
*
)
this
,
tree_key_length
,
(
void
*
)
this
,
tree_key_length
,
...
...
sql/uniques.cc
View file @
04bf9996
...
@@ -890,68 +890,17 @@ Variable_size_keys_descriptor::~Variable_size_keys_descriptor()
...
@@ -890,68 +890,17 @@ Variable_size_keys_descriptor::~Variable_size_keys_descriptor()
Variable_size_composite_key_desc
::
Variable_size_composite_key_desc
(
uint
length
)
Variable_size_composite_key_desc
::
Variable_size_composite_key_desc
(
uint
length
)
:
Variable_size_keys_descriptor
(
length
)
:
Variable_size_keys_descriptor
(
length
)
,
Encode_record
()
{
{
}
}
Variable_size_keys_simple
::
Variable_size_keys_simple
(
uint
length
)
Variable_size_keys_simple
::
Variable_size_keys_simple
(
uint
length
)
:
Variable_size_keys_descriptor
(
length
)
:
Variable_size_keys_descriptor
(
length
)
,
Encode_record
()
{
{
}
}
/*
@brief
Make a record with packed values for a key
@retval
0 NULL value
>0 length of the packed record
*/
/*uint Variable_size_composite_key_desc::make_record(bool exclude_nulls)
{
Field *field;
SORT_FIELD *sort_field;
uint length;
uchar *orig_to, *to;
orig_to= to= packed_rec_ptr;
to+= size_of_length_field;
for (sort_field=sort_keys->begin() ;
sort_field != sort_keys->end() ;
sort_field++)
{
bool maybe_null=0;
if ((field=sort_field->field))
{
// Field
length= field->make_packed_key_part(to, sort_field);
}
else
{ // Item
Item *item= sort_field->item;
length= item->type_handler()->make_packed_sort_key_part(to, item,
sort_field,
&tmp_buffer);
}
if ((maybe_null= sort_field->maybe_null))
{
if (exclude_nulls && length == 0)
return 0; // NULL value
to++;
}
to+= length;
}
length= static_cast<uint>(to - orig_to);
store_packed_length(orig_to, length);
return length;
}
*/
/*
/*
@brief
@brief
Setup the structures that are used when Unique stores packed values
Setup the structures that are used when Unique stores packed values
...
@@ -1054,8 +1003,8 @@ bool Variable_size_keys_descriptor::setup(THD *thd, Field *field)
...
@@ -1054,8 +1003,8 @@ bool Variable_size_keys_descriptor::setup(THD *thd, Field *field)
int
Variable_size_composite_key_desc
::
compare_keys
(
uchar
*
a_ptr
,
int
Variable_size_composite_key_desc
::
compare_keys
(
uchar
*
a_ptr
,
uchar
*
b_ptr
)
uchar
*
b_ptr
)
{
{
uchar
*
a
=
a_ptr
+
Variable_size_
composite_key_desc
::
size_of_length_field
;
uchar
*
a
=
a_ptr
+
Variable_size_
keys_descriptor
::
size_of_length_field
;
uchar
*
b
=
b_ptr
+
Variable_size_
composite_key_desc
::
size_of_length_field
;
uchar
*
b
=
b_ptr
+
Variable_size_
keys_descriptor
::
size_of_length_field
;
int
retval
=
0
;
int
retval
=
0
;
size_t
a_len
,
b_len
;
size_t
a_len
,
b_len
;
for
(
SORT_FIELD
*
sort_field
=
sort_keys
->
begin
();
for
(
SORT_FIELD
*
sort_field
=
sort_keys
->
begin
();
...
@@ -1075,6 +1024,30 @@ int Variable_size_composite_key_desc::compare_keys(uchar *a_ptr,
...
@@ -1075,6 +1024,30 @@ int Variable_size_composite_key_desc::compare_keys(uchar *a_ptr,
}
}
uint
Variable_size_composite_key_desc
::
make_record
(
bool
exclude_nulls
)
{
return
make_encoded_record
(
sort_keys
,
exclude_nulls
);
}
uint
Variable_size_keys_simple
::
make_record
(
bool
exclude_nulls
)
{
return
make_encoded_record
(
sort_keys
,
exclude_nulls
);
}
bool
Variable_size_composite_key_desc
::
init
()
{
return
Encode_record
::
init
(
max_length
);
}
bool
Variable_size_keys_simple
::
init
()
{
return
Encode_record
::
init
(
max_length
);
}
int
Variable_size_keys_simple
::
compare_keys
(
uchar
*
a
,
uchar
*
b
)
int
Variable_size_keys_simple
::
compare_keys
(
uchar
*
a
,
uchar
*
b
)
{
{
return
sort_keys
->
compare_keys_for_single_arg
(
a
+
size_of_length_field
,
return
sort_keys
->
compare_keys_for_single_arg
(
a
+
size_of_length_field
,
...
@@ -1236,4 +1209,89 @@ int Fixed_size_keys_for_group_concat::compare_keys(uchar *key1, uchar *key2)
...
@@ -1236,4 +1209,89 @@ int Fixed_size_keys_for_group_concat::compare_keys(uchar *key1, uchar *key2)
return
res
;
return
res
;
}
}
return
0
;
return
0
;
}
bool
Encode_record
::
init
(
uint
length
)
{
if
(
tmp_buffer
.
alloc
(
length
))
return
true
;
rec_ptr
=
(
uchar
*
)
my_malloc
(
PSI_INSTRUMENT_ME
,
length
,
MYF
(
MY_WME
|
MY_THREAD_SPECIFIC
));
return
rec_ptr
==
NULL
;
}
Encode_record
::~
Encode_record
()
{
my_free
(
rec_ptr
);
}
/*
@brief
Make a record with packed values for a key
@retval
0 NULL value
>0 length of the packed record
*/
uint
Encode_record
::
make_encoded_record
(
Sort_keys
*
sort_keys
,
bool
exclude_nulls
)
{
Field
*
field
;
SORT_FIELD
*
sort_field
;
uint
length
;
uchar
*
orig_to
,
*
to
;
orig_to
=
to
=
rec_ptr
;
to
+=
Variable_size_keys_descriptor
::
size_of_length_field
;
for
(
sort_field
=
sort_keys
->
begin
()
;
sort_field
!=
sort_keys
->
end
()
;
sort_field
++
)
{
bool
maybe_null
=
0
;
if
((
field
=
sort_field
->
field
))
{
// Field
length
=
field
->
make_packed_sort_key_part
(
to
,
sort_field
);
}
else
{
// Item
Item
*
item
=
sort_field
->
item
;
length
=
item
->
type_handler
()
->
make_packed_sort_key_part
(
to
,
item
,
sort_field
,
&
tmp_buffer
);
}
if
((
maybe_null
=
sort_field
->
maybe_null
))
{
if
(
exclude_nulls
&&
length
==
0
)
// rejecting NULLS
return
0
;
to
++
;
}
to
+=
length
;
}
length
=
static_cast
<
uint
>
(
to
-
orig_to
);
Variable_size_keys_descriptor
::
store_packed_length
(
orig_to
,
length
);
return
length
;
}
uint
Encode_record_for_count_distinct
::
make_encoded_record
(
Sort_keys
*
sort_keys
,
bool
exclude_nulls
)
{
return
0
;
}
uint
Encode_record_for_group_concat
::
make_encoded_record
(
Sort_keys
*
sort_keys
,
bool
exclude_nulls
)
{
return
0
;
}
}
\ No newline at end of file
sql/uniques.h
View file @
04bf9996
...
@@ -67,6 +67,7 @@ class Descriptor : public Sql_alloc
...
@@ -67,6 +67,7 @@ class Descriptor : public Sql_alloc
/* need to be moved to a separate class */
/* need to be moved to a separate class */
virtual
uchar
*
get_rec_ptr
()
{
return
NULL
;
}
virtual
uchar
*
get_rec_ptr
()
{
return
NULL
;
}
virtual
uint
make_record
(
bool
exclude_nulls
)
{
return
0
;
}
virtual
uint
make_record
(
bool
exclude_nulls
)
{
return
0
;
}
virtual
bool
init
()
{
return
false
;
}
};
};
...
@@ -163,7 +164,7 @@ class Fixed_size_composite_keys_descriptor : public Fixed_size_keys_descriptor
...
@@ -163,7 +164,7 @@ class Fixed_size_composite_keys_descriptor : public Fixed_size_keys_descriptor
class
Encode_record
:
public
Sql_alloc
class
Encode_record
:
public
Sql_alloc
{
{
pr
ivate
:
pr
otected
:
/*
/*
Packed record ptr for a record of the table, the packed value in this
Packed record ptr for a record of the table, the packed value in this
record is added to the unique tree
record is added to the unique tree
...
@@ -172,16 +173,11 @@ class Encode_record : public Sql_alloc
...
@@ -172,16 +173,11 @@ class Encode_record : public Sql_alloc
uchar
*
rec_ptr
;
uchar
*
rec_ptr
;
String
tmp_buffer
;
String
tmp_buffer
;
Sort_keys
*
sort_keys
;
public:
public:
Encode_record
(
Sort_keys
*
keys
)
Encode_record
()
:
rec_ptr
(
NULL
)
{}
{
virtual
~
Encode_record
();
sort_keys
=
keys
;
virtual
uint
make_encoded_record
(
Sort_keys
*
keys
,
bool
exclude_nulls
);
rec_ptr
=
NULL
;
bool
init
(
uint
length
);
}
virtual
~
Encode_record
()
{}
virtual
uint
make_record
(
bool
exclude_nulls
)
{
return
0
;
}
uchar
*
get_packed_rec_ptr
()
{
return
rec_ptr
;
}
};
};
...
@@ -189,21 +185,18 @@ class Encode_record_for_count_distinct : public Encode_record
...
@@ -189,21 +185,18 @@ class Encode_record_for_count_distinct : public Encode_record
{
{
public:
public:
Encode_record_for_count_distinct
(
Sort_keys
*
keys
)
Encode_record_for_count_distinct
()
:
Encode_record
()
{}
:
Encode_record
(
keys
)
{}
~
Encode_record_for_count_distinct
()
{}
~
Encode_record_for_count_distinct
()
{}
uint
make_
record
(
bool
exclude_nulls
)
override
{
return
0
;
}
uint
make_
encoded_record
(
Sort_keys
*
keys
,
bool
exclude_nulls
)
override
;
};
};
class
Encode_record_for_group_concat
:
public
Encode_record
class
Encode_record_for_group_concat
:
public
Encode_record
{
{
public:
public:
Encode_record_for_group_concat
(
Sort_keys
*
keys
)
Encode_record_for_group_concat
()
:
Encode_record
()
{}
:
Encode_record
(
keys
)
{}
~
Encode_record_for_group_concat
()
{}
~
Encode_record_for_group_concat
()
{}
uint
make_record
(
bool
exclude_nulls
)
override
{
return
0
;
}
uint
make_encoded_record
(
Sort_keys
*
keys
,
bool
exclude_nulls
)
override
;
};
};
...
@@ -217,8 +210,6 @@ class Variable_size_keys_descriptor : public Descriptor
...
@@ -217,8 +210,6 @@ class Variable_size_keys_descriptor : public Descriptor
{
{
return
read_packed_length
(
ptr
);
return
read_packed_length
(
ptr
);
}
}
uint
make_record
(
bool
exclude_nulls
)
{
return
0
;}
uchar
*
get_packed_rec_ptr
()
{
return
NULL
;
}
Sort_keys
*
get_keys
()
{
return
sort_keys
;
}
Sort_keys
*
get_keys
()
{
return
sort_keys
;
}
SORT_FIELD
*
get_sortorder
()
{
return
sortorder
;
}
SORT_FIELD
*
get_sortorder
()
{
return
sortorder
;
}
bool
setup
(
THD
*
thd
,
Item_sum
*
item
,
uint
non_const_args
,
uint
arg_count
);
bool
setup
(
THD
*
thd
,
Item_sum
*
item
,
uint
non_const_args
,
uint
arg_count
);
...
@@ -230,7 +221,7 @@ class Variable_size_keys_descriptor : public Descriptor
...
@@ -230,7 +221,7 @@ class Variable_size_keys_descriptor : public Descriptor
{
{
return
size_of_length_field
+
uint4korr
(
p
);
return
size_of_length_field
+
uint4korr
(
p
);
}
}
void
store_packed_length
(
uchar
*
p
,
uint
sz
)
static
void
store_packed_length
(
uchar
*
p
,
uint
sz
)
{
{
int4store
(
p
,
sz
-
size_of_length_field
);
int4store
(
p
,
sz
-
size_of_length_field
);
}
}
...
@@ -241,23 +232,31 @@ class Variable_size_keys_descriptor : public Descriptor
...
@@ -241,23 +232,31 @@ class Variable_size_keys_descriptor : public Descriptor
/*
/*
Descriptor for variable size keys
Descriptor for variable size keys
*/
*/
class
Variable_size_composite_key_desc
:
public
Variable_size_keys_descriptor
class
Variable_size_composite_key_desc
:
public
Variable_size_keys_descriptor
,
public
Encode_record
{
{
public:
public:
Variable_size_composite_key_desc
(
uint
length
);
Variable_size_composite_key_desc
(
uint
length
);
~
Variable_size_composite_key_desc
()
{}
~
Variable_size_composite_key_desc
()
{}
int
compare_keys
(
uchar
*
a
,
uchar
*
b
)
override
;
int
compare_keys
(
uchar
*
a
,
uchar
*
b
)
override
;
uint
make_record
(
bool
exclude_nulls
)
override
;
bool
init
()
override
;
uchar
*
get_rec_ptr
()
{
return
rec_ptr
;
}
};
};
/* Descriptor for variable size keys with only one component */
/* Descriptor for variable size keys with only one component */
class
Variable_size_keys_simple
:
public
Variable_size_keys_descriptor
class
Variable_size_keys_simple
:
public
Variable_size_keys_descriptor
,
public
Encode_record
{
{
public:
public:
Variable_size_keys_simple
(
uint
length
);
Variable_size_keys_simple
(
uint
length
);
~
Variable_size_keys_simple
()
{}
~
Variable_size_keys_simple
()
{}
int
compare_keys
(
uchar
*
a
,
uchar
*
b
)
override
;
int
compare_keys
(
uchar
*
a
,
uchar
*
b
)
override
;
uint
make_record
(
bool
exclude_nulls
)
override
;
bool
init
()
override
;
uchar
*
get_rec_ptr
()
{
return
rec_ptr
;
}
};
};
...
...
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