Commit f6989d17 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-10865 COLLATE keyword doesn't work in PREPARE query

Fixing applying the COLLATE clause to a parameter caused an error error:
  COLLATION '...' is not valid for CHARACTER SET 'binary'

Fix:

- Changing the collation derivation for a non-prepared Item_param
  to DERIVATION_IGNORABLE.

- Allowing to apply any COLLATE clause to expressions with DERIVATION_IGNORABLE.
  This includes:
    1. A non-prepared Item_param
    2. An explicit NULL
    3. Expressions derived from #1 and #2

  For example:
    SELECT ? COLLATE utf8mb_unicode_ci;
    SELECT NULL COLLATE utf8mb_unicode_ci;
    SELECT CONCAT(?) COLLATE utf8mb_unicode_ci;
    SELECT CONCAT(NULL) COLLATE utf8mb_unicode_ci

- Additional change: preserving the collation of an expression when
  the expression gets assigned to a PS parameter and evaluates to SQL NULL.
  Before this change, the collation of the parameter was erroneously set
  to &my_charset_binary.

- Additional change: removing the multiplication to mbmaxlen from the
  fix_char_length_ulonglong() argument, because the multiplication already
  happens inside fix_char_length_ulonglong().
  This fixes a too large column size created for a COLLATE clause.
parent c91ec6a5
......@@ -3716,3 +3716,103 @@ DROP PROCEDURE p;
#
# End of 10.9 tests
#
#
# Start of 10.11 tests
#
#
# MDEV-10865 COLLATE keyword doesn't work in PREPARE query
#
SET NAMES utf8mb4;
#
# A context collation and an explicit NULL
#
SELECT NULL COLLATE uca1400_ai_ci;
ERROR HY000: 'NULL' is not allowed in this context
SELECT CONCAT(NULL) COLLATE uca1400_ai_ci;
ERROR HY000: 'NULL' is not allowed in this context
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT NULL COLLATE uca1400_ai_ci AS c1';
ERROR HY000: 'NULL' is not allowed in this context
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT CONCAT(NULL) COLLATE uca1400_ai_ci AS c1';
ERROR HY000: 'NULL' is not allowed in this context
#
# A context collation and a parameter bound to NULL
#
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING NULL;
ERROR HY000: 'NULL' is not allowed in this context
EXECUTE stmt USING CONCAT(NULL);
ERROR HY000: 'NULL' is not allowed in this context
EXECUTE stmt USING NULL COLLATE uca1400_ai_ci;
ERROR HY000: 'NULL' is not allowed in this context
EXECUTE stmt USING CONCAT(NULL) COLLATE uca1400_ai_ci;
ERROR HY000: 'NULL' is not allowed in this context
#
# A context collation and CONVERT(NULL USING ...)
#
EXECUTE stmt USING CONVERT(NULL USING utf8mb4);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` char(0) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
EXECUTE stmt USING CONVERT(NULL USING utf8mb4) COLLATE uca1400_ai_ci;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` char(0) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
EXECUTE stmt USING CONVERT(NULL USING binary);
ERROR 42000: COLLATION 'uca1400_ai_ci' is not valid for CHARACTER SET 'binary'
EXECUTE stmt USING CONVERT(NULL USING latin1);
ERROR 42000: COLLATION 'uca1400_ai_ci' is not valid for CHARACTER SET 'latin1'
#
# A context collation and an expression with a parameter
# whose character does not get resolved when bound to a not-NULL value
#
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT LEFT(NULL,?) COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING NULL;
ERROR HY000: 'NULL' is not allowed in this context
#
# A context collation and an expression with a parameter
# whose character set gets resolved when bound to a not-NULL value
#
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING 1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING _binary'test';
ERROR 42000: COLLATION 'uca1400_ai_ci' is not valid for CHARACTER SET 'binary'
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING 'test' COLLATE utf8mb4_bin;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING _latin1'test' COLLATE latin1_bin;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
#
# End of 10.11 tests
#
......@@ -401,3 +401,103 @@ DROP PROCEDURE p;
--echo #
--echo # End of 10.9 tests
--echo #
--echo #
--echo # Start of 10.11 tests
--echo #
--echo #
--echo # MDEV-10865 COLLATE keyword doesn't work in PREPARE query
--echo #
SET NAMES utf8mb4;
--echo #
--echo # A context collation and an explicit NULL
--echo #
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
SELECT NULL COLLATE uca1400_ai_ci;
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
SELECT CONCAT(NULL) COLLATE uca1400_ai_ci;
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT NULL COLLATE uca1400_ai_ci AS c1';
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT CONCAT(NULL) COLLATE uca1400_ai_ci AS c1';
--echo #
--echo # A context collation and a parameter bound to NULL
--echo #
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
EXECUTE stmt USING NULL;
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
EXECUTE stmt USING CONCAT(NULL);
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
EXECUTE stmt USING NULL COLLATE uca1400_ai_ci;
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
EXECUTE stmt USING CONCAT(NULL) COLLATE uca1400_ai_ci;
--echo #
--echo # A context collation and CONVERT(NULL USING ...)
--echo #
EXECUTE stmt USING CONVERT(NULL USING utf8mb4);
SHOW CREATE TABLE t1;
DROP TABLE t1;
EXECUTE stmt USING CONVERT(NULL USING utf8mb4) COLLATE uca1400_ai_ci;
SHOW CREATE TABLE t1;
DROP TABLE t1;
--error ER_COLLATION_CHARSET_MISMATCH
EXECUTE stmt USING CONVERT(NULL USING binary);
--error ER_COLLATION_CHARSET_MISMATCH
EXECUTE stmt USING CONVERT(NULL USING latin1);
--echo #
--echo # A context collation and an expression with a parameter
--echo # whose character does not get resolved when bound to a not-NULL value
--echo #
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT LEFT(NULL,?) COLLATE uca1400_ai_ci AS c1';
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
EXECUTE stmt USING NULL;
--echo #
--echo # A context collation and an expression with a parameter
--echo # whose character set gets resolved when bound to a not-NULL value
--echo #
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING 1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
--error ER_COLLATION_CHARSET_MISMATCH
EXECUTE stmt USING _binary'test';
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING 'test' COLLATE utf8mb4_bin;
SHOW CREATE TABLE t1;
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE uca1400_ai_ci AS c1';
EXECUTE stmt USING _latin1'test' COLLATE latin1_bin;
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # End of 10.11 tests
--echo #
......@@ -3024,3 +3024,88 @@ HEX(DATE_FORMAT(TIME'11:22:33',@format))
#
# End of 10.4 tests
#
#
# Start of 10.11 tests
#
#
# MDEV-10865 COLLATE keyword doesn't work in PREPARE query
#
#
# The collation is not applicable to the PS parameter
#
SET NAMES utf8mb4;
CREATE TABLE t1 (
c1 varchar(500) COLLATE utf32_unicode_ci NOT NULL
);
INSERT INTO t1 VALUES ('jj');
PREPARE stmt FROM 'SELECT * FROM t1 WHERE c1 LIKE ? COLLATE utf32_unicode_ci';
EXECUTE stmt USING 'jj';
ERROR 42000: COLLATION 'utf32_unicode_ci' is not valid for CHARACTER SET 'utf8mb4'
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE utf32_unicode_ci AS c1';
EXECUTE stmt USING 'test';
ERROR 42000: COLLATION 'utf32_unicode_ci' is not valid for CHARACTER SET 'utf8mb4'
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT CONCAT(?) COLLATE utf32_unicode_ci AS c1';
EXECUTE stmt USING 'test';
ERROR 42000: COLLATION 'utf32_unicode_ci' is not valid for CHARACTER SET 'utf8mb4'
CREATE TABLE t1 AS SELECT NULL COLLATE utf32_unicode_ci AS c1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` char(0) CHARACTER SET utf32 COLLATE utf32_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
CREATE TABLE t1 AS SELECT CONCAT(NULL) COLLATE utf32_unicode_ci AS c1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` char(0) CHARACTER SET utf32 COLLATE utf32_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
#
# The collation is applicable to the PS parameter
#
SET NAMES utf8mb4, collation_connection=utf32_general_ci;
CREATE TABLE t1 (
c1 varchar(500) COLLATE utf32_unicode_ci NOT NULL
);
INSERT INTO t1 VALUES ('jj');
PREPARE stmt FROM 'SELECT * FROM t1 WHERE c1 LIKE ? COLLATE utf32_unicode_ci';
EXECUTE stmt USING 'jj';
c1
jj
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE utf32_unicode_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(4) CHARACTER SET utf32 COLLATE utf32_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT CONCAT(?) COLLATE utf32_unicode_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(4) CHARACTER SET utf32 COLLATE utf32_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
CREATE TABLE t1 AS SELECT NULL COLLATE utf32_unicode_ci AS c1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` char(0) CHARACTER SET utf32 COLLATE utf32_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
CREATE TABLE t1 AS SELECT CONCAT(NULL) COLLATE utf32_unicode_ci AS c1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` char(0) CHARACTER SET utf32 COLLATE utf32_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
SET NAMES utf8mb4;
#
# End of 10.11 tests
#
......@@ -1167,4 +1167,80 @@ SELECT HEX(DATE_FORMAT(TIME'11:22:33',@format));
--echo # End of 10.4 tests
--echo #
--echo #
--echo # Start of 10.11 tests
--echo #
--echo #
--echo # MDEV-10865 COLLATE keyword doesn't work in PREPARE query
--echo #
--echo #
--echo # The collation is not applicable to the PS parameter
--echo #
SET NAMES utf8mb4;
CREATE TABLE t1 (
c1 varchar(500) COLLATE utf32_unicode_ci NOT NULL
);
INSERT INTO t1 VALUES ('jj');
PREPARE stmt FROM 'SELECT * FROM t1 WHERE c1 LIKE ? COLLATE utf32_unicode_ci';
--error ER_COLLATION_CHARSET_MISMATCH
EXECUTE stmt USING 'jj';
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE utf32_unicode_ci AS c1';
--error ER_COLLATION_CHARSET_MISMATCH
EXECUTE stmt USING 'test';
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT CONCAT(?) COLLATE utf32_unicode_ci AS c1';
--error ER_COLLATION_CHARSET_MISMATCH
EXECUTE stmt USING 'test';
CREATE TABLE t1 AS SELECT NULL COLLATE utf32_unicode_ci AS c1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT CONCAT(NULL) COLLATE utf32_unicode_ci AS c1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # The collation is applicable to the PS parameter
--echo #
SET NAMES utf8mb4, collation_connection=utf32_general_ci;
CREATE TABLE t1 (
c1 varchar(500) COLLATE utf32_unicode_ci NOT NULL
);
INSERT INTO t1 VALUES ('jj');
PREPARE stmt FROM 'SELECT * FROM t1 WHERE c1 LIKE ? COLLATE utf32_unicode_ci';
EXECUTE stmt USING 'jj';
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE utf32_unicode_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT CONCAT(?) COLLATE utf32_unicode_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT NULL COLLATE utf32_unicode_ci AS c1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT CONCAT(NULL) COLLATE utf32_unicode_ci AS c1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
SET NAMES utf8mb4;
--echo #
--echo # End of 10.11 tests
--echo #
--enable_service_connection
......@@ -4182,24 +4182,6 @@ DROP TABLE t1;
# End of 10.2 tests
#
#
# Start of 10.5 tests
#
#
# MDEV-24584 Selecting INT column with COLLATE utf8mb4_general_ci throws an error
#
SET NAMES utf8mb4;
SELECT 1 COLLATE utf8mb4_general_ci;
1 COLLATE utf8mb4_general_ci
1
SELECT 1 COLLATE utf8mb4_bin;
1 COLLATE utf8mb4_bin
1
SELECT 1 COLLATE latin1_swedish_ci;
ERROR 42000: COLLATION 'latin1_swedish_ci' is not valid for CHARACTER SET 'utf8mb4'
#
# End of 10.5 tests
#
#
# Start of 10.6 tests
#
#
......@@ -4227,3 +4209,67 @@ DROP TABLE t1;
#
# End of 10.6 tests
#
#
# Start of 10.11 tests
#
#
# MDEV-24584 Selecting INT column with COLLATE utf8mb4_general_ci throws an error
#
SET NAMES utf8mb4;
SELECT 1 COLLATE utf8mb4_general_ci;
1 COLLATE utf8mb4_general_ci
1
SELECT 1 COLLATE utf8mb4_bin;
1 COLLATE utf8mb4_bin
1
SELECT 1 COLLATE latin1_swedish_ci;
ERROR 42000: COLLATION 'latin1_swedish_ci' is not valid for CHARACTER SET 'utf8mb4'
#
# MDEV-10865 COLLATE keyword doesn't work in PREPARE query
#
SET NAMES utf8mb4;
CREATE TABLE t1 (
c1 varchar(500) COLLATE utf8mb4_unicode_ci NOT NULL
) CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO t1 VALUES ('jj');
SELECT * FROM t1 WHERE c1 LIKE 'jj' COLLATE utf8mb4_unicode_ci;
c1
jj
PREPARE stmt FROM 'SELECT * FROM t1 WHERE c1 LIKE ? COLLATE utf8mb4_unicode_ci';
EXECUTE stmt USING 'jj';
c1
jj
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE utf8mb4_unicode_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT CONCAT(?) COLLATE utf8mb4_unicode_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
CREATE TABLE t1 AS SELECT NULL COLLATE utf8mb4_unicode_ci AS c1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` char(0) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
CREATE TABLE t1 AS SELECT CONCAT(NULL) COLLATE utf8mb4_unicode_ci AS c1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` char(0) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
#
# End of 10.11 tests
#
......@@ -2068,25 +2068,6 @@ DROP TABLE t1;
--echo # End of 10.2 tests
--echo #
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-24584 Selecting INT column with COLLATE utf8mb4_general_ci throws an error
--echo #
SET NAMES utf8mb4;
SELECT 1 COLLATE utf8mb4_general_ci;
SELECT 1 COLLATE utf8mb4_bin;
--error ER_COLLATION_CHARSET_MISMATCH
SELECT 1 COLLATE latin1_swedish_ci;
--echo #
--echo # End of 10.5 tests
--echo #
--echo #
--echo # Start of 10.6 tests
--echo #
......@@ -2112,3 +2093,55 @@ DROP TABLE t1;
--echo #
--echo # End of 10.6 tests
--echo #
--echo #
--echo # Start of 10.11 tests
--echo #
--echo #
--echo # MDEV-24584 Selecting INT column with COLLATE utf8mb4_general_ci throws an error
--echo #
SET NAMES utf8mb4;
SELECT 1 COLLATE utf8mb4_general_ci;
SELECT 1 COLLATE utf8mb4_bin;
--error ER_COLLATION_CHARSET_MISMATCH
SELECT 1 COLLATE latin1_swedish_ci;
--echo #
--echo # MDEV-10865 COLLATE keyword doesn't work in PREPARE query
--echo #
SET NAMES utf8mb4;
CREATE TABLE t1 (
c1 varchar(500) COLLATE utf8mb4_unicode_ci NOT NULL
) CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO t1 VALUES ('jj');
SELECT * FROM t1 WHERE c1 LIKE 'jj' COLLATE utf8mb4_unicode_ci;
PREPARE stmt FROM 'SELECT * FROM t1 WHERE c1 LIKE ? COLLATE utf8mb4_unicode_ci';
EXECUTE stmt USING 'jj';
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT ? COLLATE utf8mb4_unicode_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT CONCAT(?) COLLATE utf8mb4_unicode_ci AS c1';
EXECUTE stmt USING 'test';
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT NULL COLLATE utf8mb4_unicode_ci AS c1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT CONCAT(NULL) COLLATE utf8mb4_unicode_ci AS c1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # End of 10.11 tests
--echo #
......@@ -4119,6 +4119,7 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg,
*/
set_maybe_null();
with_flags= with_flags | item_with_t::PARAM;
collation= DTCollation(&my_charset_bin, DERIVATION_IGNORABLE);
}
......@@ -4174,7 +4175,7 @@ void Item_param::sync_clones()
}
void Item_param::set_null()
void Item_param::set_null(const DTCollation &c)
{
DBUG_ENTER("Item_param::set_null");
/*
......@@ -4189,6 +4190,7 @@ void Item_param::set_null()
*/
max_length= 0;
decimals= 0;
collation= c;
state= NULL_VALUE;
DBUG_VOID_RETURN;
}
......@@ -4447,7 +4449,7 @@ bool Item_param::set_from_item(THD *thd, Item *item)
longlong val= item->val_int();
if (item->null_value)
{
set_null();
set_null(DTCollation_numeric());
DBUG_RETURN(false);
}
else
......@@ -4465,7 +4467,7 @@ bool Item_param::set_from_item(THD *thd, Item *item)
DBUG_RETURN(set_value(thd, item, &tmp, h));
}
else
set_null();
set_null_string(item->collation);
DBUG_RETURN(0);
}
......@@ -5048,7 +5050,7 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
if (arg->save_in_value(thd, &tmp) ||
set_value(thd, arg, &tmp, arg->type_handler()))
{
set_null();
set_null_string(arg->collation);
return false;
}
/* It is wrapper => other set_* shoud set null_value */
......
......@@ -4234,7 +4234,32 @@ class Item_param :public Item_basic_value,
void set_default();
void set_ignore();
void set_null();
void set_null(const DTCollation &c);
void set_null_string(const DTCollation &c)
{
/*
We need to distinguish explicit NULL (marked by DERIVATION_IGNORABLE)
from other item types:
- These statements should give an error, because
the character set of the bound parameter is not known:
EXECUTE IMMEDIATE "SELECT ? COLLATE utf8mb4_bin" USING NULL;
EXECUTE IMMEDIATE "SELECT ? COLLATE utf8mb4_bin" USING CONCAT(NULL);
- These statements should return a good result, because
the character set of the bound parameter is known:
EXECUTE IMMEDIATE "SELECT ? COLLATE utf8mb4_bin"
USING CONVERT(NULL USING utf8mb4);
EXECUTE IMMEDIATE "SELECT ? COLLATE utf8mb4_bin"
USING CAST(NULL AS CHAR CHARACTER SET utf8mb4);
*/
set_null(DTCollation(c.collation, MY_MAX(c.derivation,
DERIVATION_COERCIBLE)));
}
void set_null()
{
set_null(DTCollation(&my_charset_bin, DERIVATION_IGNORABLE));
}
void set_int(longlong i, uint32 max_length_arg);
void set_double(double i);
void set_decimal(const char *str, ulong length);
......
......@@ -3880,21 +3880,43 @@ String *Item_func_set_collation::val_str(String *str)
str=args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
/*
Let SCS be the character set of the source - args[0].
Let TCS be the character set of the target - i.e. the character set
of the collation specified in the COLLATE clause.
It's OK to return SQL NULL if SCS is not equal to TCS.
This is possible on the explicit NULL or expressions derived from
the explicit NULL:
SELECT NULL COLLATE utf8mb4_general_ci;
SELECT COALESCE(NULL) COLLATE utf8mb4_general_ci;
But for a non-NULL result SCS and TCS must be compatible:
1. Either SCS==TCS
2. Or SCS can be can be reinterpeted to TCS.
This scenario is possible when args[0] is numeric and TCS->mbmaxlen==1.
If SCS and TCS are not compatible here, then something went wrong during
fix_fields(), e.g. an Item_func_conv_charset was not added two wrap args[0].
*/
DBUG_ASSERT(my_charset_same(args[0]->collation.collation,
collation.collation) ||
(args[0]->collation.repertoire == MY_REPERTOIRE_ASCII &&
!(collation.collation->state & MY_CS_NONASCII)));
str->set_charset(collation.collation);
return str;
}
bool Item_func_set_collation::fix_length_and_dec(THD *thd)
{
if (agg_arg_charsets_for_string_result(collation, args, 1))
return true;
Lex_exact_charset_opt_extended_collate cl(collation.collation, true);
if (cl.merge_collation_override(m_set_collation))
if (agg_arg_charsets_for_string_result(collation, args, 1) ||
collation.merge_collation(m_set_collation,
args[0]->collation.repertoire,
with_param() &&
thd->lex->is_ps_or_view_context_analysis()))
return true;
collation.set(cl.collation().charset_info(), DERIVATION_EXPLICIT,
args[0]->collation.repertoire);
ulonglong max_char_length= (ulonglong) args[0]->max_char_length();
fix_char_length_ulonglong(max_char_length * collation.collation->mbmaxlen);
fix_char_length_ulonglong(max_char_length);
return FALSE;
}
......
......@@ -33,6 +33,88 @@ const DTCollation &DTCollation_numeric::singleton()
return tmp;
}
bool
DTCollation::merge_charset_and_collation(CHARSET_INFO *cs,
const Lex_extended_collation_st &cl,
my_repertoire_t repertoire)
{
Lex_exact_charset_opt_extended_collate cscl(cs, true);
if (cscl.merge_collation_override(cl))
return true;
set(cscl.collation().charset_info(), DERIVATION_EXPLICIT, repertoire);
return false;
}
bool DTCollation::merge_collation(const Lex_extended_collation_st &cl,
my_repertoire_t repertoire,
bool allow_ignorable_with_context_collation)
{
if (derivation != DERIVATION_IGNORABLE)
{
// A known character set + an extended collation
return merge_charset_and_collation(collation, cl, repertoire);
}
if (cl.type() == Lex_extended_collation::TYPE_EXACT)
{
/*
An unknown character set + an exact collation.
Just use this exact collation.
Examples:
- Expressions derived from an explicit NULL:
SELECT NULL COLLATE utf8mb4_general_ci;
SELECT CONCAT(NULL) COLLATE utf8mb4_general_ci;
Any collation is applicable to an explicit NULL.
- Expressions with PS parameters (at PREPARE time, not bound yet)
SELECT ? COLLATE utf8mb4_general_ci;
SELECT CONCAT(?) COLLATE utf8mb4_general_ci;
The collation will be checked for applicability to the
character set of the actual bound parameter at the EXECUTE time.
We're now in PREPARE: let's assume it will be applicable.
*/
set(cl.charset_info(), DERIVATION_EXPLICIT, repertoire);
return false;
}
// An unknown character set + a contextually typed collation
if (allow_ignorable_with_context_collation)
{
/*
Expressions with non-bound PS parameters, PREPARE time.
SELECT ? COLLATE uca1400_ai_ci;
SELECT CONCAT(?) COLLATE uca1400_ai_ci;
There is a chance the character set of the actual bound parameter
will be known at the EXECUTE time (unless an explicit NULL is bound).
For now let's use utf8mb4 to resolve collations like uca1400_ai_ci.
The real character set of the actual bound parameter expression will be
later used to resolve the collation again, during the EXECUTE time.
*/
return merge_charset_and_collation(&my_charset_utf8mb4_general_ci,
cl, repertoire);
}
/*
Expressions with an unknown character set:
- Either without PS parameters at all:
SELECT NULL COLLATE uca1400_ai_ci;
SELECT CONCAT(NULL) COLLATE uca1400_ai_ci;
- Or with PS parameters bound to NULL at EXECUTE time:
EXECUTE IMMEDIATE
'SELECT ? COLLATE uca1400_ai_ci' USING NULL;
EXECUTE IMMEDIATE
'SELECT CONCAT(?) COLLATE uca1400_ai_ci' USING NULL;
EXECUTE IMMEDIATE
'SELECT ? COLLATE uca1400_ai_ci' USING CONCAT(NULL);
*/
my_error(ER_NOT_ALLOWED_IN_THIS_CONTEXT, MYF(0), "NULL");
return true;
}
Named_type_handler<Type_handler_row> type_handler_row("row");
Named_type_handler<Type_handler_null> type_handler_null("null");
......
......@@ -3076,6 +3076,12 @@ class DTCollation {
bool aggregate(const DTCollation &dt, uint flags= 0);
bool set(DTCollation &dt1, DTCollation &dt2, uint flags= 0)
{ set(dt1); return aggregate(dt2, flags); }
bool merge_charset_and_collation(CHARSET_INFO *cs,
const Lex_extended_collation_st &cl,
my_repertoire_t repertoire);
bool merge_collation(const Lex_extended_collation_st &cl,
my_repertoire_t repertoire,
bool allow_ignorable_with_context_collation);
const char *derivation_name() const
{
switch(derivation)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment