Merge poseidon.:/home/tomas/mysql-5.1

into  poseidon.:/home/tomas/mysql-5.1-new-ndb
This commit is contained in:
tomas@poseidon. 2007-03-19 11:37:09 +01:00
commit a0bbe77c9c
116 changed files with 1956 additions and 824 deletions

View file

@ -4,7 +4,7 @@ extra_configs="$extra_configs $local_infile_configs"
configure="./configure $base_configs $extra_configs"
commands="\
$make -k distclean || true
$make -k maintainer-clean || true
/bin/rm -rf */.deps/*.P configure config.cache storage/*/configure storage/*/config.cache autom4te.cache storage/*/autom4te.cache;
path=`dirname $0`

View file

@ -1,5 +1,7 @@
#! /bin/sh
/bin/rm -f */.deps/*.P */*.o
make -k clean
make -k maintainer-clean
/bin/rm -f */.deps/*.P */*.o
/bin/rm -f config.cache mysql-*.tar.gz

View file

@ -1,5 +1,7 @@
#! /bin/sh
/bin/rm -f */.deps/*.P */*.o
make -k clean
make -k maintainer-clean
/bin/rm -f */.deps/*.P */*.o
/bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache mysql-*.tar.gz

View file

@ -1,5 +1,7 @@
#! /bin/sh
/bin/rm -f */.deps/*.P */*.o
make -k clean
make -k maintainer-clean
/bin/rm -f */.deps/*.P */*.o
/bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache mysql-*.tar.gz

View file

@ -6,7 +6,7 @@
# tree can then be picked up by "make dist" to create the "pristine source
# package" that is used as the basis for all other binary builds.
#
test -f Makefile && make distclean
test -f Makefile && make maintainer-clean
(cd storage/innobase && aclocal && autoheader && \
libtoolize --automake --force --copy && \
automake --force --add-missing --copy && autoconf)

View file

@ -61,7 +61,7 @@ done
set -x
make distclean
make maintainer-clean
path=`dirname $0`
. "$path/autorun.sh"

View file

@ -1,4 +1,4 @@
gmake -k clean || true
gmake -k maintainer-clean || true
/bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache
path=`dirname $0`

View file

@ -33,7 +33,7 @@ else
fi
set -x
make distclean
make maintainer-clean
path=`dirname $0`
. "$path/autorun.sh"

View file

@ -1,5 +1,7 @@
#! /bin/sh
AM_MAKEFLAGS="-j 2"
gmake -k clean || true
gmake -k maintainer-clean || true
/bin/rm -f */.deps/*.P config.cache
path=`dirname $0`

View file

@ -5,7 +5,7 @@
PATH=/opt/SUNWspro/bin/:/usr/ccs/bin:$PATH
make -k clean || true
make -k maintainer-clean || true
/bin/rm -f */.deps/*.P config.cache
path=`dirname $0`

View file

@ -31,7 +31,7 @@ do
shift
done
make -k clean || true
make -k maintainer-clean || true
/bin/rm -f */.deps/*.P config.cache
path=`dirname $0`

View file

@ -72,7 +72,7 @@ X-CSetKey: <$CSETKEY>
$BH
EOF
bk changes -v -r+
bk cset -r+ -d
bk rset -r+ -ah | bk gnupatch -h -dup -T
) > $BKROOT/BitKeeper/tmp/dev_public.txt
$SENDMAIL -t < $BKROOT/BitKeeper/tmp/dev_public.txt

View file

@ -1995,12 +1995,13 @@ static char *DbugMalloc(size_t size)
/*
* strtok lookalike - splits on ':', magically handles :\ and :/
* strtok lookalike - splits on ':', magically handles ::, :\ and :/
*/
static const char *DbugStrTok(const char *s)
{
while (s[0] && (s[0] != ':' || (s[1] == '\\' || s[1] == '/')))
while (s[0] && (s[0] != ':' ||
(s[1] == '\\' || s[1] == '/' || (s[1] == ':' && s++))))
s++;
return s;
}

View file

@ -908,9 +908,10 @@ via the
.B DBUG_PUSH
or
.B DBUG_SET
macros. Control string consists of colon separate flags. A flag
may take an argument or a list of arguments. If a control string
starts from a '+' sign it works
macros. Control string consists of colon separate flags. Colons
that are part of ':\\', ':/', or '::' are not considered flag
separators. A flag may take an argument or a list of arguments.
If a control string starts from a '+' sign it works
.I incrementally,
that is, it can modify existing state without overriding it. In such a
string every flag may be preceded by a '+' or '-' to enable or disable
@ -923,9 +924,7 @@ optional.
.LI a[,file]
Redirect the debugger output stream and append it to the specified
file. The default output stream is stderr. A null argument list
causes output to be redirected to stdout. A colon that is followed by
the '\\' or '/' is cosidered a part of the path and not a flag
separator.
causes output to be redirected to stdout.
.SP 1
EX: \fCa,C:\\tmp\\log\fR
.LI A[,file]

View file

@ -172,6 +172,7 @@ typedef uint rf_SetTimer;
#endif
#define VOID_SIGHANDLER
#define SIZEOF_CHAR 1
#define SIZEOF_INT 4
#define SIZEOF_LONG 4
#define SIZEOF_LONG_LONG 8
#define SIZEOF_OFF_T 8

View file

@ -225,8 +225,8 @@ extern void heap_update_auto_increment(HP_INFO *info, const byte *record);
ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key,
key_range *max_key);
int hp_panic(enum ha_panic_function flag);
int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
uint key_len, enum ha_rkey_function find_flag);
int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
key_part_map keypart_map, enum ha_rkey_function find_flag);
extern gptr heap_find(HP_INFO *info,int inx,const byte *key);
extern int heap_check_heap(HP_INFO *info, my_bool print_status);
extern byte *heap_position(HP_INFO *info);

View file

@ -134,14 +134,6 @@ make_atomic_swap(ptr)
#undef _atomic_h_cleanup_
#endif
#if SIZEOF_CHARP == SIZEOF_INT
typedef int intptr;
#elif SIZEOF_CHARP == SIZEOF_LONG
typedef long intptr;
#else
#error
#endif
#define MY_ATOMIC_OK 0
#define MY_ATOMIC_NOT_1CPU 1
extern int my_atomic_initialize();

View file

@ -385,16 +385,20 @@ enum ha_base_keytype {
#define HA_ERR_TABLE_NEEDS_UPGRADE 164 /* The table changed in storage engine */
#define HA_ERR_TABLE_READONLY 165 /* The table is not writable */
#define HA_ERR_AUTOINC_READ_FAILED 166/* Failed to get the next autoinc value */
#define HA_ERR_AUTOINC_ERANGE 167 /* Failed to set the row autoinc value */
#define HA_ERR_LAST 167 /*Copy last error nr.*/
#define HA_ERR_AUTOINC_READ_FAILED 166 /* Failed to get next autoinc value */
#define HA_ERR_AUTOINC_ERANGE 167 /* Failed to set row autoinc value */
#define HA_ERR_GENERIC 168 /* Generic error */
#define HA_ERR_LAST 168 /*Copy last error nr.*/
/* Add error numbers before HA_ERR_LAST and change it accordingly. */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
/* Other constants */
#define HA_NAMELEN 64 /* Max length of saved filename */
#define NO_SUCH_KEY ((uint)~0) /* used as a key no. */
#define NO_SUCH_KEY (~(uint)0) /* used as a key no. */
typedef ulong key_part_map;
#define HA_WHOLE_KEY (~(key_part_map)0)
/* Intern constants in databases */
@ -468,6 +472,7 @@ typedef struct st_key_range
{
const byte *key;
uint length;
key_part_map keypart_map;
enum ha_rkey_function flag;
} key_range;

View file

@ -986,7 +986,7 @@ typedef long int32;
typedef unsigned long uint32;
#endif
#else
#error "Neither int or long is of 4 bytes width"
#error Neither int or long is of 4 bytes width
#endif
#if !defined(HAVE_ULONG) && !defined(__USE_MISC)
@ -1016,6 +1016,16 @@ typedef unsigned __int64 my_ulonglong;
typedef unsigned long long my_ulonglong;
#endif
#if SIZEOF_CHARP == SIZEOF_INT
typedef int intptr;
#elif SIZEOF_CHARP == SIZEOF_LONG
typedef long intptr;
#elif SIZEOF_CHARP == SIZEOF_LONG_LONG
typedef long long intptr;
#else
#error sizeof(void *) is neither sizeof(int) nor sizeof(long) nor sizeof(long long)
#endif
#ifdef USE_RAID
/*
The following is done with a if to not get problems with pre-processors

View file

@ -274,9 +274,8 @@ extern struct st_myisam_info *mi_open(const char *name,int mode,
uint wait_if_locked);
extern int mi_panic(enum ha_panic_function function);
extern int mi_rfirst(struct st_myisam_info *file,byte *buf,int inx);
extern int mi_rkey(struct st_myisam_info *file,byte *buf,int inx,
const byte *key,
uint key_len, enum ha_rkey_function search_flag);
extern int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key,
key_part_map keypart_map, enum ha_rkey_function search_flag);
extern int mi_rlast(struct st_myisam_info *file,byte *buf,int inx);
extern int mi_rnext(struct st_myisam_info *file,byte *buf,int inx);
extern int mi_rnext_same(struct st_myisam_info *info, byte *buf);
@ -303,7 +302,7 @@ extern int mi_extra(struct st_myisam_info *file,
enum ha_extra_function function,
void *extra_arg);
extern int mi_reset(struct st_myisam_info *file);
extern ha_rows mi_records_in_range(struct st_myisam_info *info,int inx,
extern ha_rows mi_records_in_range(MI_INFO *info, int inx,
key_range *min_key, key_range *max_key);
extern int mi_log(int activate_log);
extern int mi_is_changed(struct st_myisam_info *info);

View file

@ -86,8 +86,8 @@ extern int myrg_rlast(MYRG_INFO *file,byte *buf,int inx);
extern int myrg_rnext(MYRG_INFO *file,byte *buf,int inx);
extern int myrg_rprev(MYRG_INFO *file,byte *buf,int inx);
extern int myrg_rnext_same(MYRG_INFO *file,byte *buf);
extern int myrg_rkey(MYRG_INFO *file,byte *buf,int inx,const byte *key,
uint key_len, enum ha_rkey_function search_flag);
extern int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key,
key_part_map keypart_map, enum ha_rkey_function search_flag);
extern int myrg_rrnd(MYRG_INFO *file,byte *buf,ulonglong pos);
extern int myrg_rsame(MYRG_INFO *file,byte *record,int inx);
extern int myrg_update(MYRG_INFO *file,const byte *old,byte *new_rec);
@ -100,7 +100,7 @@ extern int myrg_extra(MYRG_INFO *file,enum ha_extra_function function,
void *extra_arg);
extern int myrg_reset(MYRG_INFO *info);
extern void myrg_extrafunc(MYRG_INFO *info,invalidator_by_filename inv);
extern ha_rows myrg_records_in_range(MYRG_INFO *info,int inx,
extern ha_rows myrg_records_in_range(MYRG_INFO *info, int inx,
key_range *min_key, key_range *max_key);
extern ulonglong myrg_position(MYRG_INFO *info);

View file

@ -881,6 +881,42 @@ create table t1 (t varchar(255) default null, key t (t(80)))
engine=myisam default charset=latin1;
alter table t1 change t t text;
drop table t1;
CREATE TABLE t1 (a varchar(500));
ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(500) DEFAULT NULL,
`b` geometry NOT NULL,
SPATIAL KEY `b` (`b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 ADD KEY(b(50));
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(500) DEFAULT NULL,
`b` geometry NOT NULL,
SPATIAL KEY `b` (`b`),
KEY `b_2` (`b`(50))
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 ADD c POINT;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(500) DEFAULT NULL,
`b` geometry NOT NULL,
`c` point DEFAULT NULL,
SPATIAL KEY `b` (`b`),
KEY `b_2` (`b`(50))
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE TABLE t2 (a INT, KEY (a(20)));
ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys
ALTER TABLE t1 ADD d INT;
ALTER TABLE t1 ADD KEY (d(20));
ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys
ALTER TABLE t1 ADD e GEOMETRY NOT NULL, ADD SPATIAL KEY (e(30));
ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys
DROP TABLE t1;
CREATE TABLE t1 (s CHAR(8) BINARY);
INSERT INTO t1 VALUES ('test');
SELECT LENGTH(s) FROM t1;

View file

@ -25,10 +25,11 @@ insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
text1
teststring
teststring
teststring
select * from t1 where text1='teststring' or text1 like 'teststring_%';
text1
teststring
@ -48,10 +49,11 @@ alter table t1 modify text1 char(32) binary not null;
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
text1
teststring
teststring
teststring
select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%';
concat('|', text1, '|')
|teststring |
@ -132,10 +134,11 @@ concat('|', text1, '|')
drop table t1;
create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap;
insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
text1
teststring
teststring
teststring
select * from t1 where text1='teststring' or text1 like 'teststring_%';
text1
teststring

View file

@ -1,26 +1,12 @@
flush logs;
set global expire_logs_days = 3;
show variables like 'log%';
show variables like 'log_bin%';
Variable_name Value
log ON
log_bin OFF
log_bin_trust_function_creators ON
log_error
log_output TABLE
log_queries_not_using_indexes OFF
log_slave_updates OFF
log_slow_queries OFF
log_warnings 1
flush logs;
show variables like 'log%';
show variables like 'log_bin%';
Variable_name Value
log ON
log_bin OFF
log_bin_trust_function_creators ON
log_error
log_output TABLE
log_queries_not_using_indexes OFF
log_slave_updates OFF
log_slow_queries OFF
log_warnings 1
set global expire_logs_days = 0;

View file

@ -10,7 +10,7 @@ t1 CREATE TABLE `t1` (
`fid` int(11) NOT NULL AUTO_INCREMENT,
`g` geometry NOT NULL,
PRIMARY KEY (`fid`),
SPATIAL KEY `g` (`g`(32))
SPATIAL KEY `g` (`g`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(150 150, 150 150)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(149 149, 151 151)'));
@ -293,7 +293,7 @@ t2 CREATE TABLE `t2` (
`fid` int(11) NOT NULL AUTO_INCREMENT,
`g` geometry NOT NULL,
PRIMARY KEY (`fid`),
SPATIAL KEY `g` (`g`(32))
SPATIAL KEY `g` (`g`)
) ENGINE=MyISAM AUTO_INCREMENT=101 DEFAULT CHARSET=latin1
SELECT count(*) FROM t2;
count(*)
@ -803,7 +803,7 @@ CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom));
INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
drop table t1, t2;
CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`(32))) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Warnings:
Warning 1101 BLOB/TEXT column 'geometry' can't have a default value
INSERT INTO t1 (geometry) VALUES
@ -820,7 +820,7 @@ test.t1 check status OK
drop table t1;
CREATE TABLE t1 (
c1 geometry NOT NULL default '',
SPATIAL KEY i1 (c1(32))
SPATIAL KEY i1 (c1)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Warnings:
Warning 1101 BLOB/TEXT column 'c1' can't have a default value
@ -836,7 +836,7 @@ test.t1 check status OK
DROP TABLE t1;
CREATE TABLE t1 (
c1 geometry NOT NULL default '',
SPATIAL KEY i1 (c1(32))
SPATIAL KEY i1 (c1)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Warnings:
Warning 1101 BLOB/TEXT column 'c1' can't have a default value
@ -879,7 +879,7 @@ c1 varchar(15) collate utf8_bin default NULL,
c3 varchar(10) collate utf8_bin default NULL,
spatial_point point NOT NULL,
PRIMARY KEY(id),
SPATIAL KEY (spatial_point(32))
SPATIAL KEY (spatial_point)
)ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
('y', 's', 'j', GeomFromText('POINT(167 74)')),

View file

@ -1035,12 +1035,110 @@ HAVING SUM(t1_inner.b)+t1_outer.b > 5);
ERROR 42000: 'test.t1_outer.b' isn't in GROUP BY
DROP TABLE t1;
SET SQL_MODE = '';
CREATE TABLE t1 (a INT, b INT, KEY(a));
INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4);
EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2;
CREATE TABLE t1 (a INT, b INT,
PRIMARY KEY (a),
KEY i2(a,b));
INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8);
INSERT INTO t1 SELECT a + 8,b FROM t1;
INSERT INTO t1 SELECT a + 16,b FROM t1;
INSERT INTO t1 SELECT a + 32,b FROM t1;
INSERT INTO t1 SELECT a + 64,b FROM t1;
INSERT INTO t1 SELECT a + 128,b FROM t1;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status OK
EXPLAIN SELECT a FROM t1 WHERE a < 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL a 5 NULL 4
EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2;
1 SIMPLE t1 range PRIMARY,i2 PRIMARY 4 NULL 2 Using where; Using index
EXPLAIN SELECT a FROM t1 WHERE a < 2 ORDER BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
DROP TABLE t1;
1 SIMPLE t1 range PRIMARY,i2 PRIMARY 4 NULL 2 Using where; Using index
EXPLAIN SELECT a FROM t1 WHERE a < 2 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY,i2 PRIMARY 4 NULL 2 Using where; Using index
EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY,i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR JOIN (PRIMARY,i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index; Using filesort
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY)
IGNORE INDEX FOR GROUP BY (i2) GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index
EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY) IGNORE INDEX FOR ORDER BY (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1 FORCE INDEX (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1 USE INDEX ();
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1 USE INDEX () USE INDEX (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1
FORCE INDEX (PRIMARY)
IGNORE INDEX FOR GROUP BY (i2)
IGNORE INDEX FOR ORDER BY (i2)
USE INDEX (i2);
ERROR HY000: Incorrect usage of USE INDEX and FORCE INDEX
EXPLAIN SELECT a FROM t1 USE INDEX (i2) USE INDEX ();
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1 FORCE INDEX ();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1
EXPLAIN SELECT a FROM t1 IGNORE INDEX ();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1
EXPLAIN SELECT a FROM t1 USE INDEX FOR JOIN (i2)
USE INDEX FOR GROUP BY (i2) GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1 FORCE INDEX FOR JOIN (i2)
FORCE INDEX FOR GROUP BY (i2) GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL i2 4 NULL 257 Using index for group-by
EXPLAIN SELECT a FROM t1 USE INDEX () IGNORE INDEX (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1 IGNORE INDEX (i2) USE INDEX ();
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1
USE INDEX FOR GROUP BY (i2)
USE INDEX FOR ORDER BY (i2)
USE INDEX FOR JOIN (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1
USE INDEX FOR JOIN (i2)
USE INDEX FOR JOIN (i2)
USE INDEX FOR JOIN (i2,i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT 1 FROM t1 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 256 Using where; Using index
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 256 Using where
CREATE TABLE t2 (a INT, b INT, KEY(a));
INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4);
EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL a 5 NULL 4
EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
EXPLAIN SELECT 1 FROM t2 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 256 Using where
DROP TABLE t1, t2;

View file

@ -236,3 +236,25 @@ INSERT INTO t2 VALUES (1), (3);
INSERT INTO t1 SELECT 1, COUNT(*) FROM t2 ON DUPLICATE KEY UPDATE j= a;
ERROR 42S22: Unknown column 'a' in 'field list'
DROP TABLE t1,t2;
SET SQL_MODE = 'TRADITIONAL';
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL);
INSERT INTO t1 (a) VALUES (1);
ERROR HY000: Field 'b' doesn't have a default value
INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE a = b;
ERROR HY000: Field 'b' doesn't have a default value
INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = b;
ERROR HY000: Field 'b' doesn't have a default value
SELECT * FROM t1;
a b
DROP TABLE t1;
CREATE TABLE t1 (f1 INT AUTO_INCREMENT PRIMARY KEY,
f2 VARCHAR(5) NOT NULL UNIQUE);
INSERT t1 (f2) VALUES ('test') ON DUPLICATE KEY UPDATE f1 = LAST_INSERT_ID(f1);
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
1
INSERT t1 (f2) VALUES ('test') ON DUPLICATE KEY UPDATE f1 = LAST_INSERT_ID(f1);
SELECT LAST_INSERT_ID();
LAST_INSERT_ID()
1
DROP TABLE t1;

View file

@ -489,3 +489,44 @@ EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
drop table t1;
CREATE TABLE t1 (
a INTEGER auto_increment PRIMARY KEY,
b INTEGER NOT NULL,
c INTEGER NOT NULL,
d CHAR(64)
);
CREATE TABLE t2 (
a INTEGER auto_increment PRIMARY KEY,
b INTEGER NOT NULL,
c SMALLINT NOT NULL,
d DATETIME NOT NULL,
e SMALLINT NOT NULL,
f INTEGER NOT NULL,
g INTEGER NOT NULL,
h SMALLINT NOT NULL,
i INTEGER NOT NULL,
j INTEGER NOT NULL,
UNIQUE INDEX (b),
INDEX (b, d, e, f, g, h, i, j, c),
INDEX (c)
);
INSERT INTO t2 VALUES
(NULL, 1, 254, '1000-01-01 00:00:00', 257, 0, 0, 0, 0, 0),
(NULL, 2, 1, '2004-11-30 12:00:00', 1, 0, 0, 0, 0, 0),
(NULL, 3, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -21600, 0),
(NULL, 4, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -10800, 0),
(NULL, 5, 1, '2004-11-30 12:00:00', 1, 0, 0, 5, -10800, 0),
(NULL, 6, 1, '2004-11-30 12:00:00', 102, 0, 0, 0, 0, 0),
(NULL, 7, 1, '2004-11-30 12:00:00', 105, 2, 0, 0, 0, 0),
(NULL, 8, 1, '2004-11-30 12:00:00', 105, 10, 0, 0, 0, 0);
INSERT INTO t1 (b, c, d) VALUES
(3388000, -553000, NULL),
(3388000, -553000, NULL);
SELECT *
FROM t2 c JOIN t1 pa ON c.b = pa.a
WHERE c.c = 1
ORDER BY c.b, c.d
;
a b c d e f g h i j a b c d
2 2 1 2004-11-30 12:00:00 1 0 0 0 0 0 2 3388000 -553000 NULL
DROP TABLE t1, t2;

View file

@ -958,6 +958,28 @@ a ratio
19 1.3333
9 2.6667
drop table t1;
CREATE TABLE t1 (a INT UNSIGNED NOT NULL, b TIME);
INSERT INTO t1 (a) VALUES (100000), (0), (100), (1000000),(10000), (1000), (10);
UPDATE t1 SET b = SEC_TO_TIME(a);
SELECT a, b FROM t1 ORDER BY b DESC;
a b
1000000 277:46:40
100000 27:46:40
10000 02:46:40
1000 00:16:40
100 00:01:40
10 00:00:10
0 00:00:00
SELECT a, b FROM t1 ORDER BY SEC_TO_TIME(a) DESC;
a b
1000000 277:46:40
100000 27:46:40
10000 02:46:40
1000 00:16:40
100 00:01:40
10 00:00:10
0 00:00:00
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a), UNIQUE KEY b (b));
INSERT INTO t1 VALUES (1,1),(2,2);
CREATE TABLE t2 (a INT, b INT, KEY a (a,b));

View file

@ -3933,4 +3933,42 @@ cc cc 7
aa aa 2
aa aa 2
DROP TABLE t1,t2;
CREATE TABLE t1 (
access_id int NOT NULL default '0',
name varchar(20) default NULL,
rank int NOT NULL default '0',
KEY idx (access_id)
);
CREATE TABLE t2 (
faq_group_id int NOT NULL default '0',
faq_id int NOT NULL default '0',
access_id int default NULL,
UNIQUE KEY idx1 (faq_id),
KEY idx2 (faq_group_id,faq_id)
);
INSERT INTO t1 VALUES
(1,'Everyone',2),(2,'Help',3),(3,'Technical Support',1),(4,'Chat User',4);
INSERT INTO t2 VALUES
(261,265,1),(490,494,1);
SELECT t2.faq_id
FROM t1 INNER JOIN t2 IGNORE INDEX (idx1)
ON (t1.access_id = t2.access_id)
LEFT JOIN t2 t
ON (t.faq_group_id = t2.faq_group_id AND
find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4'))
WHERE
t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265);
faq_id
265
SELECT t2.faq_id
FROM t1 INNER JOIN t2
ON (t1.access_id = t2.access_id)
LEFT JOIN t2 t
ON (t.faq_group_id = t2.faq_group_id AND
find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4'))
WHERE
t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265);
faq_id
265
DROP TABLE t1,t2;
End of 5.0 tests

View file

@ -58,3 +58,15 @@ DROP PROCEDURE p3;
DROP FUNCTION f1;
DROP FUNCTION f2;
DROP FUNCTION f3;
select count(*) from information_schema.COLUMN_PRIVILEGES;
count(*)
0
select count(*) from information_schema.SCHEMA_PRIVILEGES;
count(*)
0
select count(*) from information_schema.TABLE_PRIVILEGES;
count(*)
0
select count(*) from information_schema.USER_PRIVILEGES;
count(*)
0

View file

@ -3873,3 +3873,16 @@ id_1
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t1xt2;
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (3), (1), (2);
SELECT 'this is ' 'a test.' AS col1, a AS col2 FROM t1;
col1 col2
this is a test. 3
this is a test. 1
this is a test. 2
SELECT * FROM (SELECT 'this is ' 'a test.' AS col1, a AS t2 FROM t1) t;
col1 t2
this is a test. 3
this is a test. 1
this is a test. 2
DROP table t1;

View file

@ -1372,4 +1372,45 @@ INSERT INTO bug22580_t1 VALUES (1,1);
DROP TABLE bug22580_t1;
DROP PROCEDURE bug22580_proc_1;
DROP PROCEDURE bug22580_proc_2;
DROP TRIGGER IF EXISTS trg27006_a_update;
DROP TRIGGER IF EXISTS trg27006_a_insert;
CREATE TABLE t1 (
`id` int(10) unsigned NOT NULL auto_increment,
`val` varchar(10) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE t2 like t1;
CREATE TRIGGER trg27006_a_insert AFTER INSERT ON t1 FOR EACH ROW
BEGIN
insert into t2 values (NULL,new.val);
END |
CREATE TRIGGER trg27006_a_update AFTER UPDATE ON t1 FOR EACH ROW
BEGIN
insert into t2 values (NULL,new.val);
END |
INSERT INTO t1(val) VALUES ('test1'),('test2');
SELECT * FROM t1;
id val
1 test1
2 test2
SELECT * FROM t2;
id val
1 test1
2 test2
INSERT INTO t1 VALUES (2,'test2') ON DUPLICATE KEY UPDATE val=VALUES(val);
INSERT INTO t1 VALUES (3,'test3') ON DUPLICATE KEY UPDATE val=VALUES(val);
SELECT * FROM t1;
id val
1 test1
2 test2
3 test3
SELECT * FROM t2;
id val
1 test1
2 test2
3 test2
4 test3
DROP TRIGGER trg27006_a_insert;
DROP TRIGGER trg27006_a_update;
drop table t1,t2;
End of 5.0 tests

View file

@ -641,6 +641,33 @@ engine=myisam default charset=latin1;
alter table t1 change t t text;
drop table t1;
#
# Bug #26794: Adding an index with a prefix on a SPATIAL type breaks ALTER
# TABLE
#
CREATE TABLE t1 (a varchar(500));
ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b);
SHOW CREATE TABLE t1;
ALTER TABLE t1 ADD KEY(b(50));
SHOW CREATE TABLE t1;
ALTER TABLE t1 ADD c POINT;
SHOW CREATE TABLE t1;
--error ER_WRONG_SUB_KEY
CREATE TABLE t2 (a INT, KEY (a(20)));
ALTER TABLE t1 ADD d INT;
--error ER_WRONG_SUB_KEY
ALTER TABLE t1 ADD KEY (d(20));
# the 5.1 part of the test
--error ER_WRONG_SUB_KEY
ALTER TABLE t1 ADD e GEOMETRY NOT NULL, ADD SPATIAL KEY (e(30));
DROP TABLE t1;
#
# Bug#18038 MySQL server corrupts binary columns data
#

View file

@ -16,7 +16,8 @@ drop table if exists t1;
create table t1 (text1 varchar(32) not NULL, KEY key1 (text1));
insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
check table t1;
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
select * from t1 where text1='teststring' or text1 like 'teststring_%';
select * from t1 where text1='teststring' or text1 > 'teststring\t';
select * from t1 order by text1;
@ -24,7 +25,8 @@ explain select * from t1 order by text1;
alter table t1 modify text1 char(32) binary not null;
check table t1;
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%';
select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t';
select text1, length(text1) from t1 order by text1;
@ -57,7 +59,8 @@ drop table t1;
create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap;
insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
select * from t1 where text1='teststring' or text1 like 'teststring_%';
select * from t1 where text1='teststring' or text1 >= 'teststring\t';
select * from t1 order by text1;

View file

@ -3,7 +3,7 @@
#
flush logs;
set global expire_logs_days = 3;
show variables like 'log%';
show variables like 'log_bin%';
flush logs;
show variables like 'log%';
show variables like 'log_bin%';
set global expire_logs_days = 0;

View file

@ -172,7 +172,7 @@ CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom));
INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
drop table t1, t2;
CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`(32))) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO t1 (geometry) VALUES
(PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, -18.6055555000
@ -192,7 +192,7 @@ drop table t1;
#
CREATE TABLE t1 (
c1 geometry NOT NULL default '',
SPATIAL KEY i1 (c1(32))
SPATIAL KEY i1 (c1)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO t1 (c1) VALUES (
PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
@ -206,7 +206,7 @@ DROP TABLE t1;
#
CREATE TABLE t1 (
c1 geometry NOT NULL default '',
SPATIAL KEY i1 (c1(32))
SPATIAL KEY i1 (c1)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO t1 (c1) VALUES (
PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
@ -251,7 +251,7 @@ CREATE TABLE t1 (id bigint(12) unsigned NOT NULL auto_increment,
c3 varchar(10) collate utf8_bin default NULL,
spatial_point point NOT NULL,
PRIMARY KEY(id),
SPATIAL KEY (spatial_point(32))
SPATIAL KEY (spatial_point)
)ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
#
INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES

View file

@ -757,10 +757,66 @@ SET SQL_MODE = '';
# Bug #21174: Index degrades sort performance and
# optimizer does not honor IGNORE INDEX
#
CREATE TABLE t1 (a INT, b INT, KEY(a));
INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4);
CREATE TABLE t1 (a INT, b INT,
PRIMARY KEY (a),
KEY i2(a,b));
INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8);
INSERT INTO t1 SELECT a + 8,b FROM t1;
INSERT INTO t1 SELECT a + 16,b FROM t1;
INSERT INTO t1 SELECT a + 32,b FROM t1;
INSERT INTO t1 SELECT a + 64,b FROM t1;
INSERT INTO t1 SELECT a + 128,b FROM t1;
ANALYZE TABLE t1;
EXPLAIN SELECT a FROM t1 WHERE a < 2;
EXPLAIN SELECT a FROM t1 WHERE a < 2 ORDER BY a;
EXPLAIN SELECT a FROM t1 WHERE a < 2 GROUP BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY,i2);
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR JOIN (PRIMARY,i2);
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY)
IGNORE INDEX FOR GROUP BY (i2) GROUP BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY) IGNORE INDEX FOR ORDER BY (i2);
EXPLAIN SELECT a FROM t1 FORCE INDEX (i2);
EXPLAIN SELECT a FROM t1 USE INDEX ();
EXPLAIN SELECT a FROM t1 USE INDEX () USE INDEX (i2);
--error ER_WRONG_USAGE
EXPLAIN SELECT a FROM t1
FORCE INDEX (PRIMARY)
IGNORE INDEX FOR GROUP BY (i2)
IGNORE INDEX FOR ORDER BY (i2)
USE INDEX (i2);
EXPLAIN SELECT a FROM t1 USE INDEX (i2) USE INDEX ();
--error ER_PARSE_ERROR
EXPLAIN SELECT a FROM t1 FORCE INDEX ();
--error ER_PARSE_ERROR
EXPLAIN SELECT a FROM t1 IGNORE INDEX ();
EXPLAIN SELECT a FROM t1 USE INDEX FOR JOIN (i2)
USE INDEX FOR GROUP BY (i2) GROUP BY a;
EXPLAIN SELECT a FROM t1 FORCE INDEX FOR JOIN (i2)
FORCE INDEX FOR GROUP BY (i2) GROUP BY a;
EXPLAIN SELECT a FROM t1 USE INDEX () IGNORE INDEX (i2);
EXPLAIN SELECT a FROM t1 IGNORE INDEX (i2) USE INDEX ();
EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2;
EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2;
EXPLAIN SELECT a FROM t1
USE INDEX FOR GROUP BY (i2)
USE INDEX FOR ORDER BY (i2)
USE INDEX FOR JOIN (i2);
DROP TABLE t1;
EXPLAIN SELECT a FROM t1
USE INDEX FOR JOIN (i2)
USE INDEX FOR JOIN (i2)
USE INDEX FOR JOIN (i2,i2);
EXPLAIN SELECT 1 FROM t1 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
CREATE TABLE t2 (a INT, b INT, KEY(a));
INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4);
EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2;
EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2;
EXPLAIN SELECT 1 FROM t2 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
DROP TABLE t1, t2;

View file

@ -162,3 +162,36 @@ INSERT INTO t2 VALUES (1), (3);
--error ER_BAD_FIELD_ERROR
INSERT INTO t1 SELECT 1, COUNT(*) FROM t2 ON DUPLICATE KEY UPDATE j= a;
DROP TABLE t1,t2;
#
# Bug #26261: Missing default value isn't noticed in
# insert ... on duplicate key update
#
SET SQL_MODE = 'TRADITIONAL';
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL);
--error 1364
INSERT INTO t1 (a) VALUES (1);
--error 1364
INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE a = b;
--error 1364
INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = b;
SELECT * FROM t1;
DROP TABLE t1;
#
# Bug#27033: 0 as LAST_INSERT_ID() after INSERT .. ON DUPLICATE if rows were
# touched but not actually changed.
#
CREATE TABLE t1 (f1 INT AUTO_INCREMENT PRIMARY KEY,
f2 VARCHAR(5) NOT NULL UNIQUE);
INSERT t1 (f2) VALUES ('test') ON DUPLICATE KEY UPDATE f1 = LAST_INSERT_ID(f1);
SELECT LAST_INSERT_ID();
INSERT t1 (f2) VALUES ('test') ON DUPLICATE KEY UPDATE f1 = LAST_INSERT_ID(f1);
SELECT LAST_INSERT_ID();
DROP TABLE t1;

View file

@ -453,3 +453,51 @@ ALTER TABLE t1 DISABLE KEYS;
EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a);
drop table t1;
#
# Bug #24778: Innodb: No result when using ORDER BY
#
CREATE TABLE t1 (
a INTEGER auto_increment PRIMARY KEY,
b INTEGER NOT NULL,
c INTEGER NOT NULL,
d CHAR(64)
);
CREATE TABLE t2 (
a INTEGER auto_increment PRIMARY KEY,
b INTEGER NOT NULL,
c SMALLINT NOT NULL,
d DATETIME NOT NULL,
e SMALLINT NOT NULL,
f INTEGER NOT NULL,
g INTEGER NOT NULL,
h SMALLINT NOT NULL,
i INTEGER NOT NULL,
j INTEGER NOT NULL,
UNIQUE INDEX (b),
INDEX (b, d, e, f, g, h, i, j, c),
INDEX (c)
);
INSERT INTO t2 VALUES
(NULL, 1, 254, '1000-01-01 00:00:00', 257, 0, 0, 0, 0, 0),
(NULL, 2, 1, '2004-11-30 12:00:00', 1, 0, 0, 0, 0, 0),
(NULL, 3, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -21600, 0),
(NULL, 4, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -10800, 0),
(NULL, 5, 1, '2004-11-30 12:00:00', 1, 0, 0, 5, -10800, 0),
(NULL, 6, 1, '2004-11-30 12:00:00', 102, 0, 0, 0, 0, 0),
(NULL, 7, 1, '2004-11-30 12:00:00', 105, 2, 0, 0, 0, 0),
(NULL, 8, 1, '2004-11-30 12:00:00', 105, 10, 0, 0, 0, 0);
INSERT INTO t1 (b, c, d) VALUES
(3388000, -553000, NULL),
(3388000, -553000, NULL);
SELECT *
FROM t2 c JOIN t1 pa ON c.b = pa.a
WHERE c.c = 1
ORDER BY c.b, c.d
;
DROP TABLE t1, t2;

View file

@ -678,6 +678,21 @@ insert into t1 values (1,2,3), (9,8,3), (19,4,3), (1,4,9);
select a,(sum(b)/sum(c)) as ratio from t1 group by a order by sum(b)/sum(c) asc;
drop table t1;
#
# Bug#26672: Incorrect SEC_TO_TIME() casting in ORDER BY
#
CREATE TABLE t1 (a INT UNSIGNED NOT NULL, b TIME);
INSERT INTO t1 (a) VALUES (100000), (0), (100), (1000000),(10000), (1000), (10);
UPDATE t1 SET b = SEC_TO_TIME(a);
-- Correct ORDER
SELECT a, b FROM t1 ORDER BY b DESC;
-- must be ordered as the above
SELECT a, b FROM t1 ORDER BY SEC_TO_TIME(a) DESC;
DROP TABLE t1;
#
# BUG#16590: Optimized does not do right "const" table pre-read
#

View file

@ -3299,4 +3299,51 @@ SELECT * FROM t1 LEFT JOIN t2 ON t1.name=t2.name;
DROP TABLE t1,t2;
#
# Bug #26963: join with predicates that contain fields from equalities evaluated
# to constants after constant table substitution
#
CREATE TABLE t1 (
access_id int NOT NULL default '0',
name varchar(20) default NULL,
rank int NOT NULL default '0',
KEY idx (access_id)
);
CREATE TABLE t2 (
faq_group_id int NOT NULL default '0',
faq_id int NOT NULL default '0',
access_id int default NULL,
UNIQUE KEY idx1 (faq_id),
KEY idx2 (faq_group_id,faq_id)
);
INSERT INTO t1 VALUES
(1,'Everyone',2),(2,'Help',3),(3,'Technical Support',1),(4,'Chat User',4);
INSERT INTO t2 VALUES
(261,265,1),(490,494,1);
SELECT t2.faq_id
FROM t1 INNER JOIN t2 IGNORE INDEX (idx1)
ON (t1.access_id = t2.access_id)
LEFT JOIN t2 t
ON (t.faq_group_id = t2.faq_group_id AND
find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4'))
WHERE
t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265);
SELECT t2.faq_id
FROM t1 INNER JOIN t2
ON (t1.access_id = t2.access_id)
LEFT JOIN t2 t
ON (t.faq_group_id = t2.faq_group_id AND
find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4'))
WHERE
t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265);
DROP TABLE t1,t2;
--echo End of 5.0 tests

View file

@ -108,3 +108,11 @@ DROP PROCEDURE p3;
DROP FUNCTION f1;
DROP FUNCTION f2;
DROP FUNCTION f3;
#
# Bug#26285 Selecting information_schema crahes server
#
select count(*) from information_schema.COLUMN_PRIVILEGES;
select count(*) from information_schema.SCHEMA_PRIVILEGES;
select count(*) from information_schema.TABLE_PRIVILEGES;
select count(*) from information_schema.USER_PRIVILEGES;

View file

@ -2736,3 +2736,15 @@ DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t1xt2;
#
# Bug #26728: derived table with concatanation of literals in select list
#
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (3), (1), (2);
SELECT 'this is ' 'a test.' AS col1, a AS col2 FROM t1;
SELECT * FROM (SELECT 'this is ' 'a test.' AS col1, a AS t2 FROM t1) t;
DROP table t1;

View file

@ -1699,4 +1699,42 @@ DROP TABLE bug22580_t1;
DROP PROCEDURE bug22580_proc_1;
DROP PROCEDURE bug22580_proc_2;
#
# Bug#27006: AFTER UPDATE triggers not fired with INSERT ... ON DUPLICATE KEY
# UPDATE if the row wasn't actually changed.
#
--disable_warnings
DROP TRIGGER IF EXISTS trg27006_a_update;
DROP TRIGGER IF EXISTS trg27006_a_insert;
--enable_warnings
CREATE TABLE t1 (
`id` int(10) unsigned NOT NULL auto_increment,
`val` varchar(10) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE t2 like t1;
DELIMITER |;
CREATE TRIGGER trg27006_a_insert AFTER INSERT ON t1 FOR EACH ROW
BEGIN
insert into t2 values (NULL,new.val);
END |
CREATE TRIGGER trg27006_a_update AFTER UPDATE ON t1 FOR EACH ROW
BEGIN
insert into t2 values (NULL,new.val);
END |
DELIMITER ;|
INSERT INTO t1(val) VALUES ('test1'),('test2');
SELECT * FROM t1;
SELECT * FROM t2;
INSERT INTO t1 VALUES (2,'test2') ON DUPLICATE KEY UPDATE val=VALUES(val);
INSERT INTO t1 VALUES (3,'test3') ON DUPLICATE KEY UPDATE val=VALUES(val);
SELECT * FROM t1;
SELECT * FROM t2;
DROP TRIGGER trg27006_a_insert;
DROP TRIGGER trg27006_a_update;
drop table t1,t2;
--echo End of 5.0 tests

0
server-tools/CMakeLists.txt Executable file → Normal file
View file

View file

@ -288,7 +288,7 @@ Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table,
{
key_copy(key_buf, event_table->record[0], key_info, key_len);
if (!(ret= event_table->file->index_read(event_table->record[0], key_buf,
key_len, HA_READ_PREFIX)))
(key_part_map)1, HA_READ_PREFIX)))
{
DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
do
@ -843,8 +843,7 @@ Event_db_repository::find_named_event(THD *thd, LEX_STRING db, LEX_STRING name,
key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0, key,
table->key_info->key_length,
if (table->file->index_read_idx(table->record[0], 0, key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
DBUG_PRINT("info", ("Row not found"));

View file

@ -1015,6 +1015,7 @@ bool Field::type_can_have_key_part(enum enum_field_types type)
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_GEOMETRY:
return TRUE;
default:
return FALSE;

View file

@ -1374,7 +1374,10 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
}
else
{
switch ((sortorder->result_type=sortorder->item->result_type())) {
sortorder->result_type= sortorder->item->result_type();
if (sortorder->item->result_as_longlong())
sortorder->result_type= INT_RESULT;
switch (sortorder->result_type) {
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
set_if_smaller(sortorder->length, thd->variables.max_sort_length);

View file

@ -1104,7 +1104,7 @@ int ha_ndbcluster::create_indexes(Ndb *ndb, TABLE *tab)
KEY* key_info= tab->key_info;
const char **key_name= tab->s->keynames.type_names;
DBUG_ENTER("ha_ndbcluster::create_indexes");
for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
{
index_name= *key_name;
@ -3370,19 +3370,6 @@ int ha_ndbcluster::index_read(byte *buf,
}
int ha_ndbcluster::index_read_idx(byte *buf, uint index_no,
const byte *key, uint key_len,
enum ha_rkey_function find_flag)
{
statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
DBUG_ENTER("ha_ndbcluster::index_read_idx");
DBUG_PRINT("enter", ("index_no: %u, key_len: %u", index_no, key_len));
close_scan();
index_init(index_no, 0);
DBUG_RETURN(index_read(buf, key, key_len, find_flag));
}
int ha_ndbcluster::index_next(byte *buf)
{
DBUG_ENTER("ha_ndbcluster::index_next");
@ -3549,10 +3536,10 @@ int ha_ndbcluster::close_scan()
m_multi_cursor= 0;
if (!m_active_cursor && !m_multi_cursor)
DBUG_RETURN(1);
DBUG_RETURN(0);
NdbScanOperation *cursor= m_active_cursor ? m_active_cursor : m_multi_cursor;
if (m_lock_tuple)
{
/*

View file

@ -642,8 +642,6 @@ class ha_ndbcluster: public handler
int index_end();
int index_read(byte *buf, const byte *key, uint key_len,
enum ha_rkey_function find_flag);
int index_read_idx(byte *buf, uint index, const byte *key, uint key_len,
enum ha_rkey_function find_flag);
int index_next(byte *buf);
int index_prev(byte *buf);
int index_first(byte *buf);

View file

@ -3336,13 +3336,14 @@ int ha_partition::index_end()
*/
int ha_partition::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
DBUG_ENTER("ha_partition::index_read");
end_range= 0;
m_index_scan_type= partition_index_read;
DBUG_RETURN(common_index_read(buf, key, key_len, find_flag));
DBUG_RETURN(common_index_read(buf, key, keypart_map, find_flag));
}
@ -3355,14 +3356,17 @@ int ha_partition::index_read(byte * buf, const byte * key,
see index_read for rest
*/
int ha_partition::common_index_read(byte *buf, const byte *key, uint key_len,
int ha_partition::common_index_read(byte *buf, const byte *key,
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
int error;
bool reverse_order= FALSE;
uint key_len= calculate_key_len(table, active_index, key, keypart_map);
DBUG_ENTER("ha_partition::common_index_read");
memcpy((void*)m_start_key.key, key, key_len);
m_start_key.keypart_map= keypart_map;
m_start_key.length= key_len;
m_start_key.flag= find_flag;
@ -3490,33 +3494,6 @@ int ha_partition::common_first_last(byte *buf)
}
/*
Perform index read using index where always only one row is returned
SYNOPSIS
index_read_idx()
see index_read for rest of parameters and return values
DESCRIPTION
Positions an index cursor to the index specified in key. Fetches the
row if any. This is only used to read whole keys.
TODO: Optimise this code to avoid index_init and index_end
*/
int ha_partition::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len,
enum ha_rkey_function find_flag)
{
int res;
DBUG_ENTER("ha_partition::index_read_idx");
index_init(index, 0);
res= index_read(buf, key, key_len, find_flag);
index_end();
DBUG_RETURN(res);
}
/*
Read last using key
@ -3535,14 +3512,15 @@ int ha_partition::index_read_idx(byte * buf, uint index, const byte * key,
Can only be used on indexes supporting HA_READ_ORDER
*/
int ha_partition::index_read_last(byte *buf, const byte *key, uint keylen)
int ha_partition::index_read_last(byte *buf, const byte *key,
key_part_map keypart_map)
{
DBUG_ENTER("ha_partition::index_read_last");
m_ordered= TRUE; // Safety measure
end_range= 0;
m_index_scan_type= partition_index_read_last;
DBUG_RETURN(common_index_read(buf, key, keylen, HA_READ_PREFIX_LAST));
DBUG_RETURN(common_index_read(buf, key, keypart_map, HA_READ_PREFIX_LAST));
}
@ -3688,7 +3666,7 @@ int ha_partition::read_range_first(const key_range *start_key,
m_index_scan_type= partition_index_read;
error= common_index_read(m_rec0,
start_key->key,
start_key->length, start_key->flag);
start_key->keypart_map, start_key->flag);
}
DBUG_RETURN(error);
}
@ -3887,7 +3865,7 @@ int ha_partition::handle_unordered_scan_next_partition(byte * buf)
case partition_index_read:
DBUG_PRINT("info", ("index_read on partition %d", i));
error= file->index_read(buf, m_start_key.key,
m_start_key.length,
m_start_key.keypart_map,
m_start_key.flag);
break;
case partition_index_first:
@ -3979,7 +3957,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
case partition_index_read:
error= file->index_read(rec_buf_ptr,
m_start_key.key,
m_start_key.length,
m_start_key.keypart_map,
m_start_key.flag);
break;
case partition_index_first:
@ -3993,7 +3971,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
case partition_index_read_last:
error= file->index_read_last(rec_buf_ptr,
m_start_key.key,
m_start_key.length);
m_start_key.keypart_map);
reverse_order= TRUE;
break;
default:

View file

@ -384,9 +384,8 @@ public:
any end processing needed.
*/
virtual int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
virtual int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
key_part_map keypart_map,
enum ha_rkey_function find_flag);
virtual int index_init(uint idx, bool sorted);
virtual int index_end();
@ -399,7 +398,8 @@ public:
virtual int index_first(byte * buf);
virtual int index_last(byte * buf);
virtual int index_next_same(byte * buf, const byte * key, uint keylen);
virtual int index_read_last(byte * buf, const byte * key, uint keylen);
virtual int index_read_last(byte * buf, const byte * key,
key_part_map keypart_map);
/*
read_first_row is virtual method but is only implemented by
@ -425,7 +425,8 @@ public:
private:
int common_index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
key_part_map keypart_map,
enum ha_rkey_function find_flag);
int common_first_last(byte * buf);
int partition_scan_set_up(byte * buf, bool idx_read_flag);
int handle_unordered_next(byte * buf, bool next_same);

View file

@ -1843,7 +1843,7 @@ int handler::update_auto_increment()
nr= compute_next_insert_id(nr-1, variables);
}
if (table->s->next_number_key_offset == 0)
if (table->s->next_number_keypart == 0)
{
/* We must defer the appending until "nr" has been possibly truncated */
append= TRUE;
@ -1963,7 +1963,7 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
table->read_set);
column_bitmaps_signal();
index_init(table->s->next_number_index, 1);
if (!table->s->next_number_key_offset)
if (table->s->next_number_keypart == 0)
{ // Autoincrement at key-start
error=index_last(table->record[1]);
/*
@ -1979,7 +1979,8 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
key_copy(key, table->record[0],
table->key_info + table->s->next_number_index,
table->s->next_number_key_offset);
error= index_read(table->record[1], key, table->s->next_number_key_offset,
error= index_read(table->record[1], key,
make_prev_keypart_map(table->s->next_number_keypart),
HA_READ_PREFIX_LAST);
/*
MySQL needs to call us for next row: assume we are inserting ("a",null)
@ -3079,9 +3080,9 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
multi_range_curr < multi_range_end;
multi_range_curr++)
{
result= read_range_first(multi_range_curr->start_key.length ?
result= read_range_first(multi_range_curr->start_key.keypart_map ?
&multi_range_curr->start_key : 0,
multi_range_curr->end_key.length ?
multi_range_curr->end_key.keypart_map ?
&multi_range_curr->end_key : 0,
test(multi_range_curr->range_flag & EQ_RANGE),
multi_range_sorted);
@ -3146,9 +3147,9 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
multi_range_curr < multi_range_end;
multi_range_curr++)
{
result= read_range_first(multi_range_curr->start_key.length ?
result= read_range_first(multi_range_curr->start_key.keypart_map ?
&multi_range_curr->start_key : 0,
multi_range_curr->end_key.length ?
multi_range_curr->end_key.keypart_map ?
&multi_range_curr->end_key : 0,
test(multi_range_curr->range_flag & EQ_RANGE),
multi_range_sorted);
@ -3207,7 +3208,7 @@ int handler::read_range_first(const key_range *start_key,
else
result= index_read(table->record[0],
start_key->key,
start_key->length,
start_key->keypart_map,
start_key->flag);
if (result)
DBUG_RETURN((result == HA_ERR_KEY_NOT_FOUND)
@ -3279,15 +3280,19 @@ int handler::compare_key(key_range *range)
return cmp;
}
int handler::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
int error= ha_index_init(index, 0);
int error, error1;
error= index_init(index, 0);
if (!error)
error= index_read(buf, key, key_len, find_flag);
if (!error)
error= ha_index_end();
return error;
{
error= index_read(buf, key, keypart_map, find_flag);
error1= index_end();
}
return error ? error : error1;
}

View file

@ -867,6 +867,18 @@ public:
{}
};
uint calculate_key_len(TABLE *, uint, const byte *, key_part_map);
/*
bitmap with first N+1 bits set
(keypart_map for a key prefix of [0..N] keyparts)
*/
#define make_keypart_map(N) (((key_part_map)2 << (N)) - 1)
/*
bitmap with first N bits set
(keypart_map for a key prefix of [0..N-1] keyparts)
*/
#define make_prev_keypart_map(N) (((key_part_map)1 << (N)) - 1)
/*
The handler class is the interface for dynamically loadable
storage engines. Do not add ifdefs and take care when adding or
@ -1202,11 +1214,32 @@ public:
DBUG_ASSERT(FALSE);
return HA_ERR_WRONG_COMMAND;
}
virtual int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
private:
virtual int index_read(byte * buf, const byte * key, uint key_len,
enum ha_rkey_function find_flag)
{ return HA_ERR_WRONG_COMMAND; }
public:
/**
@brief
Positions an index cursor to the index specified in the handle. Fetches the
row if available. If the key value is null, begin at the first key of the
index.
*/
virtual int index_read(byte * buf, const byte * key, key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
uint key_len= calculate_key_len(table, active_index, key, keypart_map);
return index_read(buf, key, key_len, find_flag);
}
/**
@brief
Positions an index cursor to the index specified in the handle. Fetches the
row if available. If the key value is null, begin at the first key of the
index.
*/
virtual int index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
key_part_map keypart_map,
enum ha_rkey_function find_flag);
virtual int index_next(byte * buf)
{ return HA_ERR_WRONG_COMMAND; }
virtual int index_prev(byte * buf)
@ -1216,8 +1249,21 @@ public:
virtual int index_last(byte * buf)
{ return HA_ERR_WRONG_COMMAND; }
virtual int index_next_same(byte *buf, const byte *key, uint keylen);
private:
virtual int index_read_last(byte * buf, const byte * key, uint key_len)
{ return (my_errno=HA_ERR_WRONG_COMMAND); }
public:
/**
@brief
The following functions works like index_read, but it find the last
row with the current key value or prefix.
*/
virtual int index_read_last(byte * buf, const byte * key,
key_part_map keypart_map)
{
uint key_len= calculate_key_len(table, active_index, key, keypart_map);
return index_read_last(buf, key, key_len);
}
virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
KEY_MULTI_RANGE *ranges, uint range_count,
bool sorted, HANDLER_BUFFER *buffer);
@ -1243,8 +1289,7 @@ public:
{ return HA_ERR_WRONG_COMMAND; }
virtual int rnd_same(byte *buf, uint inx)
{ return HA_ERR_WRONG_COMMAND; }
virtual ha_rows records_in_range(uint inx, key_range *min_key,
key_range *max_key)
virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key)
{ return (ha_rows) 10; }
virtual void position(const byte *record)=0;
virtual int info(uint)=0; // see my_base.h for full description

View file

@ -3907,7 +3907,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
{
/* First usage of column */
table->used_fields++; // Used to optimize loops
table->used_keys.intersect(field->part_of_key);
/* purecov: begin inspected */
table->covering_keys.intersect(field->part_of_key);
/* purecov: end */
}
}
}
@ -4125,7 +4127,9 @@ bool Item_field::set_no_const_sub(byte *arg)
DESCRIPTION
The function returns a pointer to an item that is taken from
the very beginning of the item_equal list which the Item_field
object refers to (belongs to).
object refers to (belongs to) unless item_equal contains a constant
item. In this case the function returns this constant item,
(if the substitution does not require conversion).
If the Item_field object does not refer any Item_equal object
'this' is returned
@ -4134,7 +4138,8 @@ bool Item_field::set_no_const_sub(byte *arg)
of the thransformer method.
RETURN VALUES
pointer to a replacement Item_field if there is a better equal item;
pointer to a replacement Item_field if there is a better equal item or
a pointer to a constant equal item;
this - otherwise.
*/
@ -4142,6 +4147,14 @@ Item *Item_field::replace_equal_field(byte *arg)
{
if (item_equal)
{
Item *const_item= item_equal->get_const();
if (const_item)
{
if (cmp_context != (Item_result)-1 &&
const_item->cmp_context != cmp_context)
return this;
return const_item;
}
Item_field *subst= item_equal->get_first();
if (subst && !field->eq(subst->field))
return subst;

View file

@ -1811,7 +1811,11 @@ public:
str_value.length(), collation.collation);
}
Item *safe_charset_converter(CHARSET_INFO *tocs);
inline void append(char *str, uint length) { str_value.append(str, length); }
inline void append(char *str, uint length)
{
str_value.append(str, length);
max_length= str_value.numchars() * collation.collation->mbmaxlen;
}
void print(String *str);
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}

View file

@ -2045,7 +2045,8 @@ int subselect_uniquesubquery_engine::exec()
table->file->ha_index_init(tab->ref.key, 0);
error= table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
make_prev_keypart_map(tab->ref.key_parts),
HA_READ_KEY_EXACT);
if (error &&
error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
error= report_error(table, error);
@ -2154,7 +2155,8 @@ int subselect_indexsubquery_engine::exec()
table->file->ha_index_init(tab->ref.key, 1);
error= table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
make_prev_keypart_map(tab->ref.key_parts),
HA_READ_KEY_EXACT);
if (error &&
error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
error= report_error(table, error);

View file

@ -29,6 +29,7 @@
field Field to search after
key_length On partial match, contains length of fields before
field
keypart key part # of a field
NOTES
Used when calculating key for NEXT_NUMBER
@ -45,7 +46,7 @@
*/
int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
uint *key_length)
uint *key_length, uint *keypart)
{
reg2 int i;
reg3 KEY *key_info;
@ -60,8 +61,8 @@ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
{
if (key_info->key_part[0].offset == fieldpos)
{ /* Found key. Calc keylength */
*key_length=0;
return(i); /* Use this key */
*key_length= *keypart= 0;
return i; /* Use this key */
}
}
@ -78,8 +79,11 @@ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
j++, key_part++)
{
if (key_part->offset == fieldpos)
return(i); /* Use this key */
*key_length+=key_part->store_length;
{
*keypart= j;
return i; /* Use this key */
}
*key_length+= key_part->store_length;
}
}
return(-1); /* No key is ok */

View file

@ -3773,7 +3773,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
nb_elements()));
/*
If the auto_increment was second in a table's index (possible with
MyISAM or BDB) (table->next_number_key_offset != 0), such event is
MyISAM or BDB) (table->next_number_keypart != 0), such event is
in fact not necessary. We could avoid logging it.
*/
Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT,

View file

@ -6854,9 +6854,8 @@ replace_record(THD *thd, TABLE *table,
}
key_copy((byte*)key.get(), table->record[0], table->key_info + keynum, 0);
error= table->file->index_read_idx(table->record[1], keynum,
(const byte*)key.get(),
table->key_info[keynum].key_length,
error= table->file->index_read_idx(table->record[1], keynum,
(const byte*)key.get(), HA_WHOLE_KEY,
HA_READ_KEY_EXACT);
if (error)
DBUG_RETURN(error);
@ -7040,8 +7039,7 @@ static int find_and_fetch_row(TABLE *table, byte *key)
my_ptrdiff_t const pos=
table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0;
table->record[1][pos]= 0xFF;
if ((error= table->file->index_read(table->record[1], key,
table->key_info->key_length,
if ((error= table->file->index_read(table->record[1], key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT)))
{
table->file->print_error(error, MYF(0));

View file

@ -47,7 +47,6 @@ typedef Bitmap<64> key_map; /* Used for finding keys */
#else
typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
#endif
typedef ulong key_part_map; /* Used for finding key parts */
typedef ulong nesting_map; /* Used for flags of nesting constructs */
/*
Used to identify NESTED_JOIN structures within a join (applicable only to
@ -991,7 +990,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
List<Item> &fields, List_item *values,
List<Item> &update_fields,
List<Item> &update_values, enum_duplicates duplic,
COND **where, bool select_insert);
COND **where, bool select_insert,
bool check_fields, bool abort_on_warning);
bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, List<Item> &update_fields,
List<Item> &update_values, enum_duplicates flag,
@ -1492,7 +1492,7 @@ void print_plan(JOIN* join,uint idx, double record_count, double read_time,
void mysql_print_status();
/* key.cc */
int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
uint *key_length);
uint *key_length, uint *keypart);
void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length);
void key_restore(byte *to_record, byte *from_key, KEY *key_info,
uint key_length);
@ -2021,7 +2021,6 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
table->const_table= 0;
table->null_row= 0;
table->status= STATUS_NO_RECORD;
table->keys_in_use_for_query= table->s->keys_in_use;
table->maybe_null= table_list->outer_join;
TABLE_LIST *embedding= table_list->embedding;
while (!table->maybe_null && embedding)
@ -2032,6 +2031,8 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
table->tablenr= tablenr;
table->map= (table_map) 1 << tablenr;
table->force_index= table_list->force_index;
table->covering_keys= table->s->keys_for_keyread;
table->merge_keys.clear_all();
}

View file

@ -5031,7 +5031,8 @@ enum options_mysqld
OPT_MERGE,
OPT_THREAD_HANDLING,
OPT_INNODB_ROLLBACK_ON_TIMEOUT,
OPT_SECURE_FILE_PRIV
OPT_SECURE_FILE_PRIV,
OPT_OLD_MODE
};
@ -6262,6 +6263,10 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.net_write_timeout,
(gptr*) &max_system_variables.net_write_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
{ "old_mode", OPT_OLD_MODE, "Use compatible behaviour.",
(gptr*) &global_system_variables.old_mode,
(gptr*) &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
{"open_files_limit", OPT_OPEN_FILES_LIMIT,
"If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.",
(gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG,

View file

@ -312,7 +312,8 @@ public:
min_value=arg->max_value;
min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN;
}
void store_min(uint length,char **min_key,uint min_key_flag)
/* returns a number of keypart values (0 or 1) appended to the key buffer */
int store_min(uint length,char **min_key,uint min_key_flag)
{
if ((min_flag & GEOM_FLAG) ||
(!(min_flag & NO_MIN_RANGE) &&
@ -326,12 +327,13 @@ public:
else
memcpy(*min_key,min_value,length);
(*min_key)+= length;
return 1;
}
return 0;
}
void store(uint length,char **min_key,uint min_key_flag,
char **max_key, uint max_key_flag)
/* returns a number of keypart values (0 or 1) appended to the key buffer */
int store_max(uint length,char **max_key, uint max_key_flag)
{
store_min(length, min_key, min_key_flag);
if (!(max_flag & NO_MAX_RANGE) &&
!(max_key_flag & (NO_MAX_RANGE | NEAR_MAX)))
{
@ -343,33 +345,41 @@ public:
else
memcpy(*max_key,max_value,length);
(*max_key)+= length;
return 1;
}
return 0;
}
void store_min_key(KEY_PART *key,char **range_key, uint *range_key_flag)
/* returns a number of keypart values appended to the key buffer */
int 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].store_length,
range_key,*range_key_flag,range_key,NO_MAX_RANGE);
uint res= key_tree->store_min(key[key_tree->part].store_length,
range_key, *range_key_flag);
*range_key_flag|= key_tree->min_flag;
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
key_tree->next_key_part->store_min_key(key,range_key, range_key_flag);
res+= key_tree->next_key_part->store_min_key(key, range_key,
range_key_flag);
return res;
}
void store_max_key(KEY_PART *key,char **range_key, uint *range_key_flag)
/* returns a number of keypart values appended to the key buffer */
int 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].store_length,
range_key, NO_MIN_RANGE, range_key,*range_key_flag);
uint res=key_tree->store_max(key[key_tree->part].store_length,
range_key, *range_key_flag);
(*range_key_flag)|= key_tree->max_flag;
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
key_tree->next_key_part->store_max_key(key,range_key, range_key_flag);
res+= key_tree->next_key_part->store_max_key(key, range_key,
range_key_flag);
return res;
}
SEL_ARG *insert(SEL_ARG *key);
@ -583,11 +593,11 @@ static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field,
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond);
static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree,
static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree,
bool update_tbl_stats);
static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
char *min_key,uint min_key_flag,
char *max_key, uint max_key_flag);
char *min_key, uint min_key_flag, int,
char *max_key, uint max_key_flag, int);
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
SEL_ARG *key_tree,
@ -1453,6 +1463,7 @@ QUICK_ROR_UNION_SELECT::~QUICK_ROR_UNION_SELECT()
QUICK_RANGE::QUICK_RANGE()
:min_key(0),max_key(0),min_length(0),max_length(0),
min_keypart_map(0), max_keypart_map(0),
flag(NO_MIN_RANGE | NO_MAX_RANGE)
{}
@ -2111,9 +2122,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.key_parts_end=key_parts;
/* Calculate cost of full index read for the shortest covering index */
if (!head->used_keys.is_clear_all())
if (!head->covering_keys.is_clear_all())
{
int key_for_use= find_shortest_key(head, &head->used_keys);
int key_for_use= find_shortest_key(head, &head->covering_keys);
double key_read_time= (get_index_only_read_time(&param, records,
key_for_use) +
(double) records / TIME_FOR_COMPARE);
@ -4031,9 +4042,9 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
The calculation is conducted as follows:
Lets denote #records(keypart1, ... keypartK) as n_k. We need to calculate
n_{k1} n_{k_2}
n_{k1} n_{k2}
--------- * --------- * .... (3)
n_{k1-1} n_{k2_1}
n_{k1-1} n_{k2-1}
where k1,k2,... are key parts which fields were not yet marked as fixed
( this is result of application of option b) of the recursion step for
@ -4041,9 +4052,9 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
Since it is reasonable to expect that most of the fields are not marked
as fixed, we calculate (3) as
n_{i1} n_{i_2}
n_{i1} n_{i2}
(3) = n_{max_key_part} / ( --------- * --------- * .... )
n_{i1-1} n_{i2_1}
n_{i1-1} n_{i2-1}
where i1,i2, .. are key parts that were already marked as fixed.
@ -4052,7 +4063,6 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
RETURN
Selectivity of given ROR scan.
*/
static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
@ -4063,6 +4073,7 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
byte key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */
char *key_ptr= (char*) key_val;
SEL_ARG *sel_arg, *tuple_arg= NULL;
key_part_map keypart_map= 0;
bool cur_covered;
bool prev_covered= test(bitmap_is_set(&info->covered_fields,
key_part->fieldnr-1));
@ -4073,7 +4084,7 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
max_range.key= (byte*) key_val;
max_range.flag= HA_READ_AFTER_KEY;
ha_rows prev_records= info->param->table->file->stats.records;
DBUG_ENTER("ror_intersect_selectivity");
DBUG_ENTER("ror_scan_selectivity");
for (sel_arg= scan->sel_arg; sel_arg;
sel_arg= sel_arg->next_key_part)
@ -4090,13 +4101,17 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
tuple_arg= scan->sel_arg;
/* Here we use the length of the first key part */
tuple_arg->store_min(key_part->store_length, &key_ptr, 0);
keypart_map= 1;
}
while (tuple_arg->next_key_part != sel_arg)
{
tuple_arg= tuple_arg->next_key_part;
tuple_arg->store_min(key_part[tuple_arg->part].store_length, &key_ptr, 0);
tuple_arg->store_min(key_part[tuple_arg->part].store_length,
&key_ptr, 0);
keypart_map= (keypart_map << 1) | 1;
}
min_range.length= max_range.length= ((char*) key_ptr - (char*) key_val);
min_range.keypart_map= max_range.keypart_map= keypart_map;
records= (info->param->table->file->
records_in_range(scan->keynr, &min_range, &max_range));
if (cur_covered)
@ -4646,7 +4661,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
param->needed_reg->set_bit(keynr);
bool read_index_only= index_read_must_be_used ? TRUE :
(bool) param->table->used_keys.is_set(keynr);
(bool) param->table->covering_keys.is_set(keynr);
found_records= check_quick_select(param, idx, *key, update_tbl_stats);
if (param->is_ror_scan)
@ -5305,12 +5320,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
*/
for (uint i= 1 ; i < cond_func->arg_count ; i++)
{
if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM)
{
field_item= (Item_field*) (cond_func->arguments()[i]->real_item());
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func,
field_item, (Item*) i, inv);
field_item, (Item*)(intptr)i, inv);
if (inv)
tree= !tree ? tmp : tree_or(param, tree, tmp);
else
@ -7057,7 +7071,9 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats)
}
param->n_ranges= 0;
records=check_quick_keys(param,idx,tree,param->min_key,0,param->max_key,0);
records= check_quick_keys(param, idx, tree,
param->min_key, 0, -1,
param->max_key, 0, -1);
if (records != HA_POS_ERROR)
{
if (update_tbl_stats)
@ -7120,12 +7136,13 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats)
*/
static ha_rows
check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
char *min_key,uint min_key_flag, char *max_key,
uint max_key_flag)
check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree,
char *min_key, uint min_key_flag, int min_keypart,
char *max_key, uint max_key_flag, int max_keypart)
{
ha_rows records=0, tmp;
uint tmp_min_flag, tmp_max_flag, keynr, min_key_length, max_key_length;
uint tmp_min_keypart= min_keypart, tmp_max_keypart= max_keypart;
char *tmp_min_key, *tmp_max_key;
uint8 save_first_null_comp= param->first_null_comp;
@ -7139,18 +7156,21 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
This is not a ROR scan if the key is not Clustered Primary Key.
*/
param->is_ror_scan= FALSE;
records=check_quick_keys(param,idx,key_tree->left,min_key,min_key_flag,
max_key,max_key_flag);
records=check_quick_keys(param, idx, key_tree->left,
min_key, min_key_flag, min_keypart,
max_key, max_key_flag, max_keypart);
if (records == HA_POS_ERROR) // Impossible
return records;
}
tmp_min_key= min_key;
tmp_max_key= max_key;
key_tree->store(param->key[idx][key_tree->part].store_length,
&tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
min_key_length= (uint) (tmp_min_key- param->min_key);
max_key_length= (uint) (tmp_max_key- param->max_key);
tmp_min_keypart+= key_tree->store_min(param->key[idx][key_tree->part].store_length,
&tmp_min_key, min_key_flag);
tmp_max_keypart+= key_tree->store_max(param->key[idx][key_tree->part].store_length,
&tmp_max_key, max_key_flag);
min_key_length= (uint) (tmp_min_key - param->min_key);
max_key_length= (uint) (tmp_max_key - param->max_key);
if (param->is_ror_scan)
{
@ -7173,12 +7193,13 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
{ // const key as prefix
if (min_key_length == max_key_length &&
!memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) &&
!memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) &&
!key_tree->min_flag && !key_tree->max_flag)
{
tmp=check_quick_keys(param,idx,key_tree->next_key_part,
tmp_min_key, min_key_flag | key_tree->min_flag,
tmp_max_key, max_key_flag | key_tree->max_flag);
tmp=check_quick_keys(param,idx,key_tree->next_key_part, tmp_min_key,
min_key_flag | key_tree->min_flag, tmp_min_keypart,
tmp_max_key, max_key_flag | key_tree->max_flag,
tmp_max_keypart);
goto end; // Ugly, but efficient
}
else
@ -7190,18 +7211,20 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
tmp_min_flag=key_tree->min_flag;
tmp_max_flag=key_tree->max_flag;
if (!tmp_min_flag)
tmp_min_keypart+=
key_tree->next_key_part->store_min_key(param->key[idx], &tmp_min_key,
&tmp_min_flag);
if (!tmp_max_flag)
tmp_max_keypart+=
key_tree->next_key_part->store_max_key(param->key[idx], &tmp_max_key,
&tmp_max_flag);
min_key_length= (uint) (tmp_min_key- param->min_key);
max_key_length= (uint) (tmp_max_key- param->max_key);
min_key_length= (uint) (tmp_min_key - param->min_key);
max_key_length= (uint) (tmp_max_key - param->max_key);
}
else
{
tmp_min_flag=min_key_flag | key_tree->min_flag;
tmp_max_flag=max_key_flag | key_tree->max_flag;
tmp_min_flag= min_key_flag | key_tree->min_flag;
tmp_max_flag= max_key_flag | key_tree->max_flag;
}
keynr=param->real_keynr[idx];
@ -7209,9 +7232,8 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
if (!tmp_min_flag && ! tmp_max_flag &&
(uint) key_tree->part+1 == param->table->key_info[keynr].key_parts &&
(param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
HA_NOSAME &&
min_key_length == max_key_length &&
!memcmp(param->min_key,param->max_key,min_key_length) &&
HA_NOSAME && min_key_length == max_key_length &&
!memcmp(param->min_key, param->max_key, min_key_length) &&
!param->first_null_comp)
{
tmp=1; // Max one record
@ -7231,7 +7253,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
first members of clustered primary key.
*/
if (!(min_key_length == max_key_length &&
!memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) &&
!memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) &&
!key_tree->min_flag && !key_tree->max_flag &&
is_key_scan_ror(param, keynr, key_tree->part + 1)))
param->is_ror_scan= FALSE;
@ -7243,11 +7265,12 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
key_range min_range;
min_range.key= (byte*) param->min_key;
min_range.length= min_key_length;
min_range.keypart_map= make_keypart_map(tmp_min_keypart);
/* In this case tmp_min_flag contains the handler-read-function */
min_range.flag= (ha_rkey_function) (tmp_min_flag ^ GEOM_FLAG);
tmp= param->table->file->records_in_range(keynr, &min_range,
(key_range*) 0);
tmp= param->table->file->records_in_range(keynr,
&min_range, (key_range*) 0);
}
else
{
@ -7257,10 +7280,12 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
min_range.length= min_key_length;
min_range.flag= (tmp_min_flag & NEAR_MIN ? HA_READ_AFTER_KEY :
HA_READ_KEY_EXACT);
min_range.keypart_map= make_keypart_map(tmp_min_keypart);
max_range.key= (byte*) param->max_key;
max_range.length= max_key_length;
max_range.flag= (tmp_max_flag & NEAR_MAX ?
HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY);
max_range.keypart_map= make_keypart_map(tmp_max_keypart);
tmp=param->table->file->records_in_range(keynr,
(min_key_length ? &min_range :
(key_range*) 0),
@ -7281,8 +7306,9 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
This is not a ROR scan if the key is not Clustered Primary Key.
*/
param->is_ror_scan= FALSE;
tmp=check_quick_keys(param,idx,key_tree->right,min_key,min_key_flag,
max_key,max_key_flag);
tmp=check_quick_keys(param, idx, key_tree->right,
min_key, min_key_flag, min_keypart,
max_key, max_key_flag, max_keypart);
if (tmp == HA_POS_ERROR)
return tmp;
records+=tmp;
@ -7429,6 +7455,8 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
{
QUICK_RANGE *range;
uint flag;
int min_part= key_tree->part-1, // # of keypart values in min_key buffer
max_part= key_tree->part-1; // # of keypart values in max_key buffer
if (key_tree->left != &null_element)
{
@ -7437,16 +7465,18 @@ get_quick_keys(PARAM *param,QUICK_RANGE_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].store_length,
&tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
min_part+= key_tree->store_min(key[key_tree->part].store_length,
&tmp_min_key,min_key_flag);
max_part+= key_tree->store_max(key[key_tree->part].store_length,
&tmp_max_key,max_key_flag);
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
{ // const key as prefix
if (!((tmp_min_key - min_key) != (tmp_max_key - max_key) ||
memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) ||
key_tree->min_flag || key_tree->max_flag))
if ((tmp_min_key - min_key) == (tmp_max_key - max_key) &&
memcmp(min_key, max_key, (uint)(tmp_max_key - max_key))==0 &&
key_tree->min_flag==0 && key_tree->max_flag==0)
{
if (get_quick_keys(param,quick,key,key_tree->next_key_part,
tmp_min_key, min_key_flag | key_tree->min_flag,
@ -7457,10 +7487,10 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
{
uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag;
if (!tmp_min_flag)
key_tree->next_key_part->store_min_key(key, &tmp_min_key,
min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key,
&tmp_min_flag);
if (!tmp_max_flag)
key_tree->next_key_part->store_max_key(key, &tmp_max_key,
max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key,
&tmp_max_flag);
flag=tmp_min_flag | tmp_max_flag;
}
@ -7511,13 +7541,15 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
/* Get range for retrieving rows in QUICK_SELECT::get_next */
if (!(range= new QUICK_RANGE((const char *) param->min_key,
(uint) (tmp_min_key - param->min_key),
min_part >=0 ? make_keypart_map(min_part) : 0,
(const char *) param->max_key,
(uint) (tmp_max_key - param->max_key),
max_part >=0 ? make_keypart_map(max_part) : 0,
flag)))
return 1; // out of memory
set_if_bigger(quick->max_used_key_length,range->min_length);
set_if_bigger(quick->max_used_key_length,range->max_length);
set_if_bigger(quick->max_used_key_length, range->min_length);
set_if_bigger(quick->max_used_key_length, range->max_length);
set_if_bigger(quick->used_key_parts, (uint) key_tree->part+1);
if (insert_dynamic(&quick->ranges, (gptr)&range))
return 1;
@ -7615,13 +7647,13 @@ bool QUICK_ROR_UNION_SELECT::is_keys_used(const MY_BITMAP *fields)
thd Thread handle
table Table to access
ref ref[_or_null] scan parameters
records Estimate of number of records (needed only to construct
records Estimate of number of records (needed only to construct
quick select)
NOTES
This allocates things in a new memory root, as this may be called many
times during a query.
RETURN
RETURN
Quick select that retrieves the same rows as passed ref scan
NULL on error.
*/
@ -7657,8 +7689,10 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
!(range= new(alloc) QUICK_RANGE()))
goto err; // out of memory
range->min_key=range->max_key=(char*) ref->key_buff;
range->min_length=range->max_length=ref->key_length;
range->min_key= range->max_key= (char*) ref->key_buff;
range->min_length= range->max_length= ref->key_length;
range->min_keypart_map= range->max_keypart_map=
make_prev_keypart_map(ref->key_parts);
range->flag= ((ref->key_length == key_info->key_length &&
(key_info->flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
HA_NOSAME) ? EQ_RANGE : 0);
@ -7671,7 +7705,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
{
key_part->part=part;
key_part->field= key_info->key_part[part].field;
key_part->length= key_info->key_part[part].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;
key_part->flag= (uint8) key_info->key_part[part].key_part_flag;
@ -7690,11 +7724,11 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
QUICK_RANGE *null_range;
*ref->null_ref_key= 1; // Set null byte then create a range
if (!(null_range= new (alloc) QUICK_RANGE((char*)ref->key_buff,
ref->key_length,
(char*)ref->key_buff,
ref->key_length,
EQ_RANGE)))
if (!(null_range= new (alloc)
QUICK_RANGE((char*)ref->key_buff, ref->key_length,
make_prev_keypart_map(ref->key_parts),
(char*)ref->key_buff, ref->key_length,
make_prev_keypart_map(ref->key_parts), EQ_RANGE)))
goto err;
*ref->null_ref_key= 0; // Clear null byte
if (insert_dynamic(&quick->ranges,(gptr)&null_range))
@ -8146,6 +8180,7 @@ int QUICK_RANGE_SELECT::get_next()
start_key->flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
(last_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
start_key->keypart_map= last_range->min_keypart_map;
end_key->key= (const byte*) last_range->max_key;
end_key->length= last_range->max_length;
/*
@ -8154,6 +8189,7 @@ int QUICK_RANGE_SELECT::get_next()
*/
end_key->flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
end_key->keypart_map= last_range->max_keypart_map;
mrange_slot->range_flag= last_range->flag;
}
@ -8203,7 +8239,9 @@ end:
other if some error occurred
*/
int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length,
key_part_map keypart_map,
byte *cur_prefix)
{
DBUG_ENTER("QUICK_RANGE_SELECT::get_next_prefix");
@ -8215,8 +8253,7 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
{
/* Read the next record in the same range with prefix after cur_prefix. */
DBUG_ASSERT(cur_prefix != 0);
result= file->index_read(record, cur_prefix, prefix_length,
HA_READ_AFTER_KEY);
result= file->index_read(record, cur_prefix, keypart_map, HA_READ_AFTER_KEY);
if (result || (file->compare_key(file->end_range) <= 0))
DBUG_RETURN(result);
}
@ -8232,11 +8269,13 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
start_key.key= (const byte*) last_range->min_key;
start_key.length= min(last_range->min_length, prefix_length);
start_key.keypart_map= last_range->min_keypart_map & keypart_map;
start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
(last_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
end_key.key= (const byte*) last_range->max_key;
end_key.length= min(last_range->max_length, prefix_length);
end_key.keypart_map= last_range->max_keypart_map & keypart_map;
/*
We use READ_AFTER_KEY here because if we are reading on a key
prefix we want to find all keys with this prefix
@ -8244,8 +8283,8 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
result= file->read_range_first(last_range->min_length ? &start_key : 0,
last_range->max_length ? &end_key : 0,
result= file->read_range_first(last_range->min_keypart_map ? &start_key : 0,
last_range->max_keypart_map ? &end_key : 0,
test(last_range->flag & EQ_RANGE),
sorted);
if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
@ -8285,9 +8324,8 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
}
last_range= *(cur_range++);
result= file->index_read(record,
(byte*) last_range->min_key,
last_range->min_length,
result= file->index_read(record, (byte*) last_range->min_key,
last_range->min_keypart_map,
(ha_rkey_function)(last_range->flag ^ GEOM_FLAG));
if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
@ -8419,15 +8457,15 @@ int QUICK_SELECT_DESC::get_next()
if (last_range->flag & EQ_RANGE)
{
result= file->index_read(record, (byte*) last_range->max_key,
last_range->max_length, HA_READ_KEY_EXACT);
result = file->index_read(record, (byte*) last_range->max_key,
last_range->max_keypart_map, HA_READ_KEY_EXACT);
}
else
{
DBUG_ASSERT(last_range->flag & NEAR_MAX ||
range_reads_after_key(last_range));
result=file->index_read(record, (byte*) last_range->max_key,
last_range->max_length,
last_range->max_keypart_map,
((last_range->flag & NEAR_MAX) ?
HA_READ_BEFORE_KEY :
HA_READ_PREFIX_LAST_OR_PREV));
@ -8747,8 +8785,7 @@ void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names,
static inline uint get_field_keypart(KEY *index, Field *field);
static inline SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree,
PARAM *param, uint *param_idx);
static bool
get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
static bool get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
KEY_PART_INFO *first_non_group_part,
KEY_PART_INFO *min_max_arg_part,
KEY_PART_INFO *last_part, THD *thd,
@ -9012,7 +9049,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
cur_index_info++, cur_index++)
{
/* Check (B1) - if current index is covering. */
if (!table->used_keys.is_set(cur_index))
if (!table->covering_keys.is_set(cur_index))
goto next_index;
/*
@ -9146,7 +9183,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
NULL;
first_non_infix_part= min_max_arg_part ?
(min_max_arg_part < last_part) ?
min_max_arg_part + 1 :
min_max_arg_part :
NULL :
NULL;
if (first_non_group_part &&
@ -9203,7 +9240,9 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
*/
if (first_non_infix_part)
{
for (cur_part= first_non_infix_part; cur_part != last_part; cur_part++)
cur_part= first_non_infix_part +
(min_max_arg_part && (min_max_arg_part < last_part));
for (; cur_part != last_part; cur_part++)
{
if (bitmap_is_set(table->read_set, cur_part->field->field_index))
goto next_index;
@ -9749,7 +9788,7 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
RETURN
New QUICK_GROUP_MIN_MAX_SELECT object if successfully created,
NULL o/w.
NULL otherwise.
*/
QUICK_SELECT_I *
@ -9762,10 +9801,10 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table,
param->thd->lex->current_select->join,
have_min, have_max, min_max_arg_part,
group_prefix_len, used_key_parts,
index_info, index, read_cost, records,
key_infix_len, key_infix,
parent_alloc);
group_prefix_len, group_key_parts,
used_key_parts, index_info, index,
read_cost, records, key_infix_len,
key_infix, parent_alloc);
if (!quick)
DBUG_RETURN(NULL);
@ -9854,7 +9893,7 @@ QUICK_GROUP_MIN_MAX_SELECT::
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
bool have_max_arg,
KEY_PART_INFO *min_max_arg_part_arg,
uint group_prefix_len_arg,
uint group_prefix_len_arg, uint group_key_parts_arg,
uint used_key_parts_arg, KEY *index_info_arg,
uint use_index, double read_cost_arg,
ha_rows records_arg, uint key_infix_len_arg,
@ -9864,7 +9903,7 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
have_max(have_max_arg), seen_first_key(FALSE),
min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg),
key_infix_len(key_infix_len_arg), min_functions_it(NULL),
max_functions_it(NULL)
max_functions_it(NULL), group_key_parts(group_key_parts_arg)
{
head= table;
file= head->file;
@ -9874,6 +9913,7 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
read_time= read_cost_arg;
records= records_arg;
used_key_parts= used_key_parts_arg;
real_key_parts= used_key_parts_arg;
real_prefix_len= group_prefix_len + key_infix_len;
group_prefix= NULL;
min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0;
@ -10040,7 +10080,9 @@ bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range)
range_flag|= EQ_RANGE; /* equality condition */
}
range= new QUICK_RANGE(sel_range->min_value, min_max_arg_len,
make_keypart_map(sel_range->part),
sel_range->max_value, min_max_arg_len,
make_keypart_map(sel_range->part),
range_flag);
if (!range)
return TRUE;
@ -10279,7 +10321,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
first sub-group with the extended prefix.
*/
if (!have_min && !have_max && key_infix_len > 0)
result= file->index_read(record, group_prefix, real_prefix_len,
result= file->index_read(record, group_prefix,
make_prev_keypart_map(real_key_parts),
HA_READ_KEY_EXACT);
result= have_min ? min_res : have_max ? max_res : result;
@ -10342,7 +10385,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min()
/* Apply the constant equality conditions to the non-group select fields */
if (key_infix_len > 0)
{
if ((result= file->index_read(record, group_prefix, real_prefix_len,
if ((result= file->index_read(record, group_prefix,
make_prev_keypart_map(real_key_parts),
HA_READ_KEY_EXACT)))
DBUG_RETURN(result);
}
@ -10359,7 +10403,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min()
/* Find the first subsequent record without NULL in the MIN/MAX field. */
key_copy(tmp_record, record, index_info, 0);
result= file->index_read(record, tmp_record,
real_prefix_len + min_max_arg_len,
make_keypart_map(real_key_parts),
HA_READ_AFTER_KEY);
/*
Check if the new record belongs to the current group by comparing its
@ -10415,7 +10459,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max()
if (min_max_ranges.elements > 0)
result= next_max_in_range();
else
result= file->index_read(record, group_prefix, real_prefix_len,
result= file->index_read(record, group_prefix,
make_prev_keypart_map(real_key_parts),
HA_READ_PREFIX_LAST);
DBUG_RETURN(result);
}
@ -10451,7 +10496,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
{
byte *cur_prefix= seen_first_key ? group_prefix : NULL;
if ((result= quick_prefix_select->get_next_prefix(group_prefix_len,
cur_prefix)))
make_prev_keypart_map(group_key_parts), cur_prefix)))
DBUG_RETURN(result);
seen_first_key= TRUE;
}
@ -10467,7 +10512,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
else
{
/* Load the first key in this group into record. */
result= file->index_read(record, group_prefix, group_prefix_len,
result= file->index_read(record, group_prefix,
make_prev_keypart_map(group_key_parts),
HA_READ_AFTER_KEY);
if (result)
DBUG_RETURN(result);
@ -10509,7 +10555,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
{
ha_rkey_function find_flag;
uint search_prefix_len;
key_part_map keypart_map;
QUICK_RANGE *cur_range;
bool found_null= FALSE;
int result= HA_ERR_KEY_NOT_FOUND;
@ -10531,22 +10577,21 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
if (cur_range->flag & NO_MIN_RANGE)
{
keypart_map= make_prev_keypart_map(real_key_parts);
find_flag= HA_READ_KEY_EXACT;
search_prefix_len= real_prefix_len;
}
else
{
/* Extend the search key with the lower boundary for this range. */
memcpy(group_prefix + real_prefix_len, cur_range->min_key,
cur_range->min_length);
search_prefix_len= real_prefix_len + min_max_arg_len;
keypart_map= make_keypart_map(real_key_parts);
find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ?
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ?
HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT;
}
result= file->index_read(record, group_prefix, search_prefix_len,
find_flag);
result= file->index_read(record, group_prefix, keypart_map, find_flag);
if (result)
{
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) &&
@ -10643,7 +10688,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
{
ha_rkey_function find_flag;
uint search_prefix_len;
key_part_map keypart_map;
QUICK_RANGE *cur_range;
int result;
@ -10665,22 +10710,21 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
if (cur_range->flag & NO_MAX_RANGE)
{
keypart_map= make_prev_keypart_map(real_key_parts);
find_flag= HA_READ_PREFIX_LAST;
search_prefix_len= real_prefix_len;
}
else
{
/* Extend the search key with the upper boundary for this range. */
memcpy(group_prefix + real_prefix_len, cur_range->max_key,
cur_range->max_length);
search_prefix_len= real_prefix_len + min_max_arg_len;
keypart_map= make_keypart_map(real_key_parts);
find_flag= (cur_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ?
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV;
}
result= file->index_read(record, group_prefix, search_prefix_len,
find_flag);
result= file->index_read(record, group_prefix, keypart_map, find_flag);
if (result)
{

View file

@ -37,17 +37,23 @@ class QUICK_RANGE :public Sql_alloc {
public:
char *min_key,*max_key;
uint16 min_length,max_length,flag;
key_part_map min_keypart_map, // bitmap of used keyparts in min_key
max_keypart_map; // bitmap of used keyparts in max_key
#ifdef HAVE_purify
uint16 dummy; /* Avoid warnings on 'flag' */
#endif
QUICK_RANGE(); /* Full range */
QUICK_RANGE(const char *min_key_arg,uint min_length_arg,
const char *max_key_arg,uint max_length_arg,
QUICK_RANGE(const char *min_key_arg, uint min_length_arg,
key_part_map min_keypart_map_arg,
const char *max_key_arg, uint max_length_arg,
key_part_map max_keypart_map_arg,
uint flag_arg)
: min_key((char*) sql_memdup(min_key_arg,min_length_arg+1)),
max_key((char*) sql_memdup(max_key_arg,max_length_arg+1)),
min_length((uint16) min_length_arg),
max_length((uint16) max_length_arg),
min_keypart_map(min_keypart_map_arg),
max_keypart_map(max_keypart_map_arg),
flag((uint16) flag_arg)
{
#ifdef HAVE_purify
@ -60,11 +66,11 @@ class QUICK_RANGE :public Sql_alloc {
/*
Quick select interface.
This class is a parent for all QUICK_*_SELECT and FT_SELECT classes.
The usage scenario is as follows:
1. Create quick select
quick= new QUICK_XXX_SELECT(...);
2. Perform lightweight initialization. This can be done in 2 ways:
2.a: Regular initialization
if (quick->init())
@ -75,29 +81,29 @@ class QUICK_RANGE :public Sql_alloc {
2.b: Special initialization for quick selects merged by QUICK_ROR_*_SELECT
if (quick->init_ror_merged_scan())
delete quick;
3. Perform zero, one, or more scans.
while (...)
{
// initialize quick select for scan. This may allocate
// buffers and/or prefetch rows.
// buffers and/or prefetch rows.
if (quick->reset())
{
//the only valid action after failed reset() call is delete
delete quick;
//abort query
}
// perform the scan
do
{
res= quick->get_next();
} while (res && ...)
}
4. Delete the select:
delete quick;
*/
class QUICK_SELECT_I
@ -123,6 +129,8 @@ public:
Max. number of (first) key parts this quick select uses for retrieval.
eg. for "(key1p1=c1 AND key1p2=c2) OR key1p1=c2" used_key_parts == 2.
Applicable if index!= MAX_KEY.
For QUICK_GROUP_MIN_MAX_SELECT it includes MIN/MAX argument keyparts.
*/
uint used_key_parts;
@ -318,7 +326,8 @@ public:
int reset(void);
int get_next();
void range_end();
int get_next_prefix(uint prefix_length, byte *cur_prefix);
int get_next_prefix(uint prefix_length, key_part_map keypart_map,
byte *cur_prefix);
bool reverse_sorted() { return 0; }
bool unique_key_range();
int init_ror_merged_scan(bool reuse_handler);
@ -605,6 +614,7 @@ private:
byte *tmp_record; /* Temporary storage for next_min(), next_max(). */
byte *group_prefix; /* Key prefix consisting of the GROUP fields. */
uint group_prefix_len; /* Length of the group prefix. */
uint group_key_parts; /* A number of keyparts in the group prefix */
byte *last_prefix; /* Prefix of the last group for detecting EOF. */
bool have_min; /* Specify whether we are computing */
bool have_max; /* a MIN, a MAX, or both. */
@ -616,6 +626,7 @@ private:
uint key_infix_len;
DYNAMIC_ARRAY min_max_ranges; /* Array of range ptrs for the MIN/MAX field. */
uint real_prefix_len; /* Length of key prefix extended with key_infix. */
uint real_key_parts; /* A number of keyparts in the above value. */
List<Item_sum> *min_functions;
List<Item_sum> *max_functions;
List_iterator<Item_sum> *min_functions_it;
@ -638,10 +649,11 @@ private:
public:
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
bool have_max, KEY_PART_INFO *min_max_arg_part,
uint group_prefix_len, uint used_key_parts,
KEY *index_info, uint use_index, double read_cost,
ha_rows records, uint key_infix_len,
byte *key_infix, MEM_ROOT *parent_alloc);
uint group_prefix_len, uint group_key_parts,
uint used_key_parts, KEY *index_info, uint
use_index, double read_cost, ha_rows records, uint
key_infix_len, byte *key_infix, MEM_ROOT
*parent_alloc);
~QUICK_GROUP_MIN_MAX_SELECT();
bool add_range(SEL_ARG *sel_range);
void update_key_stat();

View file

@ -251,7 +251,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
error= table->file->index_first(table->record[0]);
else
error= table->file->index_read(table->record[0],key_buff,
ref.key_length,
make_prev_keypart_map(ref.key_parts),
range_fl & NEAR_MIN ?
HA_READ_AFTER_KEY :
HA_READ_KEY_OR_NEXT);
@ -338,11 +338,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
error= table->file->index_last(table->record[0]);
else
error= table->file->index_read(table->record[0], key_buff,
ref.key_length,
make_prev_keypart_map(ref.key_parts),
range_fl & NEAR_MAX ?
HA_READ_BEFORE_KEY :
HA_READ_PREFIX_LAST_OR_PREV);
if (!error && reckey_in_range(1, &ref, item_field->field,
if (!error && reckey_in_range(1, &ref, item_field->field,
conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND;
if (table->key_read)
@ -605,15 +605,13 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
/* Check if field is part of the tested partial key */
byte *key_ptr= ref->key_buff;
KEY_PART_INFO *part;
for (part= keyinfo->key_part;
;
key_ptr+= part++->store_length)
for (part= keyinfo->key_part; ; key_ptr+= part++->store_length)
{
if (part > field_part)
return 0; // Field is beyond the tested parts
if (part->field->eq(((Item_field*) args[0])->field))
break; // Found a part od the key for the field
break; // Found a part of the key for the field
}
bool is_field_part= part == field_part;
@ -625,8 +623,11 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
{
uint length= (key_ptr-ref->key_buff)+part->store_length;
if (ref->key_length < length)
{
/* Ultimately ref->key_length will contain the length of the search key */
ref->key_length= length;
ref->key_parts= (part - keyinfo->key_part) + 1;
}
if (!*prefix_len && part+1 == field_part)
*prefix_len= length;
if (is_field_part && eq_type)
@ -773,6 +774,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
{
ref->key= idx;
ref->key_length= 0;
ref->key_parts= 0;
key_part_map key_part_used= 0;
*range_fl= NO_MIN_RANGE | NO_MAX_RANGE;
if (matching_cond(max_fl, ref, keyinfo, part, cond,
@ -788,6 +790,8 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
*/
ref->key_buff[ref->key_length]= 1;
ref->key_length+= part->store_length;
ref->key_parts++;
DBUG_ASSERT(ref->key_parts == jdx+1);
*range_fl&= ~NO_MIN_RANGE;
*range_fl|= NEAR_MIN; // > NULL
}

View file

@ -31,6 +31,8 @@
#include "rpl_tblmap.h"
int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
static Log_event* next_event(RELAY_LOG_INFO* rli);
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")

View file

@ -218,8 +218,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
key_copy(key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0,
key, table->key_info->key_length,
if (table->file->index_read_idx(table->record[0], 0, key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
DBUG_RETURN(SP_KEY_NOT_FOUND);
@ -925,7 +924,7 @@ sp_drop_db_routines(THD *thd, char *db)
table->file->ha_index_init(0, 1);
if (! table->file->index_read(table->record[0],
(byte *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
key_len, HA_READ_KEY_EXACT))
(key_part_map)1, HA_READ_KEY_EXACT))
{
int nxtres;
bool deleted= FALSE;

View file

@ -1813,8 +1813,7 @@ static bool update_user_table(THD *thd, TABLE *table,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0,
(byte *) user_key,
table->key_info->key_length,
(byte *) user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
@ -1905,8 +1904,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0,
user_key, table->key_info->key_length,
if (table->file->index_read_idx(table->record[0], 0, user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
/* what == 'N' means revoke */
@ -2123,8 +2121,7 @@ static int replace_db_table(TABLE *table, const char *db,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0],0,
user_key, table->key_info->key_length,
if (table->file->index_read_idx(table->record[0],0, user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
if (what == 'N')
@ -2341,9 +2338,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
col_privs->field[4]->store("",0, &my_charset_latin1);
col_privs->file->ha_index_init(0, 1);
if (col_privs->file->index_read(col_privs->record[0],
(byte*) key,
key_prefix_len, HA_READ_KEY_EXACT))
if (col_privs->file->index_read(col_privs->record[0], (byte*) key,
(key_part_map)15, HA_READ_KEY_EXACT))
{
cols = 0; /* purecov: deadcode */
col_privs->file->ha_index_end();
@ -2479,7 +2475,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
table->field[3]->store(table_name,(uint) strlen(table_name),
system_charset_info);
/* Get length of 3 first key parts */
/* Get length of 4 first key parts */
key_prefix_length= (key_part[0].store_length + key_part[1].store_length +
key_part[2].store_length + key_part[3].store_length);
key_copy(key, table->record[0], table->key_info, key_prefix_length);
@ -2505,8 +2501,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read(table->record[0], user_key,
table->key_info->key_length,
if (table->file->index_read(table->record[0], user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
if (revoke_grant)
@ -2582,8 +2577,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
key_prefix_length);
if (table->file->index_read(table->record[0], user_key,
key_prefix_length,
if (table->file->index_read(table->record[0], user_key, (key_part_map)15,
HA_READ_KEY_EXACT))
goto end;
@ -2684,8 +2678,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0,
user_key, table->key_info->key_length,
if (table->file->index_read_idx(table->record[0], 0, user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
/*
@ -2803,13 +2796,13 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->field[3]->store(routine_name,(uint) strlen(routine_name),
&my_charset_latin1);
table->field[4]->store((longlong)(is_proc ?
table->field[4]->store((longlong)(is_proc ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION),
TRUE);
store_record(table,record[1]); // store at pos 1
if (table->file->index_read_idx(table->record[0],0,
(byte*) table->field[0]->ptr,0,
if (table->file->index_read_idx(table->record[0], 0,
(byte*) table->field[0]->ptr, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
/*
@ -5008,7 +5001,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
key_copy(user_key, table->record[0], table->key_info, key_prefix_length);
if ((error= table->file->index_read_idx(table->record[0], 0,
user_key, key_prefix_length,
user_key, (key_part_map)3,
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
@ -6086,6 +6079,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_user_privileges");
if (!initialized)
DBUG_RETURN(0);
pthread_mutex_lock(&acl_cache->lock);
for (counter=0 ; counter < acl_users.elements ; counter++)
@ -6145,6 +6140,8 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_schema_privileges");
if (!initialized)
DBUG_RETURN(0);
pthread_mutex_lock(&acl_cache->lock);
for (counter=0 ; counter < acl_dbs.elements ; counter++)

View file

@ -1851,8 +1851,6 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
table->const_table=0;
table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= share->keys_in_use;
table->used_keys= share->keys_for_keyread;
DBUG_RETURN(FALSE);
}
@ -2271,9 +2269,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->const_table=0;
table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= table->s->keys_in_use;
table->insert_values= 0;
table->used_keys= table->s->keys_for_keyread;
table->fulltext_searched= 0;
table->file->ft_handler= 0;
if (table->timestamp_field)
@ -2358,8 +2354,6 @@ static bool reopen_table(TABLE *table)
tmp.null_row= table->null_row;
tmp.maybe_null= table->maybe_null;
tmp.status= table->status;
tmp.keys_in_use_for_query= tmp.s->keys_in_use;
tmp.used_keys= tmp.s->keys_for_keyread;
tmp.s->table_map_id= table->s->table_map_id;
@ -3820,7 +3814,7 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
been set for all fields (for example for view).
*/
table->used_keys.intersect(field->part_of_key);
table->covering_keys.intersect(field->part_of_key);
table->merge_keys.merge(field->part_of_key);
if (thd->mark_used_columns == MARK_COLUMNS_READ)
@ -5060,7 +5054,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
TABLE *table_1= nj_col_1->table_ref->table;
/* Mark field_1 used for table cache. */
bitmap_set_bit(table_1->read_set, field_1->field_index);
table_1->used_keys.intersect(field_1->part_of_key);
table_1->covering_keys.intersect(field_1->part_of_key);
table_1->merge_keys.merge(field_1->part_of_key);
}
if (field_2)
@ -5068,7 +5062,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
TABLE *table_2= nj_col_2->table_ref->table;
/* Mark field_2 used for table cache. */
bitmap_set_bit(table_2->read_set, field_2->field_index);
table_2->used_keys.intersect(field_2->part_of_key);
table_2->covering_keys.intersect(field_2->part_of_key);
table_2->merge_keys.merge(field_2->part_of_key);
}
@ -5704,30 +5698,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
tablenr= 0;
}
setup_table_map(table, table_list, tablenr);
table->used_keys= table->s->keys_for_keyread;
table->merge_keys.clear_all();
if (table_list->use_index)
{
key_map map;
get_key_map_from_key_list(&map, table, table_list->use_index);
if (map.is_set_all())
DBUG_RETURN(1);
/*
Don't introduce keys in keys_in_use_for_query that weren't there
before. FORCE/USE INDEX should not add keys, it should only remove
all keys except the key(s) specified in the hint.
*/
table->keys_in_use_for_query.intersect(map);
}
if (table_list->ignore_index)
{
key_map map;
get_key_map_from_key_list(&map, table, table_list->ignore_index);
if (map.is_set_all())
DBUG_RETURN(1);
table->keys_in_use_for_query.subtract(map);
}
table->used_keys.intersect(table->keys_in_use_for_query);
if (table_list->process_index_hints(table))
DBUG_RETURN(1);
}
if (tablenr > MAX_TABLES)
{
@ -6009,7 +5981,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
bitmap_set_bit(field->table->read_set, field->field_index);
if (table)
{
table->used_keys.intersect(field->part_of_key);
table->covering_keys.intersect(field->part_of_key);
table->merge_keys.merge(field->part_of_key);
}
if (tables->is_natural_join)
@ -6027,7 +5999,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (field_table)
{
thd->used_tables|= field_table->map;
field_table->used_keys.intersect(field->part_of_key);
field_table->covering_keys.intersect(field->part_of_key);
field_table->merge_keys.merge(field->part_of_key);
field_table->used_fields++;
}

View file

@ -243,6 +243,11 @@ struct system_variables
my_bool low_priority_updates;
my_bool new_mode;
/*
compatibility option:
- index usage hints (USE INDEX without a FOR clause) behave as in 5.0
*/
my_bool old_mode;
my_bool query_cache_wlock_invalidate;
my_bool engine_condition_pushdown;
my_bool innodb_table_locks;
@ -278,6 +283,7 @@ struct system_variables
DATE_TIME_FORMAT *datetime_format;
DATE_TIME_FORMAT *time_format;
my_bool sysdate_is_now;
};

View file

@ -116,7 +116,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
/* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
table->used_keys.clear_all();
table->covering_keys.clear_all();
table->quick_keys.clear_all(); // Can't use 'only index'
select=make_select(table, 0, 0, conds, 0, &error);
if (error)
@ -553,7 +553,7 @@ multi_delete::initialize_tables(JOIN *join)
tbl->no_keyread=1;
/* Don't use record cache */
tbl->no_cache= 1;
tbl->used_keys.clear_all();
tbl->covering_keys.clear_all();
if (tbl->file->has_transactions())
transactional_tables= 1;
else

View file

@ -515,7 +515,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
List_iterator<Item> it_ke(*key_expr);
Item *item;
for (key_len=0 ; (item=it_ke++) ; key_part++)
key_part_map keypart_map;
for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++)
{
my_bitmap_map *old_map;
// 'item' can be changed by fix_fields() call
@ -532,6 +533,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
(void) item->save_in_field(key_part->field, 1);
dbug_tmp_restore_column_map(table->write_set, old_map);
key_len+=key_part->store_length;
keypart_map= (keypart_map << 1) | 1;
}
if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
@ -540,7 +542,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
table->file->ha_index_init(keyno, 1);
key_copy(key, table->record[0], table->key_info + keyno, key_len);
error= table->file->index_read(table->record[0],
key,key_len,ha_rkey_mode);
key, keypart_map, ha_rkey_mode);
mode=rkey_to_rnext[(int)ha_rkey_mode];
break;
}

View file

@ -295,8 +295,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
rkey_id->store((longlong) key_id, TRUE);
rkey_id->get_key_image(buff, rkey_id->pack_length(), Field::itRAW);
int key_res= relations->file->index_read(relations->record[0],
(byte *) buff,
rkey_id->pack_length(),
(byte *) buff, (key_part_map)1,
HA_READ_KEY_EXACT);
for ( ;
@ -310,7 +309,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
field->get_key_image(topic_id_buff, field->pack_length(), Field::itRAW);
if (!topics->file->index_read(topics->record[0], (byte *)topic_id_buff,
field->pack_length(), HA_READ_KEY_EXACT))
(key_part_map)1, HA_READ_KEY_EXACT))
{
memorize_variant_topic(thd,topics,count,find_fields,
names,name,description,example);
@ -567,7 +566,7 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond,
cond->fix_fields(thd, &cond); // can never fail
/* Assume that no indexes cover all required fields */
table->used_keys.clear_all();
table->covering_keys.clear_all();
SQL_SELECT *res= make_select(table, 0, 0, cond, 0, error);
if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)) ||

View file

@ -468,10 +468,15 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->proc_info="init";
thd->used_tables=0;
values= its++;
value_count= values->elements;
if (mysql_prepare_insert(thd, table_list, table, fields, values,
update_fields, update_values, duplic, &unused_conds,
FALSE))
FALSE,
(fields.elements || !value_count),
!ignore && (thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES))))
goto abort;
/* mysql_prepare_insert set table_list->table if it was not set */
@ -497,7 +502,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
value_count= values->elements;
while ((values= its++))
{
counter++;
@ -567,17 +571,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
table->file->ha_start_bulk_insert(values_list.elements);
thd->no_trans_update= 0;
thd->abort_on_warning= (!ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
if ((fields.elements || !value_count) &&
check_that_all_fields_are_given_values(thd, table, table_list))
{
/* thd->net.report_error is now set, which will abort the next loop */
error= 1;
}
thd->abort_on_warning= (!ignore && (thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
table->mark_columns_needed_for_insert();
@ -954,6 +950,10 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
be taken from table_list->table)
where Where clause (for insert ... select)
select_insert TRUE if INSERT ... SELECT statement
check_fields TRUE if need to check that all INSERT fields are
given values.
abort_on_warning whether to report if some INSERT field is not
assigned as an error (TRUE) or as a warning (FALSE).
TODO (in far future)
In cases of:
@ -974,7 +974,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
TABLE *table, List<Item> &fields, List_item *values,
List<Item> &update_fields, List<Item> &update_values,
enum_duplicates duplic,
COND **where, bool select_insert)
COND **where, bool select_insert,
bool check_fields, bool abort_on_warning)
{
SELECT_LEX *select_lex= &thd->lex->select_lex;
Name_resolution_context *context= &select_lex->context;
@ -1036,10 +1037,22 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
if (!(res= check_insert_fields(thd, context->table_list, fields, *values,
!insert_into_view, &map) ||
setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
&& duplic == DUP_UPDATE)
res= check_insert_fields(thd, context->table_list, fields, *values,
!insert_into_view, &map) ||
setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0);
if (!res && check_fields)
{
bool saved_abort_on_warning= thd->abort_on_warning;
thd->abort_on_warning= abort_on_warning;
res= check_that_all_fields_are_given_values(thd,
table ? table :
context->table_list->table,
context->table_list);
thd->abort_on_warning= saved_abort_on_warning;
}
if (!res && duplic == DUP_UPDATE)
{
select_lex->no_wrap_view_item= TRUE;
res= check_update_fields(thd, context->table_list, update_fields, &map);
@ -1201,9 +1214,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
}
key_copy((byte*) key,table->record[0],table->key_info+key_nr,0);
if ((error=(table->file->index_read_idx(table->record[1],key_nr,
(byte*) key,
table->key_info[key_nr].
key_length,
(byte*) key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))))
goto err;
}
@ -1249,21 +1260,22 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
compare_record(table))
{
info->updated++;
/*
If ON DUP KEY UPDATE updates a row instead of inserting one, it's
like a regular UPDATE statement: it should not affect the value of a
next SELECT LAST_INSERT_ID() or mysql_insert_id().
Except if LAST_INSERT_ID(#) was in the INSERT query, which is
handled separately by THD::arg_of_last_insert_id_function.
*/
insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0;
if (table->next_number_field)
table->file->adjust_next_insert_id_after_explicit_value(table->next_number_field->val_int());
trg_error= (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE));
info->copied++;
}
/*
If ON DUP KEY UPDATE updates a row instead of inserting one, it's
like a regular UPDATE statement: it should not affect the value of a
next SELECT LAST_INSERT_ID() or mysql_insert_id().
Except if LAST_INSERT_ID(#) was in the INSERT query, which is
handled separately by THD::arg_of_last_insert_id_function.
*/
insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0;
if (table->next_number_field)
table->file->adjust_next_insert_id_after_explicit_value(
table->next_number_field->val_int());
trg_error= (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE));
goto ok_or_after_trg_err;
}
else /* DUP_REPLACE */
@ -2443,7 +2455,7 @@ bool mysql_insert_select_prepare(THD *thd)
lex->query_tables->table, lex->field_list, 0,
lex->update_list, lex->value_list,
lex->duplicates,
&select_lex->where, TRUE))
&select_lex->where, TRUE, FALSE, FALSE))
DBUG_RETURN(TRUE);
/*
@ -2506,7 +2518,18 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
!insert_into_view, &map) ||
setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0);
if (info.handle_duplicates == DUP_UPDATE)
if (!res && fields->elements)
{
bool saved_abort_on_warning= thd->abort_on_warning;
thd->abort_on_warning= !info.ignore && (thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES));
res= check_that_all_fields_are_given_values(thd, table_list->table,
table_list);
thd->abort_on_warning= saved_abort_on_warning;
}
if (info.handle_duplicates == DUP_UPDATE && !res)
{
Name_resolution_context *context= &lex->select_lex.context;
Name_resolution_context_state ctx_state;
@ -2617,9 +2640,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
res= ((fields->elements &&
check_that_all_fields_are_given_values(thd, table, table_list)) ||
table_list->prepare_where(thd, 0, TRUE) ||
res= (table_list->prepare_where(thd, 0, TRUE) ||
table_list->prepare_check_option(thd));
if (!res)

View file

@ -69,6 +69,17 @@ static uchar to_upper_lex[]=
208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255
};
/*
Names of the index hints (for error messages). Keep in sync with
index_hint_type
*/
const char * index_hint_type_name[] =
{
"IGNORE INDEX",
"USE INDEX",
"FORCE INDEX"
};
inline int lex_casecmp(const char *s, const char *t, uint len)
{
@ -1201,7 +1212,6 @@ void st_select_lex::init_select()
group_list.empty();
type= db= 0;
having= 0;
use_index_ptr= ignore_index_ptr= 0;
table_join_options= 0;
in_sum_expr= with_wild= 0;
options= 0;
@ -1209,7 +1219,6 @@ void st_select_lex::init_select()
braces= 0;
expr_list.empty();
interval_list.empty();
use_index.empty();
ftfunc_list_alloc.empty();
inner_sum_func_list= 0;
ftfunc_list= &ftfunc_list_alloc;
@ -1436,14 +1445,11 @@ bool st_select_lex_node::inc_in_sum_expr() { return 1; }
uint st_select_lex_node::get_in_sum_expr() { return 0; }
TABLE_LIST* st_select_lex_node::get_table_list() { return 0; }
List<Item>* st_select_lex_node::get_item_list() { return 0; }
List<String>* st_select_lex_node::get_use_index() { return 0; }
List<String>* st_select_lex_node::get_ignore_index() { return 0; }
TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table,
TABLE_LIST *st_select_lex_node::add_table_to_list (THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_join_options,
thr_lock_type flags,
List<String> *use_index,
List<String> *ignore_index,
List<index_hint> *hints,
LEX_STRING *option)
{
return 0;
@ -1550,19 +1556,6 @@ List<Item>* st_select_lex::get_item_list()
return &item_list;
}
List<String>* st_select_lex::get_use_index()
{
return use_index_ptr;
}
List<String>* st_select_lex::get_ignore_index()
{
return ignore_index_ptr;
}
ulong st_select_lex::get_table_join_options()
{
return table_join_options;
@ -2328,3 +2321,61 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
are in sql_union.cc
*/
/*
Sets the kind of hints to be added by the calls to add_index_hint().
SYNOPSIS
set_index_hint_type()
type the kind of hints to be added from now on.
clause the clause to use for hints to be added from now on.
DESCRIPTION
Used in filling up the tagged hints list.
This list is filled by first setting the kind of the hint as a
context variable and then adding hints of the current kind.
Then the context variable index_hint_type can be reset to the
next hint type.
*/
void st_select_lex::set_index_hint_type(enum index_hint_type type,
index_clause_map clause)
{
current_index_hint_type= type;
current_index_hint_clause= clause;
}
/*
Makes an array to store index usage hints (ADD/FORCE/IGNORE INDEX).
SYNOPSIS
alloc_index_hints()
thd current thread.
*/
void st_select_lex::alloc_index_hints (THD *thd)
{
index_hints= new (thd->mem_root) List<index_hint>();
}
/*
adds an element to the array storing index usage hints
(ADD/FORCE/IGNORE INDEX).
SYNOPSIS
add_index_hint()
thd current thread.
str name of the index.
length number of characters in str.
RETURN VALUE
0 on success, non-zero otherwise
*/
bool st_select_lex::add_index_hint (THD *thd, char *str, uint length)
{
return index_hints->push_front (new (thd->mem_root)
index_hint(current_index_hint_type,
current_index_hint_clause,
str, length));
}

View file

@ -216,6 +216,47 @@ enum tablespace_op_type
NO_TABLESPACE_OP, DISCARD_TABLESPACE, IMPORT_TABLESPACE
};
/*
String names used to print a statement with index hints.
Keep in sync with index_hint_type.
*/
extern const char * index_hint_type_name[];
typedef byte index_clause_map;
/*
Bits in index_clause_map : one for each possible FOR clause in
USE/FORCE/IGNORE INDEX index hint specification
*/
#define INDEX_HINT_MASK_JOIN (1)
#define INDEX_HINT_MASK_GROUP (1 << 1)
#define INDEX_HINT_MASK_ORDER (1 << 2)
#define INDEX_HINT_MASK_ALL (INDEX_HINT_MASK_JOIN | INDEX_HINT_MASK_GROUP | \
INDEX_HINT_MASK_ORDER)
/* Single element of an USE/FORCE/IGNORE INDEX list specified as a SQL hint */
class index_hint : public Sql_alloc
{
public:
/* The type of the hint : USE/FORCE/IGNORE */
enum index_hint_type type;
/* Where the hit applies to. A bitmask of INDEX_HINT_MASK_<place> values */
index_clause_map clause;
/*
The index name. Empty (str=NULL) name represents an empty list
USE INDEX () clause
*/
LEX_STRING key_name;
index_hint (enum index_hint_type type_arg, index_clause_map clause_arg,
char *str, uint length) :
type(type_arg), clause(clause_arg)
{
key_name.str= str;
key_name.length= length;
}
};
/*
The state of the lex parsing for selects
@ -394,15 +435,12 @@ public:
virtual uint get_in_sum_expr();
virtual TABLE_LIST* get_table_list();
virtual List<Item>* get_item_list();
virtual List<String>* get_use_index();
virtual List<String>* get_ignore_index();
virtual ulong get_table_join_options();
virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
List<String> *use_index= 0,
List<String> *ignore_index= 0,
List<index_hint> *hints= 0,
LEX_STRING *option= 0);
virtual void set_lock_for_tables(thr_lock_type lock_type) {}
@ -532,8 +570,7 @@ public:
SQL_LIST table_list;
SQL_LIST group_list; /* GROUP BY clause. */
List<Item> item_list; /* list of fields & expressions */
List<String> interval_list, use_index, *use_index_ptr,
ignore_index, *ignore_index_ptr;
List<String> interval_list;
bool is_item_list_lookup;
/*
Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake
@ -680,8 +717,7 @@ public:
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
List<String> *use_index= 0,
List<String> *ignore_index= 0,
List<index_hint> *hints= 0,
LEX_STRING *option= 0);
TABLE_LIST* get_table_list();
bool init_nested_join(THD *thd);
@ -690,8 +726,6 @@ public:
void add_joined_table(TABLE_LIST *table);
TABLE_LIST *convert_right_join();
List<Item>* get_item_list();
List<String>* get_use_index();
List<String>* get_ignore_index();
ulong get_table_join_options();
void set_lock_for_tables(thr_lock_type lock_type);
inline void init_order()
@ -731,6 +765,33 @@ public:
select lexes.
*/
void cleanup_all_joins(bool full);
void set_index_hint_type(enum index_hint_type type, index_clause_map clause);
/*
Add a index hint to the tagged list of hints. The type and clause of the
hint will be the current ones (set by set_index_hint())
*/
bool add_index_hint (THD *thd, char *str, uint length);
/* make a list to hold index hints */
void alloc_index_hints (THD *thd);
/* read and clear the index hints */
List<index_hint>* pop_index_hints(void)
{
List<index_hint> *hints= index_hints;
index_hints= NULL;
return hints;
}
void clear_index_hints(void) { index_hints= NULL; }
private:
/* current index hint kind. used in filling up index_hints */
enum index_hint_type current_index_hint_type;
index_clause_map current_index_hint_clause;
/* a list of USE/FORCE/IGNORE INDEX */
List<index_hint> *index_hints;
};
typedef class st_select_lex SELECT_LEX;

View file

@ -1417,8 +1417,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
/* 'parent_lex' is used in init_query() so it must be before it. */
sel->parent_lex= lex;
sel->init_query();
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
(List<String> *) 0, (List<String> *) 0))
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
DBUG_RETURN(1);
lex->query_tables_last= query_tables_last;
TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
@ -4708,7 +4707,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{
uint found=0;
ulong found_access=0;
#ifndef EMBEDDED_LIBRARY
#ifndef NO_EMBEDDED_ACCESS_CHECKS
TABLE_LIST *org_tables= tables;
#endif
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
@ -5461,8 +5460,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
LEX_STRING *alias,
ulong table_options,
thr_lock_type lock_type,
List<String> *use_index_arg,
List<String> *ignore_index_arg,
List<index_hint> *index_hints_arg,
LEX_STRING *option)
{
register TABLE_LIST *ptr;
@ -5537,12 +5535,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
ptr->select_lex= lex->current_select;
ptr->cacheable_table= 1;
if (use_index_arg)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
sizeof(*use_index_arg));
if (ignore_index_arg)
ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index_arg,
sizeof(*ignore_index_arg));
ptr->index_hints= index_hints_arg;
ptr->option= option ? option->str : 0;
/* check that used name is unique */
if (lock_type != TL_IGNORE)

View file

@ -943,8 +943,7 @@ my_bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
table->use_all_columns();
table->field[0]->store(name->str, name->length, system_charset_info);
if (! table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
int error;

View file

@ -1071,7 +1071,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
if (mysql_prepare_insert(thd, table_list, table_list->table,
fields, values, update_fields, update_values,
duplic, &unused_conds, FALSE))
duplic, &unused_conds, FALSE, FALSE, FALSE))
goto error;
value_count= values->elements;

View file

@ -163,13 +163,15 @@ static COND *make_cond_for_table(COND *cond,table_map table,
static Item* part_of_refkey(TABLE *form,Field *field);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes);
ha_rows select_limit, bool no_changes,
key_map *map);
static bool list_contains_unique_index(TABLE *table,
bool (*find_func) (Field *, void *), void *data);
static bool find_field_in_item_list (Field *field, void *data);
static bool find_field_in_order_list (Field *field, void *data);
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
ha_rows filesort_limit, ha_rows select_limit);
ha_rows filesort_limit, ha_rows select_limit,
bool is_order_by);
static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields,
Item *having);
static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field,
@ -652,7 +654,7 @@ void JOIN::remove_subq_pushed_predicates(Item **where)
static void save_index_subquery_explain_info(JOIN_TAB *join_tab, Item* where)
{
join_tab->packed_info= TAB_INFO_HAVE_VALUE;
if (join_tab->table->used_keys.is_set(join_tab->ref.key))
if (join_tab->table->covering_keys.is_set(join_tab->ref.key))
join_tab->packed_info |= TAB_INFO_USING_INDEX;
if (where)
join_tab->packed_info |= TAB_INFO_USING_WHERE;
@ -1024,14 +1026,15 @@ JOIN::optimize()
JOIN_TAB *tab= &join_tab[const_tables];
bool all_order_fields_used;
if (order)
skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1);
skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1,
&tab->table->keys_in_use_for_order_by);
if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array,
order, fields_list,
&all_order_fields_used)))
{
bool skip_group= (skip_sort_order &&
test_if_skip_sort_order(tab, group_list, select_limit,
1) != 0);
test_if_skip_sort_order(tab, group_list, select_limit, 1,
&tab->table->keys_in_use_for_group_by) != 0);
if ((skip_group && all_order_fields_used) ||
select_limit == HA_POS_ERROR ||
(order && !skip_sort_order))
@ -1229,7 +1232,9 @@ JOIN::optimize()
((group_list &&
(!simple_group ||
!test_if_skip_sort_order(&join_tab[const_tables], group_list,
unit->select_limit_cnt, 0))) ||
unit->select_limit_cnt, 0,
&join_tab[const_tables].table->
keys_in_use_for_group_by))) ||
select_distinct) &&
tmp_table_param.quick_group && !procedure)
{
@ -1331,7 +1336,7 @@ JOIN::optimize()
DBUG_PRINT("info",("Sorting for group"));
thd->proc_info="Sorting for group";
if (create_sort_index(thd, this, group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
alloc_group_fields(this, group_list) ||
make_sum_func_list(all_fields, fields_list, 1) ||
setup_sum_funcs(thd, sum_funcs))
@ -1348,7 +1353,7 @@ JOIN::optimize()
DBUG_PRINT("info",("Sorting for order"));
thd->proc_info="Sorting for order";
if (create_sort_index(thd, this, order,
HA_POS_ERROR, HA_POS_ERROR))
HA_POS_ERROR, HA_POS_ERROR, TRUE))
DBUG_RETURN(1);
order=0;
}
@ -1375,7 +1380,9 @@ JOIN::optimize()
{
/* Should always succeed */
if (test_if_skip_sort_order(&join_tab[const_tables],
order, unit->select_limit_cnt, 0))
order, unit->select_limit_cnt, 0,
&join_tab[const_tables].table->
keys_in_use_for_order_by))
order=0;
}
}
@ -1568,7 +1575,9 @@ JOIN::exec()
(const_tables == tables ||
((simple_order || skip_sort_order) &&
test_if_skip_sort_order(&join_tab[const_tables], order,
select_limit, 0))))
select_limit, 0,
&join_tab[const_tables].table->
keys_in_use_for_order_by))))
order=0;
having= tmp_having;
select_describe(this, need_tmp,
@ -1744,7 +1753,7 @@ JOIN::exec()
DBUG_VOID_RETURN;
}
if (create_sort_index(thd, curr_join, curr_join->group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
make_group_fields(this, curr_join))
{
DBUG_VOID_RETURN;
@ -1960,7 +1969,8 @@ JOIN::exec()
curr_join->group_list : curr_join->order,
curr_join->select_limit,
(select_options & OPTION_FOUND_ROWS ?
HA_POS_ERROR : unit->select_limit_cnt)))
HA_POS_ERROR : unit->select_limit_cnt),
curr_join->group_list ? TRUE : FALSE))
DBUG_VOID_RETURN;
sortorder= curr_join->sortorder;
if (curr_join->const_tables != curr_join->tables &&
@ -3964,7 +3974,7 @@ best_access_path(JOIN *join,
/* Limit the number of matched rows */
tmp= records;
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys.is_set(key))
if (table->covering_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->stats.block_size/2/
@ -4131,7 +4141,7 @@ best_access_path(JOIN *join,
/* Limit the number of matched rows */
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys.is_set(key))
if (table->covering_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->stats.block_size/2/
@ -4190,7 +4200,7 @@ best_access_path(JOIN *join,
!(s->quick && best_key && s->quick->index == best_key->key && // (2)
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2)
!((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3)
! s->table->used_keys.is_clear_all() && best_key) && // (3)
! s->table->covering_keys.is_clear_all() && best_key) && // (3)
!(s->table->force_index && best_key && !s->quick)) // (4)
{ // Check full join
ha_rows rnd_records= s->found_records;
@ -6096,10 +6106,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
*/
if (!ordered_set &&
(table == join->sort_by_table &&
(!join->order || join->skip_sort_order ||
test_if_skip_sort_order(tab, join->order, join->select_limit,
1))
) ||
(!join->order || join->skip_sort_order)) ||
(join->sort_by_table == (TABLE *) 1 && i != join->const_tables))
ordered_set= 1;
@ -6115,7 +6122,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
table->status=STATUS_NO_RECORD;
tab->read_first_record= join_read_const;
tab->read_record.read_record= join_no_more_records;
if (table->used_keys.is_set(tab->ref.key) &&
if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -6133,7 +6140,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
tab->quick=0;
tab->read_first_record= join_read_key;
tab->read_record.read_record= join_no_more_records;
if (table->used_keys.is_set(tab->ref.key) &&
if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -6150,7 +6157,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
}
delete tab->quick;
tab->quick=0;
if (table->used_keys.is_set(tab->ref.key) &&
if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -6236,15 +6243,15 @@ make_join_readinfo(JOIN *join, ulonglong options)
{
if (tab->select && tab->select->quick &&
tab->select->quick->index != MAX_KEY && //not index_merge
table->used_keys.is_set(tab->select->quick->index))
table->covering_keys.is_set(tab->select->quick->index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
else if (!table->used_keys.is_clear_all() &&
else if (!table->covering_keys.is_clear_all() &&
!(tab->select && tab->select->quick))
{ // Only read index tree
tab->index=find_shortest_key(table, & table->used_keys);
tab->index=find_shortest_key(table, & table->covering_keys);
tab->read_first_record= join_read_first;
tab->type=JT_NEXT; // Read with index_first / index_next
}
@ -9378,7 +9385,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->copy_blobs= 1;
table->in_use= thd;
table->quick_keys.init();
table->used_keys.init();
table->covering_keys.init();
table->keys_in_use_for_query.init();
table->s= share;
@ -10973,7 +10980,8 @@ int safe_index_read(JOIN_TAB *tab)
TABLE *table= tab->table;
if ((error=table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length, HA_READ_KEY_EXACT)))
make_prev_keypart_map(tab->ref.key_parts),
HA_READ_KEY_EXACT)))
return report_error(table, error);
return 0;
}
@ -11003,7 +11011,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
}
else
{
if (!table->key_read && table->used_keys.is_set(tab->ref.key) &&
if (!table->key_read && table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread &&
(int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY)
{
@ -11111,7 +11119,8 @@ join_read_const(JOIN_TAB *tab)
{
error=table->file->index_read_idx(table->record[0],tab->ref.key,
(byte*) tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
make_prev_keypart_map(tab->ref.key_parts),
HA_READ_KEY_EXACT);
}
if (error)
{
@ -11154,7 +11163,8 @@ join_read_key(JOIN_TAB *tab)
}
error=table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
make_prev_keypart_map(tab->ref.key_parts),
HA_READ_KEY_EXACT);
if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
}
@ -11182,7 +11192,8 @@ join_read_always_key(JOIN_TAB *tab)
return -1;
if ((error=table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT)))
make_prev_keypart_map(tab->ref.key_parts),
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
@ -11208,8 +11219,7 @@ join_read_last_key(JOIN_TAB *tab)
if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref))
return -1;
if ((error=table->file->index_read_last(table->record[0],
tab->ref.key_buff,
tab->ref.key_length)))
tab->ref.key_buff, make_prev_keypart_map(tab->ref.key_parts))))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
@ -11310,7 +11320,7 @@ join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
if (!table->key_read && table->used_keys.is_set(tab->index) &&
if (!table->key_read && table->covering_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@ -11349,7 +11359,7 @@ join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
if (!table->key_read && table->used_keys.is_set(tab->index) &&
if (!table->key_read && table->covering_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@ -11750,7 +11760,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
group->buff[-1]= (char) group->field->is_null();
}
if (!table->file->index_read(table->record[1],
join->tmp_table_param.group_buff,0,
join->tmp_table_param.group_buff, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{ /* Update old record */
restore_record(table,record[1]);
@ -12373,7 +12383,7 @@ find_field_in_item_list (Field *field, void *data)
static bool
test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
bool no_changes)
bool no_changes, key_map *map)
{
int ref_key;
uint ref_key_parts;
@ -12383,14 +12393,11 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
DBUG_ENTER("test_if_skip_sort_order");
LINT_INIT(ref_key_parts);
/* Check which keys can be used to resolve ORDER BY. */
usable_keys= table->keys_in_use_for_query;
/*
Keys disabled by ALTER TABLE ... DISABLE KEYS should have already
been taken into account.
*/
DBUG_ASSERT(usable_keys.is_subset(table->s->keys_in_use));
usable_keys= *map;
for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
{
@ -12448,8 +12455,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
If using index only read, only consider other possible index only
keys
*/
if (table->used_keys.is_set(ref_key))
usable_keys.intersect(table->used_keys);
if (table->covering_keys.is_set(ref_key))
usable_keys.intersect(table->covering_keys);
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
&usable_keys)) < MAX_KEY)
{
@ -12564,7 +12571,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
if (select_limit >= table->file->stats.records)
{
keys= *table->file->keys_to_use_for_scanning();
keys.merge(table->used_keys);
keys.merge(table->covering_keys);
/*
We are adding here also the index specified in FORCE INDEX clause,
@ -12592,7 +12599,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
tab->read_first_record= (flag > 0 ? join_read_first:
join_read_last);
tab->type=JT_NEXT; // Read with index_first(), index_next()
if (table->used_keys.is_set(nr))
if (table->covering_keys.is_set(nr))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@ -12618,6 +12625,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
filesort_limit Max number of rows that needs to be sorted
select_limit Max number of rows in final output
Used to decide if we should use index or not
is_order_by true if we are sorting on ORDER BY, false if GROUP BY
Used to decide if we should use index or not
IMPLEMENTATION
@ -12636,7 +12645,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
static int
create_sort_index(THD *thd, JOIN *join, ORDER *order,
ha_rows filesort_limit, ha_rows select_limit)
ha_rows filesort_limit, ha_rows select_limit,
bool is_order_by)
{
uint length= 0;
ha_rows examined_rows;
@ -12657,7 +12667,9 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
*/
if ((order != join->group_list ||
!(join->select_options & SELECT_BIG_RESULT)) &&
test_if_skip_sort_order(tab,order,select_limit,0))
test_if_skip_sort_order(tab,order,select_limit,0,
is_order_by ? &table->keys_in_use_for_order_by :
&table->keys_in_use_for_group_by))
DBUG_RETURN(0);
for (ORDER *ord= join->order; ord; ord= ord->next)
length++;
@ -15285,7 +15297,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
/* Build "Extra" field and add it to item_list. */
my_bool key_read=table->key_read;
if ((tab->type == JT_NEXT || tab->type == JT_CONST) &&
table->used_keys.is_set(tab->index))
table->covering_keys.is_set(tab->index))
key_read=1;
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&
!((QUICK_ROR_INTERSECT_SELECT*)tab->select->quick)->need_to_fetch_row)

View file

@ -192,7 +192,7 @@ typedef struct st_join_table {
JOIN *join;
/* Bitmap of nested joins this table is part of */
nested_join_map embedding_map;
void cleanup();
inline bool is_using_loose_index_scan()
{

View file

@ -25,6 +25,7 @@
#include "sp_head.h"
#include "sp.h"
static my_bool servers_load(THD *thd, TABLE_LIST *tables);
HASH servers_cache;
pthread_mutex_t servers_cache_mutex; // To init the hash
uint servers_cache_initialised=FALSE;
@ -353,8 +354,7 @@ my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options)
system_charset_info);
if ((error= table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, HA_WHOLE_KEY,
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
@ -554,8 +554,7 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
/* read index until record is that specified in server_name */
if ((error= table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, HA_WHOLE_KEY,
HA_READ_KEY_EXACT)))
{
/* if not found, err */
@ -873,8 +872,7 @@ int update_server_record(TABLE *table, FOREIGN_SERVER *server)
system_charset_info);
if ((error= table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, ~(longlong)0,
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
@ -928,8 +926,7 @@ int delete_server_record(TABLE *table,
table->field[0]->store(server_name, server_name_length, system_charset_info);
if ((error= table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, HA_WHOLE_KEY,
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)

View file

@ -1221,7 +1221,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (key_part->field &&
(key_part->length !=
table->field[key_part->fieldnr-1]->key_length() &&
!(key_info->flags & HA_FULLTEXT)))
!(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))))
{
char *end;
buff[0] = '(';
@ -2266,8 +2266,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel,
ident_table.length= strlen(table);
table_ident= new Table_ident(thd, ident_db, ident_table, 1);
sel->init_query();
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
(List<String> *) 0, (List<String> *) 0))
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
return 1;
return 0;
}
@ -5033,8 +5032,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
strlen(schema_table->table_name), 0);
if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
!sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
0, 0, TL_READ, (List<String> *) 0,
(List<String> *) 0))
0, 0, TL_READ))
{
DBUG_RETURN(1);
}

View file

@ -2791,6 +2791,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
column->length*= sql_field->charset->mbmaxlen;
if (key->type == Key::SPATIAL && column->length)
{
my_error(ER_WRONG_SUB_KEY, MYF(0));
DBUG_RETURN(-1);
}
if (f_is_blob(sql_field->pack_flag) ||
(f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
{
@ -2884,6 +2890,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
else if (!f_is_geom(sql_field->pack_flag) &&
(column->length > length ||
!Field::type_can_have_key_part (sql_field->sql_type) ||
((f_is_packed(sql_field->pack_flag) ||
((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
(key_info->flags & HA_NOSAME))) &&
@ -5859,6 +5866,8 @@ view_err:
*/
if (!Field::type_can_have_key_part(cfield->field->type()) ||
!Field::type_can_have_key_part(cfield->sql_type) ||
/* spatial keys can't have sub-key length */
(key_info->flags & HA_SPATIAL) ||
(cfield->field->field_length == key_part_length &&
!f_is_blob(key_part->key_type)) ||
(cfield->length && (cfield->length < key_part_length /

View file

@ -514,8 +514,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
table->use_all_columns();
table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
if (!table->file->index_read_idx(table->record[0], 0,
(byte*) table->field[0]->ptr,
table->key_info[0].key_length,
(byte*) table->field[0]->ptr, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
int error;
@ -524,7 +523,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
}
close_thread_tables(thd);
rw_unlock(&THR_LOCK_udf);
rw_unlock(&THR_LOCK_udf);
DBUG_RETURN(0);
err:
rw_unlock(&THR_LOCK_udf);

View file

@ -126,7 +126,7 @@ int mysql_update(THD *thd,
#endif
uint table_count= 0;
ha_rows updated, found;
key_map old_used_keys;
key_map old_covering_keys;
TABLE *table;
SQL_SELECT *select;
READ_RECORD info;
@ -165,8 +165,8 @@ int mysql_update(THD *thd,
thd->proc_info="init";
table= table_list->table;
/* Calculate "table->used_keys" based on the WHERE */
table->used_keys= table->s->keys_in_use;
/* Calculate "table->covering_keys" based on the WHERE */
table->covering_keys= table->s->keys_in_use;
table->quick_keys.clear_all();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@ -176,7 +176,7 @@ int mysql_update(THD *thd,
if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
DBUG_RETURN(1);
old_used_keys= table->used_keys; // Keys used in WHERE
old_covering_keys= table->covering_keys; // Keys used in WHERE
/* Check the fields we are going to modify */
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
@ -229,7 +229,7 @@ int mysql_update(THD *thd,
limit= 0; // Impossible WHERE
}
// Don't count on usage of 'only index' when calculating which key to use
table->used_keys.clear_all();
table->covering_keys.clear_all();
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (prune_partitions(thd, table, conds))
@ -304,7 +304,7 @@ int mysql_update(THD *thd,
We can't update table directly; We must first search after all
matching rows before updating the table!
*/
if (used_index < MAX_KEY && old_used_keys.is_set(used_index))
if (used_index < MAX_KEY && old_covering_keys.is_set(used_index))
{
table->key_read=1;
table->mark_columns_used_by_index(used_index);
@ -1092,7 +1092,7 @@ int multi_update::prepare(List<Item> &not_used_values,
}
/*
We have to check values after setup_tables to get used_keys right in
We have to check values after setup_tables to get covering_keys right in
reference tables
*/
@ -1119,7 +1119,7 @@ int multi_update::prepare(List<Item> &not_used_values,
update.link_in_list((byte*) tl, (byte**) &tl->next_local);
tl->shared= table_count++;
table->no_keyread=1;
table->used_keys.clear_all();
table->covering_keys.clear_all();
table->pos_in_table_list= tl;
}
}

View file

@ -481,6 +481,7 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
struct st_lex *lex;
sp_head *sphead;
struct p_elem_val *p_elem_value;
enum index_hint_type index_hint;
}
%{
@ -1162,7 +1163,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
btree_or_rtree
%type <string_list>
key_usage_list using_list
using_list
%type <key_part>
key_part
@ -1233,7 +1234,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_column_list grant_privileges grant_ident grant_list grant_option
object_privilege object_privilege_list user_list rename_list
clear_privileges flush_options flush_option
equal optional_braces opt_key_definition key_usage_list2
equal optional_braces
opt_mi_check_type opt_to mi_check_types normal_join
db_to_db table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
@ -1269,6 +1270,8 @@ END_OF_INPUT
%type <spblock> sp_decls sp_decl
%type <lex> sp_cursor_stmt
%type <spname> sp_name
%type <index_hint> index_hint_type
%type <num> index_hint_clause
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
@ -5940,12 +5943,8 @@ keycache_list:
assign_to_keycache:
table_ident cache_keys_spec
{
LEX *lex=Lex;
SELECT_LEX *sel= &lex->select_lex;
if (!sel->add_table_to_list(lex->thd, $1, NULL, 0,
TL_READ,
sel->get_use_index(),
(List<String> *)0))
if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
;
@ -5972,33 +5971,26 @@ preload_list:
preload_keys:
table_ident cache_keys_spec opt_ignore_leaves
{
LEX *lex=Lex;
SELECT_LEX *sel= &lex->select_lex;
if (!sel->add_table_to_list(lex->thd, $1, NULL, $3,
TL_READ,
sel->get_use_index(),
(List<String> *)0))
if (!Select->add_table_to_list(YYTHD, $1, NULL, $3, TL_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
;
cache_keys_spec:
{ Select->interval_list.empty(); }
cache_key_list_or_empty
{
LEX *lex=Lex;
SELECT_LEX *sel= &lex->select_lex;
sel->use_index= sel->interval_list;
{
Lex->select_lex.alloc_index_hints(YYTHD);
Select->set_index_hint_type(INDEX_HINT_USE,
global_system_variables.old_mode ?
INDEX_HINT_MASK_JOIN :
INDEX_HINT_MASK_ALL);
}
cache_key_list_or_empty
;
cache_key_list_or_empty:
/* empty */ { Lex->select_lex.use_index_ptr= 0; }
| opt_key_or_index '(' key_usage_list2 ')'
{
SELECT_LEX *sel= &Lex->select_lex;
sel->use_index_ptr= &sel->use_index;
}
/* empty */ { }
| key_or_index '(' opt_key_usage_list ')'
;
opt_ignore_leaves:
@ -7371,20 +7363,16 @@ normal_join:
table_factor:
{
SELECT_LEX *sel= Select;
sel->use_index_ptr=sel->ignore_index_ptr=0;
sel->table_join_options= 0;
}
table_ident opt_table_alias opt_key_definition
{
LEX *lex= Lex;
SELECT_LEX *sel= lex->current_select;
if (!($$= sel->add_table_to_list(lex->thd, $2, $3,
sel->get_table_join_options(),
lex->lock_option,
sel->get_use_index(),
sel->get_ignore_index())))
if (!($$= Select->add_table_to_list(YYTHD, $2, $3,
Select->get_table_join_options(),
Lex->lock_option,
Select->pop_index_hints())))
MYSQL_YYABORT;
sel->add_joined_table($$);
Select->add_joined_table($$);
}
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref
ON
@ -7453,8 +7441,7 @@ table_factor:
lex->current_select= sel= unit->outer_select();
if (!($$= sel->
add_table_to_list(lex->thd, new Table_ident(unit), $6, 0,
TL_READ,(List<String> *)0,
(List<String> *)0)))
TL_READ)))
MYSQL_YYABORT;
sel->add_joined_table($$);
@ -7553,52 +7540,67 @@ opt_outer:
/* empty */ {}
| OUTER {};
index_hint_clause:
/* empty */
{
$$= global_system_variables.old_mode ?
INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL;
}
| FOR_SYM JOIN_SYM { $$= INDEX_HINT_MASK_JOIN; }
| FOR_SYM ORDER_SYM BY { $$= INDEX_HINT_MASK_ORDER; }
| FOR_SYM GROUP_SYM BY { $$= INDEX_HINT_MASK_GROUP; }
;
index_hint_type:
FORCE_SYM { $$= INDEX_HINT_FORCE; }
| IGNORE_SYM { $$= INDEX_HINT_IGNORE; }
;
index_hint_definition:
index_hint_type key_or_index index_hint_clause
{
Select->set_index_hint_type($1, $3);
}
'(' key_usage_list ')';
| USE_SYM key_or_index index_hint_clause
{
Select->set_index_hint_type(INDEX_HINT_USE, $3);
}
'(' opt_key_usage_list ')';
index_hints_list:
index_hint_definition
| index_hints_list index_hint_definition
;
opt_index_hints_list:
/* empty */
| { Select->alloc_index_hints(YYTHD); } index_hints_list
;
opt_key_definition:
/* empty */ {}
| USE_SYM key_usage_list
{
SELECT_LEX *sel= Select;
sel->use_index= *$2;
sel->use_index_ptr= &sel->use_index;
}
| FORCE_SYM key_usage_list
{
SELECT_LEX *sel= Select;
sel->use_index= *$2;
sel->use_index_ptr= &sel->use_index;
sel->table_join_options|= TL_OPTION_FORCE_INDEX;
}
| IGNORE_SYM key_usage_list
{
SELECT_LEX *sel= Select;
sel->ignore_index= *$2;
sel->ignore_index_ptr= &sel->ignore_index;
};
{ Select->clear_index_hints(); }
opt_index_hints_list
;
opt_key_usage_list:
/* empty */ { Select->add_index_hint(YYTHD, NULL, 0); }
| key_usage_list {}
;
key_usage_element:
ident { Select->add_index_hint(YYTHD, $1.str, $1.length); }
| PRIMARY_SYM
{
Select->add_index_hint(YYTHD, (char *)"PRIMARY", 7);
}
;
key_usage_list:
key_or_index { Select->interval_list.empty(); }
'(' key_list_or_empty ')'
{ $$= &Select->interval_list; }
;
key_list_or_empty:
/* empty */ {}
| key_usage_list2 {}
;
key_usage_list2:
key_usage_list2 ',' ident
{ Select->
interval_list.push_back(new (YYTHD->mem_root) String((const char*) $3.str, $3.length,
system_charset_info)); }
| ident
{ Select->
interval_list.push_back(new (YYTHD->mem_root) String((const char*) $1.str, $1.length,
system_charset_info)); }
| PRIMARY_SYM
{ Select->
interval_list.push_back(new (YYTHD->mem_root) String("PRIMARY", 7,
system_charset_info)); };
key_usage_element
| key_usage_list ',' key_usage_element
;
using_list:
ident

View file

@ -1222,12 +1222,12 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if ((int) (share->next_number_index= (uint)
find_ref_key(share->key_info, share->keys,
share->default_values, reg_field,
&share->next_number_key_offset)) < 0)
&share->next_number_key_offset,
&share->next_number_keypart)) < 0)
{
/* Wrong field definition */
DBUG_ASSERT(0);
reg_field->unireg_check= Field::NONE; /* purecov: inspected */
share->found_next_number_field= 0;
error= 4;
goto err;
}
else
reg_field->flags |= AUTO_INCREMENT_FLAG;
@ -1338,7 +1338,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
if (!(outparam->alias= my_strdup(alias, MYF(MY_WME))))
goto err;
outparam->quick_keys.init();
outparam->used_keys.init();
outparam->covering_keys.init();
outparam->keys_in_use_for_query.init();
/* Allocate handler */
@ -2244,6 +2244,30 @@ char *get_field(MEM_ROOT *mem, Field *field)
return to;
}
/*
DESCRIPTION
given a buffer with a key value, and a map of keyparts
that are present in this value, returns the length of the value
*/
uint calculate_key_len(TABLE *table, uint key, const byte *buf,
key_part_map keypart_map)
{
/* works only with key prefixes */
DBUG_ASSERT(((keypart_map + 1) & keypart_map) == 0);
KEY *key_info= table->s->key_info+key;
KEY_PART_INFO *key_part= key_info->key_part;
KEY_PART_INFO *end_key_part= key_part + key_info->key_parts;
uint length= 0;
while (key_part < end_key_part && keypart_map)
{
length+= key_part->store_length;
keypart_map >>= 1;
key_part++;
}
return length;
}
/*
Check if database name is valid
@ -3938,7 +3962,7 @@ void st_table::mark_auto_increment_column()
*/
bitmap_set_bit(read_set, found_next_number_field->field_index);
bitmap_set_bit(write_set, found_next_number_field->field_index);
if (s->next_number_key_offset)
if (s->next_number_keypart)
mark_columns_used_by_index_no_reset(s->next_number_index, read_set);
file->column_bitmaps_signal();
}
@ -4120,6 +4144,175 @@ Item_subselect *st_table_list::containing_subselect()
return (select_lex ? select_lex->master_unit()->item : 0);
}
/*
Compiles the tagged hints list and fills up the bitmasks.
SYNOPSIS
process_index_hints()
table the TABLE to operate on.
DESCRIPTION
The parser collects the index hints for each table in a "tagged list"
(st_table_list::index_hints). Using the information in this tagged list
this function sets the members st_table::keys_in_use_for_query,
st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
st_table::force_index and st_table::covering_keys.
Current implementation of the runtime does not allow mixing FORCE INDEX
and USE INDEX, so this is checked here. Then the FORCE INDEX list
(if non-empty) is appended to the USE INDEX list and a flag is set.
Multiple hints of the same kind are processed so that each clause
is applied to what is computed in the previous clause.
For example:
USE INDEX (i1) USE INDEX (i2)
is equivalent to
USE INDEX (i1,i2)
and means "consider only i1 and i2".
Similarly
USE INDEX () USE INDEX (i1)
is equivalent to
USE INDEX (i1)
and means "consider only the index i1"
It is OK to have the same index several times, e.g. "USE INDEX (i1,i1)" is
not an error.
Different kind of hints (USE/FORCE/IGNORE) are processed in the following
order:
1. All indexes in USE (or FORCE) INDEX are added to the mask.
2. All IGNORE INDEX
e.g. "USE INDEX i1, IGNORE INDEX i1, USE INDEX i1" will not use i1 at all
as if we had "USE INDEX i1, USE INDEX i1, IGNORE INDEX i1".
As an optimization if there is a covering index, and we have
IGNORE INDEX FOR GROUP/ORDER, and this index is used for the JOIN part,
then we have to ignore the IGNORE INDEX FROM GROUP/ORDER.
RETURN VALUE
FALSE no errors found
TRUE found and reported an error.
*/
bool st_table_list::process_index_hints(TABLE *table)
{
/* initialize the result variables */
table->keys_in_use_for_query= table->keys_in_use_for_group_by=
table->keys_in_use_for_order_by= table->s->keys_in_use;
/* index hint list processing */
if (index_hints)
{
key_map index_join[INDEX_HINT_FORCE + 1];
key_map index_order[INDEX_HINT_FORCE + 1];
key_map index_group[INDEX_HINT_FORCE + 1];
index_hint *hint;
int type;
bool have_empty_use_join= FALSE, have_empty_use_order= FALSE,
have_empty_use_group= FALSE;
List_iterator <index_hint> iter(*index_hints);
/* initialize temporary variables used to collect hints of each kind */
for (type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++)
{
index_join[type].clear_all();
index_order[type].clear_all();
index_group[type].clear_all();
}
/* iterate over the hints list */
while ((hint= iter++))
{
uint pos;
/* process empty USE INDEX () */
if (hint->type == INDEX_HINT_USE && !hint->key_name.str)
{
if (hint->clause & INDEX_HINT_MASK_JOIN)
{
index_join[hint->type].clear_all();
have_empty_use_join= TRUE;
}
if (hint->clause & INDEX_HINT_MASK_ORDER)
{
index_order[hint->type].clear_all();
have_empty_use_order= TRUE;
}
if (hint->clause & INDEX_HINT_MASK_GROUP)
{
index_group[hint->type].clear_all();
have_empty_use_group= TRUE;
}
continue;
}
/*
Check if an index with the given name exists and get his offset in
the keys bitmask for the table
*/
if (table->s->keynames.type_names == 0 ||
(pos= find_type(&table->s->keynames, hint->key_name.str,
hint->key_name.length, 1)) <= 0)
{
my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name.str, alias);
return 1;
}
pos--;
/* add to the appropriate clause mask */
if (hint->clause & INDEX_HINT_MASK_JOIN)
index_join[hint->type].set_bit (pos);
if (hint->clause & INDEX_HINT_MASK_ORDER)
index_order[hint->type].set_bit (pos);
if (hint->clause & INDEX_HINT_MASK_GROUP)
index_group[hint->type].set_bit (pos);
}
/* cannot mix USE INDEX and FORCE INDEX */
if ((!index_join[INDEX_HINT_FORCE].is_clear_all() ||
!index_order[INDEX_HINT_FORCE].is_clear_all() ||
!index_group[INDEX_HINT_FORCE].is_clear_all()) &&
(!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join ||
!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order ||
!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group))
{
my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE],
index_hint_type_name[INDEX_HINT_FORCE]);
return 1;
}
/* process FORCE INDEX as USE INDEX with a flag */
if (!index_join[INDEX_HINT_FORCE].is_clear_all() ||
!index_order[INDEX_HINT_FORCE].is_clear_all() ||
!index_group[INDEX_HINT_FORCE].is_clear_all())
{
table->force_index= TRUE;
index_join[INDEX_HINT_USE].merge(index_join[INDEX_HINT_FORCE]);
index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]);
index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]);
}
/* apply USE INDEX */
if (!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join)
table->keys_in_use_for_query.intersect(index_join[INDEX_HINT_USE]);
if (!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order)
table->keys_in_use_for_order_by.intersect (index_order[INDEX_HINT_USE]);
if (!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group)
table->keys_in_use_for_group_by.intersect (index_group[INDEX_HINT_USE]);
/* apply IGNORE INDEX */
table->keys_in_use_for_query.subtract (index_join[INDEX_HINT_IGNORE]);
table->keys_in_use_for_order_by.subtract (index_order[INDEX_HINT_IGNORE]);
table->keys_in_use_for_group_by.subtract (index_group[INDEX_HINT_IGNORE]);
}
/* make sure covering_keys don't include indexes disabled with a hint */
table->covering_keys.intersect(table->keys_in_use_for_query);
return 0;
}
/*****************************************************************************
** Instansiate templates
*****************************************************************************/

View file

@ -197,8 +197,9 @@ typedef struct st_table_share
uint rowid_field_offset; /* Field_nr +1 to rowid field */
/* Index of auto-updated TIMESTAMP field in field array */
uint primary_key;
uint next_number_index;
uint next_number_key_offset;
uint next_number_index; /* autoincrement key number */
uint next_number_key_offset; /* autoinc keypart offset in a key */
uint next_number_keypart; /* autoinc keypart number in a key */
uint error, open_errno, errarg; /* error from open_table_def() */
uint column_bitmap_size;
uchar frm_version;
@ -299,6 +300,12 @@ typedef struct st_table_share
/* Information for one open table */
enum index_hint_type
{
INDEX_HINT_IGNORE,
INDEX_HINT_USE,
INDEX_HINT_FORCE
};
struct st_table {
st_table() {} /* Remove gcc warning */
@ -318,8 +325,12 @@ struct st_table {
byte *write_row_record; /* Used as optimisation in
THD::write_row */
byte *insert_values; /* used by INSERT ... UPDATE */
key_map quick_keys, used_keys;
/*
Map of keys that can be used to retrieve all data from this table
needed by the query without reading the row.
*/
key_map covering_keys;
key_map quick_keys, merge_keys;
/*
A set of keys that can be used in the query that references this
table.
@ -332,7 +343,10 @@ struct st_table {
The set is implemented as a bitmap.
*/
key_map keys_in_use_for_query;
key_map merge_keys;
/* Map of keys that can be used to calculate GROUP BY without sorting */
key_map keys_in_use_for_group_by;
/* Map of keys that can be used to calculate ORDER BY without sorting */
key_map keys_in_use_for_order_by;
KEY *key_info; /* data of keys in database */
Field *next_number_field; /* Set if next_number is activated */
@ -666,6 +680,7 @@ public:
(TABLE_LIST::join_using_fields != NULL)
*/
class index_hint;
typedef struct st_table_list
{
st_table_list() {} /* Remove gcc warning */
@ -722,7 +737,7 @@ typedef struct st_table_list
*/
struct st_table_list *next_name_resolution_table;
/* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */
List<String> *use_index, *ignore_index;
List<index_hint> *index_hints;
TABLE *table; /* opened table */
uint table_id; /* table id (from binlog) for opened table */
/*
@ -896,6 +911,13 @@ typedef struct st_table_list
void reinit_before_use(THD *thd);
Item_subselect *containing_subselect();
/*
Compiles the tagged hints list and fills up st_table::keys_in_use_for_query,
st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
st_table::force_index and st_table::covering_keys.
*/
bool process_index_hints(TABLE *table);
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);

View file

@ -1917,9 +1917,9 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
(void)table->file->ha_index_init(0, 1);
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
HA_WHOLE_KEY, HA_READ_KEY_EXACT))
{
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
/*
Most probably user has mistyped time zone name, so no need to bark here
unless we need it for debugging.
@ -1945,7 +1945,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
(void)table->file->ha_index_init(0, 1);
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
HA_WHOLE_KEY, HA_READ_KEY_EXACT))
{
sql_print_error("Can't find description of time zone '%u'", tzid);
goto end;
@ -1972,9 +1972,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
// FIXME Is there any better approach than explicitly specifying 4 ???
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
4, HA_READ_KEY_EXACT);
(key_part_map)1, HA_READ_KEY_EXACT);
while (!res)
{
ttid= (uint)table->field[1]->val_int();
@ -2045,9 +2044,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
// FIXME Is there any better approach than explicitly specifying 4 ???
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
4, HA_READ_KEY_EXACT);
(key_part_map)1, HA_READ_KEY_EXACT);
while (!res)
{
ttime= (my_time_t)table->field[1]->val_int();

View file

@ -152,7 +152,8 @@ THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd,
int ha_blackhole::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
DBUG_ENTER("ha_blackhole::index_read");
DBUG_RETURN(HA_ERR_END_OF_FILE);
@ -160,14 +161,16 @@ int ha_blackhole::index_read(byte * buf, const byte * key,
int ha_blackhole::index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
DBUG_ENTER("ha_blackhole::index_read_idx");
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
int ha_blackhole::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_blackhole::index_read_last(byte * buf, const byte * key,
key_part_map keypart_map)
{
DBUG_ENTER("ha_blackhole::index_read_last");
DBUG_RETURN(HA_ERR_END_OF_FILE);

View file

@ -64,11 +64,11 @@ public:
int rnd_init(bool scan);
int rnd_next(byte *buf);
int rnd_pos(byte * buf, byte *pos);
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read(byte * buf, const byte * key, key_part_map keypart_map,
enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_last(byte * buf, const byte * key, uint key_len);
key_part_map keypart_map, enum ha_rkey_function find_flag);
int index_read_last(byte * buf, const byte * key, key_part_map keypart_map);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);

View file

@ -415,7 +415,7 @@ int ha_example::delete_row(const byte * buf)
*/
int ha_example::index_read(byte * buf, const byte * key,
uint key_len __attribute__((unused)),
key_part_map keypart_map __attribute__((unused)),
enum ha_rkey_function find_flag
__attribute__((unused)))
{

View file

@ -191,7 +191,7 @@ public:
skip it and and MySQL will treat it as not implemented.
*/
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
key_part_map keypart_map, enum ha_rkey_function find_flag);
/** @brief
We implement this in ha_example.cc. It's not an obligatory method;

View file

@ -363,7 +363,6 @@ static handler *federated_create_handler(handlerton *hton,
static int federated_commit(handlerton *hton, THD *thd, bool all);
static int federated_rollback(handlerton *hton, THD *thd, bool all);
/* Federated storage engine handlerton */
static handler *federated_create_handler(handlerton *hton,

View file

@ -238,34 +238,35 @@ int ha_heap::delete_row(const byte * buf)
return res;
}
int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
int ha_heap::index_read(byte * buf, const byte * key, key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
DBUG_ASSERT(inited==INDEX);
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error = heap_rkey(file,buf,active_index, key, key_len, find_flag);
int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag);
table->status = error ? STATUS_NOT_FOUND : 0;
return error;
}
int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len)
int ha_heap::index_read_last(byte *buf, const byte *key, key_part_map keypart_map)
{
DBUG_ASSERT(inited==INDEX);
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error= heap_rkey(file, buf, active_index, key, key_len,
int error= heap_rkey(file, buf, active_index, key, keypart_map,
HA_READ_PREFIX_LAST);
table->status= error ? STATUS_NOT_FOUND : 0;
return error;
}
int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error = heap_rkey(file, buf, index, key, key_len, find_flag);
int error = heap_rkey(file, buf, index, key, keypart_map, find_flag);
table->status = error ? STATUS_NOT_FOUND : 0;
return error;
}

View file

@ -75,11 +75,11 @@ public:
ulonglong nb_desired_values,
ulonglong *first_value,
ulonglong *nb_reserved_values);
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_last(byte * buf, const byte * key, uint key_len);
int index_read(byte * buf, const byte * key, key_part_map keypart_map,
enum ha_rkey_function find_flag);
int index_read_last(byte *buf, const byte *key, key_part_map keypart_map);
int index_read_idx(byte * buf, uint index, const byte * key,
key_part_map keypart_map, enum ha_rkey_function find_flag);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);

View file

@ -90,7 +90,7 @@ extern int hp_rec_key_cmp(HP_KEYDEF *keydef,const byte *rec1,
extern int hp_key_cmp(HP_KEYDEF *keydef,const byte *rec,
const byte *key);
extern void hp_make_key(HP_KEYDEF *keydef,byte *key,const byte *rec);
extern uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
extern uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
const byte *rec, byte *recpos);
extern uint hp_rb_key_length(HP_KEYDEF *keydef, const byte *key);
extern uint hp_rb_null_key_length(HP_KEYDEF *keydef, const byte *key);
@ -99,8 +99,8 @@ extern my_bool hp_if_null_in_key(HP_KEYDEF *keyinfo, const byte *record);
extern int hp_close(register HP_INFO *info);
extern void hp_clear(HP_SHARE *info);
extern void hp_clear_keys(HP_SHARE *info);
extern uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
uint k_len);
extern uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
key_part_map keypart_map);
#ifdef THREAD
extern pthread_mutex_t THR_LOCK_heap;
#else

View file

@ -35,7 +35,7 @@
HA_READ_KEY_EXACT Include the key in the range
HA_READ_AFTER_KEY Don't include key in range
max_key.flag can have one of the following values:
max_key.flag can have one of the following values:
HA_READ_BEFORE_KEY Don't include key in range
HA_READ_AFTER_KEY Include all 'end_key' values in the range
@ -62,7 +62,7 @@ ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key,
{
custom_arg.key_length= hp_rb_pack_key(keyinfo, (uchar*) info->recbuf,
(uchar*) min_key->key,
min_key->length);
min_key->keypart_map);
start_pos= tree_record_pos(rb_tree, info->recbuf, min_key->flag,
&custom_arg);
}
@ -70,12 +70,12 @@ ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key,
{
start_pos= 0;
}
if (max_key)
{
custom_arg.key_length= hp_rb_pack_key(keyinfo, (uchar*) info->recbuf,
(uchar*) max_key->key,
max_key->length);
max_key->keypart_map);
end_pos= tree_record_pos(rb_tree, info->recbuf, max_key->flag,
&custom_arg);
}
@ -772,7 +772,7 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
char_length / seg->charset->mbmaxlen);
set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
if (char_length < seg->length)
seg->charset->cset->fill(seg->charset, (char*) key + char_length,
seg->charset->cset->fill(seg->charset, (char*) key + char_length,
seg->length - char_length, ' ');
}
memcpy(key, rec + seg->start, (size_t) char_length);
@ -784,30 +784,26 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
uint k_len)
key_part_map keypart_map)
{
HA_KEYSEG *seg, *endseg;
uchar *start_key= key;
for (seg= keydef->seg, endseg= seg + keydef->keysegs;
seg < endseg && (int) k_len > 0; old+= seg->length, seg++)
seg < endseg && keypart_map; old+= seg->length, seg++)
{
uint char_length;
keypart_map>>= 1;
if (seg->null_bit)
{
k_len--;
if (!(*key++= (char) 1 - *old++))
{
k_len-= seg->length;
continue;
}
}
if (seg->flag & HA_SWAP_KEY)
{
uint length= seg->length;
byte *pos= (byte*) old + length;
k_len-= length;
while (length--)
{
*key++= *--pos;
@ -822,7 +818,6 @@ uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
CHARSET_INFO *cs= seg->charset;
char_length= length/cs->mbmaxlen;
k_len-= 2+length;
old+= 2;
set_if_smaller(length,tmp_length); /* Safety */
FIX_LENGTH(cs, old, length, char_length);
@ -843,7 +838,6 @@ uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
}
memcpy(key, old, (size_t) char_length);
key+= seg->length;
k_len-= seg->length;
}
return (uint) (key - start_key);
}

Some files were not shown because too many files have changed in this diff Show more