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
00738a2b
Commit
00738a2b
authored
Apr 08, 2004
by
monty@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge bk-internal.mysql.com:/home/bk/mysql-4.1
into mysql.com:/home/my/mysql-4.1
parents
3b6c3dd2
43546e7a
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
449 additions
and
270 deletions
+449
-270
mysql-test/mysql-test-run.sh
mysql-test/mysql-test-run.sh
+1
-1
mysql-test/r/gis-rtree.result
mysql-test/r/gis-rtree.result
+7
-0
mysql-test/r/grant.result
mysql-test/r/grant.result
+2
-0
mysql-test/t/gis-rtree.test
mysql-test/t/gis-rtree.test
+13
-0
mysql-test/t/grant.test
mysql-test/t/grant.test
+2
-0
sql/field.cc
sql/field.cc
+49
-49
sql/field.h
sql/field.h
+2
-1
sql/handler.cc
sql/handler.cc
+138
-0
sql/handler.h
sql/handler.h
+20
-0
sql/opt_range.cc
sql/opt_range.cc
+161
-180
sql/opt_range.h
sql/opt_range.h
+12
-3
sql/sql_class.cc
sql/sql_class.cc
+2
-1
sql/sql_select.cc
sql/sql_select.cc
+40
-34
sql/table.cc
sql/table.cc
+0
-1
No files found.
mysql-test/mysql-test-run.sh
View file @
00738a2b
...
...
@@ -670,7 +670,7 @@ report_stats () {
$ECHO
"The log files in
$MY_LOG_DIR
may give you some hint"
$ECHO
"of what when wrong."
$ECHO
"If you want to report this error, please read first the documentation at"
$ECHO
"http://www.mysql.com/doc/
M/y
/MySQL_test_suite.html"
$ECHO
"http://www.mysql.com/doc/
en
/MySQL_test_suite.html"
fi
if
test
-z
"
$USE_RUNNING_SERVER
"
...
...
mysql-test/r/gis-rtree.result
View file @
00738a2b
...
...
@@ -750,3 +750,10 @@ analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status OK
drop table t1;
CREATE TABLE t1 (
fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
g GEOMETRY NOT NULL,
SPATIAL KEY(g)
) ENGINE=MyISAM;
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
drop table t1;
mysql-test/r/grant.result
View file @
00738a2b
...
...
@@ -76,6 +76,8 @@ delete from mysql.db where user='mysqltest_1';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
show grants for mysqltest_1@localhost;
ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host 'localhost'
create table t1 (a int);
GRANT select,update,insert on t1 to mysqltest_1@localhost;
GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost;
...
...
mysql-test/t/gis-rtree.test
View file @
00738a2b
...
...
@@ -103,3 +103,16 @@ check table t1;
analyze
table
t1
;
drop
table
t1
;
#
# The following crashed gis
#
CREATE
TABLE
t1
(
fid
INT
NOT
NULL
AUTO_INCREMENT
PRIMARY
KEY
,
g
GEOMETRY
NOT
NULL
,
SPATIAL
KEY
(
g
)
)
ENGINE
=
MyISAM
;
INSERT
INTO
t1
(
g
)
VALUES
(
GeomFromText
(
'LineString(1 2, 2 3)'
)),(
GeomFromText
(
'LineString(1 2, 2 4)'
));
#select * from t1 where g<GeomFromText('LineString(1 2, 2 3)');
drop
table
t1
;
mysql-test/t/grant.test
View file @
00738a2b
...
...
@@ -53,6 +53,8 @@ delete from mysql.db where user='mysqltest_1';
delete
from
mysql
.
tables_priv
where
user
=
'mysqltest_1'
;
delete
from
mysql
.
columns_priv
where
user
=
'mysqltest_1'
;
flush
privileges
;
--
error
1141
show
grants
for
mysqltest_1
@
localhost
;
#
# Test what happens when you have same table and colum level grants
...
...
sql/field.cc
View file @
00738a2b
...
...
@@ -4359,7 +4359,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
set_warning
(
MYSQL_ERROR
::
WARN_LEVEL_WARN
,
ER_WARN_DATA_TRUNCATED
);
error
=
1
;
}
memcpy
(
ptr
+
2
,
from
,
length
);
memcpy
(
ptr
+
HA_KEY_BLOB_LENGTH
,
from
,
length
);
int2store
(
ptr
,
length
);
return
error
;
}
...
...
@@ -4388,18 +4388,18 @@ int Field_varstring::store(longlong nr)
double
Field_varstring
::
val_real
(
void
)
{
int
not_used
;
uint
length
=
uint2korr
(
ptr
)
+
2
;
uint
length
=
uint2korr
(
ptr
)
+
HA_KEY_BLOB_LENGTH
;
CHARSET_INFO
*
cs
=
charset
();
return
my_strntod
(
cs
,
ptr
+
2
,
length
,
(
char
**
)
0
,
&
not_used
);
return
my_strntod
(
cs
,
ptr
+
HA_KEY_BLOB_LENGTH
,
length
,
(
char
**
)
0
,
&
not_used
);
}
longlong
Field_varstring
::
val_int
(
void
)
{
int
not_used
;
uint
length
=
uint2korr
(
ptr
)
+
2
;
uint
length
=
uint2korr
(
ptr
)
+
HA_KEY_BLOB_LENGTH
;
CHARSET_INFO
*
cs
=
charset
();
return
my_strntoll
(
cs
,
ptr
+
2
,
length
,
10
,
NULL
,
&
not_used
);
return
my_strntoll
(
cs
,
ptr
+
HA_KEY_BLOB_LENGTH
,
length
,
10
,
NULL
,
&
not_used
);
}
...
...
@@ -4407,7 +4407,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String
*
val_ptr
)
{
uint
length
=
uint2korr
(
ptr
);
val_ptr
->
set
((
const
char
*
)
ptr
+
2
,
length
,
field_charset
);
val_ptr
->
set
((
const
char
*
)
ptr
+
HA_KEY_BLOB_LENGTH
,
length
,
field_charset
);
return
val_ptr
;
}
...
...
@@ -4417,18 +4417,21 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
uint
a_length
=
uint2korr
(
a_ptr
);
uint
b_length
=
uint2korr
(
b_ptr
);
int
diff
;
diff
=
my_strnncoll
(
field_charset
,
(
const
uchar
*
)
a_ptr
+
2
,
min
(
a_length
,
b_length
),
(
const
uchar
*
)
b_ptr
+
2
,
min
(
a_length
,
b_length
));
diff
=
my_strnncoll
(
field_charset
,
(
const
uchar
*
)
a_ptr
+
HA_KEY_BLOB_LENGTH
,
min
(
a_length
,
b_length
),
(
const
uchar
*
)
b_ptr
+
HA_KEY_BLOB_LENGTH
,
min
(
a_length
,
b_length
));
return
diff
?
diff
:
(
int
)
(
a_length
-
b_length
);
}
void
Field_varstring
::
sort_string
(
char
*
to
,
uint
length
)
{
uint
tot_length
=
uint2korr
(
ptr
);
tot_length
=
my_strnxfrm
(
field_charset
,
(
unsigned
char
*
)
to
,
length
,
(
unsigned
char
*
)
ptr
+
2
,
tot_length
);
tot_length
=
my_strnxfrm
(
field_charset
,
(
uchar
*
)
to
,
length
,
(
uchar
*
)
ptr
+
HA_KEY_BLOB_LENGTH
,
tot_length
);
if
(
tot_length
<
length
)
field_charset
->
cset
->
fill
(
field_charset
,
to
+
tot_length
,
length
-
tot_length
,
binary
()
?
(
char
)
0
:
' '
);
...
...
@@ -4453,7 +4456,7 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length)
if
(
max_length
>
255
)
*
to
++=
(
char
)
(
length
>>
8
);
if
(
length
)
memcpy
(
to
,
from
+
2
,
length
);
memcpy
(
to
,
from
+
HA_KEY_BLOB_LENGTH
,
length
);
return
to
+
length
;
}
...
...
@@ -4473,7 +4476,7 @@ const char *Field_varstring::unpack(char *to, const char *from)
to
[
1
]
=
*
from
++
;
}
if
(
length
)
memcpy
(
to
+
2
,
from
,
length
);
memcpy
(
to
+
HA_KEY_BLOB_LENGTH
,
from
,
length
);
return
from
+
length
;
}
...
...
@@ -4484,8 +4487,8 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
uint
b_length
;
if
(
key_length
>
255
)
{
a_length
=
uint2korr
(
a
);
a
+=
2
;
b_length
=
uint2korr
(
b
);
b
+=
2
;
a_length
=
uint2korr
(
a
);
a
+=
2
;
b_length
=
uint2korr
(
b
);
b
+=
2
;
}
else
{
...
...
@@ -4493,32 +4496,32 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
b_length
=
(
uint
)
(
uchar
)
*
b
++
;
}
return
my_strnncoll
(
field_charset
,
(
const
uchar
*
)
a
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
(
const
uchar
*
)
a
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
}
int
Field_varstring
::
pack_cmp
(
const
char
*
b
,
uint
key_length
)
{
char
*
a
=
ptr
+
2
;
uint
a_length
=
uint2korr
(
ptr
);
char
*
a
=
ptr
+
HA_KEY_BLOB_LENGTH
;
uint
a_length
=
uint2korr
(
ptr
);
uint
b_length
;
if
(
key_length
>
255
)
{
b_length
=
uint2korr
(
b
);
b
+=
2
;
b_length
=
uint2korr
(
b
);
b
+=
2
;
}
else
{
b_length
=
(
uint
)
(
uchar
)
*
b
++
;
}
return
my_strnncoll
(
field_charset
,
(
const
uchar
*
)
a
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
(
const
uchar
*
)
a
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
}
uint
Field_varstring
::
packed_col_length
(
const
char
*
data_ptr
,
uint
length
)
{
if
(
length
>
255
)
return
uint2korr
(
data_ptr
)
+
2
;
return
uint2korr
(
data_ptr
)
+
HA_KEY_BLOB_LENGTH
;
else
return
(
uint
)
((
uchar
)
*
data_ptr
)
+
1
;
}
...
...
@@ -4531,22 +4534,21 @@ uint Field_varstring::max_packed_col_length(uint max_length)
void
Field_varstring
::
get_key_image
(
char
*
buff
,
uint
length
,
CHARSET_INFO
*
cs
,
imagetype
type
)
{
length
-=
HA_KEY_BLOB_LENGTH
;
uint
f_length
=
uint2korr
(
ptr
);
if
(
f_length
>
length
)
f_length
=
length
;
int2store
(
buff
,
length
);
memcpy
(
buff
+
2
,
ptr
+
2
,
length
);
memcpy
(
buff
+
HA_KEY_BLOB_LENGTH
,
ptr
+
HA_KEY_BLOB_LENGTH
,
length
);
#ifdef HAVE_purify
if
(
f_length
<
length
)
bzero
(
buff
+
2
+
f_length
,
(
length
-
f_length
));
bzero
(
buff
+
HA_KEY_BLOB_LENGTH
+
f_length
,
(
length
-
f_length
));
#endif
}
void
Field_varstring
::
set_key_image
(
char
*
buff
,
uint
length
,
CHARSET_INFO
*
cs
)
{
length
=
uint2korr
(
buff
);
// Real length is here
(
void
)
Field_varstring
::
store
(
buff
+
2
,
length
,
cs
);
(
void
)
Field_varstring
::
store
(
buff
+
HA_KEY_BLOB_LENGTH
,
length
,
cs
);
}
...
...
@@ -4799,7 +4801,6 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
void
Field_blob
::
get_key_image
(
char
*
buff
,
uint
length
,
CHARSET_INFO
*
cs
,
imagetype
type
)
{
length
-=
HA_KEY_BLOB_LENGTH
;
uint32
blob_length
=
get_length
(
ptr
);
char
*
blob
;
...
...
@@ -4838,18 +4839,18 @@ void Field_blob::get_key_image(char *buff,uint length,
Must clear this as we do a memcmp in opt_range.cc to detect
identical keys
*/
bzero
(
buff
+
2
+
blob_length
,
(
length
-
blob_length
));
bzero
(
buff
+
HA_KEY_BLOB_LENGTH
+
blob_length
,
(
length
-
blob_length
));
length
=
(
uint
)
blob_length
;
}
int2store
(
buff
,
length
);
get_ptr
(
&
blob
);
memcpy
(
buff
+
2
,
blob
,
length
);
memcpy
(
buff
+
HA_KEY_BLOB_LENGTH
,
blob
,
length
);
}
void
Field_blob
::
set_key_image
(
char
*
buff
,
uint
length
,
CHARSET_INFO
*
cs
)
{
length
=
uint2korr
(
buff
);
(
void
)
Field_blob
::
store
(
buff
+
2
,
length
,
cs
);
length
=
uint2korr
(
buff
);
(
void
)
Field_blob
::
store
(
buff
+
HA_KEY_BLOB_LENGTH
,
length
,
cs
);
}
...
...
@@ -4857,16 +4858,16 @@ int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
{
char
*
blob1
;
uint
blob_length
=
get_length
(
ptr
);
max_key_length
-=
2
;
memcpy_fixed
(
&
blob1
,
ptr
+
packlength
,
sizeof
(
char
*
));
return
Field_blob
::
cmp
(
blob1
,
min
(
blob_length
,
max_key_length
),
(
char
*
)
key_ptr
+
2
,
uint2korr
(
key_ptr
));
(
char
*
)
key_ptr
+
HA_KEY_BLOB_LENGTH
,
uint2korr
(
key_ptr
));
}
int
Field_blob
::
key_cmp
(
const
byte
*
a
,
const
byte
*
b
)
{
return
Field_blob
::
cmp
((
char
*
)
a
+
2
,
uint2korr
(
a
),
(
char
*
)
b
+
2
,
uint2korr
(
b
));
return
Field_blob
::
cmp
((
char
*
)
a
+
HA_KEY_BLOB_LENGTH
,
uint2korr
(
a
),
(
char
*
)
b
+
HA_KEY_BLOB_LENGTH
,
uint2korr
(
b
));
}
...
...
@@ -4882,8 +4883,8 @@ void Field_blob::sort_string(char *to,uint length)
memcpy_fixed
(
&
blob
,
ptr
+
packlength
,
sizeof
(
char
*
));
blob_length
=
my_strnxfrm
(
field_charset
,
(
u
nsigned
char
*
)
to
,
length
,
(
u
nsigned
char
*
)
blob
,
blob_length
);
(
u
char
*
)
to
,
length
,
(
u
char
*
)
blob
,
blob_length
);
if
(
blob_length
<
length
)
field_charset
->
cset
->
fill
(
field_charset
,
to
+
blob_length
,
length
-
blob_length
,
...
...
@@ -4965,8 +4966,8 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
b_length
=
(
uint
)
(
uchar
)
*
b
++
;
}
return
my_strnncoll
(
field_charset
,
(
const
uchar
*
)
a
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
(
const
uchar
*
)
a
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
}
...
...
@@ -4988,8 +4989,8 @@ int Field_blob::pack_cmp(const char *b, uint key_length)
b_length
=
(
uint
)
(
uchar
)
*
b
++
;
}
return
my_strnncoll
(
field_charset
,
(
const
uchar
*
)
a
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
(
const
uchar
*
)
a
,
a_length
,
(
const
uchar
*
)
b
,
b_length
);
}
/* Create a packed key that will be used for storage from a MySQL row */
...
...
@@ -5025,7 +5026,7 @@ char *Field_blob::pack_key_from_key_image(char *to, const char *from,
if
(
max_length
>
255
)
*
to
++=
(
char
)
(
length
>>
8
);
if
(
length
)
memcpy
(
to
,
from
+
2
,
length
);
memcpy
(
to
,
from
+
HA_KEY_BLOB_LENGTH
,
length
);
return
to
+
length
;
}
...
...
@@ -5048,11 +5049,12 @@ uint Field_blob::max_packed_col_length(uint max_length)
void
Field_geom
::
get_key_image
(
char
*
buff
,
uint
length
,
CHARSET_INFO
*
cs
,
imagetype
type
)
{
length
-=
HA_KEY_BLOB_LENGTH
;
ulong
blob_length
=
get_length
(
ptr
);
char
*
blob
;
const
char
*
dummy
;
MBR
mbr
;
ulong
blob_length
=
get_length
(
ptr
);
Geometry_buffer
buffer
;
Geometry
*
gobj
;
if
(
blob_length
<
SRID_SIZE
)
{
...
...
@@ -5060,8 +5062,6 @@ void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
return
;
}
get_ptr
(
&
blob
);
Geometry_buffer
buffer
;
Geometry
*
gobj
;
gobj
=
Geometry
::
create_from_wkb
(
&
buffer
,
blob
+
SRID_SIZE
,
blob_length
-
SRID_SIZE
);
if
(
gobj
->
get_mbr
(
&
mbr
,
&
dummy
))
...
...
@@ -5554,7 +5554,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
switch
(
type
)
{
case
FIELD_TYPE_STRING
:
case
FIELD_TYPE_DECIMAL
:
return
(
length
);
case
FIELD_TYPE_VAR_STRING
:
return
(
length
+
2
);
case
FIELD_TYPE_VAR_STRING
:
return
(
length
+
HA_KEY_BLOB_LENGTH
);
case
FIELD_TYPE_YEAR
:
case
FIELD_TYPE_TINY
:
return
1
;
case
FIELD_TYPE_SHORT
:
return
2
;
...
...
sql/field.h
View file @
00738a2b
...
...
@@ -212,7 +212,8 @@ public:
{
memcpy
(
buff
,
ptr
,
length
);
}
inline
void
set_image
(
char
*
buff
,
uint
length
,
CHARSET_INFO
*
cs
)
{
memcpy
(
ptr
,
buff
,
length
);
}
virtual
void
get_key_image
(
char
*
buff
,
uint
length
,
CHARSET_INFO
*
cs
,
imagetype
type
)
virtual
void
get_key_image
(
char
*
buff
,
uint
length
,
CHARSET_INFO
*
cs
,
imagetype
type
)
{
get_image
(
buff
,
length
,
cs
);
}
virtual
void
set_key_image
(
char
*
buff
,
uint
length
,
CHARSET_INFO
*
cs
)
{
set_image
(
buff
,
length
,
cs
);
}
...
...
sql/handler.cc
View file @
00738a2b
...
...
@@ -1287,3 +1287,141 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache,
mi_change_key_cache
(
old_key_cache
,
new_key_cache
);
return
0
;
}
/*
Read first row between two ranges.
Store ranges for future calls to read_range_next
SYNOPSIS
read_range_first()
start_key Start key. Is 0 if no min range
end_key End key. Is 0 if no max range
sorted Set to 1 if result should be sorted per key
NOTES
Record is read into table->record[0]
RETURN
0 Found row
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
int
handler
::
read_range_first
(
const
key_range
*
start_key
,
const
key_range
*
end_key
,
bool
sorted
)
{
int
result
;
DBUG_ENTER
(
"handler::read_range_first"
);
end_range
=
0
;
if
(
end_key
)
{
end_range
=
&
save_end_range
;
save_end_range
=
*
end_key
;
key_compare_result_on_equal
=
((
end_key
->
flag
==
HA_READ_BEFORE_KEY
)
?
1
:
(
end_key
->
flag
==
HA_READ_AFTER_KEY
)
?
-
1
:
0
);
}
range_key_part
=
table
->
key_info
[
active_index
].
key_part
;
if
(
!
start_key
)
// Read first record
result
=
index_first
(
table
->
record
[
0
]);
else
result
=
index_read
(
table
->
record
[
0
],
start_key
->
key
,
start_key
->
length
,
start_key
->
flag
);
if
(
result
)
DBUG_RETURN
((
result
==
HA_ERR_KEY_NOT_FOUND
||
result
==
HA_ERR_END_OF_FILE
)
?
HA_ERR_END_OF_FILE
:
result
);
DBUG_RETURN
(
compare_key
(
end_range
)
<=
0
?
0
:
HA_ERR_END_OF_FILE
);
}
/*
Read next row between two ranges.
SYNOPSIS
read_range_next()
eq_range Set to 1 if start_key == end_key
NOTES
Record is read into table->record[0]
RETURN
0 Found row
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
int
handler
::
read_range_next
(
bool
eq_range
)
{
int
result
;
DBUG_ENTER
(
"handler::read_range_next"
);
if
(
eq_range
)
result
=
index_next_same
(
table
->
record
[
0
],
end_range
->
key
,
end_range
->
length
);
else
result
=
index_next
(
table
->
record
[
0
]);
if
(
result
)
DBUG_RETURN
(
result
);
DBUG_RETURN
(
compare_key
(
end_range
)
<=
0
?
0
:
HA_ERR_END_OF_FILE
);
}
/*
Compare if found key is over max-value
SYNOPSIS
compare_key
range key to compare to row
NOTES
For this to work, the row must be stored in table->record[0]
RETURN
0 Key is equal to range or 'range' == 0 (no range)
-1 Key is less than range
1 Key is larger than range
*/
int
handler
::
compare_key
(
key_range
*
range
)
{
KEY_PART_INFO
*
key_part
=
range_key_part
;
uint
store_length
;
if
(
!
range
)
return
0
;
// No max range
for
(
const
char
*
key
=
range
->
key
,
*
end
=
key
+
range
->
length
;
key
<
end
;
key
+=
store_length
,
key_part
++
)
{
int
cmp
;
store_length
=
key_part
->
store_length
;
if
(
key_part
->
null_bit
)
{
if
(
*
key
)
{
if
(
!
key_part
->
field
->
is_null
())
return
1
;
continue
;
}
else
if
(
key_part
->
field
->
is_null
())
return
0
;
key
++
;
// Skip null byte
store_length
--
;
}
if
((
cmp
=
key_part
->
field
->
key_cmp
((
byte
*
)
key
,
key_part
->
length
))
<
0
)
return
-
1
;
if
(
cmp
>
0
)
return
1
;
}
return
key_compare_result_on_equal
;
}
sql/handler.h
View file @
00738a2b
...
...
@@ -218,6 +218,14 @@ typedef struct st_ha_check_opt
}
HA_CHECK_OPT
;
typedef
struct
st_key_range
{
const
byte
*
key
;
uint
length
;
enum
ha_rkey_function
flag
;
}
key_range
;
class
handler
:
public
Sql_alloc
{
protected:
...
...
@@ -239,6 +247,12 @@ public:
time_t
create_time
;
/* When table was created */
time_t
check_time
;
time_t
update_time
;
/* The following are for read_range() */
key_range
save_end_range
,
*
end_range
;
KEY_PART_INFO
*
range_key_part
;
int
key_compare_result_on_equal
;
uint
errkey
;
/* Last dup key */
uint
sortkey
,
key_used_on_scan
;
uint
active_index
;
...
...
@@ -250,6 +264,7 @@ public:
bool
auto_increment_column_changed
;
bool
implicit_emptied
;
/* Can be !=0 only if HEAP */
handler
(
TABLE
*
table_arg
)
:
table
(
table_arg
),
ref
(
0
),
data_file_length
(
0
),
max_data_file_length
(
0
),
index_file_length
(
0
),
delete_length
(
0
),
auto_increment_value
(
0
),
...
...
@@ -298,6 +313,11 @@ public:
{
return
(
my_errno
=
HA_ERR_WRONG_COMMAND
);
}
virtual
int
handler
::
read_range_first
(
const
key_range
*
start_key
,
const
key_range
*
end_key
,
bool
sorted
);
virtual
int
handler
::
read_range_next
(
bool
eq_range
);
int
handler
::
compare_key
(
key_range
*
range
);
virtual
int
ft_init
()
{
return
-
1
;
}
virtual
FT_INFO
*
ft_init_ext
(
uint
flags
,
uint
inx
,
const
byte
*
key
,
uint
keylen
)
...
...
sql/opt_range.cc
View file @
00738a2b
...
...
@@ -177,11 +177,11 @@ public:
if
(
maybe_null
&&
*
min_value
)
{
**
min_key
=
1
;
bzero
(
*
min_key
+
1
,
length
);
bzero
(
*
min_key
+
1
,
length
-
1
);
}
else
memcpy
(
*
min_key
,
min_value
,
length
+
(
int
)
maybe_null
);
(
*
min_key
)
+=
length
+
(
int
)
maybe_null
;
memcpy
(
*
min_key
,
min_value
,
length
);
(
*
min_key
)
+=
length
;
}
if
(
!
(
max_flag
&
NO_MAX_RANGE
)
&&
!
(
max_key_flag
&
(
NO_MAX_RANGE
|
NEAR_MAX
)))
...
...
@@ -189,18 +189,18 @@ public:
if
(
maybe_null
&&
*
max_value
)
{
**
max_key
=
1
;
bzero
(
*
max_key
+
1
,
length
);
bzero
(
*
max_key
+
1
,
length
-
1
);
}
else
memcpy
(
*
max_key
,
max_value
,
length
+
(
int
)
maybe_null
);
(
*
max_key
)
+=
length
+
(
int
)
maybe_null
;
memcpy
(
*
max_key
,
max_value
,
length
);
(
*
max_key
)
+=
length
;
}
}
void
store_min_key
(
KEY_PART
*
key
,
char
**
range_key
,
uint
*
range_key_flag
)
{
SEL_ARG
*
key_tree
=
first
();
key_tree
->
store
(
key
[
key_tree
->
part
].
part
_length
,
key_tree
->
store
(
key
[
key_tree
->
part
].
store
_length
,
range_key
,
*
range_key_flag
,
range_key
,
NO_MAX_RANGE
);
*
range_key_flag
|=
key_tree
->
min_flag
;
if
(
key_tree
->
next_key_part
&&
...
...
@@ -213,7 +213,7 @@ public:
void
store_max_key
(
KEY_PART
*
key
,
char
**
range_key
,
uint
*
range_key_flag
)
{
SEL_ARG
*
key_tree
=
last
();
key_tree
->
store
(
key
[
key_tree
->
part
].
part
_length
,
key_tree
->
store
(
key
[
key_tree
->
part
].
store
_length
,
range_key
,
NO_MIN_RANGE
,
range_key
,
*
range_key_flag
);
(
*
range_key_flag
)
|=
key_tree
->
max_flag
;
if
(
key_tree
->
next_key_part
&&
...
...
@@ -646,6 +646,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
MEM_ROOT
*
old_root
,
alloc
;
SEL_TREE
*
tree
;
KEY_PART
*
key_parts
;
KEY
*
key_info
;
PARAM
param
;
/* set up parameter that is passed to all functions */
...
...
@@ -671,24 +672,26 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
old_root
=
my_pthread_getspecific_ptr
(
MEM_ROOT
*
,
THR_MALLOC
);
my_pthread_setspecific_ptr
(
THR_MALLOC
,
&
alloc
);
for
(
idx
=
0
;
idx
<
head
->
keys
;
idx
++
)
key_info
=
head
->
key_info
;
for
(
idx
=
0
;
idx
<
head
->
keys
;
idx
++
,
key_info
++
)
{
KEY_PART_INFO
*
key_part_info
;
if
(
!
keys_to_use
.
is_set
(
idx
))
continue
;
KEY
*
key_info
=
&
head
->
key_info
[
idx
];
if
(
key_info
->
flags
&
HA_FULLTEXT
)
continue
;
// ToDo: ft-keys in non-ft ranges, if possible SerG
param
.
key
[
param
.
keys
]
=
key_parts
;
for
(
uint
part
=
0
;
part
<
key_info
->
key_parts
;
part
++
,
key_parts
++
)
{
key_parts
->
key
=
param
.
keys
;
key_parts
->
part
=
part
;
key_parts
->
part_length
=
key_info
->
key_part
[
part
].
length
;
key_parts
->
field
=
key_info
->
key_part
[
part
].
field
;
key_parts
->
null_bit
=
key_info
->
key_part
[
part
].
null_bit
;
if
(
key_parts
->
field
->
type
()
==
FIELD_TYPE_BLOB
)
key_parts
->
part_length
+=
HA_KEY_BLOB_LENGTH
;
key_part_info
=
key_info
->
key_part
;
for
(
uint
part
=
0
;
part
<
key_info
->
key_parts
;
part
++
,
key_parts
++
,
key_part_info
++
)
{
key_parts
->
key
=
param
.
keys
;
key_parts
->
part
=
part
;
key_parts
->
length
=
key_part_info
->
length
;
key_parts
->
store_length
=
key_part_info
->
store_length
;
key_parts
->
field
=
key_part_info
->
field
;
key_parts
->
null_bit
=
key_part_info
->
null_bit
;
key_parts
->
image_type
=
(
key_info
->
flags
&
HA_SPATIAL
)
?
Field
::
itMBR
:
Field
::
itRAW
;
}
...
...
@@ -1043,18 +1046,26 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
DBUG_RETURN
(
0
);
// Can only optimize strings
offset
=
maybe_null
;
length
=
key_part
->
part_length
;
if
(
field
->
type
()
==
FIELD_TYPE_BLOB
)
length
=
key_part
->
store_length
;
if
(
length
!=
key_part
->
length
+
maybe_null
)
{
offset
+=
HA_KEY_BLOB_LENGTH
;
field_length
=
key_part
->
part_length
-
HA_KEY_BLOB_LENGTH
;
/* key packed with length prefix */
offset
+=
HA_KEY_BLOB_LENGTH
;
field_length
=
length
-
HA_KEY_BLOB_LENGTH
;
}
else
{
if
(
length
<
field_length
)
length
=
field_length
;
// Only if overlapping key
if
(
unlikely
(
length
<
field_length
))
{
/*
This can only happen in a table created with UNIREG where one key
overlaps many fields
*/
length
=
field_length
;
}
else
field_length
=
length
;
field_length
=
length
;
}
length
+=
offset
;
if
(
!
(
min_str
=
(
char
*
)
alloc_root
(
param
->
mem_root
,
length
*
2
)))
...
...
@@ -1067,7 +1078,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
res
->
ptr
(),
res
->
length
(),
((
Item_func_like
*
)(
param
->
cond
))
->
escape
,
wild_one
,
wild_many
,
field_length
,
field_length
-
maybe_null
,
min_str
+
offset
,
max_str
+
offset
,
&
min_length
,
&
max_length
);
if
(
like_error
)
// Can't optimize with LIKE
...
...
@@ -1105,13 +1116,13 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
if
(
field
->
key_type
()
==
HA_KEYTYPE_VARTEXT
)
copies
=
2
;
str
=
str2
=
(
char
*
)
alloc_root
(
param
->
mem_root
,
(
key_part
->
part_length
+
maybe_null
)
*
copies
+
1
);
(
key_part
->
store_length
)
*
copies
+
1
);
if
(
!
str
)
DBUG_RETURN
(
0
);
if
(
maybe_null
)
*
str
=
(
char
)
field
->
is_real_null
();
// Set to 1 if null
field
->
get_key_image
(
str
+
maybe_null
,
key_part
->
part_
length
,
field
->
charset
(),
key_part
->
image_type
);
field
->
get_key_image
(
str
+
maybe_null
,
key_part
->
length
,
field
->
charset
(),
key_part
->
image_type
);
if
(
copies
==
2
)
{
/*
...
...
@@ -1120,16 +1131,17 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
all rows between 'X' and 'X ...'
*/
uint
length
=
uint2korr
(
str
+
maybe_null
);
str2
=
str
+
key_part
->
part_length
+
maybe_null
;
str2
=
str
+
key_part
->
store_length
;
/* remove end space */
while
(
length
>
0
&&
str
[
length
+
HA_KEY_BLOB_LENGTH
+
maybe_null
-
1
]
==
' '
)
length
--
;
int2store
(
str
+
maybe_null
,
length
);
/* Create key that is space filled */
memcpy
(
str2
,
str
,
length
+
HA_KEY_BLOB_LENGTH
+
maybe_null
);
bfill
(
str2
+
length
+
HA_KEY_BLOB_LENGTH
+
maybe_null
,
key_part
->
part_length
-
length
-
HA_KEY_BLOB_LENGTH
,
' '
);
int2store
(
str2
+
maybe_null
,
key_part
->
part_length
-
HA_KEY_BLOB_LENGTH
);
my_fill_8bit
(
field
->
charset
(),
str2
+
length
+
HA_KEY_BLOB_LENGTH
+
maybe_null
,
key_part
->
length
-
length
,
' '
);
int2store
(
str2
+
maybe_null
,
key_part
->
length
);
}
if
(
!
(
tree
=
new
SEL_ARG
(
field
,
str
,
str2
)))
DBUG_RETURN
(
0
);
// out of memory
...
...
@@ -2236,7 +2248,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
uint
tmp_min_flag
,
tmp_max_flag
,
keynr
;
char
*
tmp_min_key
=
min_key
,
*
tmp_max_key
=
max_key
;
key_tree
->
store
(
param
->
key
[
idx
][
key_tree
->
part
].
part
_length
,
key_tree
->
store
(
param
->
key
[
idx
][
key_tree
->
part
].
store
_length
,
&
tmp_min_key
,
min_key_flag
,
&
tmp_max_key
,
max_key_flag
);
uint
min_key_length
=
(
uint
)
(
tmp_min_key
-
param
->
min_key
);
uint
max_key_length
=
(
uint
)
(
tmp_max_key
-
param
->
max_key
);
...
...
@@ -2332,8 +2344,14 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
{
QUICK_SELECT
*
quick
;
DBUG_ENTER
(
"get_quick_select"
);
if
((
quick
=
new
QUICK_SELECT
(
param
->
thd
,
param
->
table
,
param
->
real_keynr
[
idx
])))
if
(
param
->
table
->
key_info
[
param
->
real_keynr
[
idx
]].
flags
&
HA_SPATIAL
)
quick
=
new
QUICK_SELECT_GEOM
(
param
->
thd
,
param
->
table
,
param
->
real_keynr
[
idx
],
0
);
else
quick
=
new
QUICK_SELECT
(
param
->
thd
,
param
->
table
,
param
->
real_keynr
[
idx
]);
if
(
quick
)
{
if
(
quick
->
error
||
get_quick_keys
(
param
,
quick
,
param
->
key
[
idx
],
key_tree
,
param
->
min_key
,
0
,
...
...
@@ -2373,7 +2391,7 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
return
1
;
}
char
*
tmp_min_key
=
min_key
,
*
tmp_max_key
=
max_key
;
key_tree
->
store
(
key
[
key_tree
->
part
].
part
_length
,
key_tree
->
store
(
key
[
key_tree
->
part
].
store
_length
,
&
tmp_min_key
,
min_key_flag
,
&
tmp_max_key
,
max_key_flag
);
if
(
key_tree
->
next_key_part
&&
...
...
@@ -2491,19 +2509,17 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
{
for
(
const
char
*
end
=
key
+
length
;
key
<
end
;
key
+=
key_part
++->
part
_length
)
key
+=
key_part
++->
store
_length
)
{
if
(
key_part
->
null_bit
)
{
if
(
*
key
++
)
if
(
key_part
->
null_bit
&&
*
key
)
return
1
;
}
}
return
0
;
}
/****************************************************************************
**
Create a QUICK RANGE based on a key
Create a QUICK RANGE based on a key
****************************************************************************/
QUICK_SELECT
*
get_quick_select_for_ref
(
THD
*
thd
,
TABLE
*
table
,
TABLE_REF
*
ref
)
...
...
@@ -2541,9 +2557,8 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
{
key_part
->
part
=
part
;
key_part
->
field
=
key_info
->
key_part
[
part
].
field
;
key_part
->
part_length
=
key_info
->
key_part
[
part
].
length
;
if
(
key_part
->
field
->
type
()
==
FIELD_TYPE_BLOB
)
key_part
->
part_length
+=
HA_KEY_BLOB_LENGTH
;
key_part
->
length
=
key_info
->
key_part
[
part
].
length
;
key_part
->
store_length
=
key_info
->
key_part
[
part
].
store_length
;
key_part
->
null_bit
=
key_info
->
key_part
[
part
].
null_bit
;
}
if
(
quick
->
ranges
.
push_back
(
range
))
...
...
@@ -2585,111 +2600,74 @@ int QUICK_SELECT::get_next()
for
(;;)
{
int
result
;
key_range
start_key
,
end_key
;
if
(
range
)
{
// Already read through key
result
=
((
range
->
flag
&
(
EQ_RANGE
|
GEOM_FLAG
))
?
file
->
index_next_same
(
record
,
(
byte
*
)
range
->
min_key
,
range
->
min_length
)
:
file
->
index_next
(
record
));
if
(
!
result
)
{
if
((
range
->
flag
&
GEOM_FLAG
)
||
!
cmp_next
(
*
it
.
ref
()))
DBUG_RETURN
(
0
);
}
else
if
(
result
!=
HA_ERR_END_OF_FILE
)
// Already read through key
result
=
file
->
read_range_next
(
test
(
range
->
flag
&
EQ_RANGE
));
if
(
result
!=
HA_ERR_END_OF_FILE
)
DBUG_RETURN
(
result
);
}
if
(
!
(
range
=
it
++
))
if
(
!
(
range
=
it
++
))
DBUG_RETURN
(
HA_ERR_END_OF_FILE
);
// All ranges used
if
(
range
->
flag
&
GEOM_FLAG
)
{
if
((
result
=
file
->
index_read
(
record
,
(
byte
*
)
(
range
->
min_key
),
range
->
min_length
,
(
ha_rkey_function
)(
range
->
flag
^
GEOM_FLAG
))))
{
if
(
result
!=
HA_ERR_KEY_NOT_FOUND
)
DBUG_RETURN
(
result
);
range
=
0
;
// Not found, to next range
continue
;
}
DBUG_RETURN
(
0
);
}
if
(
range
->
flag
&
NO_MIN_RANGE
)
// Read first record
{
int
local_error
;
if
((
local_error
=
file
->
index_first
(
record
)))
DBUG_RETURN
(
local_error
);
// Empty table
if
(
cmp_next
(
range
)
==
0
)
DBUG_RETURN
(
0
);
range
=
0
;
// No matching records; go to next range
continue
;
}
if
((
result
=
file
->
index_read
(
record
,
(
byte
*
)
(
range
->
min_key
+
test
(
range
->
flag
&
GEOM_FLAG
)),
range
->
min_length
,
(
range
->
flag
&
NEAR_MIN
)
?
HA_READ_AFTER_KEY:
start_key
.
key
=
range
->
min_key
;
start_key
.
length
=
range
->
min_length
;
start_key
.
flag
=
((
range
->
flag
&
NEAR_MIN
)
?
HA_READ_AFTER_KEY
:
(
range
->
flag
&
EQ_RANGE
)
?
HA_READ_KEY_EXACT
:
HA_READ_KEY_OR_NEXT
)))
HA_READ_KEY_EXACT
:
HA_READ_KEY_OR_NEXT
);
end_key
.
key
=
range
->
max_key
;
end_key
.
length
=
range
->
max_length
;
/*
We use READ_AFTER_KEY here because if we are reading on a key
prefix we want to find all keys with this prefix
*/
end_key
.
flag
=
(
range
->
flag
&
NEAR_MAX
?
HA_READ_BEFORE_KEY
:
HA_READ_AFTER_KEY
);
{
if
(
result
!=
HA_ERR_KEY_NOT_FOUND
)
DBUG_RETURN
(
result
);
range
=
0
;
// Not found, to next range
continue
;
}
if
(
cmp_next
(
range
)
==
0
)
{
result
=
file
->
read_range_first
(
range
->
min_length
?
&
start_key
:
0
,
range
->
max_length
?
&
end_key
:
0
,
sorted
);
if
(
range
->
flag
==
(
UNIQUE_RANGE
|
EQ_RANGE
))
range
=
0
;
// Stop searching
DBUG_RETURN
(
0
);
// Found key is in range
}
range
=
0
;
// To next range
if
(
result
!=
HA_ERR_END_OF_FILE
)
DBUG_RETURN
(
result
);
range
=
0
;
// No matching rows; go to next range
}
}
/*
Compare if found key is over max-value
Returns 0 if key <= range->max_key
*/
/* Get next for geometrical indexes */
int
QUICK_SELECT
::
cmp_next
(
QUICK_RANGE
*
range_arg
)
int
QUICK_SELECT
_GEOM
::
get_next
(
)
{
if
(
range_arg
->
flag
&
NO_MAX_RANGE
)
return
0
;
/* key can't be to large */
DBUG_ENTER
(
" QUICK_SELECT_GEOM::get_next"
);
KEY_PART
*
key_part
=
key_parts
;
for
(
char
*
key
=
range_arg
->
max_key
,
*
end
=
key
+
range_arg
->
max_length
;
key
<
end
;
key
+=
key_part
++->
part_length
)
{
int
cmp
;
if
(
key_part
->
null_bit
)
for
(;;)
{
if
(
*
key
++
)
int
result
;
if
(
range
)
{
if
(
!
key_part
->
field
->
is_null
())
return
1
;
continue
;
}
else
if
(
key_part
->
field
->
is_null
())
return
0
;
// Already read through key
result
=
file
->
index_next_same
(
record
,
(
byte
*
)
range
->
min_key
,
range
->
min_length
);
if
(
result
!=
HA_ERR_END_OF_FILE
)
DBUG_RETURN
(
result
);
}
if
((
cmp
=
key_part
->
field
->
key_cmp
((
byte
*
)
key
,
key_part
->
part_length
))
<
0
)
return
0
;
if
(
cmp
>
0
)
return
1
;
if
(
!
(
range
=
it
++
))
DBUG_RETURN
(
HA_ERR_END_OF_FILE
);
// All ranges used
result
=
file
->
index_read
(
record
,
(
byte
*
)
range
->
min_key
,
range
->
min_length
,
(
ha_rkey_function
)(
range
->
flag
^
GEOM_FLAG
));
if
(
result
!=
HA_ERR_KEY_NOT_FOUND
)
DBUG_RETURN
(
result
);
range
=
0
;
// Not found, to next range
}
return
(
range_arg
->
flag
&
NEAR_MAX
)
?
1
:
0
;
// Exact match
}
...
...
@@ -2841,15 +2819,18 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range_arg)
return
0
;
/* key can't be to small */
KEY_PART
*
key_part
=
key_parts
;
uint
store_length
;
for
(
char
*
key
=
range_arg
->
min_key
,
*
end
=
key
+
range_arg
->
min_length
;
key
<
end
;
key
+=
key_part
++->
part_length
)
key
+=
store_length
,
key_part
++
)
{
int
cmp
;
store_length
=
key_part
->
store_length
;
if
(
key_part
->
null_bit
)
{
// this key part allows null values; NULL is lower than everything else
if
(
*
key
++
)
if
(
*
key
)
{
// the range is expecting a null value
if
(
!
key_part
->
field
->
is_null
())
...
...
@@ -2858,9 +2839,11 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range_arg)
}
else
if
(
key_part
->
field
->
is_null
())
return
1
;
// null -- outside the range
key
++
;
store_length
--
;
}
if
((
cmp
=
key_part
->
field
->
key_cmp
((
byte
*
)
key
,
key_part
->
part_
length
))
>
0
)
key_part
->
length
))
>
0
)
return
0
;
if
(
cmp
<
0
)
return
1
;
...
...
@@ -2888,23 +2871,20 @@ bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg)
bool
QUICK_SELECT_DESC
::
test_if_null_range
(
QUICK_RANGE
*
range_arg
,
uint
used_key_parts
)
{
uint
offset
,
end
;
uint
offset
,
end
;
KEY_PART
*
key_part
=
key_parts
,
*
key_part_end
=
key_part
+
used_key_parts
;
for
(
offset
=
0
,
end
=
min
(
range_arg
->
min_length
,
range_arg
->
max_length
)
;
offset
<
end
&&
key_part
!=
key_part_end
;
offset
+=
key_part
++->
part
_length
)
offset
+=
key_part
++->
store
_length
)
{
uint
null_length
=
test
(
key_part
->
null_bit
);
if
(
!
memcmp
((
char
*
)
range_arg
->
min_key
+
offset
,
(
char
*
)
range_arg
->
max_key
+
offset
,
key_part
->
part_length
+
null_length
))
{
offset
+=
null_length
;
key_part
->
store_length
))
continue
;
}
if
(
null_length
&&
range_arg
->
min_key
[
offset
])
if
(
key_part
->
null_bit
&&
range_arg
->
min_key
[
offset
])
return
1
;
// min_key is null and max_key isn't
// Range doesn't cover NULL. This is ok if there is no more null parts
break
;
...
...
@@ -2946,33 +2926,34 @@ static void
print_key
(
KEY_PART
*
key_part
,
const
char
*
key
,
uint
used_length
)
{
char
buff
[
1024
];
const
char
*
key_end
=
key
+
used_length
;
String
tmp
(
buff
,
sizeof
(
buff
),
&
my_charset_bin
);
uint
store_length
;
for
(
uint
length
=
0
;
length
<
used_length
;
length
+=
key_part
->
part_length
,
key
+=
key_part
->
part_length
,
key_part
++
)
for
(;
key
<
key_end
;
key
+=
store_length
,
key_part
++
)
{
Field
*
field
=
key_part
->
field
;
if
(
length
!=
0
)
fputc
(
'/'
,
DBUG_FILE
);
Field
*
field
=
key_part
->
field
;
store_length
=
key_part
->
store_length
;
if
(
field
->
real_maybe_null
())
{
length
++
;
// null byte is not in part_length
if
(
*
key
++
)
if
(
*
key
)
{
fwrite
(
"NULL"
,
sizeof
(
char
),
4
,
DBUG_FILE
);
continue
;
}
key
++
;
// Skip null byte
store_length
--
;
}
field
->
set_key_image
((
char
*
)
key
,
key_part
->
part_length
-
((
field
->
type
()
==
FIELD_TYPE_BLOB
)
?
HA_KEY_BLOB_LENGTH
:
0
),
field
->
charset
());
field
->
set_key_image
((
char
*
)
key
,
key_part
->
length
,
field
->
charset
());
field
->
val_str
(
&
tmp
);
fwrite
(
tmp
.
ptr
(),
sizeof
(
char
),
tmp
.
length
(),
DBUG_FILE
);
if
(
key
+
store_length
<
key_end
)
fputc
(
'/'
,
DBUG_FILE
);
}
}
static
void
print_quick
(
QUICK_SELECT
*
quick
,
const
key_map
*
needed_reg
)
{
QUICK_RANGE
*
range
;
...
...
sql/opt_range.h
View file @
00738a2b
...
...
@@ -35,7 +35,7 @@
typedef
struct
st_key_part
{
uint16
key
,
part
,
part_
length
;
uint16
key
,
part
,
store_length
,
length
;
uint8
null_bit
;
Field
*
field
;
Field
::
imagetype
image_type
;
...
...
@@ -68,7 +68,7 @@ class QUICK_RANGE :public Sql_alloc {
class
QUICK_SELECT
{
public:
bool
next
,
dont_free
;
bool
next
,
dont_free
,
sorted
;
int
error
;
uint
index
,
max_used_key_length
,
used_key_parts
;
TABLE
*
head
;
...
...
@@ -89,11 +89,20 @@ public:
int
init
()
{
return
error
=
file
->
index_init
(
index
);
}
virtual
int
get_next
();
virtual
bool
reverse_sorted
()
{
return
0
;
}
int
cmp_next
(
QUICK_RANGE
*
range
);
bool
unique_key_range
();
};
class
QUICK_SELECT_GEOM
:
public
QUICK_SELECT
{
public:
QUICK_SELECT_GEOM
(
THD
*
thd
,
TABLE
*
table
,
uint
index_arg
,
bool
no_alloc
)
:
QUICK_SELECT
(
thd
,
table
,
index_arg
,
no_alloc
)
{};
virtual
int
get_next
();
};
class
QUICK_SELECT_DESC
:
public
QUICK_SELECT
{
public:
...
...
sql/sql_class.cc
View file @
00738a2b
...
...
@@ -86,7 +86,8 @@ extern "C" void free_user_var(user_var_entry *entry)
THD
::
THD
()
:
user_time
(
0
),
current_statement
(
0
),
is_fatal_error
(
0
),
last_insert_id_used
(
0
),
insert_id_used
(
0
),
rand_used
(
0
),
in_lock_tables
(
0
),
global_read_lock
(
0
),
bootstrap
(
0
)
global_read_lock
(
0
),
bootstrap
(
0
),
no_table_fix_fields_cache
(
0
)
{
host
=
user
=
priv_user
=
db
=
ip
=
0
;
host_or_ip
=
"connecting host"
;
...
...
sql/sql_select.cc
View file @
00738a2b
...
...
@@ -3746,7 +3746,8 @@ make_join_readinfo(JOIN *join, uint options)
table
->
key_read
=
1
;
table
->
file
->
extra
(
HA_EXTRA_KEYREAD
);
}
else
if
(
!
table
->
used_keys
.
is_clear_all
()
&&
!
(
tab
->
select
&&
tab
->
select
->
quick
))
else
if
(
!
table
->
used_keys
.
is_clear_all
()
&&
!
(
tab
->
select
&&
tab
->
select
->
quick
))
{
// Only read index tree
tab
->
index
=
find_shortest_key
(
table
,
&
table
->
used_keys
);
tab
->
table
->
file
->
index_init
(
tab
->
index
);
...
...
@@ -6907,6 +6908,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
key_part_end
=
key_part
+
table
->
key_info
[
idx
].
key_parts
;
key_part_map
const_key_parts
=
table
->
const_key_parts
[
idx
];
int
reverse
=
0
;
DBUG_ENTER
(
"test_if_order_by_key"
);
for
(;
order
;
order
=
order
->
next
,
const_key_parts
>>=
1
)
{
...
...
@@ -6917,25 +6919,24 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
Skip key parts that are constants in the WHERE clause.
These are already skipped in the ORDER BY by const_expression_in_where()
*/
while
(
const_key_parts
&
1
)
{
key_part
++
;
const_key_parts
>>=
1
;
}
for
(;
const_key_parts
&
1
;
const_key_parts
>>=
1
)
key_part
++
;
if
(
key_part
==
key_part_end
||
key_part
->
field
!=
field
)
return
0
;
DBUG_RETURN
(
0
)
;
/* set flag to 1 if we can use read-next on key, else to -1 */
flag
=
(
order
->
asc
==
!
(
key_part
->
key_part_flag
&
HA_REVERSE_SORT
))
?
1
:
-
1
;
flag
=
((
order
->
asc
==
!
(
key_part
->
key_part_flag
&
HA_REVERSE_SORT
))
?
1
:
-
1
);
if
(
reverse
&&
flag
!=
reverse
)
return
0
;
DBUG_RETURN
(
0
)
;
reverse
=
flag
;
// Remember if reverse
key_part
++
;
}
*
used_key_parts
=
(
uint
)
(
key_part
-
table
->
key_info
[
idx
].
key_part
);
return
reverse
;
DBUG_RETURN
(
reverse
)
;
}
static
uint
find_shortest_key
(
TABLE
*
table
,
const
key_map
*
usable_keys
)
{
uint
min_length
=
(
uint
)
~
0
;
...
...
@@ -6958,18 +6959,20 @@ static uint find_shortest_key(TABLE *table, const key_map *usable_keys)
}
/*
Test if a second key is the subkey of the first one.
SYNOPSIS
is_subkey()
key_part - first key parts
ref_key_part - second key parts
ref_key_part_end - last+1 part of the second key
DESCRIPTION
Test if a second key is the subkey of the first one.
key_part First key parts
ref_key_part Second key parts
ref_key_part_end Last+1 part of the second key
NOTE
Second key MUST be shorter than the first one.
RETURN
1
- is the
subkey
0
- otherwise
1
is a
subkey
0
no sub key
*/
inline
bool
...
...
@@ -6983,20 +6986,21 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
}
/*
Test if we can use one of the 'usable_keys' instead of 'ref' key for sorting
SYNOPSIS
test_if_subkey()
ref - number of key, used for WHERE clause
usable_keys - keys for testing
DESCRIPTION
Test if we can use one of the 'usable_keys' instead of 'ref' key.
ref Number of key, used for WHERE clause
usable_keys Keys for testing
RETURN
MAX_KEY
- i
f we can't use other key
the number of found key
- o
therwise
MAX_KEY
I
f we can't use other key
the number of found key
O
therwise
*/
static
uint
test_if_subkey
(
ORDER
*
order
,
TABLE
*
table
,
uint
ref
,
uint
ref_key_parts
,
const
key_map
&
usable_keys
)
const
key_map
*
usable_keys
)
{
uint
nr
;
uint
min_length
=
(
uint
)
~
0
;
...
...
@@ -7007,7 +7011,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
for
(
nr
=
0
;
nr
<
table
->
keys
;
nr
++
)
{
if
(
usable_keys
.
is_set
(
nr
)
&&
if
(
usable_keys
->
is_set
(
nr
)
&&
table
->
key_info
[
nr
].
key_length
<
min_length
&&
table
->
key_info
[
nr
].
key_parts
>=
ref_key_parts
&&
is_subkey
(
table
->
key_info
[
nr
].
key_part
,
ref_key_part
,
...
...
@@ -7051,12 +7055,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
if
((
*
tmp_order
->
item
)
->
type
()
!=
Item
::
FIELD_ITEM
)
{
usable_keys
.
clear_all
();
break
;
DBUG_RETURN
(
0
)
;
}
usable_keys
.
intersect
(
((
Item_field
*
)
(
*
tmp_order
->
item
))
->
field
->
part_of_sortkey
);
usable_keys
.
intersect
(
((
Item_field
*
)
(
*
tmp_order
->
item
))
->
field
->
part_of_sortkey
);
if
(
usable_keys
.
is_clear_all
())
break
;
// No usable keys
DBUG_RETURN
(
0
)
;
// No usable keys
}
ref_key
=
-
1
;
...
...
@@ -7092,9 +7096,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
keys
*/
if
(
table
->
used_keys
.
is_set
(
ref_key
))
usable_keys
.
merge
(
table
->
used_keys
);
usable_keys
.
intersect
(
table
->
used_keys
);
if
((
new_ref_key
=
test_if_subkey
(
order
,
table
,
ref_key
,
ref_key_parts
,
usable_keys
))
<
MAX_KEY
)
&
usable_keys
))
<
MAX_KEY
)
{
/* Found key that can be used to retrieve data in sorted order */
if
(
tab
->
ref
.
key
>=
0
)
...
...
@@ -7154,6 +7158,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
/* fall through */
}
}
else
if
(
select
&&
select
->
quick
)
select
->
quick
->
sorted
=
1
;
DBUG_RETURN
(
1
);
/* No need to sort */
}
}
...
...
@@ -7292,9 +7298,9 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
For impossible ranges (like when doing a lookup on NULL on a NOT NULL
field, quick will contain an empty record set.
*/
if
(
!
(
select
->
quick
=
tab
->
type
==
JT_FT
?
if
(
!
(
select
->
quick
=
(
tab
->
type
==
JT_FT
?
new
FT_SELECT
(
thd
,
table
,
tab
->
ref
.
key
)
:
get_quick_select_for_ref
(
thd
,
table
,
&
tab
->
ref
)))
get_quick_select_for_ref
(
thd
,
table
,
&
tab
->
ref
)
)))
goto
err
;
}
}
...
...
sql/table.cc
View file @
00738a2b
...
...
@@ -553,7 +553,6 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keyinfo
->
key_length
+=
HA_KEY_NULL_LENGTH
;
}
if
(
field
->
type
()
==
FIELD_TYPE_BLOB
||
field
->
type
()
==
FIELD_TYPE_GEOMETRY
||
field
->
real_type
()
==
FIELD_TYPE_VAR_STRING
)
{
if
(
field
->
type
()
==
FIELD_TYPE_BLOB
)
...
...
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