Skip to content

Commit ed3a54d

Browse files
Chaithra Gopalareddydahlerlend
authored andcommitted
Bug#36246859: Collation issue: ERROR 1253 (42000): COLLATION ''
is not valid for CHARACTER SET Condition pushdown to a view fails with a collation mismatch if the view was created with a different charset than the charset used when querying the view. Problem is seen if the underlying fields in the view are literals with COLLATE statements. The string literal with the COLLATE statement is cloned when replacing expressions in the condition that is being pushed down with the expressions from the view. The string literal is currently parsed with the connection charset which in this case is different from the one that was used when the view was created. Therefore the COLLATE statement fails. Creation context for a view has the connection charset and collation information which was used when the view was created. This is currently used for parsing the view when it is later queried. We use the same now when cloning expressions from a view during condition pushdown. Change-Id: Ib040b9a67ddedd5fb9bf5de6fafafb358226e9d9
1 parent 13ed097 commit ed3a54d

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

mysql-test/r/derived_condition_pushdown.result

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2429,6 +2429,16 @@ SELECT * FROM (SELECT * FROM v1 UNION SELECT * FROM v1) as dt
24292429
WHERE field1 IN ('A');
24302430
field1
24312431
A
2432+
EXPLAIN FORMAT=tree SELECT * FROM v1
2433+
WHERE field1 IN ('C') OR
2434+
COALESCE('A' COLLATE utf8mb4_spanish_ci IN ('B'), field1);
2435+
EXPLAIN
2436+
-> Zero rows (no matching row in const table) (rows=0)
2437+
2438+
SELECT * FROM v1
2439+
WHERE field1 IN ('C') OR
2440+
COALESCE('A' COLLATE utf8mb4_spanish_ci IN ('B'), field1);
2441+
field1
24322442
DROP VIEW v1;
24332443
SET character_set_client = latin1;
24342444
SET character_set_connection = latin1;

mysql-test/t/derived_condition_pushdown.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,10 @@ SELECT 'B' COLLATE latin1_spanish_ci AS field1 FROM t1 AS t2;
15891589

15901590
# Use a different charset now to query the view.
15911591
SET character_set_connection = default;
1592+
# Condition pushdown to view "v1" should happen
1593+
# without any errors as it now uses the view's
1594+
# connection context when "field1" is replaced
1595+
# with "'A' COLLATE latin1_spanish_ci".
15921596
let $query = SELECT * FROM v1 WHERE field1 IN ('C');
15931597
--replace_regex $elide_costs
15941598
--skip_if_hypergraph # Depends on the query plan.
@@ -1600,6 +1604,17 @@ let $query = SELECT * FROM (SELECT * FROM v1 UNION SELECT * FROM v1) as dt
16001604
--skip_if_hypergraph # Depends on the query plan.
16011605
eval EXPLAIN FORMAT=tree $query;
16021606
eval $query;
1607+
# view context of "v1" is not used when cloning the condition
1608+
# "field1 IN ('C') OR COALESCE('A' COLLATE utf8mb4_spanish_ci IN ('B'), field1)"
1609+
# to be pushed down in case of SET operations. It is used only when
1610+
# "field1" is replaced with "'A' COLLATE latin1_spanish_ci".
1611+
let $query = SELECT * FROM v1
1612+
WHERE field1 IN ('C') OR
1613+
COALESCE('A' COLLATE utf8mb4_spanish_ci IN ('B'), field1);
1614+
--replace_regex $elide_costs
1615+
--skip_if_hypergraph # Depends on the query plan.
1616+
eval EXPLAIN FORMAT=tree $query;
1617+
eval $query;
16031618
DROP VIEW v1;
16041619

16051620
#Simplified repro

sql/sql_derived.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,9 @@ bool copy_field_info(THD *thd, Item *orig_expr, Item *cloned_expr) {
606606
@param item Item to be reparsed to get a clone.
607607
@param query_block query block where expression is being parsed
608608
@param derived_table derived table to which the item belongs to.
609+
"nullptr" when cloning to make a copy of the
610+
original condition to be pushed down
611+
to a derived table that has SET operations.
609612
610613
@returns A copy of the original item (unresolved) on success else nullptr.
611614
*/
@@ -678,8 +681,9 @@ static Item *parse_expression(THD *thd, Item *item, Query_block *query_block,
678681

679682
// Get a newly created item from parser. Use the view creation
680683
// context if the item being parsed is part of a view.
681-
const bool result =
682-
parse_sql(thd, &parser_state, derived_table->view_creation_ctx);
684+
View_creation_ctx *view_creation_ctx =
685+
derived_table != nullptr ? derived_table->view_creation_ctx : nullptr;
686+
const bool result = parse_sql(thd, &parser_state, view_creation_ctx);
683687

684688
// If a statement is being re-prepared, then all the parameters
685689
// that are cloned above need to be synced with the original
@@ -1122,7 +1126,7 @@ bool Condition_pushdown::make_cond_for_derived() {
11221126
if (derived_query_expression->is_set_operation()) {
11231127
m_cond_to_push =
11241128
derived_query_expression->outer_query_block()->clone_expression(
1125-
thd, orig_cond_to_push, m_derived_table);
1129+
thd, orig_cond_to_push, /*derived_table=*/nullptr);
11261130
if (m_cond_to_push == nullptr) return true;
11271131
m_cond_to_push->apply_is_true();
11281132
}

0 commit comments

Comments
 (0)