Skip to content

Commit bd3864e

Browse files
committed
Merge branch '10.1' of https://github.com/MariaDB/server into ok-debpkg-10.1
2 parents b007dfb + a3c24ee commit bd3864e

File tree

9 files changed

+208
-27
lines changed

9 files changed

+208
-27
lines changed

mysql-test/r/ctype_latin1.result

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8039,5 +8039,69 @@ Warnings:
80398039
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 'a') and (`test`.`t1`.`a` between 'a' and <cache>(('c' collate latin1_bin))))
80408040
DROP TABLE t1;
80418041
#
8042+
# MDEV-8707 Wrong result for SELECT..WHERE varchar_column=DATE'2001-01-01' AND varchar_column='2001-01-01'
8043+
#
8044+
SET NAMES latin1;
8045+
CREATE TABLE t1 (a VARCHAR(40));
8046+
INSERT INTO t1 VALUES ('2001-01-01'),('2001-01-01x');
8047+
SELECT * FROM t1 WHERE a=DATE'2001-01-01' AND a='2001-01-01';
8048+
a
8049+
2001-01-01
8050+
SELECT * FROM t1 WHERE a='2001-01-01' AND a=DATE'2001-01-01';
8051+
a
8052+
2001-01-01
8053+
SELECT * FROM t1 WHERE (a,a)=('2001-01-01x',DATE'2001-01-01');
8054+
a
8055+
2001-01-01x
8056+
Warnings:
8057+
Warning 1292 Truncated incorrect date value: '2001-01-01x'
8058+
SELECT * FROM t1 WHERE (a,a)=(DATE'2001-01-01','2001-01-01x');
8059+
a
8060+
2001-01-01x
8061+
Warnings:
8062+
Warning 1292 Truncated incorrect date value: '2001-01-01x'
8063+
SELECT * FROM t1 WHERE (a,a)=('2001-01-01',DATE'2001-01-01');
8064+
a
8065+
2001-01-01
8066+
SELECT * FROM t1 WHERE (a,a)=(DATE'2001-01-01','2001-01-01');
8067+
a
8068+
2001-01-01
8069+
DROP TABLE t1;
8070+
CREATE TABLE t1 (a ENUM('2001-01-01','2001-01-01x'));
8071+
INSERT INTO t1 VALUES ('2001-01-01'),('2001-01-01x');
8072+
SELECT * FROM t1 WHERE a=DATE'2001-01-01' AND a='2001-01-01';
8073+
a
8074+
2001-01-01
8075+
SELECT * FROM t1 WHERE a='2001-01-01' AND a=DATE'2001-01-01';
8076+
a
8077+
2001-01-01
8078+
SELECT * FROM t1 WHERE (a,a)=('2001-01-01x',DATE'2001-01-01');
8079+
a
8080+
2001-01-01x
8081+
Warnings:
8082+
Warning 1292 Truncated incorrect date value: '2001-01-01x'
8083+
SELECT * FROM t1 WHERE (a,a)=(DATE'2001-01-01','2001-01-01x');
8084+
a
8085+
2001-01-01x
8086+
Warnings:
8087+
Warning 1292 Truncated incorrect date value: '2001-01-01x'
8088+
SELECT * FROM t1 WHERE (a,a)=('2001-01-01',DATE'2001-01-01');
8089+
a
8090+
2001-01-01
8091+
SELECT * FROM t1 WHERE (a,a)=(DATE'2001-01-01','2001-01-01');
8092+
a
8093+
2001-01-01
8094+
DROP TABLE t1;
8095+
CREATE TABLE t1 (a VARCHAR(40),b VARCHAR(40));
8096+
INSERT INTO t1 VALUES ('2001-01-01','2001-01-01x');
8097+
SELECT * FROM t1 WHERE a=b AND a=DATE'2001-01-01';
8098+
a b
8099+
DROP TABLE t1;
8100+
CREATE TABLE t1 (a ENUM('2001-01-01','2001-01-01x'),b ENUM('2001-01-01','2001-01-01x'));
8101+
INSERT INTO t1 VALUES ('2001-01-01','2001-01-01x');
8102+
SELECT * FROM t1 WHERE a=b AND a=DATE'2001-01-01';
8103+
a b
8104+
DROP TABLE t1;
8105+
#
80428106
# End of 10.1 tests
80438107
#

mysql-test/t/ctype_latin1.test

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,37 @@ SELECT * FROM t1 WHERE a BETWEEN 'a' AND 'c' COLLATE latin1_bin AND a='a';
298298
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a BETWEEN 'a' AND 'c' COLLATE latin1_bin AND a='a';
299299
DROP TABLE t1;
300300

301+
--echo #
302+
--echo # MDEV-8707 Wrong result for SELECT..WHERE varchar_column=DATE'2001-01-01' AND varchar_column='2001-01-01'
303+
--echo #
304+
SET NAMES latin1;
305+
CREATE TABLE t1 (a VARCHAR(40));
306+
INSERT INTO t1 VALUES ('2001-01-01'),('2001-01-01x');
307+
SELECT * FROM t1 WHERE a=DATE'2001-01-01' AND a='2001-01-01';
308+
SELECT * FROM t1 WHERE a='2001-01-01' AND a=DATE'2001-01-01';
309+
SELECT * FROM t1 WHERE (a,a)=('2001-01-01x',DATE'2001-01-01');
310+
SELECT * FROM t1 WHERE (a,a)=(DATE'2001-01-01','2001-01-01x');
311+
SELECT * FROM t1 WHERE (a,a)=('2001-01-01',DATE'2001-01-01');
312+
SELECT * FROM t1 WHERE (a,a)=(DATE'2001-01-01','2001-01-01');
313+
DROP TABLE t1;
314+
CREATE TABLE t1 (a ENUM('2001-01-01','2001-01-01x'));
315+
INSERT INTO t1 VALUES ('2001-01-01'),('2001-01-01x');
316+
SELECT * FROM t1 WHERE a=DATE'2001-01-01' AND a='2001-01-01';
317+
SELECT * FROM t1 WHERE a='2001-01-01' AND a=DATE'2001-01-01';
318+
SELECT * FROM t1 WHERE (a,a)=('2001-01-01x',DATE'2001-01-01');
319+
SELECT * FROM t1 WHERE (a,a)=(DATE'2001-01-01','2001-01-01x');
320+
SELECT * FROM t1 WHERE (a,a)=('2001-01-01',DATE'2001-01-01');
321+
SELECT * FROM t1 WHERE (a,a)=(DATE'2001-01-01','2001-01-01');
322+
DROP TABLE t1;
323+
CREATE TABLE t1 (a VARCHAR(40),b VARCHAR(40));
324+
INSERT INTO t1 VALUES ('2001-01-01','2001-01-01x');
325+
SELECT * FROM t1 WHERE a=b AND a=DATE'2001-01-01';
326+
DROP TABLE t1;
327+
CREATE TABLE t1 (a ENUM('2001-01-01','2001-01-01x'),b ENUM('2001-01-01','2001-01-01x'));
328+
INSERT INTO t1 VALUES ('2001-01-01','2001-01-01x');
329+
SELECT * FROM t1 WHERE a=b AND a=DATE'2001-01-01';
330+
DROP TABLE t1;
331+
301332
--echo #
302333
--echo # End of 10.1 tests
303334
--echo #

sql/field.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,21 @@ double Field::pos_in_interval_val_str(Field *min, Field *max, uint data_offset)
12461246
}
12471247

12481248

1249+
bool Field::test_if_equality_guarantees_uniqueness(const Item *item) const
1250+
{
1251+
DBUG_ASSERT(cmp_type() != STRING_RESULT); // For STRING_RESULT see Field_str
1252+
/*
1253+
We use result_type() rather than cmp_type() in the below condition,
1254+
because it covers a special case that string literals guarantee uniqueness
1255+
for temporal columns, so the query:
1256+
WHERE temporal_column='string'
1257+
cannot return multiple distinct temporal values.
1258+
QQ: perhaps we could allow INT/DECIMAL/DOUBLE types for temporal items.
1259+
*/
1260+
return result_type() == item->result_type();
1261+
}
1262+
1263+
12491264
/*
12501265
This handles all numeric and BIT data types.
12511266
*/
@@ -1843,6 +1858,32 @@ Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
18431858
}
18441859

18451860

1861+
bool Field_str::test_if_equality_guarantees_uniqueness(const Item *item) const
1862+
{
1863+
/*
1864+
Can't guarantee uniqueness when comparing a CHAR/VARCHAR/TEXT,
1865+
BINARY/VARBINARY/BLOB, ENUM,SET columns to an item with cmp_type()
1866+
of INT_RESULT, DOUBLE_RESULT, DECIMAL_RESULT or TIME_RESULT.
1867+
Example:
1868+
SELECT * FROM t1 WHERE varchar_column=DATE'2001-01-01'
1869+
return non-unuque values, e.g. '2001-01-01' and '2001-01-01x'.
1870+
*/
1871+
if (!field_charset->coll->propagate(field_charset, 0, 0) ||
1872+
item->cmp_type() != STRING_RESULT)
1873+
return false;
1874+
/*
1875+
Can't guarantee uniqueness when comparing to
1876+
an item of a different collation.
1877+
Example:
1878+
SELECT * FROM t1
1879+
WHERE latin1_bin_column = _latin1'A' COLLATE latin1_swedish_ci
1880+
return non-unique values 'a' and 'A'.
1881+
*/
1882+
DTCollation tmp(field_charset, field_derivation, repertoire());
1883+
return !tmp.aggregate(item->collation) && tmp.collation == field_charset;
1884+
}
1885+
1886+
18461887
void Field_num::make_field(Send_field *field)
18471888
{
18481889
Field::make_field(field);

sql/field.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,21 @@ class Field
10121012
return (double) 0.5;
10131013
}
10141014

1015+
/*
1016+
Check if comparison between the field and an item unambiguously
1017+
identifies a distinct field value.
1018+
1019+
Example1: SELECT * FROM t1 WHERE int_column=10;
1020+
This example returns distinct integer value of 10.
1021+
1022+
Example2: SELECT * FROM t1 WHERE varchar_column=DATE'2001-01-01'
1023+
This example returns non-distinct values.
1024+
Comparison as DATE will return '2001-01-01' and '2001-01-01x',
1025+
but these two values are not equal to each other as VARCHARs.
1026+
See also the function with the same name in sql_select.cc.
1027+
*/
1028+
virtual bool test_if_equality_guarantees_uniqueness(const Item *const_item)
1029+
const;
10151030
virtual bool can_optimize_keypart_ref(const Item_bool_func *cond,
10161031
const Item *item) const;
10171032
virtual bool can_optimize_hash_join(const Item_bool_func *cond,
@@ -1187,6 +1202,7 @@ class Field_str :public Field {
11871202
{
11881203
return pos_in_interval_val_str(min, max, length_size());
11891204
}
1205+
bool test_if_equality_guarantees_uniqueness(const Item *const_item) const;
11901206
};
11911207

11921208
/* base class for Field_string, Field_varstring and Field_blob */

sql/item.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,7 +1814,7 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
18141814

18151815

18161816
static bool
1817-
left_is_superset(DTCollation *left, DTCollation *right)
1817+
left_is_superset(const DTCollation *left, const DTCollation *right)
18181818
{
18191819
/* Allow convert to Unicode */
18201820
if (left->collation->state & MY_CS_UNICODE &&
@@ -1873,7 +1873,7 @@ left_is_superset(DTCollation *left, DTCollation *right)
18731873
@endcode
18741874
*/
18751875

1876-
bool DTCollation::aggregate(DTCollation &dt, uint flags)
1876+
bool DTCollation::aggregate(const DTCollation &dt, uint flags)
18771877
{
18781878
if (!my_charset_same(collation, dt.collation))
18791879
{

sql/item.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ class DTCollation {
127127
derivation= derivation_arg;
128128
set_repertoire_from_charset(collation_arg);
129129
}
130+
DTCollation(CHARSET_INFO *collation_arg,
131+
Derivation derivation_arg,
132+
uint repertoire_arg)
133+
:collation(collation_arg),
134+
derivation(derivation_arg),
135+
repertoire(repertoire_arg)
136+
{ }
130137
void set(const DTCollation &dt)
131138
{
132139
collation= dt.collation;
@@ -160,7 +167,7 @@ class DTCollation {
160167
}
161168
void set(Derivation derivation_arg)
162169
{ derivation= derivation_arg; }
163-
bool aggregate(DTCollation &dt, uint flags= 0);
170+
bool aggregate(const DTCollation &dt, uint flags= 0);
164171
bool set(DTCollation &dt1, DTCollation &dt2, uint flags= 0)
165172
{ set(dt1); return aggregate(dt2, flags); }
166173
const char *derivation_name() const

sql/item_cmpfunc.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,8 +553,10 @@ int Arg_comparator::set_compare_func(Item_func_or_sum *item, Item_result type)
553553
my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols());
554554
return 1;
555555
}
556-
if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i),
557-
set_null))
556+
if (comparators[i].set_cmp_func_and_arg_cmp_context(owner,
557+
(*a)->addr(i),
558+
(*b)->addr(i),
559+
set_null))
558560
return 1;
559561
}
560562
break;

sql/item_cmpfunc.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ class Arg_comparator: public Sql_alloc
7979
item_cmp_type((*a1)->cmp_type(),
8080
(*a2)->cmp_type()));
8181
}
82+
int set_cmp_func_and_arg_cmp_context(Item_func_or_sum *owner_arg,
83+
Item **a1, Item **a2,
84+
bool set_null_arg)
85+
{
86+
set_null= set_null_arg;
87+
Item_result type= item_cmp_type((*a1)->cmp_type(), (*a2)->cmp_type());
88+
int rc= set_cmp_func(owner_arg, a1, a2, type);
89+
if (!rc)
90+
(*a1)->cmp_context= (*a2)->cmp_context= type;
91+
return rc;
92+
}
8293
inline int compare() { return (this->*func)(); }
8394

8495
int compare_string(); // compare args[0] & args[1]

sql/sql_select.cc

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12513,7 +12513,6 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
1251312513
*/
1251412514

1251512515
static bool check_simple_equality(THD *thd, Item *left_item, Item *right_item,
12516-
const Item_bool_func *item,
1251712516
COND_EQUAL *cond_equal)
1251812517
{
1251912518
Item *orig_left_item= left_item;
@@ -12639,28 +12638,36 @@ static bool check_simple_equality(THD *thd, Item *left_item, Item *right_item,
1263912638
}
1264012639

1264112640
if (const_item &&
12642-
field_item->result_type() == const_item->result_type())
12641+
field_item->field->test_if_equality_guarantees_uniqueness(const_item))
1264312642
{
12643+
/*
12644+
field_item and const_item are arguments of a scalar or a row
12645+
comparison function:
12646+
WHERE column=constant
12647+
WHERE (column, ...) = (constant, ...)
12648+
12649+
The owner comparison function has previously called fix_fields(),
12650+
so field_item and const_item should be directly comparable items,
12651+
field_item->cmp_context and const_item->cmp_context should be set.
12652+
In case of string comparison, charsets and collations of
12653+
field_item and const_item should have already be aggregated
12654+
for comparison, all necessary character set converters installed
12655+
and fixed.
12656+
12657+
In case of string comparison, const_item can be either:
12658+
- a weaker constant that does not need to be converted to field_item:
12659+
WHERE latin1_field = 'latin1_const'
12660+
WHERE varbinary_field = 'latin1_const'
12661+
WHERE latin1_bin_field = 'latin1_general_ci_const'
12662+
- a stronger constant that does not need to be converted to field_item:
12663+
WHERE latin1_field = binary 0xDF
12664+
WHERE latin1_field = 'a' COLLATE latin1_bin
12665+
- a result of conversion (e.g. from the session character set)
12666+
to the character set of field_item:
12667+
WHERE latin1_field = 'utf8_string_with_latin1_repertoire'
12668+
*/
1264412669
bool copyfl;
1264512670

12646-
if (field_item->cmp_type() == STRING_RESULT)
12647-
{
12648-
CHARSET_INFO *cs= field_item->field->charset();
12649-
if (!item)
12650-
{
12651-
Item_func_eq *eq_item;
12652-
if (!(eq_item= new (thd->mem_root) Item_func_eq(thd, orig_left_item,
12653-
orig_right_item)) ||
12654-
eq_item->set_cmp_func_and_arg_cmp_context())
12655-
return FALSE;
12656-
eq_item->quick_fix_field();
12657-
item= eq_item;
12658-
}
12659-
if ((cs != item->compare_collation()) ||
12660-
!cs->coll->propagate(cs, 0, 0))
12661-
return FALSE;
12662-
}
12663-
1266412671
Item_equal *item_equal = find_item_equal(cond_equal,
1266512672
field_item->field, &copyfl);
1266612673
if (copyfl)
@@ -12737,7 +12744,7 @@ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row,
1273712744
}
1273812745
else
1273912746
{
12740-
is_converted= check_simple_equality(thd, left_item, right_item, 0,
12747+
is_converted= check_simple_equality(thd, left_item, right_item,
1274112748
cond_equal);
1274212749
}
1274312750

@@ -12799,7 +12806,7 @@ bool Item_func_eq::check_equality(THD *thd, COND_EQUAL *cond_equal,
1279912806
(Item_row *) right_item,
1280012807
cond_equal, eq_list);
1280112808
}
12802-
return check_simple_equality(thd, left_item, right_item, this, cond_equal);
12809+
return check_simple_equality(thd, left_item, right_item, cond_equal);
1280312810
}
1280412811

1280512812

@@ -15457,6 +15464,8 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
1545715464
/*
1545815465
psergey-todo: this returns false for int_column='1234' (here '1234' is a
1545915466
constant. Need to discuss this with Bar).
15467+
15468+
See also Field::test_if_equality_guaranees_uniqueness(const Item *item);
1546015469
*/
1546115470
static bool
1546215471
test_if_equality_guarantees_uniqueness(Item *l, Item *r)

0 commit comments

Comments
 (0)