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
4a5ecc92
Commit
4a5ecc92
authored
Jan 17, 2003
by
monty@mashka.mysql.fi
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
36d5d147
762cb225
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
100 additions
and
72 deletions
+100
-72
sql/field.cc
sql/field.cc
+32
-33
sql/sql_base.cc
sql/sql_base.cc
+1
-0
sql/sql_lex.cc
sql/sql_lex.cc
+16
-11
sql/sql_lex.h
sql/sql_lex.h
+2
-1
strings/ctype-simple.c
strings/ctype-simple.c
+30
-20
strings/ctype-utf8.c
strings/ctype-utf8.c
+19
-7
No files found.
sql/field.cc
View file @
4a5ecc92
...
...
@@ -840,17 +840,19 @@ int Field_decimal::store(longlong nr)
double
Field_decimal
::
val_real
(
void
)
{
int
err
;
return
my_strntod
(
my_charset_bin
,
ptr
,
field_length
,
NULL
,
&
err
);
int
not_used
;
return
my_strntod
(
my_charset_bin
,
ptr
,
field_length
,
NULL
,
&
not_used
);
}
longlong
Field_decimal
::
val_int
(
void
)
{
int
err
;
int
not_used
;
if
(
unsigned_flag
)
return
my_strntoull
(
my_charset_bin
,
ptr
,
field_length
,
10
,
NULL
,
&
err
);
return
my_strntoull
(
my_charset_bin
,
ptr
,
field_length
,
10
,
NULL
,
&
not_used
);
else
return
my_strntoll
(
my_charset_bin
,
ptr
,
field_length
,
10
,
NULL
,
&
err
);
return
my_strntoll
(
my_charset_bin
,
ptr
,
field_length
,
10
,
NULL
,
&
not_used
);
}
...
...
@@ -952,9 +954,9 @@ void Field_decimal::sql_type(String &res) const
int
Field_tiny
::
store
(
const
char
*
from
,
uint
len
,
CHARSET_INFO
*
cs
)
{
int
err
;
int
not_used
;
// We can ignore result from str2int
char
*
end
;
long
tmp
=
my_strntol
(
cs
,
from
,
len
,
10
,
&
end
,
&
err
);
long
tmp
=
my_strntol
(
cs
,
from
,
len
,
10
,
&
end
,
&
not_used
);
int
error
=
0
;
if
(
unsigned_flag
)
...
...
@@ -1154,10 +1156,11 @@ void Field_tiny::sql_type(String &res) const
int
Field_short
::
store
(
const
char
*
from
,
uint
len
,
CHARSET_INFO
*
cs
)
{
int
err
;
int
not_used
;
// We can ignore result from str2int
char
*
end
;
long
tmp
=
my_strntol
(
cs
,
from
,
len
,
10
,
&
end
,
&
err
);
long
tmp
=
my_strntol
(
cs
,
from
,
len
,
10
,
&
end
,
&
not_used
);
int
error
=
0
;
if
(
unsigned_flag
)
{
if
(
tmp
<
0
)
...
...
@@ -1427,9 +1430,9 @@ void Field_short::sql_type(String &res) const
int
Field_medium
::
store
(
const
char
*
from
,
uint
len
,
CHARSET_INFO
*
cs
)
{
int
err
;
int
not_used
;
// We can ignore result from str2int
char
*
end
;
long
tmp
=
my_strntol
(
cs
,
from
,
len
,
10
,
&
end
,
&
err
);
long
tmp
=
my_strntol
(
cs
,
from
,
len
,
10
,
&
end
,
&
not_used
);
int
error
=
0
;
if
(
unsigned_flag
)
...
...
@@ -2134,7 +2137,7 @@ void Field_longlong::sql_type(String &res) const
int
Field_float
::
store
(
const
char
*
from
,
uint
len
,
CHARSET_INFO
*
cs
)
{
int
err
=
0
;
int
err
;
Field_float
::
store
(
my_strntod
(
cs
,(
char
*
)
from
,
len
,(
char
**
)
NULL
,
&
err
));
if
(
err
||
current_thd
->
count_cuted_fields
&&
!
test_if_real
(
from
,
len
,
cs
))
{
...
...
@@ -2407,7 +2410,7 @@ void Field_float::sql_type(String &res) const
int
Field_double
::
store
(
const
char
*
from
,
uint
len
,
CHARSET_INFO
*
cs
)
{
int
err
=
0
;
int
err
;
double
j
=
my_strntod
(
cs
,(
char
*
)
from
,
len
,(
char
**
)
0
,
&
err
);
if
(
err
||
current_thd
->
count_cuted_fields
&&
!
test_if_real
(
from
,
len
,
cs
))
{
...
...
@@ -3193,9 +3196,9 @@ void Field_time::sql_type(String &res) const
int
Field_year
::
store
(
const
char
*
from
,
uint
len
,
CHARSET_INFO
*
cs
)
{
int
err
;
int
not_used
;
// We can ignore result from str2int
char
*
end
;
long
nr
=
my_strntol
(
cs
,
from
,
len
,
10
,
&
end
,
&
err
);
long
nr
=
my_strntol
(
cs
,
from
,
len
,
10
,
&
end
,
&
not_used
);
if
(
nr
<
0
||
nr
>=
100
&&
nr
<=
1900
||
nr
>
2155
)
{
...
...
@@ -3932,17 +3935,17 @@ int Field_string::store(longlong nr)
double
Field_string
::
val_real
(
void
)
{
int
err
;
int
not_used
;
CHARSET_INFO
*
cs
=
charset
();
return
my_strntod
(
cs
,
ptr
,
field_length
,(
char
**
)
0
,
&
err
);
return
my_strntod
(
cs
,
ptr
,
field_length
,(
char
**
)
0
,
&
not_used
);
}
longlong
Field_string
::
val_int
(
void
)
{
int
err
;
int
not_used
;
CHARSET_INFO
*
cs
=
charset
();
return
my_strntoll
(
cs
,
ptr
,
field_length
,
10
,
NULL
,
&
err
);
return
my_strntoll
(
cs
,
ptr
,
field_length
,
10
,
NULL
,
&
not_used
);
}
...
...
@@ -4017,7 +4020,6 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length)
{
uint
a_length
=
(
uint
)
(
uchar
)
*
a
++
;
uint
b_length
=
(
uint
)
(
uchar
)
*
b
++
;
return
my_strnncoll
(
field_charset
,
(
const
uchar
*
)
a
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
...
...
@@ -4031,7 +4033,6 @@ int Field_string::pack_cmp(const char *b, uint length)
while
(
end
>
ptr
&&
end
[
-
1
]
==
' '
)
end
--
;
uint
a_length
=
(
uint
)
(
end
-
ptr
);
return
my_strnncoll
(
field_charset
,
(
const
uchar
*
)
ptr
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
...
...
@@ -4101,19 +4102,19 @@ int Field_varstring::store(longlong nr)
double
Field_varstring
::
val_real
(
void
)
{
int
err
;
int
not_used
;
uint
length
=
uint2korr
(
ptr
)
+
2
;
CHARSET_INFO
*
cs
=
charset
();
return
my_strntod
(
cs
,
ptr
+
2
,
length
,(
char
**
)
0
,
&
err
);
return
my_strntod
(
cs
,
ptr
+
2
,
length
,(
char
**
)
0
,
&
not_used
);
}
longlong
Field_varstring
::
val_int
(
void
)
{
int
err
;
int
not_used
;
uint
length
=
uint2korr
(
ptr
)
+
2
;
CHARSET_INFO
*
cs
=
charset
();
return
my_strntoll
(
cs
,
ptr
+
2
,
length
,
10
,
NULL
,
&
err
);
return
my_strntoll
(
cs
,
ptr
+
2
,
length
,
10
,
NULL
,
&
not_used
);
}
...
...
@@ -4421,26 +4422,26 @@ int Field_blob::store(longlong nr)
double
Field_blob
::
val_real
(
void
)
{
int
err
;
int
not_used
;
char
*
blob
;
memcpy_fixed
(
&
blob
,
ptr
+
packlength
,
sizeof
(
char
*
));
if
(
!
blob
)
return
0.0
;
uint32
length
=
get_length
(
ptr
);
CHARSET_INFO
*
cs
=
charset
();
return
my_strntod
(
cs
,
blob
,
length
,(
char
**
)
0
,
&
err
);
return
my_strntod
(
cs
,
blob
,
length
,(
char
**
)
0
,
&
not_used
);
}
longlong
Field_blob
::
val_int
(
void
)
{
int
err
;
int
not_used
;
char
*
blob
;
memcpy_fixed
(
&
blob
,
ptr
+
packlength
,
sizeof
(
char
*
));
if
(
!
blob
)
return
0
;
uint32
length
=
get_length
(
ptr
);
return
my_strntoll
(
charset
(),
blob
,
length
,
10
,
NULL
,
&
err
);
return
my_strntoll
(
charset
(),
blob
,
length
,
10
,
NULL
,
&
not_used
);
}
...
...
@@ -4610,10 +4611,8 @@ void Field_blob::sort_string(char *to,uint length)
blob_length
=
my_strnxfrm
(
field_charset
,
(
unsigned
char
*
)
to
,
length
,
(
unsigned
char
*
)
blob
,
blob_length
);
if
(
blob_length
>=
length
)
return
;
to
+=
blob_length
;
bzero
(
to
,
length
-
blob_length
);
if
(
blob_length
<
length
)
bzero
(
to
+
blob_length
,
length
-
blob_length
);
}
}
...
...
sql/sql_base.cc
View file @
4a5ecc92
...
...
@@ -242,6 +242,7 @@ static void free_cache_entry(TABLE *table)
DBUG_VOID_RETURN
;
}
/* Free resources allocated by filesort() and read_record() */
void
free_io_cache
(
TABLE
*
table
)
{
...
...
sql/sql_lex.cc
View file @
4a5ecc92
...
...
@@ -107,7 +107,7 @@ void lex_init(void)
state_map
[
i
]
=
(
uchar
)
STATE_CHAR
;
}
state_map
[(
uchar
)
'_'
]
=
state_map
[(
uchar
)
'$'
]
=
(
uchar
)
STATE_IDENT
;
state_map
[(
uchar
)
'\''
]
=
state_map
[(
uchar
)
'"'
]
=
(
uchar
)
STATE_STRING
;
state_map
[(
uchar
)
'\''
]
=
(
uchar
)
STATE_STRING
;
state_map
[(
uchar
)
'-'
]
=
state_map
[(
uchar
)
'+'
]
=
(
uchar
)
STATE_SIGNED_NUMBER
;
state_map
[(
uchar
)
'.'
]
=
(
uchar
)
STATE_REAL_OR_POINT
;
state_map
[(
uchar
)
'>'
]
=
state_map
[(
uchar
)
'='
]
=
state_map
[(
uchar
)
'!'
]
=
(
uchar
)
STATE_CMP_OP
;
...
...
@@ -122,10 +122,7 @@ void lex_init(void)
state_map
[(
uchar
)
'*'
]
=
(
uchar
)
STATE_END_LONG_COMMENT
;
state_map
[(
uchar
)
'@'
]
=
(
uchar
)
STATE_USER_END
;
state_map
[(
uchar
)
'`'
]
=
(
uchar
)
STATE_USER_VARIABLE_DELIMITER
;
if
(
global_system_variables
.
sql_mode
&
MODE_ANSI_QUOTES
)
{
state_map
[(
uchar
)
'"'
]
=
STATE_USER_VARIABLE_DELIMITER
;
}
state_map
[(
uchar
)
'"'
]
=
(
uchar
)
STAT_STRING_OR_DELIMITER
;
/*
Create a second map to make it faster to find identifiers
...
...
@@ -652,12 +649,13 @@ int yylex(void *arg, void *yythd)
return
(
IDENT
);
case
STATE_USER_VARIABLE_DELIMITER
:
{
char
delim
=
c
;
// Used char
lex
->
tok_start
=
lex
->
ptr
;
// Skip first `
#ifdef USE_MB
if
(
use_mb
(
system_charset_info
))
{
while
((
c
=
yyGet
())
&&
state_map
[
c
]
!=
STATE_USER_VARIABLE_DELIMITER
&&
c
!=
(
uchar
)
NAMES_SEP_CHAR
)
while
((
c
=
yyGet
())
&&
c
!=
delim
&&
c
!=
(
uchar
)
NAMES_SEP_CHAR
)
{
if
(
my_ismbhead
(
system_charset_info
,
c
))
{
...
...
@@ -673,16 +671,15 @@ int yylex(void *arg, void *yythd)
else
#endif
{
while
((
c
=
yyGet
())
&&
state_map
[
c
]
!=
STATE_USER_VARIABLE_DELIMITER
&&
c
!=
(
uchar
)
NAMES_SEP_CHAR
)
;
while
((
c
=
yyGet
())
&&
c
!=
delim
&&
c
!=
(
uchar
)
NAMES_SEP_CHAR
)
;
}
yylval
->
lex_str
=
get_token
(
lex
,
yyLength
());
if
(
lex
->
convert_set
)
lex
->
convert_set
->
convert
((
char
*
)
yylval
->
lex_str
.
str
,
lex
->
yytoklen
);
if
(
state_map
[
c
]
==
STATE_USER_VARIABLE_DELIMITER
)
if
(
c
==
delim
)
yySkip
();
// Skip end `
return
(
IDENT
);
}
case
STATE_SIGNED_NUMBER
:
// Incomplete signed number
if
(
prev_state
==
STATE_OPERATOR_OR_IDENT
)
{
...
...
@@ -795,6 +792,13 @@ int yylex(void *arg, void *yythd)
lex
->
next_state
=
STATE_START
;
// Allow signed numbers
return
(
tokval
);
case
STAT_STRING_OR_DELIMITER
:
if
(((
THD
*
)
yythd
)
->
variables
.
sql_mode
&
MODE_ANSI_QUOTES
)
{
state
=
STATE_USER_VARIABLE_DELIMITER
;
break
;
}
/* " used for strings */
case
STATE_STRING
:
// Incomplete text string
if
(
!
(
yylval
->
lex_str
.
str
=
get_text
(
lex
)))
{
...
...
@@ -889,6 +893,7 @@ int yylex(void *arg, void *yythd)
switch
(
state_map
[
yyPeek
()])
{
case
STATE_STRING
:
case
STATE_USER_VARIABLE_DELIMITER
:
case
STAT_STRING_OR_DELIMITER
:
break
;
case
STATE_USER_END
:
lex
->
next_state
=
STATE_SYSTEM_VAR
;
...
...
sql/sql_lex.h
View file @
4a5ecc92
...
...
@@ -86,7 +86,8 @@ enum lex_states
STATE_REAL_OR_POINT
,
STATE_BOOL
,
STATE_EOL
,
STATE_ESCAPE
,
STATE_LONG_COMMENT
,
STATE_END_LONG_COMMENT
,
STATE_COLON
,
STATE_SET_VAR
,
STATE_USER_END
,
STATE_HOSTNAME
,
STATE_SKIP
,
STATE_USER_VARIABLE_DELIMITER
,
STATE_SYSTEM_VAR
,
STATE_IDENT_OR_KEYWORD
,
STATE_IDENT_OR_HEX
,
STATE_IDENT_OR_BIN
STATE_IDENT_OR_KEYWORD
,
STATE_IDENT_OR_HEX
,
STATE_IDENT_OR_BIN
,
STAT_STRING_OR_DELIMITER
};
...
...
strings/ctype-simple.c
View file @
4a5ecc92
...
...
@@ -214,7 +214,8 @@ long my_strntol_8bit(CHARSET_INFO *cs,
const
char
*
save
,
*
e
;
int
overflow
;
#if 0
*
err
=
0
;
/* Initialize error indicator */
#ifdef NOT_USED
if
(
base
<
0
||
base
==
1
||
base
>
36
)
base
=
10
;
#endif
...
...
@@ -243,12 +244,12 @@ long my_strntol_8bit(CHARSET_INFO *cs,
else
negative
=
0
;
#if
0
#if
def NOT_USED
if
(
base
==
16
&&
s
[
0
]
==
'0'
&&
(
s
[
1
]
==
'X'
||
s
[
1
]
==
'x'
))
s
+=
2
;
#endif
#if
0
#if
def NOT_USED
if
(
base
==
0
)
{
if
(
*
s
==
'0'
)
...
...
@@ -336,7 +337,8 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs,
const
char
*
save
,
*
e
;
int
overflow
;
#if 0
*
err
=
0
;
/* Initialize error indicator */
#ifdef NOT_USED
if
(
base
<
0
||
base
==
1
||
base
>
36
)
base
=
10
;
#endif
...
...
@@ -364,12 +366,12 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs,
else
negative
=
0
;
#if
0
#if
def NOT_USED
if
(
base
==
16
&&
s
[
0
]
==
'0'
&&
(
s
[
1
]
==
'X'
||
s
[
1
]
==
'x'
))
s
+=
2
;
#endif
#if
0
#if
def NOT_USED
if
(
base
==
0
)
{
if
(
*
s
==
'0'
)
...
...
@@ -449,7 +451,8 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)),
const
char
*
save
;
int
overflow
;
#if 0
*
err
=
0
;
/* Initialize error indicator */
#ifdef NOT_USED
if
(
base
<
0
||
base
==
1
||
base
>
36
)
base
=
10
;
#endif
...
...
@@ -477,12 +480,12 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)),
else
negative
=
0
;
#if
0
#if
def NOT_USED
if
(
base
==
16
&&
s
[
0
]
==
'0'
&&
(
s
[
1
]
==
'X'
||
s
[
1
]
==
'x'
))
s
+=
2
;
#endif
#if
0
#if
def NOT_USED
if
(
base
==
0
)
{
if
(
*
s
==
'0'
)
...
...
@@ -571,7 +574,8 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
const
char
*
save
;
int
overflow
;
#if 0
*
err
=
0
;
/* Initialize error indicator */
#ifdef NOT_USED
if
(
base
<
0
||
base
==
1
||
base
>
36
)
base
=
10
;
#endif
...
...
@@ -599,12 +603,12 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
else
negative
=
0
;
#if
0
#if
def NOT_USED
if
(
base
==
16
&&
s
[
0
]
==
'0'
&&
(
s
[
1
]
==
'X'
||
s
[
1
]
==
'x'
))
s
+=
2
;
#endif
#if
0
#if
def NOT_USED
if
(
base
==
0
)
{
if
(
*
s
==
'0'
)
...
...
@@ -679,7 +683,8 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
cs Character set information
str String to convert to double
length Optional length for string.
end pointer to end of converted string
end result pointer to end of converted string
err Error number if failed conversion
NOTES:
If length is not INT_MAX32 or str[length] != 0 then the given str must
...
...
@@ -689,23 +694,28 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
It's implemented this way to save a buffer allocation and a memory copy.
RETURN
v
alue of number in string
V
alue of number in string
*/
double
my_strntod_8bit
(
CHARSET_INFO
*
cs
__attribute__
((
unused
)),
char
*
str
,
uint
length
,
char
**
end
,
int
*
err
__attribute__
((
unused
))
)
char
**
end
,
int
*
err
)
{
char
end_char
;
double
result
;
errno
=
0
;
/* Safety */
if
(
length
==
INT_MAX32
||
str
[
length
]
==
0
)
return
strtod
(
str
,
end
);
end_char
=
str
[
length
];
str
[
length
]
=
0
;
result
=
strtod
(
str
,
end
);
str
[
length
]
=
end_char
;
/* Restore end char */
result
=
strtod
(
str
,
end
);
else
{
end_char
=
str
[
length
];
str
[
length
]
=
0
;
result
=
strtod
(
str
,
end
);
str
[
length
]
=
end_char
;
/* Restore end char */
}
*
err
=
errno
;
return
result
;
}
...
...
strings/ctype-utf8.c
View file @
4a5ecc92
...
...
@@ -2464,7 +2464,9 @@ long my_strntol_ucs2(CHARSET_INFO *cs,
register
const
char
*
e
=
nptr
+
l
;
const
char
*
save
;
do
{
*
err
=
0
;
do
{
if
((
cnv
=
cs
->
mb_wc
(
cs
,
&
wc
,
s
,
e
))
>
0
)
{
switch
(
wc
)
...
...
@@ -2577,7 +2579,9 @@ ulong my_strntoul_ucs2(CHARSET_INFO *cs,
register
const
char
*
e
=
nptr
+
l
;
const
char
*
save
;
do
{
*
err
=
0
;
do
{
if
((
cnv
=
cs
->
mb_wc
(
cs
,
&
wc
,
s
,
e
))
>
0
)
{
switch
(
wc
)
...
...
@@ -2684,7 +2688,9 @@ longlong my_strntoll_ucs2(CHARSET_INFO *cs,
register
const
char
*
e
=
nptr
+
l
;
const
char
*
save
;
do
{
*
err
=
0
;
do
{
if
((
cnv
=
cs
->
mb_wc
(
cs
,
&
wc
,
s
,
e
))
>
0
)
{
switch
(
wc
)
...
...
@@ -2799,7 +2805,9 @@ ulonglong my_strntoull_ucs2(CHARSET_INFO *cs,
register
const
char
*
e
=
nptr
+
l
;
const
char
*
save
;
do
{
*
err
=
0
;
do
{
if
((
cnv
=
cs
->
mb_wc
(
cs
,
&
wc
,
s
,
e
))
>
0
)
{
switch
(
wc
)
...
...
@@ -2834,7 +2842,8 @@ ulonglong my_strntoull_ucs2(CHARSET_INFO *cs,
cutoff
=
(
~
(
ulonglong
)
0
)
/
(
unsigned
long
int
)
base
;
cutlim
=
(
uint
)
((
~
(
ulonglong
)
0
)
%
(
unsigned
long
int
)
base
);
do
{
do
{
if
((
cnv
=
cs
->
mb_wc
(
cs
,
&
wc
,
s
,
e
))
>
0
)
{
s
+=
cnv
;
...
...
@@ -2891,7 +2900,7 @@ ulonglong my_strntoull_ucs2(CHARSET_INFO *cs,
double
my_strntod_ucs2
(
CHARSET_INFO
*
cs
__attribute__
((
unused
)),
char
*
nptr
,
uint
length
,
char
**
endptr
,
int
*
err
__attribute__
((
unused
))
)
char
**
endptr
,
int
*
err
)
{
char
buf
[
256
];
double
res
;
...
...
@@ -2900,7 +2909,8 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
register
const
char
*
end
;
my_wc_t
wc
;
int
cnv
;
*
err
=
0
;
/* Cut too long strings */
if
(
length
>=
sizeof
(
buf
))
length
=
sizeof
(
buf
)
-
1
;
...
...
@@ -2915,7 +2925,9 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
}
*
b
=
0
;
errno
=
0
;
res
=
strtod
(
buf
,
endptr
);
*
err
=
errno
;
if
(
endptr
)
*
endptr
=
(
char
*
)
(
*
endptr
-
buf
+
nptr
);
return
res
;
...
...
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