mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 19:11:46 +01:00
Merge poseidon.:/home/tomas/mysql-5.1
into poseidon.:/home/tomas/mysql-5.1-new-ndb
This commit is contained in:
commit
a0bbe77c9c
116 changed files with 1956 additions and 824 deletions
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -61,7 +61,7 @@ done
|
|||
|
||||
|
||||
set -x
|
||||
make distclean
|
||||
make maintainer-clean
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/autorun.sh"
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -33,7 +33,7 @@ else
|
|||
fi
|
||||
|
||||
set -x
|
||||
make distclean
|
||||
make maintainer-clean
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/autorun.sh"
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
11
dbug/user.r
11
dbug/user.r
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -226,7 +226,7 @@ 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);
|
||||
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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -25,7 +25,8 @@ 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
|
||||
|
@ -48,7 +49,8 @@ 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
|
||||
|
@ -132,7 +134,8 @@ 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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)')),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
0
server-tools/CMakeLists.txt
Executable file → Normal 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"));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,7 +3536,7 @@ 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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
19
sql/item.cc
19
sql/item.cc
|
@ -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;
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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);
|
||||
|
|
12
sql/key.cc
12
sql/key.cc
|
@ -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,7 +79,10 @@ 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 */
|
||||
{
|
||||
*keypart= j;
|
||||
return i; /* Use this key */
|
||||
}
|
||||
*key_length+= key_part->store_length;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -6855,8 +6855,7 @@ 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,
|
||||
(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));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
228
sql/opt_range.cc
228
sql/opt_range.cc
|
@ -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);
|
||||
|
@ -586,8 +596,8 @@ 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,
|
||||
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(¶m, 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)
|
||||
|
@ -7121,11 +7137,12 @@ 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)
|
||||
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,16 +7156,19 @@ 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);
|
||||
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);
|
||||
|
||||
|
@ -7176,9 +7196,10 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
|
|||
!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,9 +7211,11 @@ 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);
|
||||
|
@ -7209,8 +7232,7 @@ 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 &&
|
||||
HA_NOSAME && min_key_length == max_key_length &&
|
||||
!memcmp(param->min_key, param->max_key, min_key_length) &&
|
||||
!param->first_null_comp)
|
||||
{
|
||||
|
@ -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,8 +7541,10 @@ 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
|
||||
|
||||
|
@ -7659,6 +7691,8 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
|
|||
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -8420,14 +8458,14 @@ 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);
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
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
|
||||
|
@ -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();
|
||||
|
|
|
@ -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,7 +338,7 @@ 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);
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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" ":"")
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
/*
|
||||
|
@ -2809,7 +2802,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
|
|||
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,
|
||||
(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++)
|
||||
|
|
|
@ -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())
|
||||
if (table_list->process_index_hints(table))
|
||||
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 (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++;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)) ||
|
||||
|
|
|
@ -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,18 +571,10 @@ 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 &
|
||||
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;
|
||||
}
|
||||
|
||||
table->mark_columns_needed_for_insert();
|
||||
|
||||
if (table_list->prepare_where(thd, 0, TRUE) ||
|
||||
|
@ -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,
|
||||
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)
|
||||
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,6 +1260,8 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
|
|||
compare_record(table))
|
||||
{
|
||||
info->updated++;
|
||||
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
|
||||
|
@ -1258,12 +1271,11 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
|
|||
*/
|
||||
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());
|
||||
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++;
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -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,
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 /
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> ¬_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> ¬_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;
|
||||
}
|
||||
}
|
||||
|
|
154
sql/sql_yacc.yy
154
sql/sql_yacc.yy
|
@ -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,53 +7540,68 @@ 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->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_LEX *sel= Select;
|
||||
sel->use_index= *$2;
|
||||
sel->use_index_ptr= &sel->use_index;
|
||||
Select->add_index_hint(YYTHD, (char *)"PRIMARY", 7);
|
||||
}
|
||||
| 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;
|
||||
};
|
||||
;
|
||||
|
||||
key_usage_list:
|
||||
key_or_index { Select->interval_list.empty(); }
|
||||
'(' key_list_or_empty ')'
|
||||
{ $$= &Select->interval_list; }
|
||||
key_usage_element
|
||||
| key_usage_list ',' key_usage_element
|
||||
;
|
||||
|
||||
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)); };
|
||||
|
||||
using_list:
|
||||
ident
|
||||
{
|
||||
|
|
205
sql/table.cc
205
sql/table.cc
|
@ -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
|
||||
*****************************************************************************/
|
||||
|
|
34
sql/table.h
34
sql/table.h
|
@ -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);
|
||||
|
|
|
@ -1917,7 +1917,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))
|
||||
{
|
||||
#ifdef EXTRA_DEBUG
|
||||
/*
|
||||
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -100,7 +100,7 @@ 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);
|
||||
key_part_map keypart_map);
|
||||
#ifdef THREAD
|
||||
extern pthread_mutex_t THR_LOCK_heap;
|
||||
#else
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -75,7 +75,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*) max_key->key,
|
||||
max_key->length);
|
||||
max_key->keypart_map);
|
||||
end_pos= tree_record_pos(rb_tree, info->recbuf, max_key->flag,
|
||||
&custom_arg);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "heapdef.h"
|
||||
|
||||
int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
|
||||
uint key_len, enum ha_rkey_function find_flag)
|
||||
key_part_map keypart_map, enum ha_rkey_function find_flag)
|
||||
{
|
||||
byte *pos;
|
||||
HP_SHARE *share= info->s;
|
||||
|
@ -38,7 +38,7 @@ int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
|
|||
custom_arg.keyseg= info->s->keydef[inx].seg;
|
||||
custom_arg.key_length= info->lastkey_len=
|
||||
hp_rb_pack_key(keyinfo, (uchar*) info->lastkey,
|
||||
(uchar*) key, key_len);
|
||||
(uchar*) key, keypart_map);
|
||||
custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME;
|
||||
/* for next rkey() after deletion */
|
||||
if (find_flag == HA_READ_AFTER_KEY)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue