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
69bf342a
Commit
69bf342a
authored
Jul 10, 2006
by
ingo/mydev@chilla.local
Browse files
Options
Browse Files
Download
Plain Diff
Merge chilla.local:/home/mydev/mysql-5.1-amerge
into chilla.local:/home/mydev/mysql-5.1-aid
parents
4cdb1469
99a2489e
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
335 additions
and
194 deletions
+335
-194
mysql-test/r/federated.result
mysql-test/r/federated.result
+88
-1
mysql-test/t/federated.test
mysql-test/t/federated.test
+18
-14
sql/ha_federated.cc
sql/ha_federated.cc
+218
-176
sql/ha_federated.h
sql/ha_federated.h
+11
-3
No files found.
mysql-test/r/federated.result
View file @
69bf342a
...
...
@@ -1558,6 +1558,8 @@ id
3
4
5
DROP TABLE federated.t1;
DROP TABLE federated.t1;
DROP TABLE IF EXISTS federated.bug_17377_table;
CREATE TABLE federated.bug_17377_table (
`fld_cid` bigint(20) NOT NULL auto_increment,
...
...
@@ -1601,7 +1603,92 @@ fld_cid fld_name fld_parentid fld_delt
5 Torkel 0 0
DROP TABLE federated.t1;
DROP TABLE federated.bug_17377_table;
DROP TABLE federated.t1;
create table federated.t1 (i1 int, i2 int, i3 int);
create table federated.t2 (id int, c1 varchar(20), c2 varchar(20));
create table federated.t1 (i1 int, i2 int, i3 int) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
create table federated.t2 (id int, c1 varchar(20), c2 varchar(20)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t2';
insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
select * from federated.t1 order by i1;
i1 i2 i3
1 5 10
2 2 2
3 7 12
4 5 2
9 10 15
select * from federated.t2;
id c1 c2
9 abc def
5 opq lmn
2 test t t test
update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
select * from federated.t1 order by i1;
i1 i2 i3
1 5 10
2 15 2
3 7 12
4 5 2
9 15 15
select * from federated.t2 order by id;
id c1 c2
2 test t ppc
5 opq lmn
9 abc ppc
delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
select * from federated.t1 order by i1;
i1 i2 i3
2 15 2
3 7 12
9 15 15
select * from federated.t2 order by id;
id c1 c2
2 test t ppc
9 abc ppc
drop table federated.t1, federated.t2;
drop table federated.t1, federated.t2;
create table federated.t1 (i1 int, i2 int, i3 int, primary key (i1));
create table federated.t2 (id int, c1 varchar(20), c2 varchar(20), primary key (id));
create table federated.t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
create table federated.t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t2';
insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
select * from federated.t1 order by i1;
i1 i2 i3
1 5 10
2 2 2
3 7 12
4 5 2
9 10 15
select * from federated.t2 order by id;
id c1 c2
2 test t t test
5 opq lmn
9 abc def
update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
select * from federated.t1 order by i1;
i1 i2 i3
1 5 10
2 15 2
3 7 12
4 5 2
9 15 15
select * from federated.t2 order by id;
id c1 c2
2 test t ppc
5 opq lmn
9 abc ppc
delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
select * from federated.t1 order by i1;
i1 i2 i3
2 15 2
3 7 12
9 15 15
select * from federated.t2 order by id;
id c1 c2
2 test t ppc
9 abc ppc
drop table federated.t1, federated.t2;
drop table federated.t1, federated.t2;
DROP TABLE IF EXISTS federated.t1;
DROP DATABASE IF EXISTS federated;
DROP TABLE IF EXISTS federated.t1;
...
...
mysql-test/t/federated.test
View file @
69bf342a
...
...
@@ -1256,6 +1256,10 @@ SELECT LAST_INSERT_ID();
INSERT
INTO
federated
.
t1
VALUES
();
SELECT
LAST_INSERT_ID
();
SELECT
*
FROM
federated
.
t1
;
DROP
TABLE
federated
.
t1
;
connection
slave
;
DROP
TABLE
federated
.
t1
;
#
# Bug#17377 Federated Engine returns wrong Data, always the rows
...
...
@@ -1310,19 +1314,19 @@ select * from federated.t1 where fld_parentid=0 and fld_delt=0;
DROP
TABLE
federated
.
t1
;
connection
slave
;
DROP
TABLE
federated
.
bug_17377_table
;
DROP
TABLE
federated
.
t1
;
#
# Test multi updates and deletes without keys
# BUG 19773 Crash when using multi-table updates, deletes
# with federated tables
#
# The following can be enabled when bug #19773 has been fixed
--
disable_parsing
connection
slave
;
create
table
federated
.
t1
(
i1
int
,
i2
int
,
i3
int
);
create
table
federated
.
t2
(
id
int
,
c1
varchar
(
20
),
c2
varchar
(
20
));
connection
master
;
--
replace_result
$SLAVE_MYPORT
SLAVE_PORT
eval
create
table
federated
.
t1
(
i1
int
,
i2
int
,
i3
int
)
ENGINE
=
FEDERATED
CONNECTION
=
'mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'
;
--
replace_result
$SLAVE_MYPORT
SLAVE_PORT
eval
create
table
federated
.
t2
(
id
int
,
c1
varchar
(
20
),
c2
varchar
(
20
))
ENGINE
=
FEDERATED
CONNECTION
=
'mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2'
;
insert
into
federated
.
t1
values
(
1
,
5
,
10
),(
3
,
7
,
12
),(
4
,
5
,
2
),(
9
,
10
,
15
),(
2
,
2
,
2
);
insert
into
federated
.
t2
values
(
9
,
"abc"
,
"def"
),(
5
,
"opq"
,
"lmn"
),(
2
,
"test t"
,
"t test"
);
...
...
@@ -1331,22 +1335,23 @@ select * from federated.t2;
update
federated
.
t1
,
federated
.
t2
set
t1
.
i2
=
15
,
t2
.
c2
=
"ppc"
where
t1
.
i1
=
t2
.
id
;
select
*
from
federated
.
t1
order
by
i1
;
select
*
from
federated
.
t2
order
by
id
;
delete
t1
.*
,
t2
.*
from
federated
.
t1
,
federated
.
t2
where
t1
.
i2
=
t2
.
id
;
delete
federated
.
t1
.*
,
federated
.
t2
.*
from
federated
.
t1
,
federated
.
t2
where
t1
.
i2
=
t2
.
id
;
select
*
from
federated
.
t1
order
by
i1
;
select
*
from
federated
.
t2
order
by
id
;
drop
table
federated
.
t1
,
federated
.
t2
;
connection
slave
;
drop
table
federated
.
t1
,
federated
.
t2
;
connection
master
;
# Test multi updates and deletes with keys
connection
slave
;
create
table
federated
.
t1
(
i1
int
,
i2
int
,
i3
int
,
primary
key
(
i1
));
create
table
federated
.
t2
(
id
int
,
c1
varchar
(
20
),
c2
varchar
(
20
),
primary
key
(
id
));
connection
master
;
eval
create
table
federated
.
t1
(
i1
int
auto_increment
not
null
,
i2
int
,
i3
int
,
primary
key
(
i1
))
ENGINE
=
FEDERATED
ENGINE
=
FEDERATED
CONNECTION
=
'mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'
;
eval
create
table
federated
.
t2
(
id
int
auto_increment
not
null
,
c1
varchar
(
20
),
c2
varchar
(
20
),
primary
key
(
id
))
ENGINE
=
FEDERATED
ENGINE
=
FEDERATED
CONNECTION
=
'mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2'
;
--
replace_result
$SLAVE_MYPORT
SLAVE_PORT
eval
create
table
federated
.
t1
(
i1
int
auto_increment
not
null
,
i2
int
,
i3
int
,
primary
key
(
i1
))
ENGINE
=
FEDERATED
CONNECTION
=
'mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'
;
--
replace_result
$SLAVE_MYPORT
SLAVE_PORT
eval
create
table
federated
.
t2
(
id
int
auto_increment
not
null
,
c1
varchar
(
20
),
c2
varchar
(
20
),
primary
key
(
id
))
ENGINE
=
FEDERATED
CONNECTION
=
'mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2'
;
insert
into
federated
.
t1
values
(
1
,
5
,
10
),(
3
,
7
,
12
),(
4
,
5
,
2
),(
9
,
10
,
15
),(
2
,
2
,
2
);
insert
into
federated
.
t2
values
(
9
,
"abc"
,
"def"
),(
5
,
"opq"
,
"lmn"
),(
2
,
"test t"
,
"t test"
);
select
*
from
federated
.
t1
order
by
i1
;
...
...
@@ -1354,13 +1359,12 @@ select * from federated.t2 order by id;
update
federated
.
t1
,
federated
.
t2
set
t1
.
i2
=
15
,
t2
.
c2
=
"ppc"
where
t1
.
i1
=
t2
.
id
;
select
*
from
federated
.
t1
order
by
i1
;
select
*
from
federated
.
t2
order
by
id
;
delete
t1
.*
,
t2
.*
from
federated
.
t1
,
federated
.
t2
where
t1
.
i2
=
t2
.
id
;
delete
federated
.
t1
.*
,
federated
.
t2
.*
from
federated
.
t1
,
federated
.
t2
where
t1
.
i2
=
t2
.
id
;
select
*
from
federated
.
t1
order
by
i1
;
select
*
from
federated
.
t2
order
by
id
;
drop
table
federated
.
t1
,
federated
.
t2
;
connection
slave
;
drop
table
federated
.
t1
,
federated
.
t2
;
connection
master
;
--
enable_parsing
--
source
include
/
federated_cleanup
.
inc
source
include
/
federated_cleanup
.
inc
;
sql/ha_federated.cc
View file @
69bf342a
...
...
@@ -32,13 +32,14 @@
so to read, that data has to be parsed into fields, to write, fields have to
be stored in this format to write to this data file.
With MySQL Federated storage engine, there will be no local files for each
table's data (such as .MYD). A foreign database will store the data that would
normally be in this file. This will necessitate the use of MySQL client API
to read, delete, update, insert this data. The data will have to be retrieve
via an SQL call "SELECT * FROM users". Then, to read this data, it will have
to be retrieved via mysql_fetch_row one row at a time, then converted from
the column in this select into the format that the handler expects.
With MySQL Federated storage engine, there will be no local files
for each table's data (such as .MYD). A foreign database will store
the data that would normally be in this file. This will necessitate
the use of MySQL client API to read, delete, update, insert this
data. The data will have to be retrieve via an SQL call "SELECT *
FROM users". Then, to read this data, it will have to be retrieved
via mysql_fetch_row one row at a time, then converted from the
column in this select into the format that the handler expects.
The create table will simply create the .frm file, and within the
"CREATE TABLE" SQL, there SHALL be any of the following :
...
...
@@ -385,8 +386,8 @@ static handler *federated_create_handler(TABLE_SHARE *table,
static
byte
*
federated_get_key
(
FEDERATED_SHARE
*
share
,
uint
*
length
,
my_bool
not_used
__attribute__
((
unused
)))
{
*
length
=
share
->
table_name
_length
;
return
(
byte
*
)
share
->
table_na
me
;
*
length
=
share
->
connect_string
_length
;
return
(
byte
*
)
share
->
sche
me
;
}
/*
...
...
@@ -415,7 +416,7 @@ int federated_db_init()
if
(
pthread_mutex_init
(
&
federated_mutex
,
MY_MUTEX_INIT_FAST
))
goto
error
;
if
(
!
hash_init
(
&
federated_open_tables
,
system_charset_info
,
32
,
0
,
0
,
if
(
!
hash_init
(
&
federated_open_tables
,
&
my_charset_bin
,
32
,
0
,
0
,
(
hash_get_key
)
federated_get_key
,
0
,
0
))
{
federated_init
=
TRUE
;
...
...
@@ -510,6 +511,7 @@ static int check_foreign_data_source(FEDERATED_SHARE *share,
}
else
{
int
escaped_table_name_length
=
0
;
/*
Since we do not support transactions at this version, we can let the
client API silently reconnect. For future versions, we will need more
...
...
@@ -528,17 +530,16 @@ static int check_foreign_data_source(FEDERATED_SHARE *share,
query
.
append
(
FEDERATED_STAR
);
query
.
append
(
FEDERATED_FROM
);
query
.
append
(
FEDERATED_BTICK
);
escape_string_for_mysql
(
&
my_charset_bin
,
(
char
*
)
escaped_table_name
,
escaped_table_name_length
=
escape_string_for_mysql
(
&
my_charset_bin
,
(
char
*
)
escaped_table_name
,
sizeof
(
escaped_table_name
),
share
->
table_name
,
share
->
table_name_length
);
query
.
append
(
escaped_table_name
);
query
.
append
(
escaped_table_name
,
escaped_table_name_length
);
query
.
append
(
FEDERATED_BTICK
);
query
.
append
(
FEDERATED_WHERE
);
query
.
append
(
FEDERATED_FALSE
);
DBUG_PRINT
(
"info"
,
(
"check_foreign_data_source query %s"
,
query
.
c_ptr_quick
()));
if
(
mysql_real_query
(
mysql
,
query
.
ptr
(),
query
.
length
()))
{
error_code
=
table_create_flag
?
...
...
@@ -632,8 +633,7 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table,
share
->
scheme
=
my_strndup
(
table
->
s
->
connect_string
.
str
,
table
->
s
->
connect_string
.
length
,
MYF
(
0
));
// Add a null for later termination of table name
share
->
scheme
[
table
->
s
->
connect_string
.
length
]
=
0
;
share
->
connect_string_length
=
table
->
s
->
connect_string
.
length
;
DBUG_PRINT
(
"info"
,(
"parse_url alloced share->scheme %lx"
,
share
->
scheme
));
/*
...
...
@@ -699,7 +699,7 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table,
share
->
table_name
++
;
share
->
table_name_length
=
strlen
(
share
->
table_name
);
/* make sure there's not an extra / */
if
((
strchr
(
share
->
table_name
,
'/'
)))
goto
error
;
...
...
@@ -735,8 +735,7 @@ error:
ha_federated
::
ha_federated
(
TABLE_SHARE
*
table_arg
)
:
handler
(
&
federated_hton
,
table_arg
),
mysql
(
0
),
stored_result
(
0
),
ref_length
(
sizeof
(
MYSQL_ROW_OFFSET
)),
current_position
(
0
)
mysql
(
0
),
stored_result
(
0
)
{
trx_next
=
0
;
}
...
...
@@ -747,8 +746,9 @@ ha_federated::ha_federated(TABLE_SHARE *table_arg)
SYNOPSIS
convert_row_to_internal_format()
record Byte pointer to record
row MySQL result set row from fetchrow()
record Byte pointer to record
row MySQL result set row from fetchrow()
result Result set to use
DESCRIPTION
This method simply iterates through a row returned via fetchrow with
...
...
@@ -761,15 +761,16 @@ ha_federated::ha_federated(TABLE_SHARE *table_arg)
0 After fields have had field values stored from record
*/
uint
ha_federated
::
convert_row_to_internal_format
(
byte
*
record
,
MYSQL_ROW
row
)
uint
ha_federated
::
convert_row_to_internal_format
(
byte
*
record
,
MYSQL_ROW
row
,
MYSQL_RES
*
result
)
{
ulong
*
lengths
;
Field
**
field
;
my_bitmap_map
*
old_map
=
dbug_tmp_use_all_columns
(
table
,
table
->
write_set
);
DBUG_ENTER
(
"ha_federated::convert_row_to_internal_format"
);
lengths
=
mysql_fetch_lengths
(
stored_result
);
memset
(
record
,
0
,
table
->
s
->
null_bytes
);
lengths
=
mysql_fetch_lengths
(
result
);
for
(
field
=
table
->
field
;
*
field
;
field
++
,
row
++
,
lengths
++
)
{
...
...
@@ -1314,12 +1315,11 @@ err:
static
FEDERATED_SHARE
*
get_share
(
const
char
*
table_name
,
TABLE
*
table
)
{
char
*
select_query
,
*
tmp_table_name
;
char
*
select_query
;
char
query_buffer
[
FEDERATED_QUERY_BUFFER_SIZE
];
uint
tmp_table_name_length
;
Field
**
field
;
String
query
(
query_buffer
,
sizeof
(
query_buffer
),
&
my_charset_bin
);
FEDERATED_SHARE
*
share
;
FEDERATED_SHARE
*
share
=
NULL
,
tmp_share
;
/*
In order to use this string, we must first zero it's length,
or it will contain garbage
...
...
@@ -1327,12 +1327,15 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
query
.
length
(
0
);
pthread_mutex_lock
(
&
federated_mutex
);
tmp_table_name
=
table
->
s
->
table_name
.
str
;
tmp_table_name_length
=
table
->
s
->
table_name
.
length
;
if
(
parse_url
(
&
tmp_share
,
table
,
0
))
goto
error
;
/* TODO: change tmp_share.scheme to LEX_STRING object */
if
(
!
(
share
=
(
FEDERATED_SHARE
*
)
hash_search
(
&
federated_open_tables
,
(
byte
*
)
table_name
,
tmp_table_name_length
)))
(
byte
*
)
tmp_share
.
scheme
,
tmp_share
.
connect_string_length
)))
{
query
.
set_charset
(
system_charset_info
);
query
.
append
(
FEDERATED_SELECT
);
...
...
@@ -1350,18 +1353,15 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
if
(
!
(
share
=
(
FEDERATED_SHARE
*
)
my_multi_malloc
(
MYF
(
MY_WME
),
&
share
,
sizeof
(
*
share
),
&
tmp_table_name
,
tmp_table_name_length
+
1
,
&
select_query
,
query
.
length
()
+
table
->
s
->
connect_string
.
length
+
1
,
NullS
)))
{
pthread_mutex_unlock
(
&
federated_mutex
);
return
NULL
;
}
if
(
parse_url
(
share
,
table
,
0
))
goto
error
;
memcpy
(
share
,
&
tmp_share
,
sizeof
(
tmp_share
));
share
->
table_name_length
=
strlen
(
share
->
table_name
);
/* TODO: share->table_name to LEX_STRING object */
query
.
append
(
share
->
table_name
,
share
->
table_name_length
);
query
.
append
(
FEDERATED_BTICK
);
share
->
select_query
=
select_query
;
...
...
@@ -1382,11 +1382,8 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
error:
pthread_mutex_unlock
(
&
federated_mutex
);
if
(
share
->
scheme
)
{
my_free
((
gptr
)
share
->
scheme
,
MYF
(
0
));
share
->
scheme
=
0
;
}
my_free
((
gptr
)
tmp_share
.
scheme
,
MYF
(
MY_ALLOW_ZERO_PTR
));
my_free
((
gptr
)
share
,
MYF
(
MY_ALLOW_ZERO_PTR
));
return
NULL
;
}
...
...
@@ -1406,13 +1403,7 @@ static int free_share(FEDERATED_SHARE *share)
{
hash_delete
(
&
federated_open_tables
,
(
byte
*
)
share
);
my_free
((
gptr
)
share
->
scheme
,
MYF
(
MY_ALLOW_ZERO_PTR
));
share
->
scheme
=
0
;
if
(
share
->
socket
)
{
my_free
((
gptr
)
share
->
socket
,
MYF
(
MY_ALLOW_ZERO_PTR
));
share
->
socket
=
0
;
}
my_free
((
gptr
)
share
->
socket
,
MYF
(
MY_ALLOW_ZERO_PTR
));
thr_lock_delete
(
&
share
->
lock
);
VOID
(
pthread_mutex_destroy
(
&
share
->
mutex
));
my_free
((
gptr
)
share
,
MYF
(
0
));
...
...
@@ -1474,14 +1465,15 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
/* Connect to foreign database mysql_real_connect() */
mysql
=
mysql_init
(
0
);
if
(
!
mysql_real_connect
(
mysql
,
share
->
hostname
,
share
->
username
,
share
->
password
,
share
->
database
,
share
->
port
,
share
->
socket
,
0
))
if
(
!
mysql
||
!
mysql
_real_connect
(
mysql
,
share
->
hostname
,
share
->
username
,
share
->
password
,
share
->
database
,
share
->
port
,
share
->
socket
,
0
))
{
free_share
(
share
);
DBUG_RETURN
(
stash_remote_error
());
}
/*
...
...
@@ -1491,6 +1483,11 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
*/
mysql
->
reconnect
=
1
;
ref_length
=
(
table
->
s
->
primary_key
!=
MAX_KEY
?
table
->
key_info
[
table
->
s
->
primary_key
].
key_length
:
table
->
s
->
reclength
);
DBUG_PRINT
(
"info"
,
(
"ref_length: %u"
,
ref_length
));
DBUG_RETURN
(
0
);
}
...
...
@@ -1514,13 +1511,12 @@ int ha_federated::close(void)
/* free the result set */
if
(
stored_result
)
{
DBUG_PRINT
(
"info"
,
(
"mysql_free_result result at address %lx"
,
stored_result
));
mysql_free_result
(
stored_result
);
stored_result
=
0
;
}
/* Disconnect from mysql */
mysql_close
(
mysql
);
if
(
mysql
)
// QQ is this really needed
mysql_close
(
mysql
);
retval
=
free_share
(
share
);
DBUG_RETURN
(
retval
);
...
...
@@ -1686,8 +1682,6 @@ int ha_federated::write_row(byte *buf)
/* add the values */
insert_string
.
append
(
values_string
);
DBUG_PRINT
(
"info"
,
(
"insert query %s"
,
insert_string
.
c_ptr_quick
()));
if
(
mysql_real_query
(
mysql
,
insert_string
.
ptr
(),
insert_string
.
length
()))
{
DBUG_RETURN
(
stash_remote_error
());
...
...
@@ -1763,7 +1757,7 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt)
query
.
append
(
FEDERATED_EXTENDED
);
if
(
check_opt
->
sql_flags
&
TT_USEFRM
)
query
.
append
(
FEDERATED_USE_FRM
);
if
(
mysql_real_query
(
mysql
,
query
.
ptr
(),
query
.
length
()))
{
DBUG_RETURN
(
stash_remote_error
());
...
...
@@ -1919,7 +1913,7 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
/*
This will delete a row. 'buf' will contain a copy of the row to be =deleted.
The server will call this right after the current row has been called (from
either a previous rnd_nex
T
() or index call).
either a previous rnd_nex
t
() or index call).
If you keep a pointer to the last row or can access a primary key it will
make doing the deletion quite a bit easier.
Keep in mind that the server does no guarentee consecutive deletions.
...
...
@@ -1985,6 +1979,7 @@ int ha_federated::delete_row(const byte *buf)
DBUG_RETURN
(
stash_remote_error
());
}
stats
.
deleted
+=
mysql
->
affected_rows
;
stats
.
records
-=
mysql
->
affected_rows
;
DBUG_PRINT
(
"info"
,
(
"rows deleted %d rows deleted for all time %d"
,
int
(
mysql
->
affected_rows
),
stats
.
deleted
));
...
...
@@ -2001,12 +1996,15 @@ int ha_federated::delete_row(const byte *buf)
*/
int
ha_federated
::
index_read
(
byte
*
buf
,
const
byte
*
key
,
uint
key_len
,
enum
ha_rkey_function
find_flag
)
uint
key_len
,
ha_rkey_function
find_flag
)
{
int
retval
;
DBUG_ENTER
(
"ha_federated::index_read"
);
retval
=
index_read_idx
(
buf
,
active_index
,
key
,
key_len
,
find_flag
);
DBUG_RETURN
(
retval
);
if
(
stored_result
)
mysql_free_result
(
stored_result
);
DBUG_RETURN
(
index_read_idx_with_result_set
(
buf
,
active_index
,
key
,
key_len
,
find_flag
,
&
stored_result
));
}
...
...
@@ -2015,26 +2013,60 @@ int ha_federated::index_read(byte *buf, const byte *key,
row if any. This is only used to read whole keys.
This method is called via index_read in the case of a WHERE clause using
a
regular non-primary key index,
OR is called DIRECTLY when the WHERE clause
a
primary key index
OR is called DIRECTLY when the WHERE clause
uses a PRIMARY KEY index.
NOTES
This uses an internal result set that is deleted before function
returns. We need to be able to be calable from ha_rnd_pos()
*/
int
ha_federated
::
index_read_idx
(
byte
*
buf
,
uint
index
,
const
byte
*
key
,
uint
key_len
,
enum
ha_rkey_function
find_flag
)
{
int
retval
;
MYSQL_RES
*
mysql_result
;
DBUG_ENTER
(
"ha_federated::index_read_idx"
);
if
((
retval
=
index_read_idx_with_result_set
(
buf
,
index
,
key
,
key_len
,
find_flag
,
&
mysql_result
)))
DBUG_RETURN
(
retval
);
mysql_free_result
(
mysql_result
);
DBUG_RETURN
(
retval
);
}
/*
Create result set for rows matching query and return first row
RESULT
0 ok In this case *result will contain the result set
table->status == 0
# error In this case *result will contain 0
table->status == STATUS_NOT_FOUND
*/
int
ha_federated
::
index_read_idx_with_result_set
(
byte
*
buf
,
uint
index
,
const
byte
*
key
,
uint
key_len
,
ha_rkey_function
find_flag
,
MYSQL_RES
**
result
)
{
int
retval
;
char
error_buffer
[
FEDERATED_QUERY_BUFFER_SIZE
];
char
index_value
[
STRING_BUFFER_USUAL_SIZE
];
char
sql_query_buffer
[
FEDERATED_QUERY_BUFFER_SIZE
];
String
index_string
(
index_value
,
String
index_string
(
index_value
,
sizeof
(
index_value
),
&
my_charset_bin
);
String
sql_query
(
sql_query_buffer
,
sizeof
(
sql_query_buffer
),
&
my_charset_bin
);
key_range
range
;
DBUG_ENTER
(
"ha_federated::index_read_idx"
);
DBUG_ENTER
(
"ha_federated::index_read_idx
_with_result_set
"
);
*
result
=
0
;
// In case of errors
index_string
.
length
(
0
);
sql_query
.
length
(
0
);
statistic_increment
(
table
->
in_use
->
status_var
.
ha_read_key_count
,
...
...
@@ -2051,20 +2083,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
NULL
,
0
,
0
);
sql_query
.
append
(
index_string
);
DBUG_PRINT
(
"info"
,
(
"current key %d key value %s index_string value %s length %d"
,
index
,
(
char
*
)
key
,
index_string
.
c_ptr_quick
(),
index_string
.
length
()));
DBUG_PRINT
(
"info"
,
(
"current position %d sql_query %s"
,
current_position
,
sql_query
.
c_ptr_quick
()));
if
(
stored_result
)
{
mysql_free_result
(
stored_result
);
stored_result
=
0
;
}
if
(
mysql_real_query
(
mysql
,
sql_query
.
ptr
(),
sql_query
.
length
()))
{
my_sprintf
(
error_buffer
,
(
error_buffer
,
"error: %d '%s'"
,
...
...
@@ -2072,45 +2090,41 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
retval
=
ER_QUERY_ON_FOREIGN_DATA_SOURCE
;
goto
error
;
}
stored_result
=
mysql_store_result
(
mysql
);
if
(
!
stored_result
)
if
(
!
(
*
result
=
mysql_store_result
(
mysql
)))
{
retval
=
HA_ERR_END_OF_FILE
;
goto
error
;
}
/*
This basically says that the record in table->record[0] is legal,
and that it is ok to use this record, for whatever reason, such
as with a join (without it, joins will not work)
*/
table
->
status
=
0
;
if
(
!
(
retval
=
read_next
(
buf
,
*
result
)))
DBUG_RETURN
(
retval
);
retval
=
rnd_next
(
buf
);
mysql_free_result
(
*
result
);
*
result
=
0
;
table
->
status
=
STATUS_NOT_FOUND
;
DBUG_RETURN
(
retval
);
error:
if
(
stored_result
)
{
mysql_free_result
(
stored_result
);
stored_result
=
0
;
}
table
->
status
=
STATUS_NOT_FOUND
;
my_error
(
retval
,
MYF
(
0
),
error_buffer
);
DBUG_RETURN
(
retval
);
}
/* Initialized at each key walk (called multiple times unlike rnd_init()) */
int
ha_federated
::
index_init
(
uint
keynr
,
bool
sorted
)
{
DBUG_ENTER
(
"ha_federated::index_init"
);
DBUG_PRINT
(
"info"
,
(
"table: '%s' key: %d"
,
table
->
s
->
table_name
.
str
,
keynr
));
DBUG_PRINT
(
"info"
,
(
"table: '%s' key: %u"
,
table
->
s
->
table_name
,
keynr
));
active_index
=
keynr
;
DBUG_RETURN
(
0
);
}
/*
Read first range
*/
int
ha_federated
::
read_range_first
(
const
key_range
*
start_key
,
const
key_range
*
end_key
,
bool
eq_range
,
bool
sorted
)
...
...
@@ -2122,8 +2136,7 @@ int ha_federated::read_range_first(const key_range *start_key,
&
my_charset_bin
);
DBUG_ENTER
(
"ha_federated::read_range_first"
);
if
(
start_key
==
NULL
&&
end_key
==
NULL
)
DBUG_RETURN
(
0
);
DBUG_ASSERT
(
!
(
start_key
==
NULL
&&
end_key
==
NULL
));
sql_query
.
length
(
0
);
sql_query
.
append
(
share
->
select_query
);
...
...
@@ -2131,6 +2144,11 @@ int ha_federated::read_range_first(const key_range *start_key,
&
table
->
key_info
[
active_index
],
start_key
,
end_key
,
0
,
eq_range
);
if
(
stored_result
)
{
mysql_free_result
(
stored_result
);
stored_result
=
0
;
}
if
(
mysql_real_query
(
mysql
,
sql_query
.
ptr
(),
sql_query
.
length
()))
{
retval
=
ER_QUERY_ON_FOREIGN_DATA_SOURCE
;
...
...
@@ -2138,38 +2156,21 @@ int ha_federated::read_range_first(const key_range *start_key,
}
sql_query
.
length
(
0
);
if
(
stored_result
)
{
DBUG_PRINT
(
"info"
,
(
"mysql_free_result address %lx"
,
stored_result
));
mysql_free_result
(
stored_result
);
stored_result
=
0
;
}
stored_result
=
mysql_store_result
(
mysql
);
if
(
!
stored_result
)
if
(
!
(
stored_result
=
mysql_store_result
(
mysql
)))
{
retval
=
HA_ERR_END_OF_FILE
;
goto
error
;
}
/* This was successful, please let it be known! */
table
->
status
=
0
;
retval
=
r
nd_next
(
table
->
record
[
0
]
);
retval
=
r
ead_next
(
table
->
record
[
0
],
stored_result
);
DBUG_RETURN
(
retval
);
error:
table
->
status
=
STATUS_NOT_FOUND
;
if
(
stored_result
)
{
DBUG_PRINT
(
"info"
,
(
"mysql_free_result address %lx"
,
stored_result
));
mysql_free_result
(
stored_result
);
stored_result
=
0
;
}
DBUG_RETURN
(
retval
);
table
->
status
=
STATUS_NOT_FOUND
;
DBUG_RETURN
(
retval
);
}
int
ha_federated
::
read_range_next
()
{
int
retval
;
...
...
@@ -2182,13 +2183,13 @@ int ha_federated::read_range_next()
/* Used to read forward through the index. */
int
ha_federated
::
index_next
(
byte
*
buf
)
{
int
retval
;
DBUG_ENTER
(
"ha_federated::index_next"
);
statistic_increment
(
table
->
in_use
->
status_var
.
ha_read_next_count
,
&
LOCK_status
);
retval
=
rnd_next
(
buf
);
DBUG_RETURN
(
retval
);
DBUG_RETURN
(
read_next
(
buf
,
stored_result
));
}
/*
rnd_init() is called when the system wants the storage engine to do a table
scan.
...
...
@@ -2242,11 +2243,8 @@ int ha_federated::rnd_init(bool scan)
if
(
scan
)
{
DBUG_PRINT
(
"info"
,
(
"share->select_query %s"
,
share
->
select_query
));
if
(
stored_result
)
{
DBUG_PRINT
(
"info"
,
(
"mysql_free_result address %lx"
,
stored_result
));
mysql_free_result
(
stored_result
);
stored_result
=
0
;
}
...
...
@@ -2263,28 +2261,25 @@ int ha_federated::rnd_init(bool scan)
DBUG_RETURN
(
0
);
error:
DBUG_RETURN
(
stash_remote_error
());
DBUG_RETURN
(
stash_remote_error
());
}
int
ha_federated
::
rnd_end
()
{
int
retval
;
DBUG_ENTER
(
"ha_federated::rnd_end"
);
if
(
stored_result
)
{
DBUG_PRINT
(
"info"
,
(
"mysql_free_result address %lx"
,
stored_result
));
mysql_free_result
(
stored_result
);
stored_result
=
0
;
}
retval
=
index_end
();
DBUG_RETURN
(
retval
);
DBUG_RETURN
(
index_end
());
}
int
ha_federated
::
index_end
(
void
)
{
DBUG_ENTER
(
"ha_federated::index_end"
);
if
(
stored_result
)
{
mysql_free_result
(
stored_result
);
stored_result
=
0
;
}
active_index
=
MAX_KEY
;
DBUG_RETURN
(
0
);
}
...
...
@@ -2302,8 +2297,6 @@ int ha_federated::index_end(void)
int
ha_federated
::
rnd_next
(
byte
*
buf
)
{
int
retval
;
MYSQL_ROW
row
;
DBUG_ENTER
(
"ha_federated::rnd_next"
);
if
(
stored_result
==
0
)
...
...
@@ -2311,32 +2304,60 @@ int ha_federated::rnd_next(byte *buf)
/*
Return value of rnd_init is not always checked (see records.cc),
so we can get here _even_ if there is _no_ pre-fetched result-set!
TODO: fix it.
*/
TODO: fix it.
We can delete this in 5.1 when rnd_init() is checked.
*/
DBUG_RETURN
(
1
);
}
DBUG_RETURN
(
read_next
(
buf
,
stored_result
));
}
/*
ha_federated::read_next
reads from a result set and converts to mysql internal
format
SYNOPSIS
field_in_record_is_null()
buf byte pointer to record
result mysql result set
DESCRIPTION
This method is a wrapper method that reads one record from a result
set and converts it to the internal table format
RETURN VALUE
1 error
0 no error
*/
int
ha_federated
::
read_next
(
byte
*
buf
,
MYSQL_RES
*
result
)
{
int
retval
;
my_ulonglong
num_rows
;
MYSQL_ROW
row
;
DBUG_ENTER
(
"ha_federated::read_next"
);
table
->
status
=
STATUS_NOT_FOUND
;
// For easier return
/* Fetch a row, insert it back in a row format. */
current_position
=
stored_result
->
data_cursor
;
DBUG_PRINT
(
"info"
,
(
"current position %d"
,
current_position
));
if
(
!
(
row
=
mysql_fetch_row
(
stored_result
)))
if
(
!
(
row
=
mysql_fetch_row
(
result
)))
DBUG_RETURN
(
HA_ERR_END_OF_FILE
);
retval
=
convert_row_to_internal_format
(
buf
,
row
);
if
(
!
(
retval
=
convert_row_to_internal_format
(
buf
,
row
,
result
)))
table
->
status
=
0
;
DBUG_RETURN
(
retval
);
}
/*
'position()' is called after each call to rnd_next() if the data needs to be
ordered. You can do something like the following to store the position:
my_store_ptr(ref, ref_length, current_position);
store reference to current row so that we can later find it for
a re-read, update or delete.
The server uses ref to store data. ref_length in the above case is the size
needed to store current_position. ref is just a byte array that the server
will maintain. If you are using offsets to mark rows, then current_position
should be the offset. If it is a primary key like in BDB, then it needs to
be a primary key.
In case of federated, a reference is either a primary key or
the whole record.
Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
*/
...
...
@@ -2344,32 +2365,44 @@ int ha_federated::rnd_next(byte *buf)
void
ha_federated
::
position
(
const
byte
*
record
)
{
DBUG_ENTER
(
"ha_federated::position"
);
/* my_store_ptr Add seek storage */
*
(
MYSQL_ROW_OFFSET
*
)
ref
=
current_position
;
// ref is always aligned
if
(
table
->
s
->
primary_key
!=
MAX_KEY
)
key_copy
(
ref
,
(
byte
*
)
record
,
table
->
key_info
+
table
->
s
->
primary_key
,
ref_length
);
else
memcpy
(
ref
,
record
,
ref_length
);
DBUG_VOID_RETURN
;
}
/*
This is like rnd_next, but you are given a position to use to determine the
row. The position will be of the type that you stored in ref. You can use
ha_get_ptr(pos,ref_length) to retrieve whatever key or position you saved
when position() was called.
row. The position will be of the type that you stored in ref.
This method is required for an ORDER BY
.
This method is required for an ORDER BY
Called from filesort.cc records.cc sql_insert.cc sql_select.cc sql_update.cc.
*/
int
ha_federated
::
rnd_pos
(
byte
*
buf
,
byte
*
pos
)
{
int
result
;
DBUG_ENTER
(
"ha_federated::rnd_pos"
);
statistic_increment
(
table
->
in_use
->
status_var
.
ha_read_rnd_count
,
&
LOCK_status
);
memcpy_fixed
(
&
current_position
,
pos
,
sizeof
(
MYSQL_ROW_OFFSET
));
stored_result
->
current_row
=
0
;
stored_result
->
data_cursor
=
current_position
;
DBUG_RETURN
(
rnd_next
(
buf
));
if
(
table
->
s
->
primary_key
!=
MAX_KEY
)
{
/* We have a primary key, so use index_read_idx to find row */
result
=
index_read_idx
(
buf
,
table
->
s
->
primary_key
,
pos
,
ref_length
,
HA_READ_KEY_EXACT
);
}
else
{
/* otherwise, get the old record ref as obtained in ::position */
memcpy
(
buf
,
pos
,
ref_length
);
result
=
0
;
}
table
->
status
=
result
?
STATUS_NOT_FOUND
:
0
;
DBUG_RETURN
(
result
);
}
...
...
@@ -2462,7 +2495,7 @@ void ha_federated::info(uint flag)
if
(
flag
&
HA_STATUS_VARIABLE
|
HA_STATUS_CONST
)
{
/*
/*
deleted is set in ha_federated::info
*/
/*
...
...
@@ -2474,11 +2507,13 @@ void ha_federated::info(uint flag)
delete_length = ?
*/
if
(
row
[
4
]
!=
NULL
)
stats
.
records
=
(
ha_rows
)
my_strtoll10
(
row
[
4
],
(
char
**
)
0
,
stats
.
records
=
(
ha_rows
)
my_strtoll10
(
row
[
4
],
(
char
**
)
0
,
&
error
);
if
(
row
[
5
]
!=
NULL
)
stats
.
mean_rec_length
=
(
ha_rows
)
my_strtoll10
(
row
[
5
],
(
char
**
)
0
,
&
error
);
stats
.
mean_rec_length
=
(
ha_rows
)
my_strtoll10
(
row
[
5
],
(
char
**
)
0
,
&
error
);
stats
.
data_file_length
=
stats
.
records
*
stats
.
mean_rec_length
;
if
(
row
[
12
]
!=
NULL
)
stats
.
update_time
=
(
ha_rows
)
my_strtoll10
(
row
[
12
],
(
char
**
)
0
,
&
error
);
...
...
@@ -2486,8 +2521,13 @@ void ha_federated::info(uint flag)
stats
.
check_time
=
(
ha_rows
)
my_strtoll10
(
row
[
13
],
(
char
**
)
0
,
&
error
);
}
/*
size of IO operations (This is based on a good guess, no high science
involved)
*/
if
(
flag
&
HA_STATUS_CONST
)
stats
.
block_size
=
4096
;
}
if
(
result
)
...
...
@@ -2498,6 +2538,7 @@ void ha_federated::info(uint flag)
error:
if
(
result
)
mysql_free_result
(
result
);
my_sprintf
(
error_buffer
,
(
error_buffer
,
": %d : %s"
,
mysql_errno
(
mysql
),
mysql_error
(
mysql
)));
my_error
(
error_code
,
MYF
(
0
),
error_buffer
);
...
...
@@ -2578,6 +2619,7 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
THR_LOCK_DATA
**
to
,
enum
thr_lock_type
lock_type
)
{
DBUG_ENTER
(
"ha_federated::store_lock"
);
if
(
lock_type
!=
TL_IGNORE
&&
lock
.
type
==
TL_UNLOCK
)
{
/*
...
...
@@ -2607,7 +2649,7 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
*
to
++=
&
lock
;
return
to
;
DBUG_RETURN
(
to
)
;
}
/*
...
...
sql/ha_federated.h
View file @
69bf342a
...
...
@@ -130,6 +130,7 @@ typedef struct st_federated_share {
remote host info, parse_url supplies
*/
char
*
scheme
;
char
*
connect_string
;
char
*
hostname
;
char
*
username
;
char
*
password
;
...
...
@@ -139,7 +140,7 @@ typedef struct st_federated_share {
char
*
socket
;
char
*
sport
;
ushort
port
;
uint
table_name_length
,
use_count
;
uint
table_name_length
,
connect_string_length
,
use_count
;
pthread_mutex_t
mutex
;
THR_LOCK
lock
;
}
FEDERATED_SHARE
;
...
...
@@ -153,7 +154,6 @@ class ha_federated: public handler
FEDERATED_SHARE
*
share
;
/* Shared lock info */
MYSQL
*
mysql
;
/* MySQL connection */
MYSQL_RES
*
stored_result
;
uint
ref_length
;
uint
fetch_num
;
// stores the fetch num
MYSQL_ROW_OFFSET
current_position
;
// Current position used by ::position()
int
remote_error_number
;
...
...
@@ -164,7 +164,8 @@ private:
return 0 on success
return errorcode otherwise
*/
uint
convert_row_to_internal_format
(
byte
*
buf
,
MYSQL_ROW
row
);
uint
convert_row_to_internal_format
(
byte
*
buf
,
MYSQL_ROW
row
,
MYSQL_RES
*
row
);
bool
create_where_from_key
(
String
*
to
,
KEY
*
key_info
,
const
key_range
*
start_key
,
const
key_range
*
end_key
,
...
...
@@ -304,6 +305,13 @@ public:
int
connection_rollback
();
int
connection_autocommit
(
bool
state
);
int
execute_simple_query
(
const
char
*
query
,
int
len
);
int
read_next
(
byte
*
buf
,
MYSQL_RES
*
result
);
int
index_read_idx_with_result_set
(
byte
*
buf
,
uint
index
,
const
byte
*
key
,
uint
key_len
,
ha_rkey_function
find_flag
,
MYSQL_RES
**
result
);
};
int
federated_db_init
(
void
);
...
...
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