summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/include/index_merge1.inc48
-rw-r--r--mysql-test/r/type_time.result19
-rw-r--r--mysql-test/t/type_time.test19
-rw-r--r--sql/field.cc3
-rw-r--r--sql/item_cmpfunc.cc80
-rw-r--r--sql/item_cmpfunc.h2
-rw-r--r--sql/opt_range.cc40
-rw-r--r--storage/heap/ha_heap.cc20
-rw-r--r--storage/heap/ha_heap.h9
9 files changed, 212 insertions, 28 deletions
diff --git a/mysql-test/include/index_merge1.inc b/mysql-test/include/index_merge1.inc
index a3a874a8ed2..2ecdbe583c2 100644
--- a/mysql-test/include/index_merge1.inc
+++ b/mysql-test/include/index_merge1.inc
@@ -439,3 +439,51 @@ INSERT INTO t2(a,b) VALUES(1,2);
SELECT t2.a FROM t1,t2 WHERE t2.b=2 AND t2.a=1;
UNLOCK TABLES;
DROP TABLE t1, t2;
+
+#
+# BUG#29740: HA_KEY_SCAN_NOT_ROR wasn't set for HEAP engine
+#
+CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `filler` char(200) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL,
+ KEY `a` (`a`),
+ KEY `b` (`b`)
+) ENGINE=MEMORY DEFAULT CHARSET=latin1;
+
+insert into t1 values
+(0, 'filler', 0), (1, 'filler', 1), (2, 'filler', 2), (3, 'filler', 3),
+(4, 'filler', 4), (5, 'filler', 5), (6, 'filler', 6), (7, 'filler', 7),
+(8, 'filler', 8), (9, 'filler', 9), (0, 'filler', 0), (1, 'filler', 1),
+(2, 'filler', 2), (3, 'filler', 3), (4, 'filler', 4), (5, 'filler', 5),
+(6, 'filler', 6), (7, 'filler', 7), (8, 'filler', 8), (9, 'filler', 9),
+(10, 'filler', 10), (11, 'filler', 11), (12, 'filler', 12), (13, 'filler', 13),
+(14, 'filler', 14), (15, 'filler', 15), (16, 'filler', 16), (17, 'filler', 17),
+(18, 'filler', 18), (19, 'filler', 19), (4, '5 ', 0), (5, '4 ', 0),
+(4, '4 ', 0), (4, 'qq ', 5), (5, 'qq ', 4), (4, 'zz ', 4);
+
+create table t2(
+ `a` int(11) DEFAULT NULL,
+ `filler` char(200) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL,
+ KEY USING BTREE (`a`),
+ KEY USING BTREE (`b`)
+) ENGINE=MEMORY DEFAULT CHARSET=latin1;
+insert into t2 select * from t1;
+
+--echo must use sort-union rather than union:
+--replace_column 9 #
+explain select * from t1 where a=4 or b=4;
+--sorted_result
+select * from t1 where a=4 or b=4;
+--sorted_result
+select * from t1 ignore index(a,b) where a=4 or b=4;
+
+--echo must use union, not sort-union:
+--replace_column 9 #
+explain select * from t2 where a=4 or b=4;
+--sorted_result
+select * from t2 where a=4 or b=4;
+
+drop table t1, t2;
+
diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result
index 7126dd082bd..d80a3973555 100644
--- a/mysql-test/r/type_time.result
+++ b/mysql-test/r/type_time.result
@@ -103,9 +103,28 @@ cast('100:55:50' as time) > cast('024:00:00' as time)
select cast('300:55:50' as time) > cast('240:00:00' as time);
cast('300:55:50' as time) > cast('240:00:00' as time)
1
+create table t1 (f1 time);
+insert into t1 values ('24:00:00');
+select cast('24:00:00' as time) = (select f1 from t1);
+cast('24:00:00' as time) = (select f1 from t1)
+1
+drop table t1;
create table t1(f1 time, f2 time);
insert into t1 values('20:00:00','150:00:00');
select 1 from t1 where cast('100:00:00' as time) between f1 and f2;
1
1
drop table t1;
+CREATE TABLE t1 (
+f2 date NOT NULL,
+f3 int(11) unsigned NOT NULL default '0',
+PRIMARY KEY (f3, f2)
+);
+insert into t1 values('2007-07-01', 1);
+insert into t1 values('2007-07-01', 2);
+insert into t1 values('2007-07-02', 1);
+insert into t1 values('2007-07-02', 2);
+SELECT sum(f3) FROM t1 where f2='2007-07-01 00:00:00' group by f2;
+sum(f3)
+3
+drop table t1;
diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test
index 82d701e29b5..5fc763be7fe 100644
--- a/mysql-test/t/type_time.test
+++ b/mysql-test/t/type_time.test
@@ -50,6 +50,10 @@ select cast('300:55:50' as time) < cast('240:00:00' as time);
select cast('100:55:50' as time) > cast('24:00:00' as time);
select cast('100:55:50' as time) > cast('024:00:00' as time);
select cast('300:55:50' as time) > cast('240:00:00' as time);
+create table t1 (f1 time);
+insert into t1 values ('24:00:00');
+select cast('24:00:00' as time) = (select f1 from t1);
+drop table t1;
#
# Bug#29739: Incorrect time comparison in BETWEEN.
@@ -58,3 +62,18 @@ create table t1(f1 time, f2 time);
insert into t1 values('20:00:00','150:00:00');
select 1 from t1 where cast('100:00:00' as time) between f1 and f2;
drop table t1;
+
+#
+# Bug#29729: Wrong conversion error led to an empty result set.
+#
+CREATE TABLE t1 (
+ f2 date NOT NULL,
+ f3 int(11) unsigned NOT NULL default '0',
+ PRIMARY KEY (f3, f2)
+);
+insert into t1 values('2007-07-01', 1);
+insert into t1 values('2007-07-01', 2);
+insert into t1 values('2007-07-02', 1);
+insert into t1 values('2007-07-02', 2);
+SELECT sum(f3) FROM t1 where f2='2007-07-01 00:00:00' group by f2;
+drop table t1;
diff --git a/sql/field.cc b/sql/field.cc
index 2cd81afca49..a970a6e4318 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -5406,7 +5406,8 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
else
{
tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
- if (!error && (ret != MYSQL_TIMESTAMP_DATE))
+ if (!error && (ret != MYSQL_TIMESTAMP_DATE) &&
+ thd->count_cuted_fields != CHECK_FIELD_IGNORE)
error= 3; // Datetime was cut (note)
}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 299e0435122..755e711e383 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -719,6 +719,67 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value)
}
+/*
+ Retrieves correct TIME value from the given item.
+
+ SYNOPSIS
+ get_time_value()
+ thd thread handle
+ item_arg [in/out] item to retrieve TIME value from
+ cache_arg [in/out] pointer to place to store the cache item to
+ warn_item [in] unused
+ is_null [out] TRUE <=> the item_arg is null
+
+ DESCRIPTION
+ Retrieves the correct TIME value from given item for comparison by the
+ compare_datetime() function.
+ If item's result can be compared as longlong then its int value is used
+ and a value returned by get_time function is used otherwise.
+ If an item is a constant one then its value is cached and it isn't
+ get parsed again. An Item_cache_int object is used for for cached values.
+ It seamlessly substitutes the original item. The cache item is marked as
+ non-constant to prevent re-caching it again.
+
+ RETURN
+ obtained value
+*/
+
+ulonglong
+get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
+ Item *warn_item, bool *is_null)
+{
+ ulonglong value;
+ Item *item= **item_arg;
+ MYSQL_TIME ltime;
+
+ if (item->result_as_longlong())
+ {
+ value= item->val_int();
+ *is_null= item->null_value;
+ }
+ else
+ {
+ *is_null= item->get_time(&ltime);
+ value= !*is_null ? TIME_to_ulonglong_datetime(&ltime) : 0;
+ }
+ /*
+ Do not cache GET_USER_VAR() function as its const_item() may return TRUE
+ for the current thread but it still may change during the execution.
+ */
+ if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM ||
+ ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
+ {
+ Item_cache_int *cache= new Item_cache_int();
+ /* Mark the cache as non-const to prevent re-caching. */
+ cache->set_used_tables(1);
+ cache->store(item, value);
+ *cache_arg= cache;
+ *item_arg= cache_arg;
+ }
+ return value;
+}
+
+
int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2,
Item_result type)
@@ -757,6 +818,7 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
}
is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
func= &Arg_comparator::compare_datetime;
+ get_value_func= &get_datetime_value;
return 0;
}
else if (type == STRING_RESULT && (*a)->field_type() == MYSQL_TYPE_TIME &&
@@ -765,9 +827,11 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
/* Compare TIME values as integers. */
thd= current_thd;
owner= owner_arg;
- func= ((test(owner && owner->functype() == Item_func::EQUAL_FUNC)) ?
- &Arg_comparator::compare_e_int :
- &Arg_comparator::compare_int_unsigned);
+ a_cache= 0;
+ b_cache= 0;
+ is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
+ func= &Arg_comparator::compare_datetime;
+ get_value_func= &get_time_value;
return 0;
}
@@ -788,8 +852,10 @@ void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
b_cache= 0;
is_nulls_eq= FALSE;
func= &Arg_comparator::compare_datetime;
+ get_value_func= &get_datetime_value;
}
+
/*
Retrieves correct DATETIME value from given item.
@@ -903,8 +969,8 @@ int Arg_comparator::compare_datetime()
bool is_null= FALSE;
ulonglong a_value, b_value;
- /* Get DATE/DATETIME value of the 'a' item. */
- a_value= get_datetime_value(thd, &a, &a_cache, *b, &is_null);
+ /* Get DATE/DATETIME/TIME value of the 'a' item. */
+ a_value= (*get_value_func)(thd, &a, &a_cache, *b, &is_null);
if (!is_nulls_eq && is_null)
{
if (owner)
@@ -912,8 +978,8 @@ int Arg_comparator::compare_datetime()
return -1;
}
- /* Get DATE/DATETIME value of the 'b' item. */
- b_value= get_datetime_value(thd, &b, &b_cache, *a, &is_null);
+ /* Get DATE/DATETIME/TIME value of the 'b' item. */
+ b_value= (*get_value_func)(thd, &b, &b_cache, *a, &is_null);
if (is_null)
{
if (owner)
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index ee36aca069d..fcbacc32d88 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -42,6 +42,8 @@ class Arg_comparator: public Sql_alloc
bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC
enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE,
CMP_DATE_WITH_STR, CMP_STR_WITH_DATE };
+ ulonglong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg,
+ Item *warn_item, bool *is_null);
public:
DTCollation cmp_collation;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 4944c994d3d..948b268d9a3 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1264,8 +1264,16 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
thd= head->in_use;
if (!(file= head->file->clone(thd->mem_root)))
{
+ /*
+ Manually set the error flag. Note: there seems to be quite a few
+ places where a failure could cause the server to "hang" the client by
+ sending no response to a query. ATM those are not real errors because
+ the storage engine calls in question happen to never fail with the
+ existing storage engines.
+ */
+ thd->net.report_error= 1; /* purecov: inspected */
/* Caller will free the memory */
- goto failure;
+ goto failure; /* purecov: inspected */
}
head->column_bitmaps_set(&column_bitmap, &column_bitmap);
@@ -7244,6 +7252,11 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats)
param->is_ror_scan is cleared if the function detects that the key scan is
not a Rowid-Ordered Retrieval scan ( see comments for is_key_scan_ror
function for description of which key scans are ROR scans)
+
+ RETURN
+ #records E(#records) for given subtree
+ HA_POS_ERROR if subtree cannot be used for record retrieval
+
*/
static ha_rows
@@ -7445,27 +7458,24 @@ check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree,
ROR (Rowid Ordered Retrieval) key scan is a key scan that produces
ordered sequence of rowids (ha_xxx::cmp_ref is the comparison function)
- An index scan is a ROR scan if it is done using a condition in form
+ This function is needed to handle a practically-important special case:
+ an index scan is a ROR scan if it is done using a condition in form
- "key1_1=c_1 AND ... AND key1_n=c_n" (1)
+ "key1_1=c_1 AND ... AND key1_n=c_n"
where the index is defined on (key1_1, ..., key1_N [,a_1, ..., a_n])
- and the table has a clustered Primary Key
-
- PRIMARY KEY(a_1, ..., a_n, b1, ..., b_k) with first key parts being
- identical to uncovered parts ot the key being scanned (2)
-
- Scans on HASH indexes are not ROR scans,
- any range scan on clustered primary key is ROR scan (3)
+ and the table has a clustered Primary Key defined as
- Check (1) is made in check_quick_keys()
- Check (3) is made check_quick_select()
- Check (2) is made by this function.
+ PRIMARY KEY(a_1, ..., a_n, b1, ..., b_k)
+
+ i.e. the first key parts of it are identical to uncovered parts ot the
+ key being scanned. This function assumes that the index flags do not
+ include HA_KEY_SCAN_NOT_ROR flag (that is checked elsewhere).
RETURN
- TRUE If the scan is ROR-scan
- FALSE otherwise
+ TRUE The scan is ROR-scan
+ FALSE Otherwise
*/
static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts)
diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc
index 86bc2cc516e..5d34395fa5a 100644
--- a/storage/heap/ha_heap.cc
+++ b/storage/heap/ha_heap.cc
@@ -125,6 +125,26 @@ int ha_heap::close(void)
/*
+ Create a copy of this table
+
+ DESCRIPTION
+ Do same as default implementation but use file->s->name instead of
+ table->s->path. This is needed by Windows where the clone() call sees
+ '/'-delimited path in table->s->path, while ha_peap::open() was called
+ with '\'-delimited path.
+*/
+
+handler *ha_heap::clone(MEM_ROOT *mem_root)
+{
+ handler *new_handler= get_new_handler(table, mem_root, table->s->db_type);
+ if (new_handler && !new_handler->ha_open(file->s->name, table->db_stat,
+ HA_OPEN_IGNORE_IF_LOCKED))
+ return new_handler;
+ return NULL; /* purecov: inspected */
+}
+
+
+/*
Compute which keys to use for scanning
SYNOPSIS
diff --git a/storage/heap/ha_heap.h b/storage/heap/ha_heap.h
index f41c710716d..c414383a4aa 100644
--- a/storage/heap/ha_heap.h
+++ b/storage/heap/ha_heap.h
@@ -32,6 +32,7 @@ class ha_heap: public handler
public:
ha_heap(handlerton *hton, TABLE_SHARE *table);
~ha_heap() {}
+ handler *clone(MEM_ROOT *mem_root);
const char *table_type() const
{
return (table->in_use->variables.sql_mode & MODE_MYSQL323) ?
@@ -55,8 +56,8 @@ public:
ulong index_flags(uint inx, uint part, bool all_parts) const
{
return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ?
- HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE :
- HA_ONLY_WHOLE_INDEX);
+ HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE :
+ HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
}
const key_map *keys_to_use_for_scanning() { return &btree_keys; }
uint max_supported_keys() const { return MAX_KEY; }
@@ -108,9 +109,7 @@ public:
enum thr_lock_type lock_type);
int cmp_ref(const uchar *ref1, const uchar *ref2)
{
- HEAP_PTR ptr1=*(HEAP_PTR*)ref1;
- HEAP_PTR ptr2=*(HEAP_PTR*)ref2;
- return ptr1 < ptr2? -1 : (ptr1 > ptr2? 1 : 0);
+ return memcmp(ref1, ref2, sizeof(HEAP_PTR));
}
bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes);
private: