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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
42f3c0eb
Commit
42f3c0eb
authored
Oct 05, 2004
by
marko@hundin.mysql.fi
Browse files
Options
Browse Files
Download
Plain Diff
Merge marko@build.mysql.com:/home/bk/mysql-4.0
into hundin.mysql.fi:/home/marko/k/mysql-4.0
parents
d5728b91
ca6533db
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1008 additions
and
313 deletions
+1008
-313
include/config-win.h
include/config-win.h
+7
-1
include/my_global.h
include/my_global.h
+7
-1
mysql-test/r/flush_table.result
mysql-test/r/flush_table.result
+43
-58
mysql-test/r/handler.result
mysql-test/r/handler.result
+244
-0
mysql-test/t/flush_table.test
mysql-test/t/flush_table.test
+23
-61
mysql-test/t/handler.test
mysql-test/t/handler.test
+204
-0
sql/mysql_priv.h
sql/mysql_priv.h
+7
-4
sql/mysqld.cc
sql/mysqld.cc
+6
-6
sql/records.cc
sql/records.cc
+2
-1
sql/sql_base.cc
sql/sql_base.cc
+3
-3
sql/sql_class.cc
sql/sql_class.cc
+7
-8
sql/sql_class.h
sql/sql_class.h
+1
-0
sql/sql_handler.cc
sql/sql_handler.cc
+451
-167
sql/sql_table.cc
sql/sql_table.cc
+3
-3
No files found.
include/config-win.h
View file @
42f3c0eb
...
@@ -218,7 +218,13 @@ inline double ulonglong2double(ulonglong value)
...
@@ -218,7 +218,13 @@ inline double ulonglong2double(ulonglong value)
((uint32) (uchar) (A)[0])))
((uint32) (uchar) (A)[0])))
#define sint4korr(A) (*((long *) (A)))
#define sint4korr(A) (*((long *) (A)))
#define uint2korr(A) (*((uint16 *) (A)))
#define uint2korr(A) (*((uint16 *) (A)))
#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF)
/*
ATTENTION !
Please, note, uint3korr reads 4 bytes (not 3) !
It means, that you have to provide enough allocated space !
*/
#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF)
#define uint4korr(A) (*((unsigned long *) (A)))
#define uint4korr(A) (*((unsigned long *) (A)))
#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
...
...
include/my_global.h
View file @
42f3c0eb
...
@@ -898,7 +898,13 @@ typedef char bool; /* Ordinary boolean values 0 1 */
...
@@ -898,7 +898,13 @@ typedef char bool; /* Ordinary boolean values 0 1 */
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[2])) << 16))
(((uint32) ((uchar) (A)[2])) << 16))
#else
#else
#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF)
/*
ATTENTION !
Please, note, uint3korr reads 4 bytes (not 3) !
It means, that you have to provide enough allocated space !
*/
#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF)
#endif
#endif
#define uint4korr(A) (*((unsigned long *) (A)))
#define uint4korr(A) (*((unsigned long *) (A)))
#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
...
...
mysql-test/r/flush_table.result
View file @
42f3c0eb
...
@@ -7,58 +7,6 @@ check table t1;
...
@@ -7,58 +7,6 @@ check table t1;
Table Op Msg_type Msg_text
Table Op Msg_type Msg_text
test.t1 check status OK
test.t1 check status OK
drop table t1;
drop table t1;
drop database if exists test_test;
create database test_test;
use test_test;
create table t1(table_id char(20) primary key);
insert into t1 values ('test_test.t1');
insert into t1 values ('');
handler t1 open;
handler t1 read first limit 9;
table_id
test_test.t1
create table t2(table_id char(20) primary key);
insert into t2 values ('test_test.t2');
insert into t2 values ('');
handler t2 open;
handler t2 read first limit 9;
table_id
test_test.t2
use test;
drop table if exists t1;
create table t1(table_id char(20) primary key);
insert into t1 values ('test.t1');
insert into t1 values ('');
handler t1 open;
handler t1 read first limit 9;
table_id
test.t1
use test;
handler test.t1 read first limit 9;
table_id
test.t1
handler test.t2 read first limit 9;
Unknown table 't2' in HANDLER
handler test_test.t1 read first limit 9;
table_id
test_test.t1
handler test_test.t2 read first limit 9;
table_id
test_test.t2
handler test_test.t1 close;
drop table test_test.t1;
handler test_test.t2 close;
drop table test_test.t2;
drop database test_test;
use test;
handler test.t1 close;
drop table test.t1;
drop table if exists t1;
drop table if exists t1;
drop table if exists t2;
drop table if exists t2;
create table t1(table_id char(20) primary key);
create table t1(table_id char(20) primary key);
...
@@ -84,14 +32,23 @@ test.t2
...
@@ -84,14 +32,23 @@ test.t2
flush tables;
flush tables;
handler a1 read first limit 9;
handler a1 read first limit 9;
Unknown table 'a1' in HANDLER
table_id
test.t1
handler a2 read first limit 9;
handler a2 read first limit 9;
Unknown table 'a2' in HANDLER
table_id
test.t1
handler t2 read first limit 9;
handler t2 read first limit 9;
Unknown table 't2' in HANDLER
table_id
test.t2
handler t1 open as a1;
handler t1 open as a1;
Not unique table/alias: 'a1'
handler t1 open as a2;
handler t1 open as a2;
Not unique table/alias: 'a2'
handler t2 open;
handler t2 open;
Not unique table/alias: 't2'
handler a1 read first limit 9;
handler a1 read first limit 9;
table_id
table_id
test.t1
test.t1
...
@@ -106,15 +63,43 @@ test.t2
...
@@ -106,15 +63,43 @@ test.t2
flush table t1;
flush table t1;
handler a1 read first limit 9;
handler a1 read first limit 9;
Unknown table 'a1' in HANDLER
table_id
test.t1
handler a2 read first limit 9;
handler a2 read first limit 9;
Unknown table 'a2' in HANDLER
table_id
test.t1
handler t2 read first limit 9;
handler t2 read first limit 9;
table_id
table_id
test.t2
test.t2
flush table t2;
flush table t2;
handler t2 close;
handler t2 close;
Unknown table 't2' in HANDLER
drop table t1;
drop table t1;
drop table t2;
drop table t2;
create table t1(table_id char(20) primary key);
insert into t1 values ('Record-01');
insert into t1 values ('Record-02');
insert into t1 values ('Record-03');
insert into t1 values ('Record-04');
insert into t1 values ('Record-05');
handler t1 open;
handler t1 read first limit 1;
table_id
Record-01
handler t1 read next limit 1;
table_id
Record-02
handler t1 read next limit 1;
table_id
Record-03
flush table t1;
handler t1 read next limit 1;
table_id
Record-01
handler t1 read next limit 1;
table_id
Record-02
handler t1 close;
drop table t1;
mysql-test/r/handler.result
View file @
42f3c0eb
...
@@ -203,3 +203,247 @@ handler t1 read a=(1) where b=1;
...
@@ -203,3 +203,247 @@ handler t1 read a=(1) where b=1;
a b
a b
handler t1 close;
handler t1 close;
drop table t1;
drop table t1;
drop database if exists test_test;
create database test_test;
use test_test;
create table t1(table_id char(20) primary key);
insert into t1 values ('test_test.t1');
insert into t1 values ('');
handler t1 open;
handler t1 read first limit 9;
table_id
test_test.t1
create table t2(table_id char(20) primary key);
insert into t2 values ('test_test.t2');
insert into t2 values ('');
handler t2 open;
handler t2 read first limit 9;
table_id
test_test.t2
use test;
drop table if exists t1;
create table t1(table_id char(20) primary key);
insert into t1 values ('test.t1');
insert into t1 values ('');
handler t1 open;
Not unique table/alias: 't1'
use test;
handler test.t1 read first limit 9;
Unknown table 'test.t1' in HANDLER
handler test_test.t1 read first limit 9;
table_id
test_test.t1
handler t1 read first limit 9;
table_id
test_test.t1
handler test_test.t2 read first limit 9;
table_id
test_test.t2
handler t2 read first limit 9;
table_id
test_test.t2
handler test_test.t1 close;
handler t1 close;
Unknown table 't1' in HANDLER
drop table test_test.t1;
handler test_test.t2 close;
handler t2 close;
Unknown table 't2' in HANDLER
drop table test_test.t2;
drop database test_test;
use test;
handler test.t1 close;
Unknown table 'test.t1' in HANDLER
handler t1 close;
Unknown table 't1' in HANDLER
drop table test.t1;
drop database if exists test_test;
drop table if exists t1;
drop table if exists t2;
drop table if exists t3;
create database test_test;
use test_test;
create table t1 (c1 char(20));
insert into t1 values ('test_test.t1');
create table t3 (c1 char(20));
insert into t3 values ('test_test.t3');
handler t1 open;
handler t1 read first limit 9;
c1
test_test.t1
handler t1 open h1;
handler h1 read first limit 9;
c1
test_test.t1
use test;
create table t1 (c1 char(20));
create table t2 (c1 char(20));
create table t3 (c1 char(20));
insert into t1 values ('t1');
insert into t2 values ('t2');
insert into t3 values ('t3');
handler t1 open;
Not unique table/alias: 't1'
handler t2 open t1;
Not unique table/alias: 't1'
handler t3 open t1;
Not unique table/alias: 't1'
handler t1 read first limit 9;
c1
test_test.t1
handler test.t1 close;
Unknown table 'test.t1' in HANDLER
handler test.t1 open h1;
Not unique table/alias: 'h1'
handler test_test.t1 open h1;
Not unique table/alias: 'h1'
handler test_test.t3 open h3;
handler test.t1 open h2;
handler t1 read first limit 9;
c1
test_test.t1
handler h1 read first limit 9;
c1
test_test.t1
handler h2 read first limit 9;
c1
t1
handler h3 read first limit 9;
c1
test_test.t3
handler test.h2 read first limit 9;
c1
t1
handler test.h1 close;
Unknown table 'test.h1' in HANDLER
handler test_test.t1 close;
handler test_test.h1 close;
handler h2 close;
handler t1 read first limit 9;
Unknown table 't1' in HANDLER
handler h1 read first limit 9;
Unknown table 'h1' in HANDLER
handler h2 read first limit 9;
Unknown table 'h2' in HANDLER
handler h3 read first limit 9;
c1
test_test.t3
handler test_test.h3 read first limit 9;
c1
test_test.t3
use test_test;
handler h3 read first limit 9;
c1
test_test.t3
handler test.h3 read first limit 9;
Unknown table 'test.h3' in HANDLER
handler test_test.h3 close;
use test;
drop table t3;
drop table t2;
drop table t1;
drop database test_test;
create table t1 (c1 char(20));
insert into t1 values ("t1");
handler t1 open as h1;
handler h1 read first limit 9;
c1
t1
create table t2 (c1 char(20));
insert into t2 values ("t2");
handler t2 open as h2;
handler h2 read first limit 9;
c1
t2
create table t3 (c1 char(20));
insert into t3 values ("t3");
handler t3 open as h3;
handler h3 read first limit 9;
c1
t3
create table t4 (c1 char(20));
insert into t4 values ("t4");
handler t4 open as h4;
handler h4 read first limit 9;
c1
t4
create table t5 (c1 char(20));
insert into t5 values ("t5");
handler t5 open as h5;
handler h5 read first limit 9;
c1
t5
alter table t1 engine=MyISAM;
handler h1 read first limit 9;
Unknown table 'h1' in HANDLER
handler h2 read first limit 9;
c1
t2
handler h3 read first limit 9;
c1
t3
handler h4 read first limit 9;
c1
t4
handler h5 read first limit 9;
c1
t5
alter table t5 engine=MyISAM;
handler h1 read first limit 9;
Unknown table 'h1' in HANDLER
handler h2 read first limit 9;
c1
t2
handler h3 read first limit 9;
c1
t3
handler h4 read first limit 9;
c1
t4
handler h5 read first limit 9;
Unknown table 'h5' in HANDLER
alter table t3 engine=MyISAM;
handler h1 read first limit 9;
Unknown table 'h1' in HANDLER
handler h2 read first limit 9;
c1
t2
handler h3 read first limit 9;
Unknown table 'h3' in HANDLER
handler h4 read first limit 9;
c1
t4
handler h5 read first limit 9;
Unknown table 'h5' in HANDLER
handler h2 close;
handler h4 close;
handler t1 open as h1_1;
handler t1 open as h1_2;
handler t1 open as h1_3;
handler h1_1 read first limit 9;
c1
t1
handler h1_2 read first limit 9;
c1
t1
handler h1_3 read first limit 9;
c1
t1
alter table t1 engine=MyISAM;
handler h1_1 read first limit 9;
Unknown table 'h1_1' in HANDLER
handler h1_2 read first limit 9;
Unknown table 'h1_2' in HANDLER
handler h1_3 read first limit 9;
Unknown table 'h1_3' in HANDLER
drop table t1;
drop table t2;
drop table t3;
drop table t4;
drop table t5;
mysql-test/t/flush_table.test
View file @
42f3c0eb
...
@@ -12,63 +12,10 @@ flush table t1;
...
@@ -12,63 +12,10 @@ flush table t1;
check
table
t1
;
check
table
t1
;
drop
table
t1
;
drop
table
t1
;
#
# Check if two database names beginning the same are seen as different.
#
# This database begins like the usual 'test' database.
#
--
disable_warnings
drop
database
if
exists
test_test
;
--
enable_warnings
create
database
test_test
;
use
test_test
;
create
table
t1
(
table_id
char
(
20
)
primary
key
);
insert
into
t1
values
(
'test_test.t1'
);
insert
into
t1
values
(
''
);
handler
t1
open
;
handler
t1
read
first
limit
9
;
create
table
t2
(
table_id
char
(
20
)
primary
key
);
insert
into
t2
values
(
'test_test.t2'
);
insert
into
t2
values
(
''
);
handler
t2
open
;
handler
t2
read
first
limit
9
;
#
# This is the usual 'test' database.
#
use
test
;
--
disable_warnings
drop
table
if
exists
t1
;
--
enable_warnings
create
table
t1
(
table_id
char
(
20
)
primary
key
);
insert
into
t1
values
(
'test.t1'
);
insert
into
t1
values
(
''
);
handler
t1
open
;
handler
t1
read
first
limit
9
;
#
# Check accesibility of all the tables.
#
use
test
;
handler
test
.
t1
read
first
limit
9
;
--
error
1109
;
handler
test
.
t2
read
first
limit
9
;
handler
test_test
.
t1
read
first
limit
9
;
handler
test_test
.
t2
read
first
limit
9
;
#
# Cleanup.
#
handler
test_test
.
t1
close
;
drop
table
test_test
.
t1
;
handler
test_test
.
t2
close
;
drop
table
test_test
.
t2
;
drop
database
test_test
;
#
use
test
;
handler
test
.
t1
close
;
drop
table
test
.
t1
;
#
#
# In the following test FLUSH TABLES produces a deadlock
# In the following test FLUSH TABLES produces a deadlock
# (hang forever) if the fix for bug#3565 is missing.
# (hang forever) if the fix for BUG #3565 is missing.
# And it shows that handler tables are re-opened after flush (BUG #4286).
#
#
--
disable_warnings
--
disable_warnings
drop
table
if
exists
t1
;
drop
table
if
exists
t1
;
...
@@ -87,28 +34,43 @@ handler a1 read first limit 9;
...
@@ -87,28 +34,43 @@ handler a1 read first limit 9;
handler
a2
read
first
limit
9
;
handler
a2
read
first
limit
9
;
handler
t2
read
first
limit
9
;
handler
t2
read
first
limit
9
;
flush
tables
;
flush
tables
;
--
error
1109
;
handler
a1
read
first
limit
9
;
handler
a1
read
first
limit
9
;
--
error
1109
;
handler
a2
read
first
limit
9
;
handler
a2
read
first
limit
9
;
--
error
1109
;
handler
t2
read
first
limit
9
;
handler
t2
read
first
limit
9
;
#
#
--
error
1066
handler
t1
open
as
a1
;
handler
t1
open
as
a1
;
--
error
1066
handler
t1
open
as
a2
;
handler
t1
open
as
a2
;
--
error
1066
handler
t2
open
;
handler
t2
open
;
handler
a1
read
first
limit
9
;
handler
a1
read
first
limit
9
;
handler
a2
read
first
limit
9
;
handler
a2
read
first
limit
9
;
handler
t2
read
first
limit
9
;
handler
t2
read
first
limit
9
;
flush
table
t1
;
flush
table
t1
;
--
error
1109
;
handler
a1
read
first
limit
9
;
handler
a1
read
first
limit
9
;
--
error
1109
;
handler
a2
read
first
limit
9
;
handler
a2
read
first
limit
9
;
handler
t2
read
first
limit
9
;
handler
t2
read
first
limit
9
;
flush
table
t2
;
flush
table
t2
;
--
error
1109
;
handler
t2
close
;
handler
t2
close
;
drop
table
t1
;
drop
table
t1
;
drop
table
t2
;
drop
table
t2
;
#
# The fix for BUG #4286 cannot restore the position after a flush.
#
create
table
t1
(
table_id
char
(
20
)
primary
key
);
insert
into
t1
values
(
'Record-01'
);
insert
into
t1
values
(
'Record-02'
);
insert
into
t1
values
(
'Record-03'
);
insert
into
t1
values
(
'Record-04'
);
insert
into
t1
values
(
'Record-05'
);
handler
t1
open
;
handler
t1
read
first
limit
1
;
handler
t1
read
next
limit
1
;
handler
t1
read
next
limit
1
;
flush
table
t1
;
handler
t1
read
next
limit
1
;
handler
t1
read
next
limit
1
;
handler
t1
close
;
drop
table
t1
;
mysql-test/t/handler.test
View file @
42f3c0eb
...
@@ -135,3 +135,207 @@ handler t1 read a=(1) where b=1;
...
@@ -135,3 +135,207 @@ handler t1 read a=(1) where b=1;
handler
t1
close
;
handler
t1
close
;
drop
table
t1
;
drop
table
t1
;
#
# Check if two database names beginning the same are seen as different.
#
# This database begins like the usual 'test' database.
#
--
disable_warnings
drop
database
if
exists
test_test
;
--
enable_warnings
create
database
test_test
;
use
test_test
;
create
table
t1
(
table_id
char
(
20
)
primary
key
);
insert
into
t1
values
(
'test_test.t1'
);
insert
into
t1
values
(
''
);
handler
t1
open
;
handler
t1
read
first
limit
9
;
create
table
t2
(
table_id
char
(
20
)
primary
key
);
insert
into
t2
values
(
'test_test.t2'
);
insert
into
t2
values
(
''
);
handler
t2
open
;
handler
t2
read
first
limit
9
;
#
# This is the usual 'test' database.
#
use
test
;
--
disable_warnings
drop
table
if
exists
t1
;
--
enable_warnings
create
table
t1
(
table_id
char
(
20
)
primary
key
);
insert
into
t1
values
(
'test.t1'
);
insert
into
t1
values
(
''
);
--
error
1066
handler
t1
open
;
#
# Check accesibility of all the tables.
#
use
test
;
--
error
1109
;
handler
test
.
t1
read
first
limit
9
;
handler
test_test
.
t1
read
first
limit
9
;
handler
t1
read
first
limit
9
;
handler
test_test
.
t2
read
first
limit
9
;
handler
t2
read
first
limit
9
;
#
# Cleanup.
#
handler
test_test
.
t1
close
;
--
error
1109
;
handler
t1
close
;
drop
table
test_test
.
t1
;
handler
test_test
.
t2
close
;
--
error
1109
;
handler
t2
close
;
drop
table
test_test
.
t2
;
drop
database
test_test
;
#
use
test
;
--
error
1109
;
handler
test
.
t1
close
;
--
error
1109
;
handler
t1
close
;
drop
table
test
.
t1
;
#
# BUG#4335
#
--
disable_warnings
drop
database
if
exists
test_test
;
drop
table
if
exists
t1
;
drop
table
if
exists
t2
;
drop
table
if
exists
t3
;
--
enable_warnings
create
database
test_test
;
use
test_test
;
create
table
t1
(
c1
char
(
20
));
insert
into
t1
values
(
'test_test.t1'
);
create
table
t3
(
c1
char
(
20
));
insert
into
t3
values
(
'test_test.t3'
);
handler
t1
open
;
handler
t1
read
first
limit
9
;
handler
t1
open
h1
;
handler
h1
read
first
limit
9
;
use
test
;
create
table
t1
(
c1
char
(
20
));
create
table
t2
(
c1
char
(
20
));
create
table
t3
(
c1
char
(
20
));
insert
into
t1
values
(
't1'
);
insert
into
t2
values
(
't2'
);
insert
into
t3
values
(
't3'
);
--
error
1066
handler
t1
open
;
--
error
1066
handler
t2
open
t1
;
--
error
1066
handler
t3
open
t1
;
handler
t1
read
first
limit
9
;
--
error
1109
handler
test
.
t1
close
;
--
error
1066
handler
test
.
t1
open
h1
;
--
error
1066
handler
test_test
.
t1
open
h1
;
handler
test_test
.
t3
open
h3
;
handler
test
.
t1
open
h2
;
handler
t1
read
first
limit
9
;
handler
h1
read
first
limit
9
;
handler
h2
read
first
limit
9
;
handler
h3
read
first
limit
9
;
handler
test
.
h2
read
first
limit
9
;
--
error
1109
handler
test
.
h1
close
;
handler
test_test
.
t1
close
;
handler
test_test
.
h1
close
;
handler
h2
close
;
--
error
1109
handler
t1
read
first
limit
9
;
--
error
1109
handler
h1
read
first
limit
9
;
--
error
1109
handler
h2
read
first
limit
9
;
handler
h3
read
first
limit
9
;
handler
test_test
.
h3
read
first
limit
9
;
use
test_test
;
handler
h3
read
first
limit
9
;
--
error
1109
handler
test
.
h3
read
first
limit
9
;
handler
test_test
.
h3
close
;
use
test
;
drop
table
t3
;
drop
table
t2
;
drop
table
t1
;
drop
database
test_test
;
#
# Test if fix for BUG#4286 correctly closes handler tables.
#
create
table
t1
(
c1
char
(
20
));
insert
into
t1
values
(
"t1"
);
handler
t1
open
as
h1
;
handler
h1
read
first
limit
9
;
create
table
t2
(
c1
char
(
20
));
insert
into
t2
values
(
"t2"
);
handler
t2
open
as
h2
;
handler
h2
read
first
limit
9
;
create
table
t3
(
c1
char
(
20
));
insert
into
t3
values
(
"t3"
);
handler
t3
open
as
h3
;
handler
h3
read
first
limit
9
;
create
table
t4
(
c1
char
(
20
));
insert
into
t4
values
(
"t4"
);
handler
t4
open
as
h4
;
handler
h4
read
first
limit
9
;
create
table
t5
(
c1
char
(
20
));
insert
into
t5
values
(
"t5"
);
handler
t5
open
as
h5
;
handler
h5
read
first
limit
9
;
# close first
alter
table
t1
engine
=
MyISAM
;
--
error
1109
;
handler
h1
read
first
limit
9
;
handler
h2
read
first
limit
9
;
handler
h3
read
first
limit
9
;
handler
h4
read
first
limit
9
;
handler
h5
read
first
limit
9
;
# close last
alter
table
t5
engine
=
MyISAM
;
--
error
1109
;
handler
h1
read
first
limit
9
;
handler
h2
read
first
limit
9
;
handler
h3
read
first
limit
9
;
handler
h4
read
first
limit
9
;
--
error
1109
;
handler
h5
read
first
limit
9
;
# close middle
alter
table
t3
engine
=
MyISAM
;
--
error
1109
;
handler
h1
read
first
limit
9
;
handler
h2
read
first
limit
9
;
--
error
1109
;
handler
h3
read
first
limit
9
;
handler
h4
read
first
limit
9
;
--
error
1109
;
handler
h5
read
first
limit
9
;
handler
h2
close
;
handler
h4
close
;
# close all depending handler tables
handler
t1
open
as
h1_1
;
handler
t1
open
as
h1_2
;
handler
t1
open
as
h1_3
;
handler
h1_1
read
first
limit
9
;
handler
h1_2
read
first
limit
9
;
handler
h1_3
read
first
limit
9
;
alter
table
t1
engine
=
MyISAM
;
--
error
1109
;
handler
h1_1
read
first
limit
9
;
--
error
1109
;
handler
h1_2
read
first
limit
9
;
--
error
1109
;
handler
h1_3
read
first
limit
9
;
drop
table
t1
;
drop
table
t2
;
drop
table
t3
;
drop
table
t4
;
drop
table
t5
;
sql/mysql_priv.h
View file @
42f3c0eb
...
@@ -540,12 +540,15 @@ int mysql_find_files(THD *thd,List<char> *files, const char *db,
...
@@ -540,12 +540,15 @@ int mysql_find_files(THD *thd,List<char> *files, const char *db,
const
char
*
path
,
const
char
*
wild
,
bool
dir
);
const
char
*
path
,
const
char
*
wild
,
bool
dir
);
/* sql_handler.cc */
/* sql_handler.cc */
int
mysql_ha_open
(
THD
*
thd
,
TABLE_LIST
*
tables
);
int
mysql_ha_open
(
THD
*
thd
,
TABLE_LIST
*
tables
,
bool
reopen
=
0
);
int
mysql_ha_close
(
THD
*
thd
,
TABLE_LIST
*
tables
,
int
mysql_ha_close
(
THD
*
thd
,
TABLE_LIST
*
tables
);
bool
dont_send_ok
=
0
,
bool
dont_lock
=
0
,
bool
no_alias
=
0
);
int
mysql_ha_close_list
(
THD
*
thd
,
TABLE_LIST
*
tables
,
bool
flushed
=
0
);
int
mysql_ha_read
(
THD
*
,
TABLE_LIST
*
,
enum
enum_ha_read_modes
,
char
*
,
int
mysql_ha_read
(
THD
*
,
TABLE_LIST
*
,
enum
enum_ha_read_modes
,
char
*
,
List
<
Item
>
*
,
enum
ha_rkey_function
,
Item
*
,
ha_rows
,
ha_rows
);
List
<
Item
>
*
,
enum
ha_rkey_function
,
Item
*
,
ha_rows
,
ha_rows
);
int
mysql_ha_flush
(
THD
*
thd
,
TABLE_LIST
*
tables
,
int
mode_flags
);
/* mysql_ha_flush mode_flags bits */
#define MYSQL_HA_CLOSE_FINAL 0x00
#define MYSQL_HA_REOPEN_ON_USAGE 0x01
#define MYSQL_HA_FLUSH_ALL 0x02
/* sql_base.cc */
/* sql_base.cc */
void
set_item_name
(
Item
*
item
,
char
*
pos
,
uint
length
);
void
set_item_name
(
Item
*
item
,
char
*
pos
,
uint
length
);
...
...
sql/mysqld.cc
View file @
42f3c0eb
...
@@ -1114,14 +1114,14 @@ static void set_effective_user(struct passwd *user_info)
...
@@ -1114,14 +1114,14 @@ static void set_effective_user(struct passwd *user_info)
{
{
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
DBUG_ASSERT
(
user_info
);
DBUG_ASSERT
(
user_info
);
if
(
set
egid
(
user_info
->
pw_gid
)
==
-
1
)
if
(
set
regid
((
gid_t
)
-
1
,
user_info
->
pw_gid
)
==
-
1
)
{
{
sql_perror
(
"setegid"
);
sql_perror
(
"set
r
egid"
);
unireg_abort
(
1
);
unireg_abort
(
1
);
}
}
if
(
set
euid
(
user_info
->
pw_uid
)
==
-
1
)
if
(
set
reuid
((
uid_t
)
-
1
,
user_info
->
pw_uid
)
==
-
1
)
{
{
sql_perror
(
"seteuid"
);
sql_perror
(
"set
r
euid"
);
unireg_abort
(
1
);
unireg_abort
(
1
);
}
}
#endif
#endif
...
@@ -2510,9 +2510,9 @@ You should consider changing lower_case_table_names to 1 or 2",
...
@@ -2510,9 +2510,9 @@ You should consider changing lower_case_table_names to 1 or 2",
#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT)
#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT)
if
(
locked_in_memory
&&
!
getuid
())
if
(
locked_in_memory
&&
!
getuid
())
{
{
if
(
set
euid
(
0
)
==
-
1
)
if
(
set
reuid
((
uid_t
)
-
1
,
0
)
==
-
1
)
{
// this should never happen
{
// this should never happen
sql_perror
(
"seteuid"
);
sql_perror
(
"set
r
euid"
);
unireg_abort
(
1
);
unireg_abort
(
1
);
}
}
if
(
mlockall
(
MCL_CURRENT
))
if
(
mlockall
(
MCL_CURRENT
))
...
...
sql/records.cc
View file @
42f3c0eb
...
@@ -249,9 +249,10 @@ static int init_rr_cache(READ_RECORD *info)
...
@@ -249,9 +249,10 @@ static int init_rr_cache(READ_RECORD *info)
rec_cache_size
=
info
->
cache_records
*
info
->
reclength
;
rec_cache_size
=
info
->
cache_records
*
info
->
reclength
;
info
->
rec_cache_size
=
info
->
cache_records
*
info
->
ref_length
;
info
->
rec_cache_size
=
info
->
cache_records
*
info
->
ref_length
;
// We have to allocate one more byte to use uint3korr (see comments for it)
if
(
info
->
cache_records
<=
2
||
if
(
info
->
cache_records
<=
2
||
!
(
info
->
cache
=
(
byte
*
)
my_malloc_lock
(
rec_cache_size
+
info
->
cache_records
*
!
(
info
->
cache
=
(
byte
*
)
my_malloc_lock
(
rec_cache_size
+
info
->
cache_records
*
info
->
struct_length
,
info
->
struct_length
+
1
,
MYF
(
0
))))
MYF
(
0
))))
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
#ifdef HAVE_purify
#ifdef HAVE_purify
...
...
sql/sql_base.cc
View file @
42f3c0eb
...
@@ -389,7 +389,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
...
@@ -389,7 +389,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
thd
->
proc_info
=
"Flushing tables"
;
thd
->
proc_info
=
"Flushing tables"
;
close_old_data_files
(
thd
,
thd
->
open_tables
,
1
,
1
);
close_old_data_files
(
thd
,
thd
->
open_tables
,
1
,
1
);
mysql_ha_
close_list
(
thd
,
tables
);
mysql_ha_
flush
(
thd
,
tables
,
MYSQL_HA_REOPEN_ON_USAGE
|
MYSQL_HA_FLUSH_ALL
);
bool
found
=
1
;
bool
found
=
1
;
/* Wait until all threads has closed all the tables we had locked */
/* Wait until all threads has closed all the tables we had locked */
DBUG_PRINT
(
"info"
,
(
"Waiting for others threads to close their open tables"
));
DBUG_PRINT
(
"info"
,
(
"Waiting for others threads to close their open tables"
));
...
@@ -859,7 +859,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
...
@@ -859,7 +859,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
}
}
/* close handler tables which are marked for flush */
/* close handler tables which are marked for flush */
mysql_ha_
close_list
(
thd
,
(
TABLE_LIST
*
)
NULL
,
/*flushed*/
1
);
mysql_ha_
flush
(
thd
,
(
TABLE_LIST
*
)
NULL
,
MYSQL_HA_REOPEN_ON_USAGE
);
for
(
table
=
(
TABLE
*
)
hash_search
(
&
open_cache
,(
byte
*
)
key
,
key_length
)
;
for
(
table
=
(
TABLE
*
)
hash_search
(
&
open_cache
,(
byte
*
)
key
,
key_length
)
;
table
&&
table
->
in_use
;
table
&&
table
->
in_use
;
...
@@ -1251,7 +1251,7 @@ bool wait_for_tables(THD *thd)
...
@@ -1251,7 +1251,7 @@ bool wait_for_tables(THD *thd)
{
{
thd
->
some_tables_deleted
=
0
;
thd
->
some_tables_deleted
=
0
;
close_old_data_files
(
thd
,
thd
->
open_tables
,
0
,
dropping_tables
!=
0
);
close_old_data_files
(
thd
,
thd
->
open_tables
,
0
,
dropping_tables
!=
0
);
mysql_ha_
close_list
(
thd
,
(
TABLE_LIST
*
)
NULL
,
/*flushed*/
1
);
mysql_ha_
flush
(
thd
,
(
TABLE_LIST
*
)
NULL
,
MYSQL_HA_REOPEN_ON_USAGE
);
if
(
!
table_is_used
(
thd
->
open_tables
,
1
))
if
(
!
table_is_used
(
thd
->
open_tables
,
1
))
break
;
break
;
(
void
)
pthread_cond_wait
(
&
COND_refresh
,
&
LOCK_open
);
(
void
)
pthread_cond_wait
(
&
COND_refresh
,
&
LOCK_open
);
...
...
sql/sql_class.cc
View file @
42f3c0eb
...
@@ -78,9 +78,9 @@ extern "C" void free_user_var(user_var_entry *entry)
...
@@ -78,9 +78,9 @@ extern "C" void free_user_var(user_var_entry *entry)
** Thread specific functions
** Thread specific functions
****************************************************************************/
****************************************************************************/
THD
::
THD
()
:
user_time
(
0
),
fatal_error
(
0
),
last_insert_id_used
(
0
),
THD
::
THD
()
:
user_time
(
0
),
global_read_lock
(
0
),
fatal_error
(
0
),
insert_id_used
(
0
),
rand_used
(
0
),
in_lock_tables
(
0
),
last_insert_id_used
(
0
),
insert_id_used
(
0
),
rand_used
(
0
),
global_read_lock
(
0
),
bootstrap
(
0
)
in_lock_tables
(
0
),
bootstrap
(
0
)
{
{
host
=
user
=
priv_user
=
db
=
query
=
ip
=
0
;
host
=
user
=
priv_user
=
db
=
query
=
ip
=
0
;
host_or_ip
=
"connecting host"
;
host_or_ip
=
"connecting host"
;
...
@@ -90,6 +90,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
...
@@ -90,6 +90,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
query_error
=
0
;
query_error
=
0
;
next_insert_id
=
last_insert_id
=
0
;
next_insert_id
=
last_insert_id
=
0
;
open_tables
=
temporary_tables
=
handler_tables
=
0
;
open_tables
=
temporary_tables
=
handler_tables
=
0
;
hash_clear
(
&
handler_tables_hash
);
current_tablenr
=
0
;
current_tablenr
=
0
;
handler_items
=
0
;
handler_items
=
0
;
tmp_table
=
0
;
tmp_table
=
0
;
...
@@ -215,11 +216,9 @@ void THD::cleanup(void)
...
@@ -215,11 +216,9 @@ void THD::cleanup(void)
lock
=
locked_tables
;
locked_tables
=
0
;
lock
=
locked_tables
;
locked_tables
=
0
;
close_thread_tables
(
this
);
close_thread_tables
(
this
);
}
}
if
(
handler_tables
)
mysql_ha_flush
(
this
,
(
TABLE_LIST
*
)
0
,
{
MYSQL_HA_CLOSE_FINAL
|
MYSQL_HA_FLUSH_ALL
);
open_tables
=
handler_tables
;
handler_tables
=
0
;
hash_free
(
&
handler_tables_hash
);
close_thread_tables
(
this
);
}
close_temporary_tables
(
this
);
close_temporary_tables
(
this
);
hash_free
(
&
user_vars
);
hash_free
(
&
user_vars
);
if
(
global_read_lock
)
if
(
global_read_lock
)
...
...
sql/sql_class.h
View file @
42f3c0eb
...
@@ -421,6 +421,7 @@ public:
...
@@ -421,6 +421,7 @@ public:
and are still in use by this thread
and are still in use by this thread
*/
*/
TABLE
*
open_tables
,
*
temporary_tables
,
*
handler_tables
;
TABLE
*
open_tables
,
*
temporary_tables
,
*
handler_tables
;
HASH
handler_tables_hash
;
// TODO: document the variables below
// TODO: document the variables below
MYSQL_LOCK
*
lock
,
*
locked_tables
;
MYSQL_LOCK
*
lock
,
*
locked_tables
;
ULL
*
ull
;
ULL
*
ull
;
...
...
sql/sql_handler.cc
View file @
42f3c0eb
...
@@ -17,10 +17,6 @@
...
@@ -17,10 +17,6 @@
/* HANDLER ... commands - direct access to ISAM */
/* HANDLER ... commands - direct access to ISAM */
#include "mysql_priv.h"
#include "sql_select.h"
#include <assert.h>
/* TODO:
/* TODO:
HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]
HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]
...
@@ -38,34 +34,215 @@
...
@@ -38,34 +34,215 @@
all the sql_alloc'ed memory. It's harder to work around...
all the sql_alloc'ed memory. It's harder to work around...
*/
*/
/*
There are two containers holding information about open handler tables.
The first is 'thd->handler_tables'. It is a linked list of TABLE objects.
It is used like 'thd->open_tables' in the table cache. The trick is to
exchange these two lists during open and lock of tables. Thus the normal
table cache code can be used.
The second container is a HASH. It holds objects of the type TABLE_LIST.
Despite its name, no lists of tables but only single structs are hashed
(the 'next' pointer is always NULL). The reason for theis second container
is, that we want handler tables to survive FLUSH TABLE commands. A table
affected by FLUSH TABLE must be closed so that other threads are not
blocked by handler tables still in use. Since we use the normal table cache
functions with 'thd->handler_tables', the closed tables are removed from
this list. Hence we need the original open information for the handler
table in the case that it is used again. This information is handed over
to mysql_ha_open() as a TABLE_LIST. So we store this information in the
second container, where it is not affected by FLUSH TABLE. The second
container is implemented as a hash for performance reasons. Consequently,
we use it not only for re-opening a handler table, but also for the
HANDLER ... READ commands. For this purpose, we store a pointer to the
TABLE structure (in the first container) in the TBALE_LIST object in the
second container. When the table is flushed, the pointer is cleared.
*/
#include "mysql_priv.h"
#include "sql_select.h"
#include <assert.h>
#define HANDLER_TABLES_HASH_SIZE 120
static
enum
enum_ha_read_modes
rkey_to_rnext
[]
=
{
RNEXT_SAME
,
RNEXT
,
RPREV
,
RNEXT
,
RPREV
,
RNEXT
,
RPREV
};
#define HANDLER_TABLES_HACK(thd) { \
#define HANDLER_TABLES_HACK(thd) { \
TABLE *tmp=thd->open_tables; \
TABLE *tmp=thd->open_tables; \
thd->open_tables=thd->handler_tables; \
thd->open_tables=thd->handler_tables; \
thd->handler_tables=tmp; }
thd->handler_tables=tmp; }
static
TABLE
**
find_table_ptr_by_name
(
THD
*
thd
,
const
char
*
db
,
static
int
mysql_ha_flush_table
(
THD
*
thd
,
TABLE
**
table_ptr
,
int
mode_flags
);
const
char
*
table_name
,
bool
is_alias
,
bool
dont_lock
,
bool
*
was_flushed
);
/*
Get hash key and hash key length.
SYNOPSIS
mysql_ha_hash_get_key()
tables Pointer to the hash object.
key_len_p (out) Pointer to the result for key length.
first Unused.
DESCRIPTION
The hash object is an TABLE_LIST struct.
The hash key is the alias name.
The hash key length is the alias name length plus one for the
terminateing NUL character.
RETURN
Pointer to the TABLE_LIST struct.
*/
static
char
*
mysql_ha_hash_get_key
(
TABLE_LIST
*
tables
,
uint
*
key_len_p
,
my_bool
first
__attribute__
((
unused
)))
{
*
key_len_p
=
strlen
(
tables
->
alias
)
+
1
;
/* include '\0' in comparisons */
return
tables
->
alias
;
}
/*
Free an hash object.
SYNOPSIS
mysql_ha_hash_free()
tables Pointer to the hash object.
int
mysql_ha_open
(
THD
*
thd
,
TABLE_LIST
*
tables
)
DESCRIPTION
The hash object is an TABLE_LIST struct.
RETURN
Nothing
*/
static
void
mysql_ha_hash_free
(
TABLE_LIST
*
tables
)
{
{
my_free
((
char
*
)
tables
,
MYF
(
0
));
}
/*
Open a HANDLER table.
SYNOPSIS
mysql_ha_open()
thd Thread identifier.
tables A list of tables with the first entry to open.
reopen Re-open a previously opened handler table.
DESCRIPTION
Though this function takes a list of tables, only the first list entry
will be opened.
'reopen' is set when a handler table is to be re-opened. In this case,
'tables' is the pointer to the hashed TABLE_LIST object which has been
saved on the original open.
'reopen' is also used to suppress the sending of an 'ok' message or
error messages.
RETURN
0 ok
!= 0 error
*/
int
mysql_ha_open
(
THD
*
thd
,
TABLE_LIST
*
tables
,
bool
reopen
)
{
TABLE_LIST
*
hash_tables
;
char
*
db
;
char
*
name
;
char
*
alias
;
uint
dblen
;
uint
namelen
;
uint
aliaslen
;
int
err
;
DBUG_ENTER
(
"mysql_ha_open"
);
DBUG_PRINT
(
"enter"
,(
"mysql_ha_open: '%s'.'%s' as '%s' reopen %d"
,
tables
->
db
,
tables
->
real_name
,
tables
->
alias
,
reopen
));
if
(
!
hash_inited
(
&
thd
->
handler_tables_hash
))
{
/*
HASH entries are of type TABLE_LIST.
*/
if
(
hash_init
(
&
thd
->
handler_tables_hash
,
HANDLER_TABLES_HASH_SIZE
,
0
,
0
,
(
hash_get_key
)
mysql_ha_hash_get_key
,
(
hash_free_key
)
mysql_ha_hash_free
,
0
))
goto
err
;
}
else
if
(
!
reopen
)
/* Otherwise we have 'tables' already. */
{
if
(
hash_search
(
&
thd
->
handler_tables_hash
,
(
byte
*
)
tables
->
alias
,
strlen
(
tables
->
alias
)
+
1
))
{
DBUG_PRINT
(
"info"
,(
"mysql_ha_open: duplicate '%s'"
,
tables
->
alias
));
if
(
!
reopen
)
my_printf_error
(
ER_NONUNIQ_TABLE
,
ER
(
ER_NONUNIQ_TABLE
),
MYF
(
0
),
tables
->
alias
);
goto
err
;
}
}
/*
open_tables() will set 'tables->table' if successful.
It must be NULL for a real open when calling open_tables().
*/
DBUG_ASSERT
(
!
tables
->
table
);
HANDLER_TABLES_HACK
(
thd
);
HANDLER_TABLES_HACK
(
thd
);
int
err
=
open_tables
(
thd
,
tables
);
err
=
open_tables
(
thd
,
tables
);
HANDLER_TABLES_HACK
(
thd
);
HANDLER_TABLES_HACK
(
thd
);
if
(
err
)
if
(
err
)
return
-
1
;
goto
err
;
/
/ there can be only one table in *tables
/
* There can be only one table in '*tables'. */
if
(
!
(
tables
->
table
->
file
->
table_flags
()
&
HA_CAN_SQL_HANDLER
))
if
(
!
(
tables
->
table
->
file
->
table_flags
()
&
HA_CAN_SQL_HANDLER
))
{
{
if
(
!
reopen
)
my_printf_error
(
ER_ILLEGAL_HA
,
ER
(
ER_ILLEGAL_HA
),
MYF
(
0
),
tables
->
alias
);
my_printf_error
(
ER_ILLEGAL_HA
,
ER
(
ER_ILLEGAL_HA
),
MYF
(
0
),
tables
->
alias
);
mysql_ha_close
(
thd
,
tables
,
1
);
mysql_ha_close
(
thd
,
tables
);
return
-
1
;
goto
err
;
}
}
if
(
!
reopen
)
{
/* copy the TABLE_LIST struct */
dblen
=
strlen
(
tables
->
db
)
+
1
;
namelen
=
strlen
(
tables
->
real_name
)
+
1
;
aliaslen
=
strlen
(
tables
->
alias
)
+
1
;
if
(
!
(
my_multi_malloc
(
MYF
(
MY_WME
),
&
hash_tables
,
sizeof
(
*
hash_tables
),
&
db
,
dblen
,
&
name
,
namelen
,
&
alias
,
aliaslen
,
NullS
)))
{
DBUG_PRINT
(
"exit"
,(
"mysql_ha_open: malloc ERROR"
));
goto
err
;
}
/* structure copy */
*
hash_tables
=
*
tables
;
hash_tables
->
db
=
db
;
hash_tables
->
real_name
=
name
;
hash_tables
->
alias
=
alias
;
memcpy
(
hash_tables
->
db
,
tables
->
db
,
dblen
);
memcpy
(
hash_tables
->
real_name
,
tables
->
real_name
,
namelen
);
memcpy
(
hash_tables
->
alias
,
tables
->
alias
,
aliaslen
);
/* add to hash */
if
(
hash_insert
(
&
thd
->
handler_tables_hash
,
(
byte
*
)
hash_tables
))
{
mysql_ha_close
(
thd
,
tables
);
goto
err
;
}
}
if
(
!
reopen
)
send_ok
(
&
thd
->
net
);
send_ok
(
&
thd
->
net
);
return
0
;
DBUG_PRINT
(
"exit"
,(
"mysql_ha_open: OK"
));
DBUG_RETURN
(
0
);
err:
DBUG_PRINT
(
"exit"
,(
"mysql_ha_open: ERROR"
));
DBUG_RETURN
(
-
1
);
}
}
...
@@ -76,145 +253,185 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables)
...
@@ -76,145 +253,185 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables)
mysql_ha_close()
mysql_ha_close()
thd Thread identifier.
thd Thread identifier.
tables A list of tables with the first entry to close.
tables A list of tables with the first entry to close.
dont_send_ok Suppresses the commands' ok message and
error message and error return.
dont_lock Suppresses the normal locking of LOCK_open.
DESCRIPTION
DESCRIPTION
Though this function takes a list of tables, only the first list entry
Though this function takes a list of tables, only the first list entry
will be closed. Broadcasts a COND_refresh condition.
will be closed. Broadcasts a COND_refresh condition.
If mysql_ha_close() is not called from the parser, 'dont_send_ok'
must be set.
If the caller did already lock LOCK_open, it must set 'dont_lock'.
IMPLEMENTATION
find_table_ptr_by_name() closes the table, if a FLUSH TABLE is outstanding.
It returns a NULL pointer in this case, but flags the situation in
'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages
is suppressed.
RETURN
RETURN
0 ok
0 ok
-1
error
!= 0
error
*/
*/
int
mysql_ha_close
(
THD
*
thd
,
TABLE_LIST
*
tables
,
int
mysql_ha_close
(
THD
*
thd
,
TABLE_LIST
*
tables
)
bool
dont_send_ok
,
bool
dont_lock
,
bool
no_alias
)
{
{
TABLE_LIST
*
hash_tables
;
TABLE
**
table_ptr
;
TABLE
**
table_ptr
;
bool
was_flushed
;
bool
was_flushed
=
FALSE
;
bool
not_opened
;
table_ptr
=
find_table_ptr_by_name
(
thd
,
tables
->
db
,
tables
->
alias
,
DBUG_ENTER
(
"mysql_ha_close"
);
!
no_alias
,
dont_lock
,
&
was_flushed
);
DBUG_PRINT
(
"enter"
,(
"mysql_ha_close: '%s'.'%s' as '%s'"
,
tables
->
db
,
tables
->
real_name
,
tables
->
alias
));
if
((
hash_tables
=
(
TABLE_LIST
*
)
hash_search
(
&
thd
->
handler_tables_hash
,
(
byte
*
)
tables
->
alias
,
strlen
(
tables
->
alias
)
+
1
)))
{
/*
Though we could take the table pointer from hash_tables->table,
we must follow the thd->handler_tables chain anyway, as we need the
address of the 'next' pointer referencing this table
for close_thread_table().
*/
for
(
table_ptr
=
&
(
thd
->
handler_tables
);
*
table_ptr
&&
(
*
table_ptr
!=
hash_tables
->
table
);
table_ptr
=
&
(
*
table_ptr
)
->
next
);
#if MYSQL_VERSION_ID < 40100
if
(
*
tables
->
db
&&
strcmp
(
hash_tables
->
db
,
tables
->
db
))
{
DBUG_PRINT
(
"info"
,(
"mysql_ha_close: wrong db"
));
hash_tables
=
NULL
;
}
else
#endif
{
if
(
*
table_ptr
)
if
(
*
table_ptr
)
{
{
if
(
!
dont_lock
)
VOID
(
pthread_mutex_lock
(
&
LOCK_open
));
VOID
(
pthread_mutex_lock
(
&
LOCK_open
));
if
(
close_thread_table
(
thd
,
table_ptr
))
if
(
close_thread_table
(
thd
,
table_ptr
))
{
{
/* Tell threads waiting for refresh that something has happened */
/* Tell threads waiting for refresh that something has happened */
VOID
(
pthread_cond_broadcast
(
&
COND_refresh
));
VOID
(
pthread_cond_broadcast
(
&
COND_refresh
));
}
}
if
(
!
dont_lock
)
VOID
(
pthread_mutex_unlock
(
&
LOCK_open
));
VOID
(
pthread_mutex_unlock
(
&
LOCK_open
));
}
}
else
if
(
!
was_flushed
&&
!
dont_send_ok
)
hash_delete
(
&
thd
->
handler_tables_hash
,
(
byte
*
)
hash_tables
);
}
}
if
(
!
hash_tables
)
{
{
#if MYSQL_VERSION_ID < 40100
char
buff
[
MAX_DBKEY_LENGTH
];
if
(
*
tables
->
db
)
strxnmov
(
buff
,
sizeof
(
buff
),
tables
->
db
,
"."
,
tables
->
real_name
,
NullS
);
else
strncpy
(
buff
,
tables
->
alias
,
sizeof
(
buff
));
my_printf_error
(
ER_UNKNOWN_TABLE
,
ER
(
ER_UNKNOWN_TABLE
),
MYF
(
0
),
buff
,
"HANDLER"
);
#else
my_printf_error
(
ER_UNKNOWN_TABLE
,
ER
(
ER_UNKNOWN_TABLE
),
MYF
(
0
),
my_printf_error
(
ER_UNKNOWN_TABLE
,
ER
(
ER_UNKNOWN_TABLE
),
MYF
(
0
),
tables
->
alias
,
"HANDLER"
);
tables
->
alias
,
"HANDLER"
);
return
-
1
;
#endif
DBUG_PRINT
(
"exit"
,(
"mysql_ha_close: ERROR"
));
DBUG_RETURN
(
-
1
);
}
}
if
(
!
dont_send_ok
)
send_ok
(
&
thd
->
net
);
send_ok
(
&
thd
->
net
);
return
0
;
DBUG_PRINT
(
"exit"
,(
"mysql_ha_close: OK"
));
DBUG_RETURN
(
0
);
}
}
/*
/*
Close a list of HANDLER tables
.
Read from a HANDLER table
.
SYNOPSIS
SYNOPSIS
mysql_ha_
close_list
()
mysql_ha_
read
()
thd Thread identifier.
thd Thread identifier.
tables The list of tables to close. If NULL,
tables A list of tables with the first entry to read.
close all HANDLER tables.
mode
flushed Close only tables which are marked flushed.
keyname
Used only if tables is NULL.
key_expr
ha_rkey_mode
DESCRIPTION
cond
The list of HANDLER tables may be NULL, in which case all HANDLER
select_limit
tables are closed. Broadcasts a COND_refresh condition, for
offset_limit
every table closed. If 'tables' is NULL and 'flushed' is set,
all HANDLER tables marked for flush are closed.
The caller must lock LOCK_open.
IMPLEMENTATION
find_table_ptr_by_name() closes the table, if it is marked for flush.
It returns a NULL pointer in this case, but flags the situation in
'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages
is suppressed.
RETURN
RETURN
0 ok
0 ok
!= 0 error
*/
*/
int
mysql_ha_close_list
(
THD
*
thd
,
TABLE_LIST
*
tables
,
bool
flushed
)
int
mysql_ha_read
(
THD
*
thd
,
TABLE_LIST
*
tables
,
enum
enum_ha_read_modes
mode
,
char
*
keyname
,
List
<
Item
>
*
key_expr
,
enum
ha_rkey_function
ha_rkey_mode
,
Item
*
cond
,
ha_rows
select_limit
,
ha_rows
offset_limit
)
{
{
TABLE_LIST
*
tl_item
;
TABLE_LIST
*
hash_tables
;
TABLE
**
table_ptr
;
TABLE
*
table
;
int
err
;
int
keyno
=-
1
;
uint
num_rows
;
bool
was_flushed
;
MYSQL_LOCK
*
lock
;
DBUG_ENTER
(
"mysql_ha_read"
);
DBUG_PRINT
(
"enter"
,(
"mysql_ha_read: '%s'.'%s' as '%s'"
,
tables
->
db
,
tables
->
real_name
,
tables
->
alias
));
if
(
tables
)
List
<
Item
>
list
;
{
list
.
push_front
(
new
Item_field
(
NULL
,
NULL
,
"*"
));
for
(
tl_item
=
tables
;
tl_item
;
tl_item
=
tl_item
->
next
)
List_iterator
<
Item
>
it
(
list
);
{
it
++
;
mysql_ha_close
(
thd
,
tl_item
,
/*dont_send_ok*/
1
,
/*dont_lock*/
1
,
/*no_alias*/
1
);
if
((
hash_tables
=
(
TABLE_LIST
*
)
hash_search
(
&
thd
->
handler_tables_hash
,
}
(
byte
*
)
tables
->
alias
,
}
strlen
(
tables
->
alias
)
+
1
)))
else
{
table_ptr
=
&
(
thd
->
handler_tables
);
while
(
*
table_ptr
)
{
{
if
(
!
flushed
||
((
*
table_ptr
)
->
version
!=
refresh_version
))
table
=
hash_tables
->
table
;
DBUG_PRINT
(
"info"
,(
"mysql_ha_read: found in hash '%s'.'%s' as '%s' tab %p"
,
hash_tables
->
db
,
hash_tables
->
real_name
,
hash_tables
->
alias
,
table
));
if
(
!
table
)
{
{
if
(
close_thread_table
(
thd
,
table_ptr
))
/*
The handler table has been closed. Re-open it.
*/
if
(
mysql_ha_open
(
thd
,
hash_tables
,
1
))
{
{
/* Tell threads waiting for refresh that something has happened */
DBUG_PRINT
(
"exit"
,(
"mysql_ha_read: reopen failed"
));
VOID
(
pthread_cond_broadcast
(
&
COND_refresh
))
;
goto
err0
;
}
}
continue
;
table
=
hash_tables
->
table
;
DBUG_PRINT
(
"info"
,(
"mysql_ha_read: re-opened '%s'.'%s' as '%s' tab %p"
,
hash_tables
->
db
,
hash_tables
->
real_name
,
hash_tables
->
alias
,
table
));
}
}
table_ptr
=
&
((
*
table_ptr
)
->
next
);
#if MYSQL_VERSION_ID < 40100
if
(
*
tables
->
db
&&
strcmp
(
table
->
table_cache_key
,
tables
->
db
))
{
DBUG_PRINT
(
"info"
,(
"mysql_ha_read: wrong db"
));
table
=
NULL
;
}
}
#endif
}
}
return
0
;
else
}
table
=
NULL
;
static
enum
enum_ha_read_modes
rkey_to_rnext
[]
=
{
RNEXT_SAME
,
RNEXT
,
RPREV
,
RNEXT
,
RPREV
,
RNEXT
,
RPREV
};
int
mysql_ha_read
(
THD
*
thd
,
TABLE_LIST
*
tables
,
enum
enum_ha_read_modes
mode
,
char
*
keyname
,
List
<
Item
>
*
key_expr
,
enum
ha_rkey_function
ha_rkey_mode
,
Item
*
cond
,
ha_rows
select_limit
,
ha_rows
offset_limit
)
{
int
err
,
keyno
=-
1
;
bool
was_flushed
;
TABLE
*
table
=
*
find_table_ptr_by_name
(
thd
,
tables
->
db
,
tables
->
alias
,
/*is_alias*/
1
,
/*dont_lock*/
0
,
&
was_flushed
);
if
(
!
table
)
if
(
!
table
)
{
{
my_printf_error
(
ER_UNKNOWN_TABLE
,
ER
(
ER_UNKNOWN_TABLE
),
MYF
(
0
),
#if MYSQL_VERSION_ID < 40100
tables
->
alias
,
"HANDLER"
);
char
buff
[
MAX_DBKEY_LENGTH
];
return
-
1
;
if
(
*
tables
->
db
)
strxnmov
(
buff
,
sizeof
(
buff
),
tables
->
db
,
"."
,
tables
->
real_name
,
NullS
);
else
strncpy
(
buff
,
tables
->
alias
,
sizeof
(
buff
));
my_printf_error
(
ER_UNKNOWN_TABLE
,
ER
(
ER_UNKNOWN_TABLE
),
MYF
(
0
),
buff
,
"HANDLER"
);
#else
my_printf_error
(
ER_UNKNOWN_TABLE
,
ER
(
ER_UNKNOWN_TABLE
),
MYF
(
0
),
tables
->
alias
,
"HANDLER"
);
#endif
goto
err0
;
}
}
tables
->
table
=
table
;
tables
->
table
=
table
;
if
(
cond
&&
cond
->
fix_fields
(
thd
,
tables
))
if
(
cond
&&
cond
->
fix_fields
(
thd
,
tables
))
return
-
1
;
goto
err0
;
table
->
file
->
init_table_handle_for_HANDLER
();
// Only InnoDB requires it
table
->
file
->
init_table_handle_for_HANDLER
();
// Only InnoDB requires it
...
@@ -224,24 +441,19 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
...
@@ -224,24 +441,19 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
{
{
my_printf_error
(
ER_KEY_DOES_NOT_EXITS
,
ER
(
ER_KEY_DOES_NOT_EXITS
),
MYF
(
0
),
my_printf_error
(
ER_KEY_DOES_NOT_EXITS
,
ER
(
ER_KEY_DOES_NOT_EXITS
),
MYF
(
0
),
keyname
,
tables
->
alias
);
keyname
,
tables
->
alias
);
return
-
1
;
goto
err0
;
}
}
table
->
file
->
index_init
(
keyno
);
table
->
file
->
index_init
(
keyno
);
}
}
List
<
Item
>
list
;
if
(
insert_fields
(
thd
,
tables
,
tables
->
db
,
tables
->
alias
,
&
it
))
list
.
push_front
(
new
Item_field
(
NULL
,
NULL
,
"*"
));
goto
err0
;
List_iterator
<
Item
>
it
(
list
);
uint
num_rows
;
it
++
;
insert_fields
(
thd
,
tables
,
tables
->
db
,
tables
->
alias
,
&
it
);
select_limit
+=
offset_limit
;
select_limit
+=
offset_limit
;
send_fields
(
thd
,
list
,
1
);
send_fields
(
thd
,
list
,
1
);
HANDLER_TABLES_HACK
(
thd
);
HANDLER_TABLES_HACK
(
thd
);
MYSQL_LOCK
*
lock
=
mysql_lock_tables
(
thd
,
&
tables
->
table
,
1
);
lock
=
mysql_lock_tables
(
thd
,
&
tables
->
table
,
1
);
HANDLER_TABLES_HACK
(
thd
);
HANDLER_TABLES_HACK
(
thd
);
byte
*
key
;
byte
*
key
;
...
@@ -363,83 +575,155 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
...
@@ -363,83 +575,155 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
ok:
ok:
mysql_unlock_tables
(
thd
,
lock
);
mysql_unlock_tables
(
thd
,
lock
);
send_eof
(
&
thd
->
net
);
send_eof
(
&
thd
->
net
);
return
0
;
DBUG_PRINT
(
"exit"
,(
"mysql_ha_read: OK"
));
DBUG_RETURN
(
0
);
err:
err:
mysql_unlock_tables
(
thd
,
lock
);
mysql_unlock_tables
(
thd
,
lock
);
err0:
err0:
return
-
1
;
DBUG_PRINT
(
"exit"
,(
"mysql_ha_read: ERROR"
));
DBUG_RETURN
(
-
1
);
}
}
/*
/*
F
ind a HANDLER table by name
.
F
lush (close) a list of HANDLER tables
.
SYNOPSIS
SYNOPSIS
find_table_ptr_by_name
()
mysql_ha_flush
()
thd Thread identifier.
thd Thread identifier.
db Database (schema) name.
tables The list of tables to close. If NULL,
table_name Table name ;-).
close all HANDLER tables [marked as flushed].
is_alias Table name may be an alias name.
mode_flags MYSQL_HA_CLOSE_FINAL finally close the table.
dont_lock Suppresses the normal locking of LOCK_open.
MYSQL_HA_REOPEN_ON_USAGE mark for reopen.
MYSQL_HA_FLUSH_ALL flush all tables, not only
those marked for flush.
DESCRIPTION
DESCRIPTION
Find the table 'db'.'table_name' in the list of HANDLER tables of the
The list of HANDLER tables may be NULL, in which case all HANDLER
thread 'thd'. If the table has been marked by FLUSH TABLE(S), close it,
tables are closed (if MYSQL_HA_FLUSH_ALL) is set.
flag this situation in '*was_flushed' and broadcast a COND_refresh
If 'tables' is NULL and MYSQL_HA_FLUSH_ALL is not set,
condition.
all HANDLER tables marked for flush are closed.
An empty database (schema) name matches all database (schema) names.
Broadcasts a COND_refresh condition, for every table closed.
If the caller did already lock LOCK_open, it must set 'dont_lock'.
The caller must lock LOCK_open.
IMPLEMENTATION
NOTE
Just in case that the table is twice in 'thd->handler_tables' (!?!),
Since mysql_ha_flush() is called when the base table has to be closed,
the loop does not break when the table was flushed. If another table
we compare real table names, not aliases. Hence, database names matter.
by that name was found and not flushed, '*was_flushed' is cleared again,
since a pointer to an open HANDLER table is returned.
RETURN
RETURN
*was_flushed Table has been closed due to FLUSH TABLE.
0 ok
NULL A HANDLER Table by that name does not exist (any more).
!= NULL Pointer to the TABLE structure.
*/
*/
static
TABLE
**
find_table_ptr_by_name
(
THD
*
thd
,
const
char
*
db
,
int
mysql_ha_flush
(
THD
*
thd
,
TABLE_LIST
*
tables
,
int
mode_flags
)
const
char
*
table_name
,
bool
is_alias
,
bool
dont_lock
,
bool
*
was_flushed
)
{
{
int
dblen
;
TABLE_LIST
**
tmp_tables_p
;
TABLE_LIST
*
tmp_tables
;
TABLE
**
table_ptr
;
TABLE
**
table_ptr
;
bool
was_flushed
;
DBUG_ENTER
(
"mysql_ha_flush"
);
DBUG_PRINT
(
"enter"
,(
"mysql_ha_flush: tables %p mode_flags 0x%02x"
,
tables
,
mode_flags
));
DBUG_ASSERT
(
db
);
if
(
tables
)
dblen
=
*
db
?
strlen
(
db
)
+
1
:
0
;
{
/* Close all tables in the list. */
for
(
tmp_tables
=
tables
;
tmp_tables
;
tmp_tables
=
tmp_tables
->
next
)
{
DBUG_PRINT
(
"info"
,(
"mysql_ha_flush: in tables list '%s'.'%s' as '%s'"
,
tmp_tables
->
db
,
tmp_tables
->
real_name
,
tmp_tables
->
alias
));
/* Close all currently open handler tables with the same base table. */
table_ptr
=
&
(
thd
->
handler_tables
);
while
(
*
table_ptr
)
{
if
((
!
*
tmp_tables
->
db
||
!
my_strcasecmp
((
*
table_ptr
)
->
table_cache_key
,
tmp_tables
->
db
))
&&
!
my_strcasecmp
((
*
table_ptr
)
->
real_name
,
tmp_tables
->
real_name
))
{
DBUG_PRINT
(
"info"
,(
"mysql_ha_flush: *table_ptr '%s'.'%s' as '%s'"
,
(
*
table_ptr
)
->
table_cache_key
,
(
*
table_ptr
)
->
real_name
,
(
*
table_ptr
)
->
table_name
));
mysql_ha_flush_table
(
thd
,
table_ptr
,
mode_flags
);
continue
;
}
table_ptr
=
&
(
*
table_ptr
)
->
next
;
}
/* end of handler_tables list */
}
/* end of flush tables list */
}
else
{
/* Close all currently open tables [which are marked for flush]. */
table_ptr
=
&
(
thd
->
handler_tables
);
table_ptr
=
&
(
thd
->
handler_tables
);
*
was_flushed
=
FALSE
;
while
(
*
table_ptr
)
{
if
((
mode_flags
&
MYSQL_HA_FLUSH_ALL
)
||
((
*
table_ptr
)
->
version
!=
refresh_version
))
{
mysql_ha_flush_table
(
thd
,
table_ptr
,
mode_flags
);
continue
;
}
table_ptr
=
&
(
*
table_ptr
)
->
next
;
}
}
DBUG_PRINT
(
"exit"
,(
"mysql_ha_flush: OK"
));
DBUG_RETURN
(
0
);
}
/*
Flush (close) a table.
for
(
TABLE
*
table
=*
table_ptr
;
table
;
table
=*
table_ptr
)
SYNOPSIS
mysql_ha_flush_table()
thd Thread identifier.
table The table to close.
mode_flags MYSQL_HA_CLOSE_FINAL finally close the table.
MYSQL_HA_REOPEN_ON_USAGE mark for reopen.
DESCRIPTION
Broadcasts a COND_refresh condition, for every table closed.
The caller must lock LOCK_open.
RETURN
0 ok
*/
static
int
mysql_ha_flush_table
(
THD
*
thd
,
TABLE
**
table_ptr
,
int
mode_flags
)
{
TABLE_LIST
*
hash_tables
;
TABLE
*
table
=
*
table_ptr
;
bool
was_flushed
;
DBUG_ENTER
(
"mysql_ha_flush_table"
);
DBUG_PRINT
(
"info"
,(
"mysql_ha_flush_table: '%s'.'%s' as '%s' flags 0x%02x"
,
table
->
table_cache_key
,
table
->
real_name
,
table
->
table_name
,
mode_flags
));
if
((
hash_tables
=
(
TABLE_LIST
*
)
hash_search
(
&
thd
->
handler_tables_hash
,
(
*
table_ptr
)
->
table_name
,
strlen
((
*
table_ptr
)
->
table_name
)
+
1
)))
{
{
if
((
!
dblen
||
!
memcmp
(
table
->
table_cache_key
,
db
,
dblen
))
&&
if
(
!
(
mode_flags
&
MYSQL_HA_REOPEN_ON_USAGE
))
!
my_strcasecmp
((
is_alias
?
table
->
table_name
:
table
->
real_name
),
table_name
))
{
{
if
(
table
->
version
!=
refresh_version
)
/* This is a final close. Remove from hash. */
hash_delete
(
&
thd
->
handler_tables_hash
,
(
byte
*
)
hash_tables
);
}
else
{
{
if
(
!
dont_lock
)
/* Mark table as closed, ready for re-open. */
VOID
(
pthread_mutex_lock
(
&
LOCK_open
));
hash_tables
->
table
=
NULL
;
}
}
if
(
close_thread_table
(
thd
,
table_ptr
))
if
(
close_thread_table
(
thd
,
table_ptr
))
{
{
/* Tell threads waiting for refresh that something has happened */
/* Tell threads waiting for refresh that something has happened */
VOID
(
pthread_cond_broadcast
(
&
COND_refresh
));
VOID
(
pthread_cond_broadcast
(
&
COND_refresh
));
}
}
if
(
!
dont_lock
)
VOID
(
pthread_mutex_unlock
(
&
LOCK_open
));
DBUG_PRINT
(
"exit"
,(
"mysql_ha_flush_table: OK"
));
*
was_flushed
=
TRUE
;
DBUG_RETURN
(
0
);
continue
;
}
*
was_flushed
=
FALSE
;
break
;
}
table_ptr
=&
(
table
->
next
);
}
return
table_ptr
;
}
}
sql/sql_table.cc
View file @
42f3c0eb
...
@@ -186,7 +186,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
...
@@ -186,7 +186,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
{
{
char
*
db
=
table
->
db
;
char
*
db
=
table
->
db
;
mysql_ha_
close
(
thd
,
table
,
/*dont_send_ok*/
1
,
/*dont_lock*/
1
);
mysql_ha_
flush
(
thd
,
table
,
MYSQL_HA_CLOSE_FINAL
);
if
(
!
close_temporary_table
(
thd
,
db
,
table
->
real_name
))
if
(
!
close_temporary_table
(
thd
,
db
,
table
->
real_name
))
{
{
tmp_table_deleted
=
1
;
tmp_table_deleted
=
1
;
...
@@ -1253,7 +1253,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
...
@@ -1253,7 +1253,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
if
(
send_fields
(
thd
,
field_list
,
1
))
if
(
send_fields
(
thd
,
field_list
,
1
))
DBUG_RETURN
(
-
1
);
DBUG_RETURN
(
-
1
);
mysql_ha_
close
(
thd
,
tables
,
/*dont_send_ok*/
1
,
/*dont_lock*/
1
);
mysql_ha_
flush
(
thd
,
tables
,
MYSQL_HA_CLOSE_FINAL
);
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
{
{
char
table_name
[
NAME_LEN
*
2
+
2
];
char
table_name
[
NAME_LEN
*
2
+
2
];
...
@@ -1514,7 +1514,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
...
@@ -1514,7 +1514,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
}
used_fields
=
create_info
->
used_fields
;
used_fields
=
create_info
->
used_fields
;
mysql_ha_
close
(
thd
,
table_list
,
/*dont_send_ok*/
1
,
/*dont_lock*/
1
);
mysql_ha_
flush
(
thd
,
table_list
,
MYSQL_HA_CLOSE_FINAL
);
if
(
!
(
table
=
open_ltable
(
thd
,
table_list
,
TL_WRITE_ALLOW_READ
)))
if
(
!
(
table
=
open_ltable
(
thd
,
table_list
,
TL_WRITE_ALLOW_READ
)))
DBUG_RETURN
(
-
1
);
DBUG_RETURN
(
-
1
);
...
...
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