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
f90828cb
Commit
f90828cb
authored
Sep 24, 2004
by
unknown
Browse files
Options
Browse Files
Download
Plain Diff
Merge tulin@bk-internal.mysql.com:/home/bk/mysql-4.1-ndb
into poseidon.ndb.mysql.com:/home/tomas/mysql-4.1-ndb-merge
parents
2917d9fd
6876d28c
Changes
26
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
377 additions
and
126 deletions
+377
-126
BitKeeper/etc/logging_ok
BitKeeper/etc/logging_ok
+1
-0
configure.in
configure.in
+1
-1
include/hash.h
include/hash.h
+1
-1
include/my_sys.h
include/my_sys.h
+2
-1
libmysql/client_settings.h
libmysql/client_settings.h
+1
-0
libmysql/libmysql.c
libmysql/libmysql.c
+21
-12
mysql-test/r/gis.result
mysql-test/r/gis.result
+7
-0
mysql-test/r/ps.result
mysql-test/r/ps.result
+8
-0
mysql-test/r/rpl_charset.result
mysql-test/r/rpl_charset.result
+8
-0
mysql-test/r/type_enum.result
mysql-test/r/type_enum.result
+16
-0
mysql-test/t/gis.test
mysql-test/t/gis.test
+4
-0
mysql-test/t/ps.test
mysql-test/t/ps.test
+10
-0
mysql-test/t/rpl_charset.test
mysql-test/t/rpl_charset.test
+18
-0
mysql-test/t/type_enum.test
mysql-test/t/type_enum.test
+14
-0
mysys/hash.c
mysys/hash.c
+26
-0
mysys/my_alloc.c
mysys/my_alloc.c
+32
-5
sql-common/client.c
sql-common/client.c
+27
-14
sql/item_cmpfunc.cc
sql/item_cmpfunc.cc
+14
-12
sql/item_geofunc.cc
sql/item_geofunc.cc
+15
-18
sql/item_geofunc.h
sql/item_geofunc.h
+32
-30
sql/log_event.cc
sql/log_event.cc
+9
-1
sql/opt_range.cc
sql/opt_range.cc
+6
-2
sql/sql_class.cc
sql/sql_class.cc
+47
-23
sql/sql_class.h
sql/sql_class.h
+24
-5
sql/sql_show.cc
sql/sql_show.cc
+2
-0
tests/client_test.c
tests/client_test.c
+31
-1
No files found.
BitKeeper/etc/logging_ok
View file @
f90828cb
...
...
@@ -24,6 +24,7 @@ bar@bar.udmsearch.izhnet.ru
bar@deer.(none)
bar@gw.udmsearch.izhnet.ru
bar@mysql.com
bar@noter.intranet.mysql.r18.ru
bell@laptop.sanja.is.com.ua
bell@sanja.is.com.ua
bk@admin.bk
...
...
configure.in
View file @
f90828cb
...
...
@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT
(
sql/mysqld.cc
)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
AM_INIT_AUTOMAKE
(
mysql, 4.1.
5
-gamma
)
AM_INIT_AUTOMAKE
(
mysql, 4.1.
6
-gamma
)
AM_CONFIG_HEADER
(
config.h
)
PROTOCOL_VERSION
=
10
...
...
include/hash.h
View file @
f90828cb
...
...
@@ -47,6 +47,7 @@ my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
uint
key_length
,
hash_get_key
get_key
,
void
(
*
free_element
)(
void
*
),
uint
flags
CALLER_INFO_PROTO
);
void
hash_free
(
HASH
*
tree
);
void
hash_reset
(
HASH
*
hash
);
byte
*
hash_element
(
HASH
*
hash
,
uint
idx
);
gptr
hash_search
(
HASH
*
info
,
const
byte
*
key
,
uint
length
);
gptr
hash_next
(
HASH
*
info
,
const
byte
*
key
,
uint
length
);
...
...
@@ -56,7 +57,6 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length);
void
hash_replace
(
HASH
*
hash
,
uint
idx
,
byte
*
new_row
);
my_bool
hash_check
(
HASH
*
hash
);
/* Only in debug library */
#define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
#define hash_inited(H) ((H)->array.buffer != 0)
#ifdef __cplusplus
...
...
include/my_sys.h
View file @
f90828cb
...
...
@@ -725,7 +725,8 @@ extern void my_free_lock(byte *ptr,myf flags);
#define my_free_lock(A,B) my_free((A),(B))
#endif
#define alloc_root_inited(A) ((A)->min_malloc != 0)
#define clear_alloc_root(A) bzero((void *) (A), sizeof(MEM_ROOT))
#define ALLOC_ROOT_MIN_BLOCK_SIZE (MALLOC_OVERHEAD + sizeof(USED_MEM) + 8)
#define clear_alloc_root(A) do { (A)->free= (A)->used= (A)->pre_alloc= 0; } while(0)
extern
void
init_alloc_root
(
MEM_ROOT
*
mem_root
,
uint
block_size
,
uint
pre_alloc_size
);
extern
gptr
alloc_root
(
MEM_ROOT
*
mem_root
,
unsigned
int
Size
);
...
...
libmysql/client_settings.h
View file @
f90828cb
...
...
@@ -42,6 +42,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename);
void
mysql_read_default_options
(
struct
st_mysql_options
*
options
,
const
char
*
filename
,
const
char
*
group
);
void
mysql_detach_stmt_list
(
LIST
**
stmt_list
);
MYSQL
*
STDCALL
cli_mysql_real_connect
(
MYSQL
*
mysql
,
const
char
*
host
,
const
char
*
user
,
const
char
*
passwd
,
const
char
*
db
,
...
...
libmysql/libmysql.c
View file @
f90828cb
...
...
@@ -662,6 +662,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const
char
*
passwd
,
const
char
*
db
)
{
char
buff
[
512
],
*
end
=
buff
;
int
rc
;
DBUG_ENTER
(
"mysql_change_user"
);
if
(
!
user
)
...
...
@@ -695,18 +696,26 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
/* Write authentication package */
simple_command
(
mysql
,
COM_CHANGE_USER
,
buff
,(
ulong
)
(
end
-
buff
),
1
);
if
((
*
mysql
->
methods
->
read_change_user_result
)(
mysql
,
buff
,
passwd
))
DBUG_RETURN
(
1
);
/* Free old connect information */
my_free
(
mysql
->
user
,
MYF
(
MY_ALLOW_ZERO_PTR
));
my_free
(
mysql
->
passwd
,
MYF
(
MY_ALLOW_ZERO_PTR
));
my_free
(
mysql
->
db
,
MYF
(
MY_ALLOW_ZERO_PTR
));
/* alloc new connect information */
mysql
->
user
=
my_strdup
(
user
,
MYF
(
MY_WME
));
mysql
->
passwd
=
my_strdup
(
passwd
,
MYF
(
MY_WME
));
mysql
->
db
=
db
?
my_strdup
(
db
,
MYF
(
MY_WME
))
:
0
;
DBUG_RETURN
(
0
);
rc
=
(
*
mysql
->
methods
->
read_change_user_result
)(
mysql
,
buff
,
passwd
);
/*
The server will close all statements no matter was the attempt
to change user successful or not.
*/
mysql_detach_stmt_list
(
&
mysql
->
stmts
);
if
(
rc
==
0
)
{
/* Free old connect information */
my_free
(
mysql
->
user
,
MYF
(
MY_ALLOW_ZERO_PTR
));
my_free
(
mysql
->
passwd
,
MYF
(
MY_ALLOW_ZERO_PTR
));
my_free
(
mysql
->
db
,
MYF
(
MY_ALLOW_ZERO_PTR
));
/* alloc new connect information */
mysql
->
user
=
my_strdup
(
user
,
MYF
(
MY_WME
));
mysql
->
passwd
=
my_strdup
(
passwd
,
MYF
(
MY_WME
));
mysql
->
db
=
db
?
my_strdup
(
db
,
MYF
(
MY_WME
))
:
0
;
}
DBUG_RETURN
(
rc
);
}
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
...
...
mysql-test/r/gis.result
View file @
f90828cb
...
...
@@ -485,3 +485,10 @@ MBRContains(GeomFromText('Polygon((0 0, 0 7, 7 7, 7 0, 0 0))'), a);
AsText(a)
POINT(1 1)
drop table t1;
create table t1 select POINT(1,3);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`POINT(1,3)` longblob NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
mysql-test/r/ps.result
View file @
f90828cb
...
...
@@ -289,3 +289,11 @@ execute stmt using @var;
select * from t1;
deallocate prepare stmt;
drop table t1;
prepare stmt from "select 'abc' like convert('abc' using utf8)";
execute stmt;
'abc' like convert('abc' using utf8)
1
execute stmt;
'abc' like convert('abc' using utf8)
1
deallocate prepare stmt;
mysql-test/r/rpl_charset.result
View file @
f90828cb
...
...
@@ -198,4 +198,12 @@ CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3
select hex(c1), hex(c2) from t1;
hex(c1) hex(c2)
CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3
stop slave;
delete from t1;
change master to master_log_pos=5801;
start slave until master_log_file='master-bin.000001', master_log_pos=5937;
start slave;
select hex(c1), hex(c2) from t1;
hex(c1) hex(c2)
CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3
drop table t1;
mysql-test/r/type_enum.result
View file @
f90828cb
...
...
@@ -1661,3 +1661,19 @@ t1 CREATE TABLE `t1` (
`a` enum('','1','2') NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
set names latin1;
CREATE TABLE t1 (
a INT default 1,
b ENUM('value','_value','') character set latin1 NOT NULL
);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) default '1',
`b` enum('value','_value','') NOT NULL default 'value'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show columns from t1;
Field Type Null Key Default Extra
a int(11) YES 1
b enum('value','_value','') value
drop table t1;
mysql-test/t/gis.test
View file @
f90828cb
...
...
@@ -190,3 +190,7 @@ select AsText(a) from t1 where
and
MBRContains
(
GeomFromText
(
'Polygon((0 0, 0 7, 7 7, 7 0, 0 0))'
),
a
);
drop
table
t1
;
create
table
t1
select
POINT
(
1
,
3
);
show
create
table
t1
;
drop
table
t1
;
mysql-test/t/ps.test
View file @
f90828cb
...
...
@@ -304,3 +304,13 @@ select * from t1;
deallocate
prepare
stmt
;
drop
table
t1
;
#
# BUG#5688 "Upgraded 4.1.5 Server seg faults" # (prepared statements)
# The test case speaks for itself.
# Just another place where we used wrong memory root for Items created
# during statement prepare.
#
prepare
stmt
from
"select 'abc' like convert('abc' using utf8)"
;
execute
stmt
;
execute
stmt
;
deallocate
prepare
stmt
;
mysql-test/t/rpl_charset.test
View file @
f90828cb
...
...
@@ -148,6 +148,24 @@ INSERT INTO t1 (c1, c2) VALUES ('
select
hex
(
c1
),
hex
(
c2
)
from
t1
;
sync_slave_with_master
;
select
hex
(
c1
),
hex
(
c2
)
from
t1
;
# Now test for BUG##5705: SET CHARATER_SET_SERVERetc will be lost if
# STOP SLAVE before following query
stop
slave
;
delete
from
t1
;
change
master
to
master_log_pos
=
5801
;
start
slave
until
master_log_file
=
'master-bin.000001'
,
master_log_pos
=
5937
;
# Slave is supposed to stop _after_ the INSERT, even though 5937 is
# the position of the beginning of the INSERT; after SET slave is not
# supposed to increment position.
wait_for_slave_to_stop
;
# When you merge this into 5.0 you will have to adjust positions
# above; the first master_log_pos above should be the one of the SET,
# the second should be the one of the INSERT.
start
slave
;
sync_with_master
;
select
hex
(
c1
),
hex
(
c2
)
from
t1
;
connection
master
;
drop
table
t1
;
sync_slave_with_master
;
mysql-test/t/type_enum.test
View file @
f90828cb
...
...
@@ -45,3 +45,17 @@ create table t1 (a enum(0xE4, '1', '2') not null default 0xE4);
show
columns
from
t1
;
show
create
table
t1
;
drop
table
t1
;
#
# Bug #5628 German characters in field-defs will be '?'
# with some table definitions
#
set
names
latin1
;
CREATE
TABLE
t1
(
a
INT
default
1
,
b
ENUM
(
'value'
,
'_value'
,
''
)
character
set
latin1
NOT
NULL
);
show
create
table
t1
;
show
columns
from
t1
;
drop
table
t1
;
mysys/hash.c
View file @
f90828cb
...
...
@@ -88,6 +88,32 @@ void hash_free(HASH *hash)
DBUG_VOID_RETURN
;
}
/*
Delete all elements from the hash (the hash itself is to be reused).
SYNOPSIS
hash_reset()
hash the hash to delete elements of
*/
void
hash_reset
(
HASH
*
hash
)
{
DBUG_ENTER
(
"hash_reset"
);
if
(
hash
->
free
)
{
HASH_LINK
*
link
=
dynamic_element
(
&
hash
->
array
,
0
,
HASH_LINK
*
);
HASH_LINK
*
end
=
link
+
hash
->
records
;
for
(;
link
<
end
;
++
link
)
(
*
hash
->
free
)(
link
->
data
);
}
reset_dynamic
(
&
hash
->
array
);
hash
->
records
=
0
;
hash
->
blength
=
1
;
hash
->
current_record
=
NO_RECORD
;
DBUG_VOID_RETURN
;
}
/* some helper functions */
/*
...
...
mysys/my_alloc.c
View file @
f90828cb
...
...
@@ -22,6 +22,27 @@
#undef EXTRA_DEBUG
#define EXTRA_DEBUG
/*
Initialize memory root
SYNOPSIS
init_alloc_root()
mem_root - memory root to initialize
block_size - size of chunks (blocks) used for memory allocation
(It is external size of chunk i.e. it should include
memory required for internal structures, thus it
should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
pre_alloc_size - if non-0, then size of block that should be
pre-allocated during memory root initialization.
DESCRIPTION
This function prepares memory root for further use, sets initial size of
chunk for memory allocation and pre-allocates first block if specified.
Altough error can happen during execution of this function if pre_alloc_size
is non-0 it won't be reported. Instead it will be reported as error in first
alloc_root() on this memory root.
*/
void
init_alloc_root
(
MEM_ROOT
*
mem_root
,
uint
block_size
,
uint
pre_alloc_size
__attribute__
((
unused
)))
{
...
...
@@ -29,7 +50,7 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
DBUG_PRINT
(
"enter"
,(
"root: 0x%lx"
,
mem_root
));
mem_root
->
free
=
mem_root
->
used
=
mem_root
->
pre_alloc
=
0
;
mem_root
->
min_malloc
=
32
;
mem_root
->
block_size
=
block_size
-
MALLOC_OVERHEAD
-
sizeof
(
USED_MEM
)
-
8
;
mem_root
->
block_size
=
block_size
-
ALLOC_ROOT_MIN_BLOCK_SIZE
;
mem_root
->
error_handler
=
0
;
mem_root
->
block_num
=
4
;
/* We shift this with >>2 */
mem_root
->
first_block_usage
=
0
;
...
...
@@ -54,9 +75,9 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
SYNOPSIS
reset_root_defaults()
mem_root memory root to change defaults of
block_size new value of block size. Must be
greater than ~68 bytes (the exact value depends on
platform and compilation flags)
block_size new value of block size. Must be
greater or equal
than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
68 bytes and depends on
platform and compilation flags)
pre_alloc_size new size of preallocated block. If not zero,
must be equal to or greater than block size,
otherwise means 'no prealloc'.
...
...
@@ -70,7 +91,9 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
void
reset_root_defaults
(
MEM_ROOT
*
mem_root
,
uint
block_size
,
uint
pre_alloc_size
__attribute__
((
unused
)))
{
mem_root
->
block_size
=
block_size
-
MALLOC_OVERHEAD
-
sizeof
(
USED_MEM
)
-
8
;
DBUG_ASSERT
(
alloc_root_inited
(
mem_root
));
mem_root
->
block_size
=
block_size
-
ALLOC_ROOT_MIN_BLOCK_SIZE
;
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
if
(
pre_alloc_size
)
{
...
...
@@ -123,6 +146,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
DBUG_ENTER
(
"alloc_root"
);
DBUG_PRINT
(
"enter"
,(
"root: 0x%lx"
,
mem_root
));
DBUG_ASSERT
(
alloc_root_inited
(
mem_root
));
Size
+=
ALIGN_SIZE
(
sizeof
(
USED_MEM
));
if
(
!
(
next
=
(
USED_MEM
*
)
my_malloc
(
Size
,
MYF
(
MY_WME
))))
{
...
...
@@ -140,6 +165,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
reg1
USED_MEM
*
next
=
0
;
reg2
USED_MEM
**
prev
;
DBUG_ASSERT
(
alloc_root_inited
(
mem_root
));
Size
=
ALIGN_SIZE
(
Size
);
if
((
*
(
prev
=
&
mem_root
->
free
))
!=
NULL
)
{
...
...
sql-common/client.c
View file @
f90828cb
...
...
@@ -2239,6 +2239,32 @@ static void mysql_close_free(MYSQL *mysql)
}
/*
Clear connection pointer of every statement: this is necessary
to give error on attempt to use a prepared statement of closed
connection.
SYNOPSYS
mysql_detach_stmt_list()
stmt_list pointer to mysql->stmts
*/
void
mysql_detach_stmt_list
(
LIST
**
stmt_list
)
{
#ifdef MYSQL_CLIENT
/* Reset connection handle in all prepared statements. */
LIST
*
element
=
*
stmt_list
;
for
(;
element
;
element
=
element
->
next
)
{
MYSQL_STMT
*
stmt
=
(
MYSQL_STMT
*
)
element
->
data
;
stmt
->
mysql
=
0
;
/* No need to call list_delete for statement here */
}
*
stmt_list
=
0
;
#endif
/* MYSQL_CLIENT */
}
void
STDCALL
mysql_close
(
MYSQL
*
mysql
)
{
DBUG_ENTER
(
"mysql_close"
);
...
...
@@ -2255,20 +2281,7 @@ void STDCALL mysql_close(MYSQL *mysql)
}
mysql_close_free_options
(
mysql
);
mysql_close_free
(
mysql
);
#ifdef MYSQL_CLIENT
if
(
mysql
->
stmts
)
{
/* Reset connection handle in all prepared statements. */
LIST
*
element
;
for
(
element
=
mysql
->
stmts
;
element
;
element
=
element
->
next
)
{
MYSQL_STMT
*
stmt
=
(
MYSQL_STMT
*
)
element
->
data
;
stmt
->
mysql
=
0
;
/* No need to call list_delete for statement here */
}
mysql
->
stmts
=
0
;
}
#endif
/*MYSQL_CLIENT*/
mysql_detach_stmt_list
(
&
mysql
->
stmts
);
#ifndef TO_BE_DELETED
/* free/close slave list */
if
(
mysql
->
rpl_pivot
)
...
...
sql/item_cmpfunc.cc
View file @
f90828cb
...
...
@@ -188,17 +188,27 @@ void Item_bool_func2::fix_length_and_dec()
{
uint
strong
=
0
;
uint
weak
=
0
;
uint32
dummy_offset
;
DTCollation
coll
;
if
(
args
[
0
]
->
result_type
()
==
STRING_RESULT
&&
args
[
1
]
->
result_type
()
==
STRING_RESULT
&&
!
my_charset_same
(
args
[
0
]
->
collation
.
collation
,
args
[
1
]
->
collation
.
collation
)
&&
String
::
needs_conversion
(
0
,
args
[
0
]
->
collation
.
collation
,
args
[
1
]
->
collation
.
collation
,
&
dummy_offset
)
&&
!
coll
.
set
(
args
[
0
]
->
collation
,
args
[
1
]
->
collation
,
TRUE
))
{
Item
*
conv
=
0
;
THD
*
thd
=
current_thd
;
Item_arena
*
arena
=
thd
->
current_arena
,
backup
;
strong
=
coll
.
strong
;
weak
=
strong
?
0
:
1
;
/*
In case we're in statement prepare, create conversion item
in its memory: it will be reused on each execute.
*/
if
(
arena
->
is_stmt_prepare
())
thd
->
set_n_backup_item_arena
(
arena
,
&
backup
);
if
(
args
[
weak
]
->
type
()
==
STRING_ITEM
)
{
String
tmp
,
cstr
;
...
...
@@ -211,21 +221,13 @@ void Item_bool_func2::fix_length_and_dec()
}
else
{
THD
*
thd
=
current_thd
;
/*
In case we're in statement prepare, create conversion item
in its memory: it will be reused on each execute.
*/
Item_arena
*
arena
=
thd
->
current_arena
,
backup
;
if
(
arena
->
is_stmt_prepare
())
thd
->
set_n_backup_item_arena
(
arena
,
&
backup
);
conv
=
new
Item_func_conv_charset
(
args
[
weak
],
args
[
strong
]
->
collation
.
collation
);
if
(
arena
->
is_stmt_prepare
())
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
conv
->
collation
.
set
(
args
[
weak
]
->
collation
.
derivation
);
conv
->
fix_fields
(
thd
,
0
,
&
conv
);
}
if
(
arena
->
is_stmt_prepare
())
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
args
[
weak
]
=
conv
?
conv
:
args
[
weak
];
}
}
...
...
sql/item_geofunc.cc
View file @
f90828cb
...
...
@@ -27,6 +27,13 @@
#include "sql_acl.h"
#include <m_ctype.h>
void
Item_geometry_func
::
fix_length_and_dec
()
{
collation
.
set
(
&
my_charset_bin
);
decimals
=
0
;
max_length
=
MAX_BLOB_WIDTH
;
}
String
*
Item_func_geometry_from_text
::
val_str
(
String
*
str
)
{
...
...
@@ -44,6 +51,7 @@ String *Item_func_geometry_from_text::val_str(String *str)
if
((
arg_count
==
2
)
&&
!
args
[
1
]
->
null_value
)
srid
=
(
uint32
)
args
[
1
]
->
val_int
();
str
->
set_charset
(
&
my_charset_bin
);
if
(
str
->
reserve
(
SRID_SIZE
,
512
))
return
0
;
str
->
length
(
0
);
...
...
@@ -54,12 +62,6 @@ String *Item_func_geometry_from_text::val_str(String *str)
}
void
Item_func_geometry_from_text
::
fix_length_and_dec
()
{
max_length
=
MAX_BLOB_WIDTH
;
}
String
*
Item_func_geometry_from_wkb
::
val_str
(
String
*
str
)
{
DBUG_ASSERT
(
fixed
==
1
);
...
...
@@ -71,6 +73,7 @@ String *Item_func_geometry_from_wkb::val_str(String *str)
if
((
arg_count
==
2
)
&&
!
args
[
1
]
->
null_value
)
srid
=
(
uint32
)
args
[
1
]
->
val_int
();
str
->
set_charset
(
&
my_charset_bin
);
if
(
str
->
reserve
(
SRID_SIZE
,
512
))
return
0
;
str
->
length
(
0
);
...
...
@@ -84,12 +87,6 @@ String *Item_func_geometry_from_wkb::val_str(String *str)
}
void
Item_func_geometry_from_wkb
::
fix_length_and_dec
()
{
max_length
=
MAX_BLOB_WIDTH
;
}
String
*
Item_func_as_wkt
::
val_str
(
String
*
str
)
{
DBUG_ASSERT
(
fixed
==
1
);
...
...
@@ -138,12 +135,6 @@ String *Item_func_as_wkb::val_str(String *str)
}
void
Item_func_as_wkb
::
fix_length_and_dec
()
{
max_length
=
MAX_BLOB_WIDTH
;
}
String
*
Item_func_geometry_type
::
val_str
(
String
*
str
)
{
DBUG_ASSERT
(
fixed
==
1
);
...
...
@@ -180,6 +171,7 @@ String *Item_func_envelope::val_str(String *str)
return
0
;
srid
=
uint4korr
(
swkb
->
ptr
());
str
->
set_charset
(
&
my_charset_bin
);
str
->
length
(
0
);
if
(
str
->
reserve
(
SRID_SIZE
,
512
))
return
0
;
...
...
@@ -202,6 +194,7 @@ String *Item_func_centroid::val_str(String *str)
swkb
->
length
()
-
SRID_SIZE
))))
return
0
;
str
->
set_charset
(
&
my_charset_bin
);
if
(
str
->
reserve
(
SRID_SIZE
,
512
))
return
0
;
str
->
length
(
0
);
...
...
@@ -232,6 +225,7 @@ String *Item_func_spatial_decomp::val_str(String *str)
return
0
;
srid
=
uint4korr
(
swkb
->
ptr
());
str
->
set_charset
(
&
my_charset_bin
);
if
(
str
->
reserve
(
SRID_SIZE
,
512
))
goto
err
;
str
->
length
(
0
);
...
...
@@ -279,6 +273,7 @@ String *Item_func_spatial_decomp_n::val_str(String *str)
swkb
->
length
()
-
SRID_SIZE
)))))
return
0
;
str
->
set_charset
(
&
my_charset_bin
);
if
(
str
->
reserve
(
SRID_SIZE
,
512
))
goto
err
;
srid
=
uint4korr
(
swkb
->
ptr
());
...
...
@@ -333,6 +328,7 @@ String *Item_func_point::val_str(String *str)
str
->
realloc
(
1
+
4
+
SIZEOF_STORED_DOUBLE
*
2
))))
return
0
;
str
->
set_charset
(
&
my_charset_bin
);
str
->
length
(
0
);
str
->
q_append
((
char
)
Geometry
::
wkb_ndr
);
str
->
q_append
((
uint32
)
Geometry
::
wkb_point
);
...
...
@@ -358,6 +354,7 @@ String *Item_func_spatial_collection::val_str(String *str)
String
arg_value
;
uint
i
;
str
->
set_charset
(
&
my_charset_bin
);
str
->
length
(
0
);
if
(
str
->
reserve
(
1
+
4
+
4
,
512
))
goto
err
;
...
...
sql/item_geofunc.h
View file @
f90828cb
...
...
@@ -23,24 +23,33 @@
#pragma interface
/* gcc class implementation */
#endif
class
Item_
func_geometry_from_text
:
public
Item_str_func
class
Item_
geometry_func
:
public
Item_str_func
{
public:
Item_func_geometry_from_text
(
Item
*
a
)
:
Item_str_func
(
a
)
{}
Item_func_geometry_from_text
(
Item
*
a
,
Item
*
srid
)
:
Item_str_func
(
a
,
srid
)
{}
Item_geometry_func
()
:
Item_str_func
()
{}
Item_geometry_func
(
Item
*
a
)
:
Item_str_func
(
a
)
{}
Item_geometry_func
(
Item
*
a
,
Item
*
b
)
:
Item_str_func
(
a
,
b
)
{}
Item_geometry_func
(
Item
*
a
,
Item
*
b
,
Item
*
c
)
:
Item_str_func
(
a
,
b
,
c
)
{}
Item_geometry_func
(
List
<
Item
>
&
list
)
:
Item_str_func
(
list
)
{}
void
fix_length_and_dec
();
};
class
Item_func_geometry_from_text
:
public
Item_geometry_func
{
public:
Item_func_geometry_from_text
(
Item
*
a
)
:
Item_geometry_func
(
a
)
{}
Item_func_geometry_from_text
(
Item
*
a
,
Item
*
srid
)
:
Item_geometry_func
(
a
,
srid
)
{}
const
char
*
func_name
()
const
{
return
"geometryfromtext"
;
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
();
};
class
Item_func_geometry_from_wkb
:
public
Item_
str
_func
class
Item_func_geometry_from_wkb
:
public
Item_
geometry
_func
{
public:
Item_func_geometry_from_wkb
(
Item
*
a
)
:
Item_
str
_func
(
a
)
{}
Item_func_geometry_from_wkb
(
Item
*
a
,
Item
*
srid
)
:
Item_
str
_func
(
a
,
srid
)
{}
Item_func_geometry_from_wkb
(
Item
*
a
)
:
Item_
geometry
_func
(
a
)
{}
Item_func_geometry_from_wkb
(
Item
*
a
,
Item
*
srid
)
:
Item_
geometry
_func
(
a
,
srid
)
{}
const
char
*
func_name
()
const
{
return
"geometryfromwkb"
;
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
();
};
class
Item_func_as_wkt
:
public
Item_str_func
...
...
@@ -52,13 +61,12 @@ class Item_func_as_wkt: public Item_str_func
void
fix_length_and_dec
();
};
class
Item_func_as_wkb
:
public
Item_
str
_func
class
Item_func_as_wkb
:
public
Item_
geometry
_func
{
public:
Item_func_as_wkb
(
Item
*
a
)
:
Item_
str
_func
(
a
)
{}
Item_func_as_wkb
(
Item
*
a
)
:
Item_
geometry
_func
(
a
)
{}
const
char
*
func_name
()
const
{
return
"aswkb"
;
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
();
};
class
Item_func_geometry_type
:
public
Item_str_func
...
...
@@ -73,40 +81,37 @@ class Item_func_geometry_type: public Item_str_func
};
};
class
Item_func_centroid
:
public
Item_
str
_func
class
Item_func_centroid
:
public
Item_
geometry
_func
{
public:
Item_func_centroid
(
Item
*
a
)
:
Item_
str
_func
(
a
)
{}
Item_func_centroid
(
Item
*
a
)
:
Item_
geometry
_func
(
a
)
{}
const
char
*
func_name
()
const
{
return
"centroid"
;
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
(){
max_length
=
MAX_BLOB_WIDTH
;}
};
class
Item_func_envelope
:
public
Item_
str
_func
class
Item_func_envelope
:
public
Item_
geometry
_func
{
public:
Item_func_envelope
(
Item
*
a
)
:
Item_
str
_func
(
a
)
{}
Item_func_envelope
(
Item
*
a
)
:
Item_
geometry
_func
(
a
)
{}
const
char
*
func_name
()
const
{
return
"envelope"
;
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
(){
max_length
=
MAX_BLOB_WIDTH
;}
};
class
Item_func_point
:
public
Item_
str
_func
class
Item_func_point
:
public
Item_
geometry
_func
{
public:
Item_func_point
(
Item
*
a
,
Item
*
b
)
:
Item_
str
_func
(
a
,
b
)
{}
Item_func_point
(
Item
*
a
,
Item
*
b
,
Item
*
srid
)
:
Item_
str
_func
(
a
,
b
,
srid
)
{}
Item_func_point
(
Item
*
a
,
Item
*
b
)
:
Item_
geometry
_func
(
a
,
b
)
{}
Item_func_point
(
Item
*
a
,
Item
*
b
,
Item
*
srid
)
:
Item_
geometry
_func
(
a
,
b
,
srid
)
{}
const
char
*
func_name
()
const
{
return
"point"
;
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
(){
max_length
=
MAX_BLOB_WIDTH
;}
};
class
Item_func_spatial_decomp
:
public
Item_
str
_func
class
Item_func_spatial_decomp
:
public
Item_
geometry
_func
{
enum
Functype
decomp_func
;
public:
Item_func_spatial_decomp
(
Item
*
a
,
Item_func
::
Functype
ft
)
:
Item_
str
_func
(
a
)
{
decomp_func
=
ft
;
}
Item_
geometry
_func
(
a
)
{
decomp_func
=
ft
;
}
const
char
*
func_name
()
const
{
switch
(
decomp_func
)
...
...
@@ -123,15 +128,14 @@ class Item_func_spatial_decomp: public Item_str_func
}
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
(){
max_length
=
MAX_BLOB_WIDTH
;}
};
class
Item_func_spatial_decomp_n
:
public
Item_
str
_func
class
Item_func_spatial_decomp_n
:
public
Item_
geometry
_func
{
enum
Functype
decomp_func_n
;
public:
Item_func_spatial_decomp_n
(
Item
*
a
,
Item
*
b
,
Item_func
::
Functype
ft
)
:
Item_
str
_func
(
a
,
b
)
{
decomp_func_n
=
ft
;
}
Item_
geometry
_func
(
a
,
b
)
{
decomp_func_n
=
ft
;
}
const
char
*
func_name
()
const
{
switch
(
decomp_func_n
)
...
...
@@ -148,10 +152,9 @@ class Item_func_spatial_decomp_n: public Item_str_func
}
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
(){
max_length
=
MAX_BLOB_WIDTH
;}
};
class
Item_func_spatial_collection
:
public
Item_
str
_func
class
Item_func_spatial_collection
:
public
Item_
geometry
_func
{
String
tmp_value
;
enum
Geometry
::
wkbType
coll_type
;
...
...
@@ -159,13 +162,12 @@ class Item_func_spatial_collection: public Item_str_func
public:
Item_func_spatial_collection
(
List
<
Item
>
&
list
,
enum
Geometry
::
wkbType
ct
,
enum
Geometry
::
wkbType
it
)
:
Item_
str
_func
(
list
)
Item_
geometry
_func
(
list
)
{
coll_type
=
ct
;
item_type
=
it
;
}
String
*
val_str
(
String
*
);
void
fix_length_and_dec
(){
max_length
=
MAX_BLOB_WIDTH
;}
const
char
*
func_name
()
const
{
return
"multipoint"
;
}
};
...
...
sql/log_event.cc
View file @
f90828cb
...
...
@@ -1091,7 +1091,15 @@ Default database: '%s'. Query: '%s'",
VOID
(
pthread_mutex_unlock
(
&
LOCK_thread_count
));
close_thread_tables
(
thd
);
free_root
(
&
thd
->
mem_root
,
MYF
(
MY_KEEP_PREALLOC
));
return
(
thd
->
query_error
?
thd
->
query_error
:
Log_event
::
exec_event
(
rli
));
/*
If there was an error we stop. Otherwise we increment positions. Note that
we will not increment group* positions if we are just after a SET
ONE_SHOT, because SET ONE_SHOT should not be separated from its following
updating query.
*/
return
(
thd
->
query_error
?
thd
->
query_error
:
(
thd
->
one_shot_set
?
(
rli
->
inc_event_relay_log_pos
(
get_event_len
()),
0
)
:
Log_event
::
exec_event
(
rli
)));
}
#endif
...
...
sql/opt_range.cc
View file @
f90828cb
...
...
@@ -2554,7 +2554,8 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
QUICK_SELECT
*
get_quick_select_for_ref
(
THD
*
thd
,
TABLE
*
table
,
TABLE_REF
*
ref
)
{
QUICK_SELECT
*
quick
=
new
QUICK_SELECT
(
thd
,
table
,
ref
->
key
,
1
);
MEM_ROOT
*
old_root
=
my_pthread_getspecific_ptr
(
MEM_ROOT
*
,
THR_MALLOC
);
QUICK_SELECT
*
quick
=
new
QUICK_SELECT
(
thd
,
table
,
ref
->
key
);
KEY
*
key_info
=
&
table
->
key_info
[
ref
->
key
];
KEY_PART
*
key_part
;
QUICK_RANGE
*
range
;
...
...
@@ -2566,7 +2567,7 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
{
if
(
thd
->
is_fatal_error
)
goto
err
;
// out of memory
return
quick
;
// empty range
goto
ok
;
// empty range
}
if
(
!
(
range
=
new
QUICK_RANGE
()))
...
...
@@ -2613,9 +2614,12 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
goto
err
;
}
ok:
my_pthread_setspecific_ptr
(
THR_MALLOC
,
old_root
);
return
quick
;
err:
my_pthread_setspecific_ptr
(
THR_MALLOC
,
old_root
);
delete
quick
;
return
0
;
}
...
...
sql/sql_class.cc
View file @
f90828cb
...
...
@@ -221,7 +221,6 @@ THD::THD()
init
();
/* Initialize sub structures */
clear_alloc_root
(
&
transaction
.
mem_root
);
init_alloc_root
(
&
warn_root
,
WARN_ALLOC_BLOCK_SIZE
,
WARN_ALLOC_PREALLOC_SIZE
);
user_connect
=
(
USER_CONN
*
)
0
;
hash_init
(
&
user_vars
,
&
my_charset_bin
,
USER_VARS_HASH_SIZE
,
0
,
0
,
...
...
@@ -258,6 +257,7 @@ THD::THD()
transaction
.
trans_log
.
end_of_file
=
max_binlog_cache_size
;
}
#endif
init_alloc_root
(
&
transaction
.
mem_root
,
ALLOC_ROOT_MIN_BLOCK_SIZE
,
0
);
{
ulong
tmp
=
sql_rnd_with_mutex
();
randominit
(
&
rand
,
tmp
+
(
ulong
)
&
rand
,
tmp
+
(
ulong
)
::
query_id
);
...
...
@@ -303,12 +303,12 @@ void THD::init(void)
void
THD
::
init_for_queries
()
{
ha_enable_transaction
(
this
,
TRUE
);
init_sql_alloc
(
&
mem_root
,
variables
.
query_alloc_block_size
,
variables
.
query_prealloc_size
);
init_sql_alloc
(
&
transaction
.
mem_root
,
variables
.
trans_alloc_block_size
,
variables
.
trans_prealloc_size
);
reset_root_defaults
(
&
mem_root
,
variables
.
query_alloc_block_size
,
variables
.
query_prealloc_size
);
reset_root_defaults
(
&
transaction
.
mem_root
,
variables
.
trans_alloc_block_size
,
variables
.
trans_prealloc_size
);
}
...
...
@@ -328,6 +328,7 @@ void THD::change_user(void)
cleanup
();
cleanup_done
=
0
;
init
();
stmt_map
.
reset
();
hash_init
(
&
user_vars
,
&
my_charset_bin
,
USER_VARS_HASH_SIZE
,
0
,
0
,
(
hash_get_key
)
get_var_key
,
(
hash_free_key
)
free_user_var
,
0
);
...
...
@@ -1331,6 +1332,17 @@ void select_dumpvar::cleanup()
}
/*
Create arena for already constructed THD.
SYNOPSYS
Item_arena()
thd - thread for which arena is created
DESCRIPTION
Create arena for already existing THD using its variables as parameters
for memory root initialization.
*/
Item_arena
::
Item_arena
(
THD
*
thd
)
:
free_list
(
0
),
state
(
INITIALIZED
)
...
...
@@ -1341,24 +1353,31 @@ Item_arena::Item_arena(THD* thd)
}
/* This constructor is called when Item_arena is a subobject of THD */
/*
Create arena and optionally initialize memory root.
Item_arena
::
Item_arena
()
:
free_list
(
0
),
state
(
CONVENTIONAL_EXECUTION
)
{
clear_alloc_root
(
&
mem_root
);
}
SYNOPSYS
Item_arena()
init_mem_root - whenever we need to initialize memory root
DESCRIPTION
Create arena and optionally initialize memory root with minimal
possible parameters.
NOTE
We use this constructor when arena is part of THD, but reinitialize
its memory root in THD::init_for_queries() before execution of real
statements.
*/
Item_arena
::
Item_arena
(
bool
init_mem_root
)
:
free_list
(
0
),
state
(
INITIALIZED
)
state
(
CONVENTIONAL_EXECUTION
)
{
if
(
init_mem_root
)
clear_alloc_root
(
&
mem_root
);
init_alloc_root
(
&
mem_root
,
ALLOC_ROOT_MIN_BLOCK_SIZE
,
0
);
}
Item_arena
::
Type
Item_arena
::
type
()
const
{
DBUG_ASSERT
(
"Item_arena::type()"
==
"abstract"
);
...
...
@@ -1366,10 +1385,6 @@ Item_arena::Type Item_arena::type() const
}
Item_arena
::~
Item_arena
()
{}
/*
Statement functions
*/
...
...
@@ -1393,7 +1408,8 @@ Statement::Statement(THD *thd)
*/
Statement
::
Statement
()
:
id
(
0
),
:
Item_arena
((
bool
)
TRUE
),
id
(
0
),
set_query_id
(
1
),
allow_sum_func
(
0
),
/* initialized later */
lex
(
&
main_lex
),
...
...
@@ -1461,8 +1477,16 @@ void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup)
{
set
->
set_item_arena
(
this
);
set_item_arena
(
backup
);
// reset backup mem_root to avoid its freeing
init_alloc_root
(
&
backup
->
mem_root
,
0
,
0
);
#ifdef NOT_NEEDED_NOW
/*
Reset backup mem_root to avoid its freeing.
Since Item_arena's mem_root is freed only when it is part of Statement
we need this only if we use some Statement's arena as backup storage.
But we do this only with THD::stmt_backup and this Statement is specially
handled in this respect. So this code is not really needed now.
*/
clear_alloc_root
(
&
backup
->
mem_root
);
#endif
}
void
Item_arena
::
set_item_arena
(
Item_arena
*
set
)
...
...
sql/sql_class.h
View file @
f90828cb
...
...
@@ -441,11 +441,23 @@ class Item_arena
STATEMENT
,
PREPARED_STATEMENT
,
STORED_PROCEDURE
};
/*
This constructor is used only when Item_arena is created as
backup storage for another instance of Item_arena.
*/
Item_arena
()
{};
/*
Create arena for already constructed THD using its variables as
parameters for memory root initialization.
*/
Item_arena
(
THD
*
thd
);
Item_arena
();
/*
Create arena and optionally init memory root with minimal values.
Particularly used if Item_arena is part of Statement.
*/
Item_arena
(
bool
init_mem_root
);
virtual
Type
type
()
const
;
virtual
~
Item_arena
();
virtual
~
Item_arena
()
{}
;
inline
bool
is_stmt_prepare
()
const
{
return
(
int
)
state
<
(
int
)
PREPARED
;
}
inline
bool
is_first_stmt_execute
()
const
{
return
state
==
PREPARED
;
}
...
...
@@ -566,7 +578,7 @@ class Statement: public Item_arena
assignment in Statement::Statement)
Non-empty statement names are unique too: attempt to insert a new statement
with duplicate name causes older statement to be deleted
Statements are auto-deleted when they are removed from the map and when the
map is deleted.
*/
...
...
@@ -575,7 +587,7 @@ class Statement_map
{
public:
Statement_map
();
int
insert
(
Statement
*
statement
);
Statement
*
find_by_name
(
LEX_STRING
*
name
)
...
...
@@ -608,11 +620,18 @@ class Statement_map
}
hash_delete
(
&
st_hash
,
(
byte
*
)
statement
);
}
/* Erase all statements (calls Statement destructor) */
void
reset
()
{
hash_reset
(
&
names_hash
);
hash_reset
(
&
st_hash
);
last_found_statement
=
0
;
}
~
Statement_map
()
{
hash_free
(
&
st_hash
);
hash_free
(
&
names_hash
);
hash_free
(
&
st_hash
);
}
private:
HASH
st_hash
;
...
...
sql/sql_show.cc
View file @
f90828cb
...
...
@@ -1265,6 +1265,8 @@ store_create_info(THD *thd, TABLE *table, String *packet)
// check for surprises from the previous call to Field::sql_type()
if
(
type
.
ptr
()
!=
tmp
)
type
.
set
(
tmp
,
sizeof
(
tmp
),
system_charset_info
);
else
type
.
set_charset
(
system_charset_info
);
field
->
sql_type
(
type
);
packet
->
append
(
type
.
ptr
(),
type
.
length
(),
system_charset_info
);
...
...
tests/client_test.c
View file @
f90828cb
...
...
@@ -10251,7 +10251,7 @@ static void test_bug5194()
/* Number of columns per row */
const
int
COLUMN_COUNT
=
sizeof
(
float_array
)
/
sizeof
(
*
float_array
);
/* Number of rows per bulk insert to start with */
const
int
MIN_ROWS_PER_INSERT
=
26
0
;
const
int
MIN_ROWS_PER_INSERT
=
26
2
;
/* Max number of rows per bulk insert to end with */
const
int
MAX_ROWS_PER_INSERT
=
300
;
const
int
MAX_PARAM_COUNT
=
COLUMN_COUNT
*
MAX_ROWS_PER_INSERT
;
...
...
@@ -10391,6 +10391,34 @@ static void test_bug5194()
}
static
void
test_bug5315
()
{
MYSQL_STMT
*
stmt
;
const
char
*
stmt_text
;
int
rc
;
myheader
(
"test_bug5315"
);
stmt_text
=
"SELECT 1"
;
stmt
=
mysql_stmt_init
(
mysql
);
rc
=
mysql_stmt_prepare
(
stmt
,
stmt_text
,
strlen
(
stmt_text
));
DBUG_ASSERT
(
rc
==
0
);
mysql_change_user
(
mysql
,
opt_user
,
opt_password
,
current_db
);
rc
=
mysql_stmt_execute
(
stmt
);
DBUG_ASSERT
(
rc
!=
0
);
if
(
rc
)
printf
(
"Got error (as expected):
\n
%s"
,
mysql_stmt_error
(
stmt
));
/* check that connection is OK */
mysql_stmt_close
(
stmt
);
stmt
=
mysql_stmt_init
(
mysql
);
rc
=
mysql_stmt_prepare
(
stmt
,
stmt_text
,
strlen
(
stmt_text
));
DBUG_ASSERT
(
rc
==
0
);
rc
=
mysql_stmt_execute
(
stmt
);
DBUG_ASSERT
(
rc
==
0
);
mysql_stmt_close
(
stmt
);
}
/*
Read and parse arguments and MySQL options from my.cnf
*/
...
...
@@ -10694,6 +10722,8 @@ int main(int argc, char **argv)
test_bug5399
();
/* check that statement id uniquely identifies
statement */
test_bug5194
();
/* bulk inserts in prepared mode */
test_bug5315
();
/* check that mysql_change_user closes all
prepared statements */
/*
XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.
...
...
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