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
bba81555
Commit
bba81555
authored
Jan 31, 2006
by
aivanov@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge aivanov@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/alexi/innodb/mysql-5.0-ss162
parents
e899ab07
9296fb24
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
376 additions
and
69 deletions
+376
-69
innobase/btr/btr0sea.c
innobase/btr/btr0sea.c
+39
-5
innobase/dict/dict0dict.c
innobase/dict/dict0dict.c
+2
-1
innobase/dict/dict0load.c
innobase/dict/dict0load.c
+15
-5
innobase/fil/fil0fil.c
innobase/fil/fil0fil.c
+81
-2
innobase/include/univ.i
innobase/include/univ.i
+0
-6
innobase/os/os0sync.c
innobase/os/os0sync.c
+15
-15
innobase/srv/srv0start.c
innobase/srv/srv0start.c
+14
-0
mysql-test/r/innodb.result
mysql-test/r/innodb.result
+71
-0
mysql-test/t/innodb.test
mysql-test/t/innodb.test
+102
-0
sql/ha_innodb.cc
sql/ha_innodb.cc
+36
-23
sql/ha_innodb.h
sql/ha_innodb.h
+1
-12
No files found.
innobase/btr/btr0sea.c
View file @
bba81555
...
@@ -191,7 +191,7 @@ static
...
@@ -191,7 +191,7 @@ static
void
void
btr_search_info_update_hash
(
btr_search_info_update_hash
(
/*========================*/
/*========================*/
btr_search_t
*
info
,
/* in: search info */
btr_search_t
*
info
,
/* in
/out
: search info */
btr_cur_t
*
cursor
)
/* in: cursor which was just positioned */
btr_cur_t
*
cursor
)
/* in: cursor which was just positioned */
{
{
dict_index_t
*
index
;
dict_index_t
*
index
;
...
@@ -452,7 +452,7 @@ Updates the search info. */
...
@@ -452,7 +452,7 @@ Updates the search info. */
void
void
btr_search_info_update_slow
(
btr_search_info_update_slow
(
/*========================*/
/*========================*/
btr_search_t
*
info
,
/* in: search info */
btr_search_t
*
info
,
/* in
/out
: search info */
btr_cur_t
*
cursor
)
/* in: cursor which was just positioned */
btr_cur_t
*
cursor
)
/* in: cursor which was just positioned */
{
{
buf_block_t
*
block
;
buf_block_t
*
block
;
...
@@ -912,12 +912,12 @@ btr_search_drop_page_hash_index(
...
@@ -912,12 +912,12 @@ btr_search_drop_page_hash_index(
ut_ad
(
!
rw_lock_own
(
&
btr_search_latch
,
RW_LOCK_SHARED
));
ut_ad
(
!
rw_lock_own
(
&
btr_search_latch
,
RW_LOCK_SHARED
));
ut_ad
(
!
rw_lock_own
(
&
btr_search_latch
,
RW_LOCK_EX
));
ut_ad
(
!
rw_lock_own
(
&
btr_search_latch
,
RW_LOCK_EX
));
#endif
/* UNIV_SYNC_DEBUG */
#endif
/* UNIV_SYNC_DEBUG */
retry:
rw_lock_s_lock
(
&
btr_search_latch
);
rw_lock_s_lock
(
&
btr_search_latch
);
block
=
buf_block_align
(
page
);
block
=
buf_block_align
(
page
);
if
(
!
block
->
is_hashed
)
{
if
(
UNIV_LIKELY
(
!
block
->
is_hashed
)
)
{
rw_lock_s_unlock
(
&
btr_search_latch
);
rw_lock_s_unlock
(
&
btr_search_latch
);
...
@@ -958,6 +958,8 @@ btr_search_drop_page_hash_index(
...
@@ -958,6 +958,8 @@ btr_search_drop_page_hash_index(
tree_id
=
btr_page_get_index_id
(
page
);
tree_id
=
btr_page_get_index_id
(
page
);
ut_a
(
0
==
ut_dulint_cmp
(
tree_id
,
index
->
id
));
prev_fold
=
0
;
prev_fold
=
0
;
heap
=
NULL
;
heap
=
NULL
;
...
@@ -992,6 +994,26 @@ btr_search_drop_page_hash_index(
...
@@ -992,6 +994,26 @@ btr_search_drop_page_hash_index(
rw_lock_x_lock
(
&
btr_search_latch
);
rw_lock_x_lock
(
&
btr_search_latch
);
if
(
UNIV_UNLIKELY
(
!
block
->
is_hashed
))
{
/* Someone else has meanwhile dropped the hash index */
goto
cleanup
;
}
ut_a
(
block
->
index
==
index
);
if
(
UNIV_UNLIKELY
(
block
->
curr_n_fields
!=
n_fields
)
||
UNIV_UNLIKELY
(
block
->
curr_n_bytes
!=
n_bytes
))
{
/* Someone else has meanwhile built a new hash index on the
page, with different parameters */
rw_lock_x_unlock
(
&
btr_search_latch
);
mem_free
(
folds
);
goto
retry
;
}
for
(
i
=
0
;
i
<
n_cached
;
i
++
)
{
for
(
i
=
0
;
i
<
n_cached
;
i
++
)
{
ha_remove_all_nodes_to_page
(
table
,
folds
[
i
],
page
);
ha_remove_all_nodes_to_page
(
table
,
folds
[
i
],
page
);
...
@@ -999,8 +1021,20 @@ btr_search_drop_page_hash_index(
...
@@ -999,8 +1021,20 @@ btr_search_drop_page_hash_index(
block
->
is_hashed
=
FALSE
;
block
->
is_hashed
=
FALSE
;
block
->
index
=
NULL
;
block
->
index
=
NULL
;
cleanup:
if
(
UNIV_UNLIKELY
(
block
->
n_pointers
))
{
/* Corruption */
ut_print_timestamp
(
stderr
);
fprintf
(
stderr
,
" InnoDB: Corruption of adaptive hash index. After dropping
\n
"
"InnoDB: the hash index to a page of %s, still %lu hash nodes remain.
\n
"
,
index
->
name
,
(
ulong
)
block
->
n_pointers
);
rw_lock_x_unlock
(
&
btr_search_latch
);
rw_lock_x_unlock
(
&
btr_search_latch
);
btr_search_validate
();
}
else
{
rw_lock_x_unlock
(
&
btr_search_latch
);
}
mem_free
(
folds
);
mem_free
(
folds
);
}
}
...
...
innobase/dict/dict0dict.c
View file @
bba81555
...
@@ -2803,7 +2803,8 @@ dict_table_get_highest_foreign_id(
...
@@ -2803,7 +2803,8 @@ dict_table_get_highest_foreign_id(
if
(
ut_strlen
(
foreign
->
id
)
>
((
sizeof
dict_ibfk
)
-
1
)
+
len
if
(
ut_strlen
(
foreign
->
id
)
>
((
sizeof
dict_ibfk
)
-
1
)
+
len
&&
0
==
ut_memcmp
(
foreign
->
id
,
table
->
name
,
len
)
&&
0
==
ut_memcmp
(
foreign
->
id
,
table
->
name
,
len
)
&&
0
==
ut_memcmp
(
foreign
->
id
+
len
,
&&
0
==
ut_memcmp
(
foreign
->
id
+
len
,
dict_ibfk
,
(
sizeof
dict_ibfk
)
-
1
))
{
dict_ibfk
,
(
sizeof
dict_ibfk
)
-
1
)
&&
foreign
->
id
[
len
+
((
sizeof
dict_ibfk
)
-
1
)]
!=
'0'
)
{
/* It is of the >= 4.0.18 format */
/* It is of the >= 4.0.18 format */
id
=
strtoul
(
foreign
->
id
+
len
+
((
sizeof
dict_ibfk
)
-
1
),
id
=
strtoul
(
foreign
->
id
+
len
+
((
sizeof
dict_ibfk
)
-
1
),
...
...
innobase/dict/dict0load.c
View file @
bba81555
...
@@ -385,13 +385,23 @@ dict_load_columns(
...
@@ -385,13 +385,23 @@ dict_load_columns(
field
=
rec_get_nth_field_old
(
rec
,
6
,
&
len
);
field
=
rec_get_nth_field_old
(
rec
,
6
,
&
len
);
prtype
=
mach_read_from_4
(
field
);
prtype
=
mach_read_from_4
(
field
);
if
(
dtype_is_non_binary_string_type
(
mtype
,
prtype
)
if
(
dtype_get_charset_coll
(
prtype
)
==
0
&&
dtype_get_charset_coll
(
prtype
)
==
0
)
{
&&
dtype_is_string_type
(
mtype
))
{
/* This is a non-binary string type, and the table
/* The table was created with < 4.1.2. */
was created with < 4.1.2. Use the default charset. */
prtype
=
dtype_form_prtype
(
prtype
,
if
(
dtype_is_binary_string_type
(
mtype
,
prtype
))
{
/* Use the binary collation for
string columns of binary type. */
prtype
=
dtype_form_prtype
(
prtype
,
DATA_MYSQL_BINARY_CHARSET_COLL
);
}
else
{
/* Use the default charset for
other than binary columns. */
prtype
=
dtype_form_prtype
(
prtype
,
data_mysql_default_charset_coll
);
data_mysql_default_charset_coll
);
}
}
}
field
=
rec_get_nth_field_old
(
rec
,
7
,
&
len
);
field
=
rec_get_nth_field_old
(
rec
,
7
,
&
len
);
...
...
innobase/fil/fil0fil.c
View file @
bba81555
...
@@ -181,6 +181,11 @@ struct fil_space_struct {
...
@@ -181,6 +181,11 @@ struct fil_space_struct {
hash_node_t
name_hash
;
/* hash chain the name_hash table */
hash_node_t
name_hash
;
/* hash chain the name_hash table */
rw_lock_t
latch
;
/* latch protecting the file space storage
rw_lock_t
latch
;
/* latch protecting the file space storage
allocation */
allocation */
UT_LIST_NODE_T
(
fil_space_t
)
unflushed_spaces
;
/* list of spaces with at least one unflushed
file we have written to */
ibool
is_in_unflushed_spaces
;
/* TRUE if this space is
currently in the list above */
UT_LIST_NODE_T
(
fil_space_t
)
space_list
;
UT_LIST_NODE_T
(
fil_space_t
)
space_list
;
/* list of all spaces */
/* list of all spaces */
ibuf_data_t
*
ibuf_data
;
ibuf_data_t
*
ibuf_data
;
...
@@ -213,6 +218,12 @@ struct fil_system_struct {
...
@@ -213,6 +218,12 @@ struct fil_system_struct {
not put to this list: they are opened
not put to this list: they are opened
after the startup, and kept open until
after the startup, and kept open until
shutdown */
shutdown */
UT_LIST_BASE_NODE_T
(
fil_space_t
)
unflushed_spaces
;
/* base node for the list of those
tablespaces whose files contain
unflushed writes; those spaces have
at least one file node where
modification_counter > flush_counter */
ulint
n_open
;
/* number of files currently open */
ulint
n_open
;
/* number of files currently open */
ulint
max_n_open
;
/* n_open is not allowed to exceed
ulint
max_n_open
;
/* n_open is not allowed to exceed
this */
this */
...
@@ -389,6 +400,36 @@ fil_space_get_ibuf_data(
...
@@ -389,6 +400,36 @@ fil_space_get_ibuf_data(
return
(
space
->
ibuf_data
);
return
(
space
->
ibuf_data
);
}
}
/**************************************************************************
Checks if all the file nodes in a space are flushed. The caller must hold
the fil_system mutex. */
static
ibool
fil_space_is_flushed
(
/*=================*/
/* out: TRUE if all are flushed */
fil_space_t
*
space
)
/* in: space */
{
fil_node_t
*
node
;
#ifdef UNIV_SYNC_DEBUG
ut_ad
(
mutex_own
(
&
(
fil_system
->
mutex
)));
#endif
/* UNIV_SYNC_DEBUG */
node
=
UT_LIST_GET_FIRST
(
space
->
chain
);
while
(
node
)
{
if
(
node
->
modification_counter
>
node
->
flush_counter
)
{
return
(
FALSE
);
}
node
=
UT_LIST_GET_NEXT
(
chain
,
node
);
}
return
(
TRUE
);
}
/***********************************************************************
/***********************************************************************
Appends a new file to the chain of files of a space. File must be closed. */
Appends a new file to the chain of files of a space. File must be closed. */
...
@@ -841,6 +882,16 @@ fil_node_free(
...
@@ -841,6 +882,16 @@ fil_node_free(
node
->
modification_counter
=
node
->
flush_counter
;
node
->
modification_counter
=
node
->
flush_counter
;
if
(
space
->
is_in_unflushed_spaces
&&
fil_space_is_flushed
(
space
))
{
space
->
is_in_unflushed_spaces
=
FALSE
;
UT_LIST_REMOVE
(
unflushed_spaces
,
system
->
unflushed_spaces
,
space
);
}
fil_node_close_file
(
node
,
system
);
fil_node_close_file
(
node
,
system
);
}
}
...
@@ -1004,6 +1055,8 @@ fil_space_create(
...
@@ -1004,6 +1055,8 @@ fil_space_create(
HASH_INSERT
(
fil_space_t
,
name_hash
,
system
->
name_hash
,
HASH_INSERT
(
fil_space_t
,
name_hash
,
system
->
name_hash
,
ut_fold_string
(
name
),
space
);
ut_fold_string
(
name
),
space
);
space
->
is_in_unflushed_spaces
=
FALSE
;
UT_LIST_ADD_LAST
(
space_list
,
system
->
space_list
,
space
);
UT_LIST_ADD_LAST
(
space_list
,
system
->
space_list
,
space
);
mutex_exit
(
&
(
system
->
mutex
));
mutex_exit
(
&
(
system
->
mutex
));
...
@@ -1099,6 +1152,13 @@ fil_space_free(
...
@@ -1099,6 +1152,13 @@ fil_space_free(
HASH_DELETE
(
fil_space_t
,
name_hash
,
system
->
name_hash
,
HASH_DELETE
(
fil_space_t
,
name_hash
,
system
->
name_hash
,
ut_fold_string
(
space
->
name
),
space
);
ut_fold_string
(
space
->
name
),
space
);
if
(
space
->
is_in_unflushed_spaces
)
{
space
->
is_in_unflushed_spaces
=
FALSE
;
UT_LIST_REMOVE
(
unflushed_spaces
,
system
->
unflushed_spaces
,
space
);
}
UT_LIST_REMOVE
(
space_list
,
system
->
space_list
,
space
);
UT_LIST_REMOVE
(
space_list
,
system
->
space_list
,
space
);
ut_a
(
space
->
magic_n
==
FIL_SPACE_MAGIC_N
);
ut_a
(
space
->
magic_n
==
FIL_SPACE_MAGIC_N
);
...
@@ -1250,6 +1310,7 @@ fil_system_create(
...
@@ -1250,6 +1310,7 @@ fil_system_create(
system
->
tablespace_version
=
0
;
system
->
tablespace_version
=
0
;
UT_LIST_INIT
(
system
->
unflushed_spaces
);
UT_LIST_INIT
(
system
->
space_list
);
UT_LIST_INIT
(
system
->
space_list
);
return
(
system
);
return
(
system
);
...
@@ -3742,6 +3803,14 @@ fil_node_complete_io(
...
@@ -3742,6 +3803,14 @@ fil_node_complete_io(
if
(
type
==
OS_FILE_WRITE
)
{
if
(
type
==
OS_FILE_WRITE
)
{
system
->
modification_counter
++
;
system
->
modification_counter
++
;
node
->
modification_counter
=
system
->
modification_counter
;
node
->
modification_counter
=
system
->
modification_counter
;
if
(
!
node
->
space
->
is_in_unflushed_spaces
)
{
node
->
space
->
is_in_unflushed_spaces
=
TRUE
;
UT_LIST_ADD_FIRST
(
unflushed_spaces
,
system
->
unflushed_spaces
,
node
->
space
);
}
}
}
if
(
node
->
n_pending
==
0
&&
node
->
space
->
purpose
==
FIL_TABLESPACE
if
(
node
->
n_pending
==
0
&&
node
->
space
->
purpose
==
FIL_TABLESPACE
...
@@ -4162,6 +4231,16 @@ fil_flush(
...
@@ -4162,6 +4231,16 @@ fil_flush(
skip_flush:
skip_flush:
if
(
node
->
flush_counter
<
old_mod_counter
)
{
if
(
node
->
flush_counter
<
old_mod_counter
)
{
node
->
flush_counter
=
old_mod_counter
;
node
->
flush_counter
=
old_mod_counter
;
if
(
space
->
is_in_unflushed_spaces
&&
fil_space_is_flushed
(
space
))
{
space
->
is_in_unflushed_spaces
=
FALSE
;
UT_LIST_REMOVE
(
unflushed_spaces
,
system
->
unflushed_spaces
,
space
);
}
}
}
if
(
space
->
purpose
==
FIL_TABLESPACE
)
{
if
(
space
->
purpose
==
FIL_TABLESPACE
)
{
...
@@ -4193,7 +4272,7 @@ fil_flush_file_spaces(
...
@@ -4193,7 +4272,7 @@ fil_flush_file_spaces(
mutex_enter
(
&
(
system
->
mutex
));
mutex_enter
(
&
(
system
->
mutex
));
space
=
UT_LIST_GET_FIRST
(
system
->
space_list
);
space
=
UT_LIST_GET_FIRST
(
system
->
unflushed_spaces
);
while
(
space
)
{
while
(
space
)
{
if
(
space
->
purpose
==
purpose
&&
!
space
->
is_being_deleted
)
{
if
(
space
->
purpose
==
purpose
&&
!
space
->
is_being_deleted
)
{
...
@@ -4209,7 +4288,7 @@ fil_flush_file_spaces(
...
@@ -4209,7 +4288,7 @@ fil_flush_file_spaces(
space
->
n_pending_flushes
--
;
space
->
n_pending_flushes
--
;
}
}
space
=
UT_LIST_GET_NEXT
(
space_list
,
space
);
space
=
UT_LIST_GET_NEXT
(
unflushed_spaces
,
space
);
}
}
mutex_exit
(
&
(
system
->
mutex
));
mutex_exit
(
&
(
system
->
mutex
));
...
...
innobase/include/univ.i
View file @
bba81555
...
@@ -126,14 +126,8 @@ by one. */
...
@@ -126,14 +126,8 @@ by one. */
#
ifdef
__WIN__
#
ifdef
__WIN__
#
define
UNIV_INLINE
__inline
#
define
UNIV_INLINE
__inline
#
else
#
else
/* config.h contains the right def for 'inline' for the current compiler */
#
if
(
__GNUC__
==
2
)
#
define
UNIV_INLINE
extern
inline
#
else
/* extern inline doesn't work with gcc 3.0.2 */
#
define
UNIV_INLINE
static
inline
#
define
UNIV_INLINE
static
inline
#
endif
#
endif
#
endif
#
else
#
else
/* If we want to compile a noninlined version we use the following macro
/* If we want to compile a noninlined version we use the following macro
...
...
innobase/os/os0sync.c
View file @
bba81555
...
@@ -317,28 +317,28 @@ os_event_wait(
...
@@ -317,28 +317,28 @@ os_event_wait(
os_fast_mutex_lock
(
&
(
event
->
os_mutex
));
os_fast_mutex_lock
(
&
(
event
->
os_mutex
));
old_signal_count
=
event
->
signal_count
;
old_signal_count
=
event
->
signal_count
;
loop:
if
(
event
->
is_set
==
TRUE
||
event
->
signal_count
!=
old_signal_count
)
{
os_fast_mutex_unlock
(
&
(
event
->
os_mutex
));
for
(;;)
{
if
(
event
->
is_set
==
TRUE
||
event
->
signal_count
!=
old_signal_count
)
{
if
(
srv_shutdown_state
==
SRV_SHUTDOWN_EXIT_THREADS
)
{
os_fast_mutex_unlock
(
&
(
event
->
os_mutex
));
os_thread_exit
(
NULL
);
if
(
srv_shutdown_state
==
SRV_SHUTDOWN_EXIT_THREADS
)
{
}
/* Ok, we may return */
return
;
os_thread_exit
(
NULL
);
}
}
/* Ok, we may return */
pthread_cond_wait
(
&
(
event
->
cond_var
),
&
(
event
->
os_mutex
));
return
;
}
/* Solaris manual said that spurious wakeups may occur: we have to
pthread_cond_wait
(
&
(
event
->
cond_var
),
&
(
event
->
os_mutex
));
check if the event really has been signaled after we came here to
wait */
goto
loop
;
/* Solaris manual said that spurious wakeups may occur: we
have to check if the event really has been signaled after
we came here to wait */
}
#endif
#endif
}
}
...
...
innobase/srv/srv0start.c
View file @
bba81555
...
@@ -233,6 +233,13 @@ srv_parse_data_file_paths_and_sizes(
...
@@ -233,6 +233,13 @@ srv_parse_data_file_paths_and_sizes(
}
}
}
}
if
(
i
==
0
)
{
/* If innodb_data_file_path was defined it must contain
at least one data file definition */
return
(
FALSE
);
}
*
data_file_names
=
(
char
**
)
ut_malloc
(
i
*
sizeof
(
void
*
));
*
data_file_names
=
(
char
**
)
ut_malloc
(
i
*
sizeof
(
void
*
));
*
data_file_sizes
=
(
ulint
*
)
ut_malloc
(
i
*
sizeof
(
ulint
));
*
data_file_sizes
=
(
ulint
*
)
ut_malloc
(
i
*
sizeof
(
ulint
));
*
data_file_is_raw_partition
=
(
ulint
*
)
ut_malloc
(
i
*
sizeof
(
ulint
));
*
data_file_is_raw_partition
=
(
ulint
*
)
ut_malloc
(
i
*
sizeof
(
ulint
));
...
@@ -379,6 +386,13 @@ srv_parse_log_group_home_dirs(
...
@@ -379,6 +386,13 @@ srv_parse_log_group_home_dirs(
}
}
}
}
if
(
i
!=
1
)
{
/* If innodb_log_group_home_dir was defined it must
contain exactly one path definition under current MySQL */
return
(
FALSE
);
}
*
log_group_home_dirs
=
(
char
**
)
ut_malloc
(
i
*
sizeof
(
void
*
));
*
log_group_home_dirs
=
(
char
**
)
ut_malloc
(
i
*
sizeof
(
void
*
));
/* Then store the actual values to our array */
/* Then store the actual values to our array */
...
...
mysql-test/r/innodb.result
View file @
bba81555
...
@@ -3180,3 +3180,74 @@ a hex(b)
...
@@ -3180,3 +3180,74 @@ a hex(b)
7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2
7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2
update t1 set b = 'three' where a = 6;
update t1 set b = 'three' where a = 6;
drop table t1;
drop table t1;
CREATE TABLE t1(a INT, PRIMARY KEY(a)) ENGINE=InnoDB;
CREATE TABLE t2(a INT) ENGINE=InnoDB;
ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a);
ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1;
ALTER TABLE t2 ADD CONSTRAINT t2_ibfk_0 FOREIGN KEY (a) REFERENCES t1(a);
ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) default NULL,
KEY `t2_ibfk_0` (`a`)
)
ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t2,t1;
create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
insert into t1(a) values (1),(2),(3);
commit;
set autocommit = 0;
update t1 set b = 5 where a = 2;
create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end |
set autocommit = 0;
insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100),
(11),(21),(31),(41),(51),(61),(71),(81),(91),(101),
(12),(22),(32),(42),(52),(62),(72),(82),(92),(102),
(13),(23),(33),(43),(53),(63),(73),(83),(93),(103),
(14),(24),(34),(44),(54),(64),(74),(84),(94),(104);
commit;
commit;
drop trigger t1t;
drop table t1;
create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
insert into t1(a) values (1),(2),(3);
insert into t2(a) values (1),(2),(3);
insert into t3(a) values (1),(2),(3);
insert into t4(a) values (1),(2),(3);
insert into t3(a) values (5),(7),(8);
insert into t4(a) values (5),(7),(8);
insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12);
create trigger t1t before insert on t1 for each row begin
INSERT INTO t2 SET a = NEW.a;
end |
create trigger t2t before insert on t2 for each row begin
DELETE FROM t3 WHERE a = NEW.a;
end |
create trigger t3t before delete on t3 for each row begin
UPDATE t4 SET b = b + 1 WHERE a = OLD.a;
end |
create trigger t4t before update on t4 for each row begin
UPDATE t5 SET b = b + 1 where a = NEW.a;
end |
commit;
set autocommit = 0;
update t1 set b = b + 5 where a = 1;
update t2 set b = b + 5 where a = 1;
update t3 set b = b + 5 where a = 1;
update t4 set b = b + 5 where a = 1;
insert into t5(a) values(20);
set autocommit = 0;
insert into t1(a) values(7);
insert into t2(a) values(8);
delete from t2 where a = 3;
update t4 set b = b + 1 where a = 3;
commit;
drop trigger t1t;
drop trigger t2t;
drop trigger t3t;
drop trigger t4t;
drop table t1, t2, t3, t4, t5;
mysql-test/t/innodb.test
View file @
bba81555
...
@@ -2047,3 +2047,105 @@ insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1
...
@@ -2047,3 +2047,105 @@ insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1
select
a
,
hex
(
b
)
from
t1
order
by
b
;
select
a
,
hex
(
b
)
from
t1
order
by
b
;
update
t1
set
b
=
'three'
where
a
=
6
;
update
t1
set
b
=
'three'
where
a
=
6
;
drop
table
t1
;
drop
table
t1
;
# Ensure that <tablename>_ibfk_0 is not mistreated as a
# generated foreign key identifier. (Bug #16387)
CREATE
TABLE
t1
(
a
INT
,
PRIMARY
KEY
(
a
))
ENGINE
=
InnoDB
;
CREATE
TABLE
t2
(
a
INT
)
ENGINE
=
InnoDB
;
ALTER
TABLE
t2
ADD
FOREIGN
KEY
(
a
)
REFERENCES
t1
(
a
);
ALTER
TABLE
t2
DROP
FOREIGN
KEY
t2_ibfk_1
;
ALTER
TABLE
t2
ADD
CONSTRAINT
t2_ibfk_0
FOREIGN
KEY
(
a
)
REFERENCES
t1
(
a
);
ALTER
TABLE
t2
DROP
FOREIGN
KEY
t2_ibfk_0
;
SHOW
CREATE
TABLE
t2
;
DROP
TABLE
t2
,
t1
;
#
# Test case for bug #16229: MySQL/InnoDB uses full explicit table locks in trigger processing
#
connect
(
a
,
localhost
,
root
,,);
connect
(
b
,
localhost
,
root
,,);
connection
a
;
create
table
t1
(
a
int
not
null
,
b
int
,
c
int
,
d
int
,
primary
key
(
a
))
engine
=
innodb
;
insert
into
t1
(
a
)
values
(
1
),(
2
),(
3
);
commit
;
connection
b
;
set
autocommit
=
0
;
update
t1
set
b
=
5
where
a
=
2
;
connection
a
;
delimiter
|
;
create
trigger
t1t
before
insert
on
t1
for
each
row
begin
set
NEW
.
b
=
NEW
.
a
*
10
+
5
,
NEW
.
c
=
NEW
.
a
/
10
;
end
|
delimiter
;
|
set
autocommit
=
0
;
connection
a
;
insert
into
t1
(
a
)
values
(
10
),(
20
),(
30
),(
40
),(
50
),(
60
),(
70
),(
80
),(
90
),(
100
),
(
11
),(
21
),(
31
),(
41
),(
51
),(
61
),(
71
),(
81
),(
91
),(
101
),
(
12
),(
22
),(
32
),(
42
),(
52
),(
62
),(
72
),(
82
),(
92
),(
102
),
(
13
),(
23
),(
33
),(
43
),(
53
),(
63
),(
73
),(
83
),(
93
),(
103
),
(
14
),(
24
),(
34
),(
44
),(
54
),(
64
),(
74
),(
84
),(
94
),(
104
);
connection
b
;
commit
;
connection
a
;
commit
;
drop
trigger
t1t
;
drop
table
t1
;
disconnect
a
;
disconnect
b
;
#
# Another trigger test
#
connect
(
a
,
localhost
,
root
,,);
connect
(
b
,
localhost
,
root
,,);
connection
a
;
create
table
t1
(
a
int
not
null
,
b
int
,
c
int
,
d
int
,
primary
key
(
a
))
engine
=
innodb
;
create
table
t2
(
a
int
not
null
,
b
int
,
c
int
,
d
int
,
primary
key
(
a
))
engine
=
innodb
;
create
table
t3
(
a
int
not
null
,
b
int
,
c
int
,
d
int
,
primary
key
(
a
))
engine
=
innodb
;
create
table
t4
(
a
int
not
null
,
b
int
,
c
int
,
d
int
,
primary
key
(
a
))
engine
=
innodb
;
create
table
t5
(
a
int
not
null
,
b
int
,
c
int
,
d
int
,
primary
key
(
a
))
engine
=
innodb
;
insert
into
t1
(
a
)
values
(
1
),(
2
),(
3
);
insert
into
t2
(
a
)
values
(
1
),(
2
),(
3
);
insert
into
t3
(
a
)
values
(
1
),(
2
),(
3
);
insert
into
t4
(
a
)
values
(
1
),(
2
),(
3
);
insert
into
t3
(
a
)
values
(
5
),(
7
),(
8
);
insert
into
t4
(
a
)
values
(
5
),(
7
),(
8
);
insert
into
t5
(
a
)
values
(
1
),(
2
),(
3
),(
4
),(
5
),(
6
),(
7
),(
8
),(
9
),(
10
),(
11
),(
12
);
delimiter
|
;
create
trigger
t1t
before
insert
on
t1
for
each
row
begin
INSERT
INTO
t2
SET
a
=
NEW
.
a
;
end
|
create
trigger
t2t
before
insert
on
t2
for
each
row
begin
DELETE
FROM
t3
WHERE
a
=
NEW
.
a
;
end
|
create
trigger
t3t
before
delete
on
t3
for
each
row
begin
UPDATE
t4
SET
b
=
b
+
1
WHERE
a
=
OLD
.
a
;
end
|
create
trigger
t4t
before
update
on
t4
for
each
row
begin
UPDATE
t5
SET
b
=
b
+
1
where
a
=
NEW
.
a
;
end
|
delimiter
;
|
commit
;
set
autocommit
=
0
;
update
t1
set
b
=
b
+
5
where
a
=
1
;
update
t2
set
b
=
b
+
5
where
a
=
1
;
update
t3
set
b
=
b
+
5
where
a
=
1
;
update
t4
set
b
=
b
+
5
where
a
=
1
;
insert
into
t5
(
a
)
values
(
20
);
connection
b
;
set
autocommit
=
0
;
insert
into
t1
(
a
)
values
(
7
);
insert
into
t2
(
a
)
values
(
8
);
delete
from
t2
where
a
=
3
;
update
t4
set
b
=
b
+
1
where
a
=
3
;
commit
;
drop
trigger
t1t
;
drop
trigger
t2t
;
drop
trigger
t3t
;
drop
trigger
t4t
;
drop
table
t1
,
t2
,
t3
,
t4
,
t5
;
disconnect
a
;
disconnect
b
;
sql/ha_innodb.cc
View file @
bba81555
...
@@ -138,8 +138,6 @@ extern "C" {
...
@@ -138,8 +138,6 @@ extern "C" {
#define HA_INNOBASE_ROWS_IN_TABLE 10000
/* to get optimization right */
#define HA_INNOBASE_ROWS_IN_TABLE 10000
/* to get optimization right */
#define HA_INNOBASE_RANGE_COUNT 100
#define HA_INNOBASE_RANGE_COUNT 100
uint
innobase_init_flags
=
0
;
ulong
innobase_cache_size
=
0
;
ulong
innobase_large_page_size
=
0
;
ulong
innobase_large_page_size
=
0
;
/* The default values for the following, type long or longlong, start-up
/* The default values for the following, type long or longlong, start-up
...
@@ -187,8 +185,6 @@ it every INNOBASE_WAKE_INTERVAL'th step. */
...
@@ -187,8 +185,6 @@ it every INNOBASE_WAKE_INTERVAL'th step. */
#define INNOBASE_WAKE_INTERVAL 32
#define INNOBASE_WAKE_INTERVAL 32
ulong
innobase_active_counter
=
0
;
ulong
innobase_active_counter
=
0
;
char
*
innobase_home
=
NULL
;
static
HASH
innobase_open_tables
;
static
HASH
innobase_open_tables
;
#ifdef __NETWARE__
/* some special cleanup for NetWare */
#ifdef __NETWARE__
/* some special cleanup for NetWare */
...
@@ -814,7 +810,6 @@ ha_innobase::ha_innobase(TABLE *table_arg)
...
@@ -814,7 +810,6 @@ ha_innobase::ha_innobase(TABLE *table_arg)
HA_PRIMARY_KEY_IN_READ_INDEX
|
HA_PRIMARY_KEY_IN_READ_INDEX
|
HA_CAN_GEOMETRY
|
HA_CAN_GEOMETRY
|
HA_TABLE_SCAN_ON_INDEX
),
HA_TABLE_SCAN_ON_INDEX
),
last_dup_key
((
uint
)
-
1
),
start_of_scan
(
0
),
start_of_scan
(
0
),
num_write_row
(
0
)
num_write_row
(
0
)
{}
{}
...
@@ -983,6 +978,11 @@ innobase_query_caching_of_table_permitted(
...
@@ -983,6 +978,11 @@ innobase_query_caching_of_table_permitted(
sql_print_error
(
"The calling thread is holding the adaptive "
sql_print_error
(
"The calling thread is holding the adaptive "
"search, latch though calling "
"search, latch though calling "
"innobase_query_caching_of_table_permitted."
);
"innobase_query_caching_of_table_permitted."
);
mutex_enter_noninline
(
&
kernel_mutex
);
trx_print
(
stderr
,
trx
,
1024
);
mutex_exit_noninline
(
&
kernel_mutex
);
ut_error
;
}
}
innobase_release_stat_resources
(
trx
);
innobase_release_stat_resources
(
trx
);
...
@@ -6329,14 +6329,17 @@ ha_innobase::external_lock(
...
@@ -6329,14 +6329,17 @@ ha_innobase::external_lock(
TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
an InnoDB table lock if it is released immediately at the end
an InnoDB table lock if it is released immediately at the end
of LOCK TABLES, and InnoDB's table locks in that case cause
of LOCK TABLES, and InnoDB's table locks in that case cause
VERY easily deadlocks. We do not set InnoDB table locks when
VERY easily deadlocks.
MySQL sets them at the start of a stored procedure call
(MySQL does have thd->in_lock_tables TRUE there). */
We do not set InnoDB table locks if user has not explicitly
requested a table lock. Note that thd->in_lock_tables
can be TRUE on some cases e.g. at the start of a stored
procedure call (SQLCOM_CALL). */
if
(
prebuilt
->
select_lock_type
!=
LOCK_NONE
)
{
if
(
prebuilt
->
select_lock_type
!=
LOCK_NONE
)
{
if
(
thd
->
in_lock_tables
&&
if
(
thd
->
in_lock_tables
&&
thd
->
lex
->
sql_command
!=
SQLCOM_CALL
&&
thd
->
lex
->
sql_command
==
SQLCOM_LOCK_TABLES
&&
thd
->
variables
.
innodb_table_locks
&&
thd
->
variables
.
innodb_table_locks
&&
(
thd
->
options
&
OPTION_NOT_AUTOCOMMIT
))
{
(
thd
->
options
&
OPTION_NOT_AUTOCOMMIT
))
{
...
@@ -6838,7 +6841,7 @@ ha_innobase::store_lock(
...
@@ -6838,7 +6841,7 @@ ha_innobase::store_lock(
}
else
if
(
lock_type
!=
TL_IGNORE
)
{
}
else
if
(
lock_type
!=
TL_IGNORE
)
{
/* We set possible LOCK_X value in external_lock, not yet
/* We set possible LOCK_X value in external_lock, not yet
here even if this would be SELECT ... FOR UPDATE */
here even if this would be SELECT ... FOR UPDATE */
prebuilt
->
select_lock_type
=
LOCK_NONE
;
prebuilt
->
select_lock_type
=
LOCK_NONE
;
...
@@ -6847,7 +6850,7 @@ ha_innobase::store_lock(
...
@@ -6847,7 +6850,7 @@ ha_innobase::store_lock(
if
(
lock_type
!=
TL_IGNORE
&&
lock
.
type
==
TL_UNLOCK
)
{
if
(
lock_type
!=
TL_IGNORE
&&
lock
.
type
==
TL_UNLOCK
)
{
/* Starting from 5.0.7, we weaken also the table locks
/* Starting from 5.0.7, we weaken also the table locks
set at the start of a MySQL stored procedure call, just like
set at the start of a MySQL stored procedure call, just like
we weaken the locks set at the start of an SQL statement.
we weaken the locks set at the start of an SQL statement.
MySQL does set thd->in_lock_tables TRUE there, but in reality
MySQL does set thd->in_lock_tables TRUE there, but in reality
...
@@ -6870,26 +6873,36 @@ ha_innobase::store_lock(
...
@@ -6870,26 +6873,36 @@ ha_innobase::store_lock(
lock_type
=
TL_READ_NO_INSERT
;
lock_type
=
TL_READ_NO_INSERT
;
}
}
/* If we are not doing a LOCK TABLE or DISCARD/IMPORT
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
TABLESPACE or TRUNCATE TABLE, then allow multiple writers */
TABLESPACE or TRUNCATE TABLE then allow multiple
writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
< TL_WRITE_CONCURRENT_INSERT.
if
((
lock_type
>=
TL_WRITE_CONCURRENT_INSERT
&&
We especially allow multiple writers if MySQL is at the
lock_type
<=
TL_WRITE
)
start of a stored procedure call (SQLCOM_CALL)
(MySQL does have thd->in_lock_tables TRUE there). */
if
((
lock_type
>=
TL_WRITE_CONCURRENT_INSERT
&&
lock_type
<=
TL_WRITE
)
&&
(
!
thd
->
in_lock_tables
&&
(
!
thd
->
in_lock_tables
||
thd
->
lex
->
sql_command
==
SQLCOM_CALL
)
||
thd
->
lex
->
sql_command
==
SQLCOM_CALL
)
&&
!
thd
->
tablespace_op
&&
!
thd
->
tablespace_op
&&
thd
->
lex
->
sql_command
!=
SQLCOM_TRUNCATE
&&
thd
->
lex
->
sql_command
!=
SQLCOM_TRUNCATE
&&
thd
->
lex
->
sql_command
!=
SQLCOM_OPTIMIZE
&&
thd
->
lex
->
sql_command
!=
SQLCOM_OPTIMIZE
&&
thd
->
lex
->
sql_command
!=
SQLCOM_CREATE_TABLE
)
{
&&
thd
->
lex
->
sql_command
!=
SQLCOM_CREATE_TABLE
)
{
lock_type
=
TL_WRITE_ALLOW_WRITE
;
lock_type
=
TL_WRITE_ALLOW_WRITE
;
}
}
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
to t2. Convert the lock to a normal read lock to allow
to t2. Convert the lock to a normal read lock to allow
concurrent inserts to t2. */
concurrent inserts to t2.
We especially allow concurrent inserts if MySQL is at the
start of a stored procedure call (SQLCOM_CALL)
(MySQL does have thd->in_lock_tables TRUE there). */
if
(
lock_type
==
TL_READ_NO_INSERT
if
(
lock_type
==
TL_READ_NO_INSERT
&&
(
!
thd
->
in_lock_tables
&&
(
!
thd
->
in_lock_tables
...
@@ -6898,10 +6911,10 @@ ha_innobase::store_lock(
...
@@ -6898,10 +6911,10 @@ ha_innobase::store_lock(
lock_type
=
TL_READ
;
lock_type
=
TL_READ
;
}
}
lock
.
type
=
lock_type
;
lock
.
type
=
lock_type
;
}
}
*
to
++=
&
lock
;
*
to
++=
&
lock
;
return
(
to
);
return
(
to
);
}
}
...
...
sql/ha_innodb.h
View file @
bba81555
...
@@ -52,7 +52,6 @@ class ha_innobase: public handler
...
@@ -52,7 +52,6 @@ class ha_innobase: public handler
THR_LOCK_DATA
lock
;
THR_LOCK_DATA
lock
;
INNOBASE_SHARE
*
share
;
INNOBASE_SHARE
*
share
;
gptr
alloc_ptr
;
byte
*
upd_buff
;
/* buffer used in updates */
byte
*
upd_buff
;
/* buffer used in updates */
byte
*
key_val_buff
;
/* buffer used in converting
byte
*
key_val_buff
;
/* buffer used in converting
search key values from MySQL format
search key values from MySQL format
...
@@ -62,7 +61,6 @@ class ha_innobase: public handler
...
@@ -62,7 +61,6 @@ class ha_innobase: public handler
two buffers */
two buffers */
ulong
int_table_flags
;
ulong
int_table_flags
;
uint
primary_key
;
uint
primary_key
;
uint
last_dup_key
;
ulong
start_of_scan
;
/* this is set to 1 when we are
ulong
start_of_scan
;
/* this is set to 1 when we are
starting a table scan but have not
starting a table scan but have not
yet fetched any row, else 0 */
yet fetched any row, else 0 */
...
@@ -70,7 +68,6 @@ class ha_innobase: public handler
...
@@ -70,7 +68,6 @@ class ha_innobase: public handler
ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX,
ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX,
or undefined */
or undefined */
uint
num_write_row
;
/* number of write_row() calls */
uint
num_write_row
;
/* number of write_row() calls */
ulong
max_supported_row_length
(
const
byte
*
buf
);
uint
store_key_val_for_row
(
uint
keynr
,
char
*
buff
,
uint
buff_len
,
uint
store_key_val_for_row
(
uint
keynr
,
char
*
buff
,
uint
buff_len
,
const
byte
*
record
);
const
byte
*
record
);
...
@@ -199,11 +196,8 @@ class ha_innobase: public handler
...
@@ -199,11 +196,8 @@ class ha_innobase: public handler
};
};
extern
struct
show_var_st
innodb_status_variables
[];
extern
struct
show_var_st
innodb_status_variables
[];
extern
uint
innobase_init_flags
,
innobase_lock_type
;
extern
ulong
innobase_fast_shutdown
;
extern
ulong
innobase_cache_size
,
innobase_fast_shutdown
;
extern
ulong
innobase_large_page_size
;
extern
ulong
innobase_large_page_size
;
extern
char
*
innobase_home
,
*
innobase_tmpdir
,
*
innobase_logdir
;
extern
long
innobase_lock_scan_time
;
extern
long
innobase_mirrored_log_groups
,
innobase_log_files_in_group
;
extern
long
innobase_mirrored_log_groups
,
innobase_log_files_in_group
;
extern
longlong
innobase_buffer_pool_size
,
innobase_log_file_size
;
extern
longlong
innobase_buffer_pool_size
,
innobase_log_file_size
;
extern
long
innobase_log_buffer_size
;
extern
long
innobase_log_buffer_size
;
...
@@ -240,8 +234,6 @@ extern ulong srv_commit_concurrency;
...
@@ -240,8 +234,6 @@ extern ulong srv_commit_concurrency;
extern
ulong
srv_flush_log_at_trx_commit
;
extern
ulong
srv_flush_log_at_trx_commit
;
}
}
extern
TYPELIB
innobase_lock_typelib
;
bool
innobase_init
(
void
);
bool
innobase_init
(
void
);
bool
innobase_end
(
void
);
bool
innobase_end
(
void
);
bool
innobase_flush_logs
(
void
);
bool
innobase_flush_logs
(
void
);
...
@@ -311,9 +303,6 @@ int innobase_rollback_by_xid(
...
@@ -311,9 +303,6 @@ int innobase_rollback_by_xid(
XID
*
xid
);
/* in : X/Open XA Transaction Identification */
XID
*
xid
);
/* in : X/Open XA Transaction Identification */
int
innobase_xa_end
(
THD
*
thd
);
int
innobase_repl_report_sent_binlog
(
THD
*
thd
,
char
*
log_file_name
,
int
innobase_repl_report_sent_binlog
(
THD
*
thd
,
char
*
log_file_name
,
my_off_t
end_offset
);
my_off_t
end_offset
);
...
...
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