Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 46 additions & 16 deletions mysql-test/suite/vcol/r/vcol_sargable.result
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,24 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE TBL ref vcol1 vcol1 5 const 1
explain select * from t1 where a+1<=2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range vcol1 vcol1 5 NULL 1 Using index condition
1 SIMPLE t1 ALL NULL NULL NULL NULL 100 Using where
Warnings:
Note 1105 Cannot substitute virtual column expression `t1`.`a` + 1 -> vcol1 due to failed supertype check
explain select * from t1 where a+1<2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range vcol1 vcol1 5 NULL 1 Using index condition
1 SIMPLE t1 ALL NULL NULL NULL NULL 100 Using where
Warnings:
Note 1105 Cannot substitute virtual column expression `t1`.`a` + 1 -> vcol1 due to failed supertype check
explain select * from t1 where a+1>100;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range vcol1 vcol1 5 NULL 6 Using index condition
1 SIMPLE t1 ALL NULL NULL NULL NULL 100 Using where
Warnings:
Note 1105 Cannot substitute virtual column expression `t1`.`a` + 1 -> vcol1 due to failed supertype check
explain select * from t1 where a+1>=100;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range vcol1 vcol1 5 NULL 13 Using index condition
1 SIMPLE t1 ALL NULL NULL NULL NULL 100 Using where
Warnings:
Note 1105 Cannot substitute virtual column expression `t1`.`a` + 1 -> vcol1 due to failed supertype check
explain select * from t1 where a+1 between 10 and 12;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range vcol1 vcol1 5 NULL 2 Using index condition
Expand Down Expand Up @@ -150,7 +158,7 @@ explain select * from t3 where concat('100', a)=10010;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 ALL NULL NULL NULL NULL 100 Using where
Warnings:
Note 1105 Cannot substitute virtual column expression concat('100',`t3`.`a`) -> vcol1 due to type mismatch
Note 1105 Cannot substitute virtual column expression concat('100',`t3`.`a`) -> vcol1 due to collation mismatch
# Character set change
explain select * from t3 where concat('hello-', a)='abcd';
id select_type table type possible_keys key key_len ref rows Extra
Expand Down Expand Up @@ -182,9 +190,20 @@ a js1 size1 color
2 {"size":2, "color":"hue2"} 2 hue2
3 {"size":3, "color":"hue3"} 3 hue3
# Index is used:
## TODO: actually does not work because
## capacity_limit_is_in_characters() returns false for
## the expression with type mediumtext, and true for
## Item_string 'hue5'
## set collation_connection so that the constant string has the
## correct collation
set @old_collation_connection=@@collation_connection;
set collation_connection=utf8mb4_bin;
explain select * from t1 where json_unquote(json_extract(js1, '$.color'))='hue5';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref color color 403 const 1 Using index condition
1 SIMPLE t1 ALL NULL NULL NULL NULL 100 Using where
Warnings:
Note 1105 Cannot substitute virtual column expression json_unquote(json_extract(`t1`.`js1`,'$.color')) -> color due to failed supertype check
set collation_connection=@old_collation_connection;
explain select * from t1 where json_unquote(json_extract(js1, '$.color')) IS NULL;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref color color 403 const 1 Using index condition
Expand Down Expand Up @@ -228,12 +247,18 @@ select collation(json_value(js1, '$.color')) from t1 limit 1;
collation(json_value(js1, '$.color'))
utf8mb4_bin
# If one is fine with _bin comparisons, they can use index access:
## same problem with capacity_limit_is_in_characters
alter table t1
add color1 varchar(100) collate utf8mb4_bin as (json_value(js1, '$.color')),
add index(color1);
set @old_collation_connection=@@collation_connection;
set collation_connection=utf8mb4_bin;
explain select * from t1 where json_value(js1, '$.color')='hue10';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref color1 color1 403 const 1 Using index condition
1 SIMPLE t1 ALL NULL NULL NULL NULL 100 Using where
Warnings:
Note 1105 Cannot substitute virtual column expression json_value(`t1`.`js1`,'$.color') -> color1 due to failed supertype check
set collation_connection=@old_collation_connection;
alter table t1 drop column color1;
# Using different collation in column substitution prevents
# the optimization from working:
Expand All @@ -247,19 +272,26 @@ Warnings:
Note 1105 Cannot substitute virtual column expression json_value(`t1`.`js1`,'$.color') -> color2 due to collation mismatch
alter table t1 drop column color2;
# Explicitly specifying the collation helps:
## TODO: same problem with capacity_limit_is_in_characters
alter table t1
add color3 varchar(100) collate utf8mb4_unicode_ci as
(json_value(js1, '$.color') collate utf8mb4_unicode_ci),
add index(color3);
set @old_collation_connection=@@collation_connection;
set collation_connection=utf8mb4_unicode_ci;
explain select * from t1
where
json_value(js1, '$.color') collate utf8mb4_unicode_ci='hue10';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref color3 color3 403 const 1 Using index condition
1 SIMPLE t1 ALL NULL NULL NULL NULL 100 Using where
Warnings:
Note 1105 Cannot substitute virtual column expression json_value(`t1`.`js1`,'$.color') collate utf8mb4_unicode_ci -> color3 due to failed supertype check
set collation_connection=@old_collation_connection;
#
# Alternatively, one can store JSON in a column with the same
# collation as default and then casts are not needed:
#
## TODO: same problem with capacity_limit_is_in_characters
create table t2(
js1 longtext COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL CHECK (json_valid(`js1`))
);
Expand All @@ -271,7 +303,9 @@ explain select * from t2
where
json_value(js1, '$.color')='hue10';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref color3 color3 403 const 1 Using index condition
1 SIMPLE t2 ALL NULL NULL NULL NULL 100 Using where
Warnings:
Note 1105 Cannot substitute virtual column expression json_value(`t2`.`js1`,'$.color') -> color3 due to failed supertype check
drop table t1,t2;
#
# Test interplay with sargable_casefold optimization:
Expand Down Expand Up @@ -387,16 +421,12 @@ EXPLAIN
"table": {
"delete": 1,
"table_name": "t1",
"access_type": "range",
"possible_keys": ["a1"],
"key": "a1",
"key_length": "5",
"used_key_parts": ["a1"],
"access_type": "ALL",
"rows": 2,
"attached_condition": "t1.a1 > 'a'"
"attached_condition": "t1.v2 + t1.v3 > 'a'"
}
}
}
Warnings:
Warning 1292 Truncated incorrect DECIMAL value: 'a'
Note 1105 Cannot substitute virtual column expression `t1`.`v2` + `t1`.`v3` -> a1 due to failed supertype check
drop table t1;
19 changes: 19 additions & 0 deletions mysql-test/suite/vcol/t/vcol_sargable.test
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,17 @@ alter table t1 add index(color);
select * from t1 limit 3;

--echo # Index is used:
--echo ## TODO: actually does not work because
--echo ## capacity_limit_is_in_characters() returns false for
--echo ## the expression with type mediumtext, and true for
--echo ## Item_string 'hue5'

--echo ## set collation_connection so that the constant string has the
--echo ## correct collation
set @old_collation_connection=@@collation_connection;
set collation_connection=utf8mb4_bin;
explain select * from t1 where json_unquote(json_extract(js1, '$.color'))='hue5';
set collation_connection=@old_collation_connection;
explain select * from t1 where json_unquote(json_extract(js1, '$.color')) IS NULL;
explain select * from t1 force index(color)
where json_unquote(json_extract(js1, '$.color')) IS NOT NULL;
Expand Down Expand Up @@ -162,10 +172,14 @@ select * from t1 where size1=10;
select collation(json_value(js1, '$.color')) from t1 limit 1;

--echo # If one is fine with _bin comparisons, they can use index access:
--echo ## same problem with capacity_limit_is_in_characters
alter table t1
add color1 varchar(100) collate utf8mb4_bin as (json_value(js1, '$.color')),
add index(color1);
set @old_collation_connection=@@collation_connection;
set collation_connection=utf8mb4_bin;
explain select * from t1 where json_value(js1, '$.color')='hue10';
set collation_connection=@old_collation_connection;
alter table t1 drop column color1;

--echo # Using different collation in column substitution prevents
Expand All @@ -178,18 +192,23 @@ alter table t1 drop column color2;


--echo # Explicitly specifying the collation helps:
--echo ## TODO: same problem with capacity_limit_is_in_characters
alter table t1
add color3 varchar(100) collate utf8mb4_unicode_ci as
(json_value(js1, '$.color') collate utf8mb4_unicode_ci),
add index(color3);
set @old_collation_connection=@@collation_connection;
set collation_connection=utf8mb4_unicode_ci;
explain select * from t1
where
json_value(js1, '$.color') collate utf8mb4_unicode_ci='hue10';
set collation_connection=@old_collation_connection;

--echo #
--echo # Alternatively, one can store JSON in a column with the same
--echo # collation as default and then casts are not needed:
--echo #
--echo ## TODO: same problem with capacity_limit_is_in_characters
create table t2(
js1 longtext COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL CHECK (json_valid(`js1`))
);
Expand Down
8 changes: 8 additions & 0 deletions sql/field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11600,6 +11600,14 @@ void Field::raise_note_cannot_use_key_part(THD *thd,
}
}

bool Field::is_supertype(Item *item) const
{
return type_handler()->is_supertype(type_std_attributes(),
type_extra_attributes(),
item->type_handler(),
*item /*Type_std_attributes*/,
item->type_extra_attributes());
}

/*
Give warning for unusable key
Expand Down
1 change: 1 addition & 0 deletions sql/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -1776,6 +1776,7 @@ class Field: public Value_source
const Data_type_compatibility reason)
const;
void raise_note_key_become_unused(THD *thd, const String &expr) const;
bool is_supertype(Item *item) const;
protected:
bool set_warning(unsigned int code, int cuted_increment) const
{
Expand Down
8 changes: 8 additions & 0 deletions sql/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -2854,6 +2854,14 @@ class Item :public Value_source,
DBUG_ASSERT(fixed());
return false;
}
bool is_supertype(Item *item) const
{
return type_handler()->is_supertype(*this /*Type_std_attributes*/,
type_extra_attributes(),
item->type_handler(),
*item /*Type_std_attributes*/,
item->type_extra_attributes());
}

protected:
/*
Expand Down
77 changes: 46 additions & 31 deletions sql/opt_vcol_substitution.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ static
void subst_vcol_if_compatible(Vcol_subst_context *ctx,
Item_bool_func *cond,
Item **vcol_expr_ref,
Field *vcol_field);
Field *vcol_field,
bool skip_supertype_check= false);

static
bool collect_indexed_vcols_for_table(TABLE *table, List<Field> *vcol_fields)
Expand Down Expand Up @@ -440,41 +441,29 @@ static
void subst_vcol_if_compatible(Vcol_subst_context *ctx,
Item_bool_func *cond,
Item **vcol_expr_ref,
Field *vcol_field)
Field *vcol_field,
bool skip_supertype_check)
{
Item *vcol_expr= *vcol_expr_ref;
THD *thd= ctx->thd;

const char *fail_cause= NULL;
if (cond) /* WHERE substitution (MDEV-39525) */
if (cond)
{
if (vcol_expr->type_handler_for_comparison() !=
vcol_field->type_handler_for_comparison() ||
(vcol_expr->maybe_null() && !vcol_field->maybe_null()))
fail_cause="type mismatch";
else
{
CHARSET_INFO *cs= cond ? cond->compare_collation() : NULL;
if (vcol_expr->collation.collation != vcol_field->charset() &&
cs != vcol_field->charset())
fail_cause= "collation mismatch";
}
if (vcol_expr->collation.collation != vcol_field->charset() &&
cond->compare_collation() != vcol_field->charset())
fail_cause= "collation mismatch";
}
else /* ORDER/GROUP BY substitution */
if (!fail_cause && !skip_supertype_check &&
!vcol_field->is_supertype(vcol_expr))
{
if (!vcol_field->type_handler()->is_supertype(
vcol_field->type_std_attributes(),
vcol_field->type_extra_attributes(),
vcol_expr->type_handler(),
*vcol_expr /*Type_std_attributes*/,
vcol_expr->type_extra_attributes()))
fail_cause="failed supertype check";
else if (vcol_expr->maybe_null() && !vcol_field->maybe_null())
{
/* NOT NULL is not allowed for vcol definition */
DBUG_ASSERT(0);
fail_cause= "nullability mismatch";
}
}
if (!fail_cause && vcol_expr->maybe_null() && !vcol_field->maybe_null())
{
/* NOT NULL is not allowed for vcol definition */
DBUG_ASSERT(0);
fail_cause= "nullability mismatch";
}

if (fail_cause)
Expand Down Expand Up @@ -530,25 +519,41 @@ bool Item::vcol_subst_analyzer(uchar **)
(((Item_func*)this)->bitmap_bit() & allowed_cmp_funcs))); // (2)
}

static bool vcol_type_both_bounded(Field *vcol_field, Item *vcol_expr, Item *rhs)
{
return vcol_field->is_supertype(rhs) && vcol_expr->is_supertype(rhs);
}

Item* Item_bool_rowready_func2::vcol_subst_transformer(THD *thd, uchar *arg)
{
DBUG_ASSERT(this->vcol_subst_analyzer(NULL));
Vcol_subst_context *ctx= (Vcol_subst_context*)arg;
Field *vcol_field;
Item **vcol_expr;
Item *other= NULL;

if (!args[0]->used_tables() && (vcol_field= is_vcol_expr(ctx, args[1])))
{
vcol_expr= &args[1];
if (functype() == EQ_FUNC)
other= args[0];
}
else if (!args[1]->used_tables() && (vcol_field= is_vcol_expr(ctx, args[0])))
{
vcol_expr= &args[0];
if (functype() == EQ_FUNC)
other= args[1];
}
else
return this; /* No substitution */

DBUG_EXECUTE_IF("vcol_subst_simulate_oom",
DBUG_SET("+d,simulate_out_of_memory"););

subst_vcol_if_compatible(ctx, this, vcol_expr, vcol_field);
if (other && vcol_type_both_bounded(vcol_field, *vcol_expr, other))
subst_vcol_if_compatible(ctx, this, vcol_expr, vcol_field, true);
else
subst_vcol_if_compatible(ctx, this, vcol_expr, vcol_field, false);

DBUG_EXECUTE_IF("vcol_subst_simulate_oom",
DBUG_SET("-d,vcol_subst_simulate_oom"););
Expand All @@ -564,7 +569,11 @@ Item* Item_func_between::vcol_subst_transformer(THD *thd, uchar *arg)
!args[2]->used_tables() &&
(vcol_field= is_vcol_expr(ctx, args[0])))
{
subst_vcol_if_compatible(ctx, this, &args[0], vcol_field);
if (vcol_type_both_bounded(vcol_field, args[0], args[1]) &&
vcol_type_both_bounded(vcol_field, args[0], args[2]))
subst_vcol_if_compatible(ctx, this, &args[0], vcol_field, true);
else
subst_vcol_if_compatible(ctx, this, &args[0], vcol_field, false);
}
return this;
}
Expand All @@ -575,7 +584,7 @@ Item* Item_func_null_predicate::vcol_subst_transformer(THD *thd, uchar *arg)
Vcol_subst_context *ctx= (Vcol_subst_context*)arg;
Field *vcol_field;
if ((vcol_field= is_vcol_expr(ctx, args[0])))
subst_vcol_if_compatible(ctx, this, &args[0], vcol_field);
subst_vcol_if_compatible(ctx, this, &args[0], vcol_field, true);
return this;
}

Expand All @@ -584,6 +593,7 @@ Item* Item_func_in::vcol_subst_transformer(THD *thd, uchar *arg)
{
Vcol_subst_context *ctx= (Vcol_subst_context*)arg;
Field *vcol_field= nullptr;
uint i= 1;

/*
Check that the left hand side of IN() is a virtual column expression and
Expand All @@ -592,8 +602,13 @@ Item* Item_func_in::vcol_subst_transformer(THD *thd, uchar *arg)
if (!(vcol_field= is_vcol_expr(ctx, args[0])) ||
!compatible_types_scalar_bisection_possible())
return this;
for (; i < arg_count; i++)
{
if (!vcol_type_both_bounded(vcol_field, args[0], args[i]))
break;
}

subst_vcol_if_compatible(ctx, this, &args[0], vcol_field);
subst_vcol_if_compatible(ctx, this, &args[0], vcol_field, i == arg_count);
return this;
}