1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-04 01:23:45 +03:00

parser cleanup: don't store field properties in LEX, use Create_field directly

length/dec/charset are still in LEX, because they're also used
for CAST and dynamic columns.

also
1. fix "MDEV-7041 COLLATION(CAST('a' AS CHAR BINARY)) returns a wrong result"
2. allow BINARY modifier in stored function RETURN clause
3. allow "COLLATION without CHARSET" in SP/SF (parameters, RETURN, DECLARE)
4. print correct variable name in error messages for stored routine parameters
This commit is contained in:
Sergei Golubchik
2014-11-08 17:37:19 +01:00
parent d1522af72d
commit 227510e039
30 changed files with 573 additions and 664 deletions

View File

@ -796,3 +796,26 @@ DATE("foo")
NULL NULL
Warnings: Warnings:
Warning 1292 Incorrect datetime value: 'foo' Warning 1292 Incorrect datetime value: 'foo'
create table t1 (a int, b char(5) as (cast("a" as char(10) binary) + a) );
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` char(5) AS (cast("a" as char(10) binary) + a) VIRTUAL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select collation(cast("a" as char(10) binary));
collation(cast("a" as char(10) binary))
latin1_bin
select collation(cast("a" as char(10) charset utf8 binary));
collation(cast("a" as char(10) charset utf8 binary))
utf8_bin
select collation(cast("a" as char(10) ascii binary));
collation(cast("a" as char(10) ascii binary))
latin1_bin
select collation(cast("a" as char(10) binary charset utf8));
collation(cast("a" as char(10) binary charset utf8))
utf8_bin
select collation(cast("a" as char(10) binary ascii));
collation(cast("a" as char(10) binary ascii))
latin1_bin

View File

@ -5535,3 +5535,12 @@ a aa
# #
# End of 10.0 tests # End of 10.0 tests
# #
select collation(cast("a" as char(10) unicode binary));
collation(cast("a" as char(10) unicode binary))
ucs2_bin
select collation(cast("a" as char(10) binary unicode));
collation(cast("a" as char(10) binary unicode))
ucs2_bin
#
# End of 10.1 tests
#

View File

@ -1411,7 +1411,7 @@ end|
ERROR 0A000: Not allowed to return a result set from a function ERROR 0A000: Not allowed to return a result set from a function
drop function if exists bug20701; drop function if exists bug20701;
create function bug20701() returns varchar(25) binary return "test"; create function bug20701() returns varchar(25) binary return "test";
ERROR 42000: This version of MariaDB doesn't yet support 'return value collation' drop function bug20701;
create function bug20701() returns varchar(25) return "test"; create function bug20701() returns varchar(25) return "test";
drop function bug20701; drop function bug20701;
create procedure proc_26503_error_1() create procedure proc_26503_error_1()

View File

@ -106,20 +106,20 @@ RETURNS VARCHAR(64) CHARACTER SET ucs2
BEGIN BEGIN
RETURN 'str'; RETURN 'str';
END| END|
ERROR 42000: This version of MariaDB doesn't yet support 'COLLATE with no CHARACTER SET in SP parameters, RETURNS, DECLARE' ERROR 42000: COLLATION 'ucs2_unicode_ci' is not valid for CHARACTER SET 'latin1'
CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2) CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2)
RETURNS VARCHAR(64) COLLATE ucs2_unicode_ci RETURNS VARCHAR(64) COLLATE ucs2_unicode_ci
BEGIN BEGIN
RETURN 'str'; RETURN 'str';
END| END|
ERROR 42000: This version of MariaDB doesn't yet support 'COLLATE with no CHARACTER SET in SP parameters, RETURNS, DECLARE' ERROR 42000: COLLATION 'ucs2_unicode_ci' is not valid for CHARACTER SET 'latin1'
CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2) CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2)
RETURNS VARCHAR(64) CHARACTER SET ucs2 RETURNS VARCHAR(64) CHARACTER SET ucs2
BEGIN BEGIN
DECLARE f2 VARCHAR(64) COLLATE ucs2_unicode_ci; DECLARE f2 VARCHAR(64) COLLATE ucs2_unicode_ci;
RETURN 'str'; RETURN 'str';
END| END|
ERROR 42000: This version of MariaDB doesn't yet support 'COLLATE with no CHARACTER SET in SP parameters, RETURNS, DECLARE' ERROR 42000: COLLATION 'ucs2_unicode_ci' is not valid for CHARACTER SET 'latin1'
SET NAMES utf8; SET NAMES utf8;
DROP FUNCTION IF EXISTS bug48766; DROP FUNCTION IF EXISTS bug48766;
CREATE FUNCTION bug48766 () CREATE FUNCTION bug48766 ()

View File

@ -3548,7 +3548,10 @@ begin
set f1= concat( 'hello', f1 ); set f1= concat( 'hello', f1 );
return f1; return f1;
end| end|
ERROR 42000: This version of MariaDB doesn't yet support 'return value collation' select collation(bug9048("foo"))|
collation(bug9048("foo"))
latin1_bin
drop function bug9048|
drop procedure if exists bug12849_1| drop procedure if exists bug12849_1|
create procedure bug12849_1(inout x char) select x into x| create procedure bug12849_1(inout x char) select x into x|
set @var='a'| set @var='a'|
@ -7858,3 +7861,22 @@ v1
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP TABLE t1; DROP TABLE t1;
# End of 5.5 test # End of 5.5 test
CREATE FUNCTION f(f1 VARCHAR(64) COLLATE latin1_german2_ci)
RETURNS VARCHAR(64)
BEGIN
RETURN 'str';
END|
DROP FUNCTION f|
CREATE FUNCTION f(f1 VARCHAR(64))
RETURNS VARCHAR(64) COLLATE latin1_german2_ci
BEGIN
RETURN 'str';
END|
DROP FUNCTION f|
CREATE FUNCTION f(f1 VARCHAR(64))
RETURNS VARCHAR(64)
BEGIN
DECLARE f2 VARCHAR(64) COLLATE latin1_german2_ci;
RETURN 'str';
END|
DROP FUNCTION f|

View File

@ -142,7 +142,7 @@ BEGIN
SET @v1 = f1; SET @v1 = f1;
SELECT @v1; SELECT @v1;
END// END//
ERROR 42000: Too big precision 256 specified for ''. Maximum is 65. ERROR 42000: Too big precision 256 specified for 'f1'. Maximum is 65.
DROP PROCEDURE IF EXISTS sp1// DROP PROCEDURE IF EXISTS sp1//
Warnings: Warnings:
Note 1305 PROCEDURE db_storedproc.sp1 does not exist Note 1305 PROCEDURE db_storedproc.sp1 does not exist
@ -152,7 +152,7 @@ BEGIN
SET @v1 = f1; SET @v1 = f1;
SELECT @v1; SELECT @v1;
END// END//
ERROR 42000: Too big precision 66 specified for ''. Maximum is 65. ERROR 42000: Too big precision 66 specified for 'f1'. Maximum is 65.
DROP PROCEDURE IF EXISTS sp1// DROP PROCEDURE IF EXISTS sp1//
Warnings: Warnings:
Note 1305 PROCEDURE db_storedproc.sp1 does not exist Note 1305 PROCEDURE db_storedproc.sp1 does not exist
@ -1407,12 +1407,12 @@ BEGIN
SELECT f1; SELECT f1;
END// END//
Warnings: Warnings:
Note 1291 Column '' has duplicated value 'value1' in ENUM Note 1291 Column 'f1' has duplicated value 'value1' in ENUM
CALL sp1( "value1" ); CALL sp1( "value1" );
f1 f1
value1 value1
Warnings: Warnings:
Note 1291 Column '' has duplicated value 'value1' in ENUM Note 1291 Column 'f1' has duplicated value 'value1' in ENUM
SHOW PROCEDURE STATUS WHERE db = 'db_storedproc'; SHOW PROCEDURE STATUS WHERE db = 'db_storedproc';
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
db_storedproc sp1 PROCEDURE root@localhost <modified> <created> INVOKER this is simple latin1 latin1_swedish_ci latin1_swedish_ci db_storedproc sp1 PROCEDURE root@localhost <modified> <created> INVOKER this is simple latin1 latin1_swedish_ci latin1_swedish_ci
@ -1423,12 +1423,12 @@ BEGIN
SELECT f1; SELECT f1;
END// END//
Warnings: Warnings:
Note 1291 Column '' has duplicated value 'value1' in SET Note 1291 Column 'f1' has duplicated value 'value1' in SET
CALL sp1( "value1, value1" ); CALL sp1( "value1, value1" );
f1 f1
value1 value1
Warnings: Warnings:
Note 1291 Column '' has duplicated value 'value1' in SET Note 1291 Column 'f1' has duplicated value 'value1' in SET
Warning 1265 Data truncated for column 'f1' at row 1 Warning 1265 Data truncated for column 'f1' at row 1
SHOW PROCEDURE STATUS WHERE db = 'db_storedproc'; SHOW PROCEDURE STATUS WHERE db = 'db_storedproc';
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
@ -1440,12 +1440,12 @@ BEGIN
SELECT f1; SELECT f1;
END// END//
Warnings: Warnings:
Note 1291 Column '' has duplicated value 'value1' in ENUM Note 1291 Column 'f1' has duplicated value 'value1' in ENUM
CALL sp1( "value1" ); CALL sp1( "value1" );
f1 f1
value1 value1
Warnings: Warnings:
Note 1291 Column '' has duplicated value 'value1' in ENUM Note 1291 Column 'f1' has duplicated value 'value1' in ENUM
SHOW PROCEDURE STATUS WHERE db = 'db_storedproc'; SHOW PROCEDURE STATUS WHERE db = 'db_storedproc';
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
db_storedproc sp1 PROCEDURE root@localhost <modified> <created> INVOKER this is simple latin1 latin1_swedish_ci latin1_swedish_ci db_storedproc sp1 PROCEDURE root@localhost <modified> <created> INVOKER this is simple latin1 latin1_swedish_ci latin1_swedish_ci
@ -1548,7 +1548,7 @@ BEGIN
SET f1 = 1000000 + f1; SET f1 = 1000000 + f1;
RETURN f1; RETURN f1;
END// END//
ERROR 42000: Too big scale 31 specified for ''. Maximum is 30. ERROR 42000: Too big scale 31 specified for 'f1'. Maximum is 30.
SELECT fn1( 1.3326e+8 ); SELECT fn1( 1.3326e+8 );
ERROR 42000: FUNCTION db_storedproc.fn1 does not exist ERROR 42000: FUNCTION db_storedproc.fn1 does not exist
CREATE FUNCTION fn1( f1 DECIMAL(63, 30) ) RETURNS DECIMAL(63, 30) CREATE FUNCTION fn1( f1 DECIMAL(63, 30) ) RETURNS DECIMAL(63, 30)
@ -1570,7 +1570,7 @@ BEGIN
RETURN f1; RETURN f1;
END// END//
Warnings: Warnings:
Note 1291 Column '' has duplicated value 'value1' in ENUM Note 1291 Column 'f1' has duplicated value 'value1' in ENUM
SELECT fn1( "value1" ); SELECT fn1( "value1" );
fn1( "value1" ) fn1( "value1" )
1.000000000000000000000000000000 1.000000000000000000000000000000
@ -1584,7 +1584,7 @@ BEGIN
RETURN f1; RETURN f1;
END// END//
Warnings: Warnings:
Note 1291 Column '' has duplicated value 'value1' in SET Note 1291 Column 'f1' has duplicated value 'value1' in SET
SELECT fn1( "value1, value1" ); SELECT fn1( "value1, value1" );
fn1( "value1, value1" ) fn1( "value1, value1" )
1.000000000000000000000000000000 1.000000000000000000000000000000
@ -3119,10 +3119,7 @@ return f1;
DROP FUNCTION IF EXISTS fn1; DROP FUNCTION IF EXISTS fn1;
CREATE FUNCTION fn1(f1 char binary ) returns char binary CREATE FUNCTION fn1(f1 char binary ) returns char binary
return f1; return f1;
ERROR 42000: This version of MariaDB doesn't yet support 'return value collation'
DROP FUNCTION IF EXISTS fn1; DROP FUNCTION IF EXISTS fn1;
Warnings:
Note 1305 FUNCTION db_storedproc.fn1 does not exist
CREATE FUNCTION fn1(f1 char ascii ) returns char ascii CREATE FUNCTION fn1(f1 char ascii ) returns char ascii
return f1; return f1;
DROP FUNCTION IF EXISTS fn1; DROP FUNCTION IF EXISTS fn1;
@ -5836,7 +5833,7 @@ fetch cur1 into e;
SELECT x, y, z, a, b, c, d, e; SELECT x, y, z, a, b, c, d, e;
close cur1; close cur1;
END// END//
ERROR 42000: Too big scale 255 specified for ''. Maximum is 30. ERROR 42000: Too big scale 255 specified for 'b'. Maximum is 30.
CALL sp6(); CALL sp6();
ERROR 42000: PROCEDURE db_storedproc.sp6 does not exist ERROR 42000: PROCEDURE db_storedproc.sp6 does not exist
DROP PROCEDURE IF EXISTS sp6; DROP PROCEDURE IF EXISTS sp6;

View File

@ -2155,7 +2155,6 @@ CREATE FUNCTION fn1(f1 char ) returns char
return f1; return f1;
DROP FUNCTION IF EXISTS fn1; DROP FUNCTION IF EXISTS fn1;
--error ER_NOT_SUPPORTED_YET
CREATE FUNCTION fn1(f1 char binary ) returns char binary CREATE FUNCTION fn1(f1 char binary ) returns char binary
return f1; return f1;

View File

@ -456,3 +456,19 @@ SELECT CAST(TIME('10:20:30') AS DATE) + INTERVAL 1 DAY;
SET SQL_MODE=ALLOW_INVALID_DATES; SET SQL_MODE=ALLOW_INVALID_DATES;
SELECT DATE("foo"); SELECT DATE("foo");
#
# CAST and field definition using same fields in LEX
#
create table t1 (a int, b char(5) as (cast("a" as char(10) binary) + a) );
show create table t1;
drop table t1;
#
# CAST (... BINARY)
#
select collation(cast("a" as char(10) binary));
select collation(cast("a" as char(10) charset utf8 binary));
select collation(cast("a" as char(10) ascii binary));
select collation(cast("a" as char(10) binary charset utf8));
select collation(cast("a" as char(10) binary ascii));

View File

@ -914,7 +914,16 @@ SELECT CONCAT(CONVERT('pi=' USING ucs2),PI()) AS PI;
SET NAMES utf8, character_set_connection=ucs2; SET NAMES utf8, character_set_connection=ucs2;
SELECT 'a','aa'; SELECT 'a','aa';
--echo # --echo #
--echo # End of 10.0 tests --echo # End of 10.0 tests
--echo # --echo #
#
# CAST (... BINARY)
#
select collation(cast("a" as char(10) unicode binary));
select collation(cast("a" as char(10) binary unicode));
--echo #
--echo # End of 10.1 tests
--echo #

View File

@ -2051,13 +2051,8 @@ delimiter ;|
--disable_warnings --disable_warnings
drop function if exists bug20701; drop function if exists bug20701;
--enable_warnings --enable_warnings
#
# This was disabled in 5.1.12. See bug #20701
# When collation support in SP is implemented, then this test should
# be removed.
#
--error ER_NOT_SUPPORTED_YET
create function bug20701() returns varchar(25) binary return "test"; create function bug20701() returns varchar(25) binary return "test";
drop function bug20701;
create function bug20701() returns varchar(25) return "test"; create function bug20701() returns varchar(25) return "test";
drop function bug20701; drop function bug20701;

View File

@ -114,7 +114,7 @@ DROP FUNCTION f1|
# #
# COLLATE with no CHARACTER SET in IN param # COLLATE with no CHARACTER SET in IN param
# #
--error ER_NOT_SUPPORTED_YET --error ER_COLLATION_CHARSET_MISMATCH
CREATE FUNCTION f(f1 VARCHAR(64) COLLATE ucs2_unicode_ci) CREATE FUNCTION f(f1 VARCHAR(64) COLLATE ucs2_unicode_ci)
RETURNS VARCHAR(64) CHARACTER SET ucs2 RETURNS VARCHAR(64) CHARACTER SET ucs2
BEGIN BEGIN
@ -125,7 +125,7 @@ END|
# #
# COLLATE with no CHARACTER SET in RETURNS # COLLATE with no CHARACTER SET in RETURNS
# #
--error ER_NOT_SUPPORTED_YET --error ER_COLLATION_CHARSET_MISMATCH
CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2) CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2)
RETURNS VARCHAR(64) COLLATE ucs2_unicode_ci RETURNS VARCHAR(64) COLLATE ucs2_unicode_ci
BEGIN BEGIN
@ -136,7 +136,7 @@ END|
# #
# COLLATE with no CHARACTER SET in DECLARE # COLLATE with no CHARACTER SET in DECLARE
# #
--error ER_NOT_SUPPORTED_YET --error ER_COLLATION_CHARSET_MISMATCH
CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2) CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2)
RETURNS VARCHAR(64) CHARACTER SET ucs2 RETURNS VARCHAR(64) CHARACTER SET ucs2
BEGIN BEGIN

View File

@ -4355,17 +4355,14 @@ begin
return f1; return f1;
end| end|
drop function bug9048| drop function bug9048|
#
# This was disabled in 5.1.12. See bug #20701
# When collation support in SP is implemented, then this test should
# be removed.
#
--error ER_NOT_SUPPORTED_YET
create function bug9048(f1 char binary) returns char binary create function bug9048(f1 char binary) returns char binary
begin begin
set f1= concat( 'hello', f1 ); set f1= concat( 'hello', f1 );
return f1; return f1;
end| end|
select collation(bug9048("foo"))|
drop function bug9048|
# Bug #12849 Stored Procedure: Crash on procedure call with CHAR type # Bug #12849 Stored Procedure: Crash on procedure call with CHAR type
# 'INOUT' parameter # 'INOUT' parameter
@ -9303,3 +9300,27 @@ DROP PROCEDURE p1;
DROP TABLE t1; DROP TABLE t1;
--echo # End of 5.5 test --echo # End of 5.5 test
DELIMITER |;
CREATE FUNCTION f(f1 VARCHAR(64) COLLATE latin1_german2_ci)
RETURNS VARCHAR(64)
BEGIN
RETURN 'str';
END|
DROP FUNCTION f|
CREATE FUNCTION f(f1 VARCHAR(64))
RETURNS VARCHAR(64) COLLATE latin1_german2_ci
BEGIN
RETURN 'str';
END|
DROP FUNCTION f|
CREATE FUNCTION f(f1 VARCHAR(64))
RETURNS VARCHAR(64)
BEGIN
DECLARE f2 VARCHAR(64) COLLATE latin1_german2_ci;
RETURN 'str';
END|
DROP FUNCTION f|
DELIMITER ;|

View File

@ -9163,96 +9163,100 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg,
} }
/** static inline bool is_item_func(Item* x)
Initialize field definition for create.
@param thd Thread handle
@param fld_name Field name
@param fld_type Field type
@param fld_length Field length
@param fld_decimals Decimal (if any)
@param fld_type_modifier Additional type information
@param fld_default_value Field default value (if any)
@param fld_on_update_value The value of ON UPDATE clause
@param fld_comment Field comment
@param fld_change Field change
@param fld_interval_list Interval list (if any)
@param fld_charset Field charset
@param fld_geom_type Field geometry type (if any)
@param fld_vcol_info Virtual column data
@retval
FALSE on success
@retval
TRUE on error
*/
bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
char *fld_length, char *fld_decimals,
uint fld_type_modifier, Item *fld_default_value,
Item *fld_on_update_value, LEX_STRING *fld_comment,
char *fld_change, List<String> *fld_interval_list,
CHARSET_INFO *fld_charset, uint fld_geom_type,
Virtual_column_info *fld_vcol_info,
engine_option_value *create_opt, bool check_exists)
{ {
return x != NULL && x->type() == Item::FUNC_ITEM;
}
bool Create_field::check(THD *thd)
{
const uint conditional_type_modifiers= AUTO_INCREMENT_FLAG;
uint sign_len, allowed_type_modifier= 0; uint sign_len, allowed_type_modifier= 0;
ulong max_field_charlength= MAX_FIELD_CHARLENGTH; ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
const bool on_update_is_function= DBUG_ENTER("Create_field::check");
(fld_on_update_value != NULL &&
fld_on_update_value->type() == Item::FUNC_ITEM);
DBUG_ENTER("Create_field::init()"); if (vcol_info)
{
vcol_info->set_field_type(sql_type);
sql_type= (enum enum_field_types)MYSQL_TYPE_VIRTUAL;
}
field= 0; if (length > MAX_FIELD_BLOBLENGTH)
field_name= fld_name; {
flags= fld_type_modifier; my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, MAX_FIELD_BLOBLENGTH);
option_list= create_opt; DBUG_RETURN(1);
}
if (fld_default_value != NULL && fld_default_value->type() == Item::FUNC_ITEM) if (decimals >= NOT_FIXED_DEC)
{
my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, field_name,
static_cast<ulong>(NOT_FIXED_DEC - 1));
DBUG_RETURN(TRUE);
}
if (def)
{
/*
Default value should be literal => basic constants =>
no need fix_fields()
We allow only one function as part of default value -
NOW() as default for TIMESTAMP and DATETIME type.
*/
if (def->type() == Item::FUNC_ITEM &&
(static_cast<Item_func*>(def)->functype() != Item_func::NOW_FUNC ||
(mysql_type_to_time_type(sql_type) != MYSQL_TIMESTAMP_DATETIME) ||
def->decimals < length))
{
my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
DBUG_RETURN(1);
}
else if (def->type() == Item::NULL_ITEM)
{
def= 0;
if ((flags & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == NOT_NULL_FLAG)
{
my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
DBUG_RETURN(1);
}
}
else if (flags & AUTO_INCREMENT_FLAG)
{
my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
DBUG_RETURN(1);
}
}
if (is_item_func(def))
{ {
/* There is a function default for insertions. */ /* There is a function default for insertions. */
def= NULL; def= NULL;
unireg_check= (on_update_is_function ? unireg_check= (is_item_func(on_update) ?
Field::TIMESTAMP_DNUN_FIELD : // for insertions and for updates. Field::TIMESTAMP_DNUN_FIELD : // for insertions and for updates.
Field::TIMESTAMP_DN_FIELD); // only for insertions. Field::TIMESTAMP_DN_FIELD); // only for insertions.
} }
else else
{ {
/* No function default for insertions. Either NULL or a constant. */ /* No function default for insertions. Either NULL or a constant. */
def= fld_default_value; if (is_item_func(on_update))
if (on_update_is_function)
unireg_check= Field::TIMESTAMP_UN_FIELD; // function default for updates unireg_check= Field::TIMESTAMP_UN_FIELD; // function default for updates
else else
unireg_check= ((fld_type_modifier & AUTO_INCREMENT_FLAG) != 0 ? unireg_check= ((flags & AUTO_INCREMENT_FLAG) ?
Field::NEXT_NUMBER : // Automatic increment. Field::NEXT_NUMBER : // Automatic increment.
Field::NONE); Field::NONE);
} }
decimals= fld_decimals ? (uint)atoi(fld_decimals) : 0; if (on_update &&
if (decimals >= NOT_FIXED_DEC) (mysql_type_to_time_type(sql_type) != MYSQL_TIMESTAMP_DATETIME ||
on_update->decimals < length))
{ {
my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, fld_name, my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
static_cast<ulong>(NOT_FIXED_DEC - 1)); DBUG_RETURN(1);
DBUG_RETURN(TRUE);
} }
sql_type= fld_type;
length= 0;
change= fld_change;
interval= 0;
pack_length= key_length= 0;
charset= fld_charset;
geom_type= (Field::geometry_type) fld_geom_type;
interval_list.empty();
comment= *fld_comment;
vcol_info= fld_vcol_info;
create_if_not_exists= check_exists;
stored_in_db= TRUE;
/* Initialize data for a computed field */ /* Initialize data for a computed field */
if ((uchar)fld_type == (uchar)MYSQL_TYPE_VIRTUAL) if (sql_type == MYSQL_TYPE_VIRTUAL)
{ {
DBUG_ASSERT(vcol_info && vcol_info->expr_item); DBUG_ASSERT(vcol_info && vcol_info->expr_item);
stored_in_db= vcol_info->is_stored(); stored_in_db= vcol_info->is_stored();
@ -9272,56 +9276,42 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
Field::vcol_info. It is is always NULL for a column that is not Field::vcol_info. It is is always NULL for a column that is not
computed. computed.
*/ */
sql_type= fld_type= vcol_info->get_real_type(); sql_type= vcol_info->get_real_type();
} }
/* /*
Set NO_DEFAULT_VALUE_FLAG if this field doesn't have a default value and Set NO_DEFAULT_VALUE_FLAG if this field doesn't have a default value and
it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP. it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP.
*/ */
if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) && if (!def && unireg_check == Field::NONE &&
(fld_type_modifier & NOT_NULL_FLAG) && !is_timestamp_type(fld_type)) (flags & NOT_NULL_FLAG) && !is_timestamp_type(sql_type))
flags|= NO_DEFAULT_VALUE_FLAG; flags|= NO_DEFAULT_VALUE_FLAG;
if (fld_length != NULL) sign_len= flags & UNSIGNED_FLAG ? 0 : 1;
{
errno= 0;
length= strtoul(fld_length, NULL, 10);
if ((errno != 0) || (length > MAX_FIELD_BLOBLENGTH))
{
my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name, MAX_FIELD_BLOBLENGTH);
DBUG_RETURN(TRUE);
}
if (length == 0) switch (sql_type) {
fld_length= NULL; /* purecov: inspected */
}
sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;
switch (fld_type) {
case MYSQL_TYPE_TINY: case MYSQL_TYPE_TINY:
if (!fld_length) if (!length)
length= MAX_TINYINT_WIDTH+sign_len; length= MAX_TINYINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG; allowed_type_modifier= AUTO_INCREMENT_FLAG;
break; break;
case MYSQL_TYPE_SHORT: case MYSQL_TYPE_SHORT:
if (!fld_length) if (!length)
length= MAX_SMALLINT_WIDTH+sign_len; length= MAX_SMALLINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG; allowed_type_modifier= AUTO_INCREMENT_FLAG;
break; break;
case MYSQL_TYPE_INT24: case MYSQL_TYPE_INT24:
if (!fld_length) if (!length)
length= MAX_MEDIUMINT_WIDTH+sign_len; length= MAX_MEDIUMINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG; allowed_type_modifier= AUTO_INCREMENT_FLAG;
break; break;
case MYSQL_TYPE_LONG: case MYSQL_TYPE_LONG:
if (!fld_length) if (!length)
length= MAX_INT_WIDTH+sign_len; length= MAX_INT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG; allowed_type_modifier= AUTO_INCREMENT_FLAG;
break; break;
case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_LONGLONG:
if (!fld_length) if (!length)
length= MAX_BIGINT_WIDTH; length= MAX_BIGINT_WIDTH;
allowed_type_modifier= AUTO_INCREMENT_FLAG; allowed_type_modifier= AUTO_INCREMENT_FLAG;
break; break;
@ -9331,18 +9321,17 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
my_decimal_trim(&length, &decimals); my_decimal_trim(&length, &decimals);
if (length > DECIMAL_MAX_PRECISION) if (length > DECIMAL_MAX_PRECISION)
{ {
my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast<int>(length), my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name,
fld_name, static_cast<ulong>(DECIMAL_MAX_PRECISION)); DECIMAL_MAX_PRECISION);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
if (length < decimals) if (length < decimals)
{ {
my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name); my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
length= length=
my_decimal_precision_to_length(length, decimals, my_decimal_precision_to_length(length, decimals, flags & UNSIGNED_FLAG);
fld_type_modifier & UNSIGNED_FLAG);
pack_length= pack_length=
my_decimal_get_binary_size(length, decimals); my_decimal_get_binary_size(length, decimals);
break; break;
@ -9360,11 +9349,11 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_GEOMETRY: case MYSQL_TYPE_GEOMETRY:
if (fld_default_value) if (def)
{ {
/* Allow empty as default value. */ /* Allow empty as default value. */
String str,*res; String str,*res;
res= fld_default_value->val_str(&str); res= def->val_str(&str);
/* /*
A default other than '' is always an error, and any non-NULL A default other than '' is always an error, and any non-NULL
specified default is an error in strict mode. specified default is an error in strict mode.
@ -9372,7 +9361,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
if (res->length() || thd->is_strict_mode()) if (res->length() || thd->is_strict_mode())
{ {
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
fld_name); /* purecov: inspected */ field_name); /* purecov: inspected */
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
else else
@ -9383,39 +9372,21 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_BLOB_CANT_HAVE_DEFAULT, ER_BLOB_CANT_HAVE_DEFAULT,
ER(ER_BLOB_CANT_HAVE_DEFAULT), ER(ER_BLOB_CANT_HAVE_DEFAULT),
fld_name); field_name);
} }
def= 0; def= 0;
} }
flags|= BLOB_FLAG; flags|= BLOB_FLAG;
break; break;
case MYSQL_TYPE_YEAR: case MYSQL_TYPE_YEAR:
if (!fld_length || length != 2) if (!length || length != 2)
length= 4; /* Default length */ length= 4; /* Default length */
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
break; break;
case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_FLOAT:
/* change FLOAT(precision) to FLOAT or DOUBLE */ /* change FLOAT(precision) to FLOAT or DOUBLE */
allowed_type_modifier= AUTO_INCREMENT_FLAG; allowed_type_modifier= AUTO_INCREMENT_FLAG;
if (fld_length && !fld_decimals) if (!length && !decimals)
{
uint tmp_length= length;
if (tmp_length > PRECISION_FOR_DOUBLE)
{
my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
DBUG_RETURN(TRUE);
}
else if (tmp_length > PRECISION_FOR_FLOAT)
{
sql_type= MYSQL_TYPE_DOUBLE;
length= MAX_DOUBLE_STR_LENGTH;
}
else
length= MAX_FLOAT_STR_LENGTH;
decimals= NOT_FIXED_DEC;
break;
}
if (!fld_length && !fld_decimals)
{ {
length= MAX_FLOAT_STR_LENGTH; length= MAX_FLOAT_STR_LENGTH;
decimals= NOT_FIXED_DEC; decimals= NOT_FIXED_DEC;
@ -9423,13 +9394,13 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
if (length < decimals && if (length < decimals &&
decimals != NOT_FIXED_DEC) decimals != NOT_FIXED_DEC)
{ {
my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name); my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
break; break;
case MYSQL_TYPE_DOUBLE: case MYSQL_TYPE_DOUBLE:
allowed_type_modifier= AUTO_INCREMENT_FLAG; allowed_type_modifier= AUTO_INCREMENT_FLAG;
if (!fld_length && !fld_decimals) if (!length && !decimals)
{ {
length= DBL_DIG+7; length= DBL_DIG+7;
decimals= NOT_FIXED_DEC; decimals= NOT_FIXED_DEC;
@ -9437,7 +9408,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
if (length < decimals && if (length < decimals &&
decimals != NOT_FIXED_DEC) decimals != NOT_FIXED_DEC)
{ {
my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name); my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
break; break;
@ -9445,7 +9416,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
case MYSQL_TYPE_TIMESTAMP2: case MYSQL_TYPE_TIMESTAMP2:
if (length > MAX_DATETIME_PRECISION) if (length > MAX_DATETIME_PRECISION)
{ {
my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name, my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name,
MAX_DATETIME_PRECISION); MAX_DATETIME_PRECISION);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
@ -9463,7 +9434,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
case MYSQL_TYPE_TIME2: case MYSQL_TYPE_TIME2:
if (length > MAX_DATETIME_PRECISION) if (length > MAX_DATETIME_PRECISION)
{ {
my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name, my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name,
MAX_DATETIME_PRECISION); MAX_DATETIME_PRECISION);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
@ -9473,50 +9444,29 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
case MYSQL_TYPE_DATETIME2: case MYSQL_TYPE_DATETIME2:
if (length > MAX_DATETIME_PRECISION) if (length > MAX_DATETIME_PRECISION)
{ {
my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name, my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name,
MAX_DATETIME_PRECISION); MAX_DATETIME_PRECISION);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
length+= MAX_DATETIME_WIDTH + (length ? 1 : 0); length+= MAX_DATETIME_WIDTH + (length ? 1 : 0);
break; break;
case MYSQL_TYPE_SET: case MYSQL_TYPE_SET:
{ pack_length= get_set_pack_length(interval_list.elements);
pack_length= get_set_pack_length(fld_interval_list->elements); break;
List_iterator<String> it(*fld_interval_list);
String *tmp;
while ((tmp= it++))
interval_list.push_back(tmp);
/*
Set fake length to 1 to pass the below conditions.
Real length will be set in mysql_prepare_table()
when we know the character set of the column
*/
length= 1;
break;
}
case MYSQL_TYPE_ENUM: case MYSQL_TYPE_ENUM:
{ /* Should be safe. */
/* Should be safe. */ pack_length= get_enum_pack_length(interval_list.elements);
pack_length= get_enum_pack_length(fld_interval_list->elements); break;
List_iterator<String> it(*fld_interval_list);
String *tmp;
while ((tmp= it++))
interval_list.push_back(tmp);
length= 1; /* See comment for MYSQL_TYPE_SET above. */
break;
}
case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VAR_STRING:
DBUG_ASSERT(0); /* Impossible. */ DBUG_ASSERT(0); /* Impossible. */
break; break;
case MYSQL_TYPE_BIT: case MYSQL_TYPE_BIT:
{ {
if (!fld_length) if (!length)
length= 1; length= 1;
if (length > MAX_BIT_FIELD_LENGTH) if (length > MAX_BIT_FIELD_LENGTH)
{ {
my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name, my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name,
static_cast<ulong>(MAX_BIT_FIELD_LENGTH)); static_cast<ulong>(MAX_BIT_FIELD_LENGTH));
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
@ -9525,37 +9475,35 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
} }
case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_DECIMAL:
DBUG_ASSERT(0); /* Was obsolete */ DBUG_ASSERT(0); /* Was obsolete */
} }
/* Remember the value of length */ /* Remember the value of length */
char_length= length; char_length= length;
if (!(flags & BLOB_FLAG) && if (!(flags & BLOB_FLAG) &&
((length > max_field_charlength && fld_type != MYSQL_TYPE_SET && ((length > max_field_charlength &&
fld_type != MYSQL_TYPE_ENUM && (sql_type != MYSQL_TYPE_VARCHAR || def)) ||
(fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) || (length == 0 &&
((length == 0) && sql_type != MYSQL_TYPE_ENUM && sql_type != MYSQL_TYPE_SET &&
fld_type != MYSQL_TYPE_STRING && sql_type != MYSQL_TYPE_STRING && sql_type != MYSQL_TYPE_VARCHAR &&
fld_type != MYSQL_TYPE_VARCHAR && fld_type != MYSQL_TYPE_GEOMETRY))) sql_type != MYSQL_TYPE_GEOMETRY)))
{ {
my_error((fld_type == MYSQL_TYPE_VAR_STRING || my_error((sql_type == MYSQL_TYPE_VAR_STRING ||
fld_type == MYSQL_TYPE_VARCHAR || sql_type == MYSQL_TYPE_VARCHAR ||
fld_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH : sql_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH :
ER_TOO_BIG_DISPLAYWIDTH, ER_TOO_BIG_DISPLAYWIDTH,
MYF(0), MYF(0),
fld_name, max_field_charlength); /* purecov: inspected */ field_name, max_field_charlength); /* purecov: inspected */
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
fld_type_modifier&= AUTO_INCREMENT_FLAG; if ((~allowed_type_modifier) & flags & conditional_type_modifiers)
if ((~allowed_type_modifier) & fld_type_modifier)
{ {
my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name); my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
DBUG_RETURN(FALSE); /* success */ DBUG_RETURN(FALSE); /* success */
} }
enum_field_types get_blob_type_from_length(ulong length) enum_field_types get_blob_type_from_length(ulong length)
{ {
enum_field_types type; enum_field_types type;

View File

@ -2835,13 +2835,13 @@ public:
const char *change; // If done with alter table const char *change; // If done with alter table
const char *after; // Put column after this one const char *after; // Put column after this one
LEX_STRING comment; // Comment for field LEX_STRING comment; // Comment for field
Item *def; // Default value Item *def, *on_update; // Default value
enum enum_field_types sql_type; enum enum_field_types sql_type;
/* /*
At various stages in execution this can be length of field in bytes or At various stages in execution this can be length of field in bytes or
max number of characters. max number of characters.
*/ */
ulong length; ulonglong length;
/* /*
The value of `length' as set by parser: is the number of characters The value of `length' as set by parser: is the number of characters
for most of the types, or of bytes for BLOBs or numeric types. for most of the types, or of bytes for BLOBs or numeric types.
@ -2877,9 +2877,13 @@ public:
*/ */
bool stored_in_db; bool stored_in_db;
Create_field() :after(0), option_list(NULL), option_struct(NULL), Create_field() :after(0), pack_length(0), key_length(0), interval(0),
create_if_not_exists(FALSE) field(0), option_list(NULL), option_struct(NULL),
{} create_if_not_exists(false), stored_in_db(true)
{
interval_list.empty();
}
Create_field(Field *field, Field *orig_field); Create_field(Field *field, Field *orig_field);
/* Used to make a clone of this object for ALTER/CREATE TABLE */ /* Used to make a clone of this object for ALTER/CREATE TABLE */
Create_field *clone(MEM_ROOT *mem_root) const; Create_field *clone(MEM_ROOT *mem_root) const;
@ -2891,12 +2895,7 @@ public:
bool maybe_null, bool is_unsigned, bool maybe_null, bool is_unsigned,
uint pack_length = ~0U); uint pack_length = ~0U);
bool init(THD *thd, char *field_name, enum_field_types type, char *length, bool check(THD *thd);
char *decimals, uint type_modifier, Item *default_value,
Item *on_update_value, LEX_STRING *comment, char *change,
List<String> *interval_list, CHARSET_INFO *cs,
uint uint_geom_type, Virtual_column_info *vcol_info,
engine_option_value *option_list, bool check_exists);
bool field_flags_are_binary() bool field_flags_are_binary()
{ {

View File

@ -53,13 +53,12 @@ static const char* item_name(Item *a, String *str)
static void wrong_precision_error(uint errcode, Item *a, static void wrong_precision_error(uint errcode, Item *a,
ulonglong number, ulong maximum) ulonglong number, uint maximum)
{ {
char buff[1024]; char buff[1024];
String buf(buff, sizeof(buff), system_charset_info); String buf(buff, sizeof(buff), system_charset_info);
my_error(errcode, MYF(0), (uint) MY_MIN(number, UINT_MAX32), my_error(errcode, MYF(0), number, item_name(a, &buf), maximum);
item_name(a, &buf), maximum);
} }
@ -87,9 +86,9 @@ bool get_length_and_scale(ulonglong length, ulonglong decimals,
return 1; return 1;
} }
*out_length= (ulong) length;
*out_decimals= (uint) decimals; *out_decimals= (uint) decimals;
my_decimal_trim(out_length, out_decimals); my_decimal_trim(&length, out_decimals);
*out_length= (ulong) length;
if (*out_length < *out_decimals) if (*out_length < *out_decimals)
{ {

View File

@ -1628,8 +1628,8 @@ bool Item_func_curtime::fix_fields(THD *thd, Item **items)
{ {
if (decimals > TIME_SECOND_PART_DIGITS) if (decimals > TIME_SECOND_PART_DIGITS)
{ {
my_error(ER_TOO_BIG_PRECISION, MYF(0), decimals, func_name(), my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast<ulonglong>(decimals),
TIME_SECOND_PART_DIGITS); func_name(), TIME_SECOND_PART_DIGITS);
return 1; return 1;
} }
return Item_timefunc::fix_fields(thd, items); return Item_timefunc::fix_fields(thd, items);
@ -1690,8 +1690,8 @@ bool Item_func_now::fix_fields(THD *thd, Item **items)
{ {
if (decimals > TIME_SECOND_PART_DIGITS) if (decimals > TIME_SECOND_PART_DIGITS)
{ {
my_error(ER_TOO_BIG_PRECISION, MYF(0), decimals, func_name(), my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast<ulonglong>(decimals),
TIME_SECOND_PART_DIGITS); func_name(), TIME_SECOND_PART_DIGITS);
return 1; return 1;
} }
return Item_temporal_func::fix_fields(thd, items); return Item_temporal_func::fix_fields(thd, items);

View File

@ -335,7 +335,7 @@ my_decimal *date2my_decimal(MYSQL_TIME *ltime, my_decimal *dec)
} }
void my_decimal_trim(ulong *precision, uint *scale) void my_decimal_trim(ulonglong *precision, uint *scale)
{ {
if (!(*precision) && !(*scale)) if (!(*precision) && !(*scale))
{ {

View File

@ -486,7 +486,7 @@ int my_decimal_intg(const my_decimal *a)
} }
void my_decimal_trim(ulong *precision, uint *scale); void my_decimal_trim(ulonglong *precision, uint *scale);
#endif /*my_decimal_h*/ #endif /*my_decimal_h*/

View File

@ -5472,8 +5472,8 @@ ER_TOO_BIG_SCALE 42000 S1009
eng "Too big scale %u specified for '%-.192s'. Maximum is %lu." eng "Too big scale %u specified for '%-.192s'. Maximum is %lu."
ger "Zu großer Skalierungsfaktor %u für '%-.192s' angegeben. Maximum ist %lu" ger "Zu großer Skalierungsfaktor %u für '%-.192s' angegeben. Maximum ist %lu"
ER_TOO_BIG_PRECISION 42000 S1009 ER_TOO_BIG_PRECISION 42000 S1009
eng "Too big precision %u specified for '%-.192s'. Maximum is %lu." eng "Too big precision %llu specified for '%-.192s'. Maximum is %u."
ger "Zu große Genauigkeit %u für '%-.192s' angegeben. Maximum ist %lu" ger "Zu große Genauigkeit %llu für '%-.192s' angegeben. Maximum ist %u"
ER_M_BIGGER_THAN_D 42000 S1009 ER_M_BIGGER_THAN_D 42000 S1009
eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s')." eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s')."
ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.192s')" ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.192s')"

View File

@ -2216,16 +2216,6 @@ sp_head::reset_lex(THD *thd)
sublex->trg_table_fields.empty(); sublex->trg_table_fields.empty();
sublex->sp_lex_in_use= FALSE; sublex->sp_lex_in_use= FALSE;
/* Reset type info. */
sublex->charset= NULL;
sublex->length= NULL;
sublex->dec= NULL;
sublex->interval_list.empty();
sublex->type= 0;
sublex->uint_geom_type= 0;
sublex->vcol_info= 0;
/* Reset part of parser state which needs this. */ /* Reset part of parser state which needs this. */
thd->m_parser_state->m_yacc.reset_before_substatement(); thd->m_parser_state->m_yacc.reset_before_substatement();
@ -2351,16 +2341,9 @@ sp_head::fill_field_definition(THD *thd, LEX *lex,
enum enum_field_types field_type, enum enum_field_types field_type,
Create_field *field_def) Create_field *field_def)
{ {
LEX_STRING cmt = { 0, 0 };
uint unused1= 0; uint unused1= 0;
if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec, if (field_def->check(thd))
lex->type, (Item*) 0, (Item*) 0, &cmt, 0,
&lex->interval_list,
lex->charset ? lex->charset :
thd->variables.collation_database,
lex->uint_geom_type,
lex->vcol_info, NULL, FALSE))
return TRUE; return TRUE;
if (field_def->interval_list.elements) if (field_def->interval_list.elements)

View File

@ -183,13 +183,10 @@ sp_variable *sp_pcontext::find_variable(uint offset) const
} }
sp_variable *sp_pcontext::add_variable(THD *thd, sp_variable *sp_pcontext::add_variable(THD *thd, LEX_STRING name)
LEX_STRING name,
enum enum_field_types type,
sp_variable::enum_mode mode)
{ {
sp_variable *p= sp_variable *p=
new (thd->mem_root) sp_variable(name, type,mode, current_var_count()); new (thd->mem_root) sp_variable(name, current_var_count());
if (!p) if (!p)
return NULL; return NULL;

View File

@ -63,12 +63,11 @@ public:
Create_field field_def; Create_field field_def;
public: public:
sp_variable(LEX_STRING _name, enum_field_types _type, enum_mode _mode, sp_variable(LEX_STRING _name, uint _offset)
uint _offset)
:Sql_alloc(), :Sql_alloc(),
name(_name), name(_name),
type(_type), type(MYSQL_TYPE_NULL),
mode(_mode), mode(MODE_IN),
offset(_offset), offset(_offset),
default_value(NULL) default_value(NULL)
{ } { }
@ -340,14 +339,9 @@ public:
/// ///
/// @param thd Thread context. /// @param thd Thread context.
/// @param name Name of the SP-variable. /// @param name Name of the SP-variable.
/// @param type Type of the SP-variable.
/// @param mode Mode of the SP-variable.
/// ///
/// @return instance of newly added SP-variable. /// @return instance of newly added SP-variable.
sp_variable *add_variable(THD *thd, sp_variable *add_variable(THD *thd, LEX_STRING name);
LEX_STRING name,
enum enum_field_types type,
sp_variable::enum_mode mode);
/// Retrieve full type information about SP-variables in this parsing /// Retrieve full type information about SP-variables in this parsing
/// context and its children. /// context and its children.

View File

@ -125,6 +125,7 @@ struct LEX_TYPE
#if MYSQL_LEX #if MYSQL_LEX
#include "item_func.h" /* Cast_target used in sql_yacc.h */ #include "item_func.h" /* Cast_target used in sql_yacc.h */
#include "sql_get_diagnostics.h" /* Types used in sql_yacc.h */ #include "sql_get_diagnostics.h" /* Types used in sql_yacc.h */
#include "sp_pcontext.h"
#include "sql_yacc.h" #include "sql_yacc.h"
#define LEX_YYSTYPE YYSTYPE * #define LEX_YYSTYPE YYSTYPE *
#else #else
@ -2380,7 +2381,10 @@ struct LEX: public Query_tables_list
/* Query Plan Footprint of a currently running select */ /* Query Plan Footprint of a currently running select */
Explain_query *explain; Explain_query *explain;
char *length,*dec,*change; // type information
char *length,*dec;
CHARSET_INFO *charset;
LEX_STRING name; LEX_STRING name;
char *help_arg; char *help_arg;
char *backup_dir; /* For RESTORE/BACKUP */ char *backup_dir; /* For RESTORE/BACKUP */
@ -2389,18 +2393,15 @@ struct LEX: public Query_tables_list
String *wild; /* Wildcard in SHOW {something} LIKE 'wild'*/ String *wild; /* Wildcard in SHOW {something} LIKE 'wild'*/
sql_exchange *exchange; sql_exchange *exchange;
select_result *result; select_result *result;
Item *default_value, *on_update_value;
LEX_STRING comment, ident; LEX_STRING comment, ident;
LEX_USER *grant_user; LEX_USER *grant_user;
XID *xid; XID *xid;
THD *thd; THD *thd;
Virtual_column_info *vcol_info;
/* maintain a list of used plugins for this LEX */ /* maintain a list of used plugins for this LEX */
DYNAMIC_ARRAY plugins; DYNAMIC_ARRAY plugins;
plugin_ref plugins_static_buffer[INITIAL_LEX_PLUGIN_LIST_SIZE]; plugin_ref plugins_static_buffer[INITIAL_LEX_PLUGIN_LIST_SIZE];
CHARSET_INFO *charset;
bool text_string_is_7bit; bool text_string_is_7bit;
/** SELECT of CREATE VIEW statement */ /** SELECT of CREATE VIEW statement */
@ -2422,7 +2423,6 @@ struct LEX: public Query_tables_list
List<Key_part_spec> col_list; List<Key_part_spec> col_list;
List<Key_part_spec> ref_list; List<Key_part_spec> ref_list;
List<String> interval_list;
List<LEX_USER> users_list; List<LEX_USER> users_list;
List<LEX_COLUMN> columns; List<LEX_COLUMN> columns;
List<Item> *insert_list,field_list,value_list,update_list; List<Item> *insert_list,field_list,value_list,update_list;
@ -2512,7 +2512,6 @@ struct LEX: public Query_tables_list
uint profile_query_id; uint profile_query_id;
uint profile_options; uint profile_options;
uint uint_geom_type;
uint grant, grant_tot_col, which_columns; uint grant, grant_tot_col, which_columns;
enum Foreign_key::fk_match_opt fk_match_option; enum Foreign_key::fk_match_opt fk_match_option;
enum Foreign_key::fk_option fk_update_opt; enum Foreign_key::fk_option fk_update_opt;
@ -2623,9 +2622,17 @@ struct LEX: public Query_tables_list
}; };
/** /**
Collects create options for Field and KEY Collects create options for KEY
*/ */
engine_option_value *option_list, *option_list_last; engine_option_value *option_list;
/**
Helper pointer to the end of the list when parsing options for
LEX::create_info.option_list (for table)
LEX::last_field->option_list (for fields)
LEX::option_list (for indexes)
*/
engine_option_value *option_list_last;
/** /**
During name resolution search only in the table list given by During name resolution search only in the table list given by
@ -2806,6 +2813,10 @@ struct LEX: public Query_tables_list
int print_explain(select_result_sink *output, uint8 explain_flags, int print_explain(select_result_sink *output, uint8 explain_flags,
bool is_analyze, bool *printed_anything); bool is_analyze, bool *printed_anything);
void restore_set_statement_var(); void restore_set_statement_var();
void init_last_field(Create_field *field, const char *name, CHARSET_INFO *cs);
void set_last_field_type(enum enum_field_types type);
bool set_bincmp(CHARSET_INFO *cs, bool bin);
}; };

View File

@ -7097,113 +7097,6 @@ bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length)
#endif #endif
/**
Store field definition for create.
@return
Return 0 if ok
*/
bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
char *length, char *decimals,
uint type_modifier,
Item *default_value, Item *on_update_value,
LEX_STRING *comment,
char *change,
List<String> *interval_list, CHARSET_INFO *cs,
uint uint_geom_type,
Virtual_column_info *vcol_info,
engine_option_value *create_options)
{
register Create_field *new_field;
LEX *lex= thd->lex;
uint8 datetime_precision= length ? atoi(length) : 0;
DBUG_ENTER("add_field_to_list");
if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
system_charset_info, 1))
{
my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
if (type_modifier & PRI_KEY_FLAG)
{
Key *key;
lex->col_list.push_back(new Key_part_spec(*field_name, 0));
key= new Key(Key::PRIMARY, null_lex_str,
&default_key_create_info,
0, lex->col_list, NULL, lex->check_exists);
lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{
Key *key;
lex->col_list.push_back(new Key_part_spec(*field_name, 0));
key= new Key(Key::UNIQUE, null_lex_str,
&default_key_create_info, 0,
lex->col_list, NULL, lex->check_exists);
lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
if (default_value)
{
/*
Default value should be literal => basic constants =>
no need fix_fields()
We allow only one function as part of default value -
NOW() as default for TIMESTAMP and DATETIME type.
*/
if (default_value->type() == Item::FUNC_ITEM &&
(static_cast<Item_func*>(default_value)->functype() !=
Item_func::NOW_FUNC ||
(mysql_type_to_time_type(type) != MYSQL_TIMESTAMP_DATETIME) ||
default_value->decimals < datetime_precision))
{
my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
}
else if (default_value->type() == Item::NULL_ITEM)
{
default_value= 0;
if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
NOT_NULL_FLAG)
{
my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
}
}
else if (type_modifier & AUTO_INCREMENT_FLAG)
{
my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
}
}
if (on_update_value &&
(mysql_type_to_time_type(type) != MYSQL_TIMESTAMP_DATETIME ||
on_update_value->decimals < datetime_precision))
{
my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
DBUG_RETURN(1);
}
if (!(new_field= new Create_field()) ||
new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
default_value, on_update_value, comment, change,
interval_list, cs, uint_geom_type, vcol_info,
create_options, lex->check_exists))
DBUG_RETURN(1);
lex->alter_info.create_list.push_back(new_field);
lex->last_field=new_field;
DBUG_RETURN(0);
}
/** Store position for column in ALTER TABLE .. ADD column. */ /** Store position for column in ALTER TABLE .. ADD column. */
void store_position_for_column(const char *name) void store_position_for_column(const char *name)
@ -9138,3 +9031,18 @@ merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl)
} }
return cs; return cs;
} }
/** find a collation with binary comparison rules
*/
CHARSET_INFO *find_bin_collation(CHARSET_INFO *cs)
{
const char *csname= cs->csname;
cs= get_charset_by_csname(csname, MY_CS_BINSORT, MYF(0));
if (!cs)
{
char tmp[65];
strxnmov(tmp, sizeof(tmp)-1, csname, "_bin", NULL);
my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
}
return cs;
}

View File

@ -73,6 +73,7 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg,
uint max_char_length, CHARSET_INFO *cs, uint max_char_length, CHARSET_INFO *cs,
bool no_error); bool no_error);
CHARSET_INFO* merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl); CHARSET_INFO* merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl);
CHARSET_INFO *find_bin_collation(CHARSET_INFO *cs);
bool check_host_name(LEX_STRING *str); bool check_host_name(LEX_STRING *str);
bool check_identifier_name(LEX_STRING *str, uint max_char_length, bool check_identifier_name(LEX_STRING *str, uint max_char_length,
uint err_code, const char *param_for_err_msg); uint err_code, const char *param_for_err_msg);
@ -104,16 +105,6 @@ bool append_file_to_dir(THD *thd, const char **filename_ptr,
const char *table_name); const char *table_name);
void execute_init_command(THD *thd, LEX_STRING *init_command, void execute_init_command(THD *thd, LEX_STRING *init_command,
mysql_rwlock_t *var_lock); mysql_rwlock_t *var_lock);
bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum enum_field_types type,
char *length, char *decimal,
uint type_modifier,
Item *default_value, Item *on_update_value,
LEX_STRING *comment,
char *change, List<String> *interval_list,
CHARSET_INFO *cs,
uint uint_geom_type,
Virtual_column_info *vcol_info,
engine_option_value *create_options);
bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *group, bool asc); bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *group, bool asc);
void add_join_on(TABLE_LIST *b,Item *expr); void add_join_on(TABLE_LIST *b,Item *expr);
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields, void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields,

View File

@ -3077,7 +3077,9 @@ void plugin_thdvar_init(THD *thd)
intern_plugin_unlock(NULL, old_table_plugin); intern_plugin_unlock(NULL, old_table_plugin);
intern_plugin_unlock(NULL, old_tmp_table_plugin); intern_plugin_unlock(NULL, old_tmp_table_plugin);
mysql_mutex_unlock(&LOCK_plugin); mysql_mutex_unlock(&LOCK_plugin);
} else { }
else
{
thd->variables.table_plugin= NULL; thd->variables.table_plugin= NULL;
thd->variables.tmp_table_plugin= NULL; thd->variables.tmp_table_plugin= NULL;
} }

View File

@ -3248,18 +3248,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
*/ */
sql_field->length= sql_field->char_length; sql_field->length= sql_field->char_length;
/* Set field charset. */ /* Set field charset. */
save_cs= sql_field->charset= get_sql_field_charset(sql_field, save_cs= sql_field->charset= get_sql_field_charset(sql_field, create_info);
create_info);
if ((sql_field->flags & BINCMP_FLAG) && if ((sql_field->flags & BINCMP_FLAG) &&
!(sql_field->charset= get_charset_by_csname(sql_field->charset->csname, !(sql_field->charset= find_bin_collation(sql_field->charset)))
MY_CS_BINSORT,MYF(0))))
{
char tmp[65];
strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4),
STRING_WITH_LEN("_bin"));
my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
}
/* /*
Convert the default value from client character Convert the default value from client character

View File

@ -45,7 +45,6 @@
#include "lex_symbol.h" #include "lex_symbol.h"
#include "item_create.h" #include "item_create.h"
#include "sp_head.h" #include "sp_head.h"
#include "sp_pcontext.h"
#include "sp_rcontext.h" #include "sp_rcontext.h"
#include "sp.h" #include "sp.h"
#include "sql_show.h" #include "sql_show.h"
@ -731,7 +730,6 @@ static bool add_create_index_prepare (LEX *lex, Table_ident *table)
lex->alter_info.reset(); lex->alter_info.reset();
lex->alter_info.flags= Alter_info::ALTER_ADD_INDEX; lex->alter_info.flags= Alter_info::ALTER_ADD_INDEX;
lex->col_list.empty(); lex->col_list.empty();
lex->change= NullS;
lex->option_list= NULL; lex->option_list= NULL;
return FALSE; return FALSE;
} }
@ -862,6 +860,85 @@ static bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
} }
static void add_key_to_list(LEX *lex, LEX_STRING *field_name,
enum Key::Keytype type)
{
Key *key;
lex->col_list.push_back(new Key_part_spec(*field_name, 0));
key= new Key(type, null_lex_str,
&default_key_create_info, 0,
lex->col_list, NULL, lex->check_exists);
lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
void LEX::init_last_field(Create_field *field, const char *name, CHARSET_INFO *cs)
{
last_field= field;
field->field_name= name;
field->flags= 0;
field->def= 0;
field->on_update= 0;
field->sql_type= MYSQL_TYPE_NULL;
field->change= 0;
field->geom_type= Field::GEOM_GEOMETRY;
field->comment= null_lex_str;
field->vcol_info= 0;
field->interval_list.empty();
/* reset LEX fields that are used in Create_field::set_and_check() */
length= 0;
dec= 0;
charset= cs;
}
void LEX::set_last_field_type(enum enum_field_types type)
{
last_field->sql_type= type;
last_field->create_if_not_exists= check_exists;
last_field->charset= charset;
if (length)
{
int err;
last_field->length= my_strtoll10(length, NULL, &err);
if (err)
last_field->length= ~0ULL; // safety
}
else
last_field->length= 0;
last_field->decimals= dec ? (uint)atoi(dec) : 0;
}
bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
{
/*
if charset is NULL - we're parsing a field declaration.
we cannot call find_bin_collation for a field here, because actual
field charset is determined in get_sql_field_charset() much later.
so we only set a flag.
*/
if (!charset)
{
charset= cs;
last_field->flags|= bin ? BINCMP_FLAG : 0;
return false;
}
charset= bin ? find_bin_collation(cs ? cs : charset)
: cs ? cs : charset;
return charset == NULL;
}
#define bincmp_collation(X,Y) \
do \
{ \
if (Lex->set_bincmp(X,Y)) \
MYSQL_YYABORT; \
} while(0)
%} %}
%union { %union {
int num; int num;
@ -871,7 +948,6 @@ static bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
LEX_STRING lex_str; LEX_STRING lex_str;
LEX_STRING *lex_str_ptr; LEX_STRING *lex_str_ptr;
LEX_SYMBOL symbol; LEX_SYMBOL symbol;
LEX_TYPE lex_type;
Table_ident *table; Table_ident *table;
char *simple_string; char *simple_string;
Item *item; Item *item;
@ -888,6 +964,8 @@ static bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
enum enum_var_type var_type; enum enum_var_type var_type;
Key::Keytype key_type; Key::Keytype key_type;
enum ha_key_alg key_alg; enum ha_key_alg key_alg;
enum enum_field_types field_type;
enum Field::geometry_type geom_type;
handlerton *db_type; handlerton *db_type;
enum row_type row_type; enum row_type row_type;
enum ha_rkey_function ha_rkey_mode; enum ha_rkey_function ha_rkey_mode;
@ -907,12 +985,14 @@ static bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
class sp_label *splabel; class sp_label *splabel;
LEX *lex; LEX *lex;
class my_var *myvar; class my_var *myvar;
sp_head *sphead; class sp_head *sphead;
class sp_variable *spvar;
struct p_elem_val *p_elem_value; struct p_elem_val *p_elem_value;
enum index_hint_type index_hint; enum index_hint_type index_hint;
enum enum_filetype filetype; enum enum_filetype filetype;
enum Foreign_key::fk_option m_fk_option; enum Foreign_key::fk_option m_fk_option;
enum enum_yes_no_unknown m_yes_no_unk; enum enum_yes_no_unknown m_yes_no_unk;
enum sp_variable::enum_mode spvar_mode;
Diag_condition_item_name diag_condition_item_name; Diag_condition_item_name diag_condition_item_name;
Diagnostics_information::Which_area diag_area; Diagnostics_information::Which_area diag_area;
Diagnostics_information *diag_info; Diagnostics_information *diag_info;
@ -1643,14 +1723,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <string> %type <string>
text_string hex_or_bin_String opt_gconcat_separator text_string hex_or_bin_String opt_gconcat_separator
%type <lex_type> field_def %type <field_type> type_with_opt_collate int_type real_type field_type
%type <geom_type> spatial_type
%type <num> %type <num>
type type_with_opt_collate int_type real_type order_dir lock_option order_dir lock_option
udf_type opt_if_exists opt_local opt_table_options table_options udf_type opt_if_exists opt_local opt_table_options table_options
table_option opt_if_not_exists create_or_replace opt_no_write_to_binlog table_option opt_if_not_exists create_or_replace opt_no_write_to_binlog
opt_temporary all_or_any opt_distinct opt_temporary all_or_any opt_distinct
opt_ignore_leaves fulltext_options spatial_type union_option opt_ignore_leaves fulltext_options union_option
opt_not opt_union_order_or_limit opt_not opt_union_order_or_limit
union_opt select_derived_init transaction_access_mode_types union_opt select_derived_init transaction_access_mode_types
opt_natural_language_mode opt_query_expansion opt_natural_language_mode opt_query_expansion
@ -1659,7 +1741,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
optional_flush_tables_arguments opt_dyncol_type dyncol_type optional_flush_tables_arguments opt_dyncol_type dyncol_type
opt_time_precision kill_type kill_option int_num opt_time_precision kill_type kill_option int_num
opt_default_time_precision opt_default_time_precision
case_stmt_body case_stmt_body opt_bin_mod
/* /*
Bit field of MYSQL_START_TRANS_OPT_* flags. Bit field of MYSQL_START_TRANS_OPT_* flags.
@ -1763,6 +1845,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <charset> %type <charset>
opt_collate opt_collate
charset_name charset_name
charset_or_alias
charset_name_or_default charset_name_or_default
old_or_new_charset_name old_or_new_charset_name
old_or_new_charset_name_or_default old_or_new_charset_name_or_default
@ -1805,10 +1888,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
select_item_list select_item values_list no_braces select_item_list select_item values_list no_braces
opt_limit_clause delete_limit_clause fields opt_values values opt_limit_clause delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item procedure_list procedure_list2 procedure_item
handler field_def handler opt_generated_always
opt_precision opt_ignore opt_column opt_restrict opt_precision opt_ignore opt_column opt_restrict
grant revoke set lock unlock string_list field_options field_option grant revoke set lock unlock string_list field_options field_option
field_opt_list opt_binary ascii unicode table_lock_list table_lock field_opt_list opt_binary table_lock_list table_lock
ref_list opt_match_clause opt_on_update_delete use ref_list opt_match_clause opt_on_update_delete use
opt_delete_options opt_delete_option varchar nchar nvarchar opt_delete_options opt_delete_option varchar nchar nvarchar
opt_outer table_list table_name table_alias_ref_list table_alias_ref opt_outer table_list table_name table_alias_ref_list table_alias_ref
@ -1863,12 +1946,14 @@ END_OF_INPUT
%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close %type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
%type <NONE> case_stmt_specification %type <NONE> case_stmt_specification
%type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list %type <num> sp_decl_idents sp_handler_type sp_hcond_list
%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value %type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
%type <spblock> sp_decls sp_decl %type <spblock> sp_decls sp_decl
%type <lex> sp_cursor_stmt %type <lex> sp_cursor_stmt
%type <spname> sp_name %type <spname> sp_name
%type <splabel> sp_block_content %type <splabel> sp_block_content
%type <spvar> sp_param_name_and_type
%type <spvar_mode> sp_opt_inout
%type <index_hint> index_hint_type %type <index_hint> index_hint_type
%type <num> index_hint_clause normal_join inner_join %type <num> index_hint_clause normal_join inner_join
%type <filetype> data_or_xml %type <filetype> data_or_xml
@ -2379,7 +2464,6 @@ create:
MYSQL_YYABORT; MYSQL_YYABORT;
lex->alter_info.reset(); lex->alter_info.reset();
lex->col_list.empty(); lex->col_list.empty();
lex->change=NullS;
bzero((char*) &lex->create_info,sizeof(lex->create_info)); bzero((char*) &lex->create_info,sizeof(lex->create_info));
/* /*
For CREATE TABLE we should not open the table even if it exists. For CREATE TABLE we should not open the table even if it exists.
@ -2836,33 +2920,12 @@ sp_fdparam_list:
; ;
sp_fdparams: sp_fdparams:
sp_fdparams ',' sp_fdparam sp_fdparams ',' sp_param_name_and_type
| sp_fdparam | sp_param_name_and_type
; ;
sp_init_param: sp_param_name_and_type:
/* Empty */ ident
{
LEX *lex= Lex;
lex->length= 0;
lex->dec= 0;
lex->type= 0;
lex->default_value= 0;
lex->on_update_value= 0;
lex->comment= null_lex_str;
lex->charset= NULL;
lex->interval_list.empty();
lex->uint_geom_type= 0;
lex->vcol_info= 0;
}
;
sp_fdparam:
ident sp_init_param type_with_opt_collate
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_pcontext *spc= lex->spcont; sp_pcontext *spc= lex->spcont;
@ -2873,19 +2936,27 @@ sp_fdparam:
MYSQL_YYABORT; MYSQL_YYABORT;
} }
sp_variable *spvar= spc->add_variable(thd, sp_variable *spvar= spc->add_variable(thd, $1);
$1,
(enum enum_field_types) $3,
sp_variable::MODE_IN);
if (lex->sphead->fill_field_definition(thd, lex, lex->init_last_field(&spvar->field_def, $1.str,
(enum enum_field_types) $3, thd->variables.collation_database);
&spvar->field_def)) $<spvar>$= spvar;
}
type_with_opt_collate
{
LEX *lex= Lex;
sp_variable *spvar= $<spvar>2;
spvar->type= $3;
if (lex->sphead->fill_field_definition(thd, lex, $3,
lex->last_field))
{ {
MYSQL_YYABORT; MYSQL_YYABORT;
} }
spvar->field_def.field_name= spvar->name.str; spvar->field_def.field_name= spvar->name.str;
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
$$= spvar;
} }
; ;
@ -2901,30 +2972,7 @@ sp_pdparams:
; ;
sp_pdparam: sp_pdparam:
sp_opt_inout sp_init_param ident type_with_opt_collate sp_opt_inout sp_param_name_and_type { $2->mode=$1; }
{
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
if (spc->find_variable($3, TRUE))
{
my_error(ER_SP_DUP_PARAM, MYF(0), $3.str);
MYSQL_YYABORT;
}
sp_variable *spvar= spc->add_variable(thd,
$3,
(enum enum_field_types) $4,
(sp_variable::enum_mode) $1);
if (lex->sphead->fill_field_definition(thd, lex,
(enum enum_field_types) $4,
&spvar->field_def))
{
MYSQL_YYABORT;
}
spvar->field_def.field_name= spvar->name.str;
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
}
; ;
sp_opt_inout: sp_opt_inout:
@ -2978,9 +3026,17 @@ sp_decl:
DECLARE_SYM sp_decl_idents DECLARE_SYM sp_decl_idents
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_pcontext *pctx= lex->spcont;
// get the last variable:
uint num_vars= pctx->context_var_count();
uint var_idx= pctx->var_context2runtime(num_vars - 1);
sp_variable *spvar= pctx->find_variable(var_idx);
lex->sphead->reset_lex(thd); lex->sphead->reset_lex(thd);
lex->spcont->declare_var_boundary($2); pctx->declare_var_boundary($2);
thd->lex->init_last_field(&spvar->field_def, spvar->name.str,
thd->variables.collation_database);
} }
type_with_opt_collate type_with_opt_collate
sp_opt_default sp_opt_default
@ -2988,7 +3044,7 @@ sp_decl:
LEX *lex= Lex; LEX *lex= Lex;
sp_pcontext *pctx= lex->spcont; sp_pcontext *pctx= lex->spcont;
uint num_vars= pctx->context_var_count(); uint num_vars= pctx->context_var_count();
enum enum_field_types var_type= (enum enum_field_types) $4; enum enum_field_types var_type= $4;
Item *dflt_value_item= $5; Item *dflt_value_item= $5;
if (!dflt_value_item) if (!dflt_value_item)
@ -3003,12 +3059,17 @@ sp_decl:
{ {
uint var_idx= pctx->var_context2runtime(i); uint var_idx= pctx->var_context2runtime(i);
sp_variable *spvar= pctx->find_variable(var_idx); sp_variable *spvar= pctx->find_variable(var_idx);
bool last= i == num_vars - 1;
if (!spvar) if (!spvar)
MYSQL_YYABORT; MYSQL_YYABORT;
if (!last)
spvar->field_def= *lex->last_field;
spvar->type= var_type; spvar->type= var_type;
spvar->default_value= dflt_value_item; spvar->default_value= dflt_value_item;
spvar->field_def.field_name= spvar->name.str;
if (lex->sphead->fill_field_definition(thd, lex, var_type, if (lex->sphead->fill_field_definition(thd, lex, var_type,
&spvar->field_def)) &spvar->field_def))
@ -3016,7 +3077,6 @@ sp_decl:
MYSQL_YYABORT; MYSQL_YYABORT;
} }
spvar->field_def.field_name= spvar->name.str;
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
/* The last instruction is responsible for freeing LEX. */ /* The last instruction is responsible for freeing LEX. */
@ -3027,7 +3087,7 @@ sp_decl:
dflt_value_item, dflt_value_item,
var_type, var_type,
lex, lex,
(i == num_vars - 1)); last);
if (is == NULL || if (is == NULL ||
lex->sphead->add_instr(is)) lex->sphead->add_instr(is))
MYSQL_YYABORT; MYSQL_YYABORT;
@ -3581,10 +3641,7 @@ sp_decl_idents:
my_error(ER_SP_DUP_VAR, MYF(0), $1.str); my_error(ER_SP_DUP_VAR, MYF(0), $1.str);
MYSQL_YYABORT; MYSQL_YYABORT;
} }
spc->add_variable(thd, spc->add_variable(thd, $1);
$1,
MYSQL_TYPE_DECIMAL,
sp_variable::MODE_IN);
$$= 1; $$= 1;
} }
| sp_decl_idents ',' ident | sp_decl_idents ',' ident
@ -3599,10 +3656,7 @@ sp_decl_idents:
my_error(ER_SP_DUP_VAR, MYF(0), $3.str); my_error(ER_SP_DUP_VAR, MYF(0), $3.str);
MYSQL_YYABORT; MYSQL_YYABORT;
} }
spc->add_variable(thd, spc->add_variable(thd, $3);
$3,
MYSQL_TYPE_DECIMAL,
sp_variable::MODE_IN);
$$= $1 + 1; $$= $1 + 1;
} }
; ;
@ -6038,58 +6092,62 @@ field_spec:
field_ident field_ident
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->length=lex->dec=0; Create_field *f= new Create_field();
lex->type=0;
lex->default_value= lex->on_update_value= 0; if (check_string_char_length(&$1, "", NAME_CHAR_LEN,
lex->comment=null_lex_str; system_charset_info, 1))
lex->charset=NULL; {
lex->vcol_info= 0; my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str);
lex->option_list= NULL; MYSQL_YYABORT;
}
if (!f)
MYSQL_YYABORT;
lex->init_last_field(f, $1.str, NULL);
} }
field_type { Lex->set_last_field_type($3); }
field_def field_def
{ {
LEX *lex=Lex; LEX *lex=Lex;
if (add_field_to_list(lex->thd, &$1, $3.type, Create_field *f= lex->last_field;
$3.length, $3.dec, lex->type,
lex->default_value, lex->on_update_value, if (f->check(thd))
&lex->comment,
lex->change, &lex->interval_list, $3.charset,
lex->uint_geom_type,
lex->vcol_info, lex->option_list))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->alter_info.create_list.push_back(f);
if (f->flags & PRI_KEY_FLAG)
add_key_to_list(lex, &$1, Key::PRIMARY);
else if (f->flags & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
add_key_to_list(lex, &$1, Key::UNIQUE);
} }
; ;
field_def: field_def:
type opt_attribute opt_attribute
{ $$.set($1, Lex->length, Lex->dec, Lex->charset); } | opt_generated_always AS
| type opt_generated_always AS '(' virtual_column_func ')'
{ $<lex_type>$.set($1, Lex->length, Lex->dec, Lex->charset); } vcol_opt_specifier vcol_opt_attribute
'(' virtual_column_func ')' vcol_opt_specifier vcol_opt_attribute
{
$$= $<lex_type>4;
Lex->vcol_info->set_field_type($$.type);
$$.type= (enum enum_field_types)MYSQL_TYPE_VIRTUAL;
}
; ;
opt_generated_always: opt_generated_always:
/* empty */ /* empty */ {}
| GENERATED_SYM ALWAYS_SYM {} | GENERATED_SYM ALWAYS_SYM {}
; ;
vcol_opt_specifier: vcol_opt_specifier:
/* empty */ /* empty */
{ {
Lex->vcol_info->set_stored_in_db_flag(FALSE); Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE);
} }
| VIRTUAL_SYM | VIRTUAL_SYM
{ {
Lex->vcol_info->set_stored_in_db_flag(FALSE); Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE);
} }
| PERSISTENT_SYM | PERSISTENT_SYM
{ {
Lex->vcol_info->set_stored_in_db_flag(TRUE); Lex->last_field->vcol_info->set_stored_in_db_flag(TRUE);
} }
; ;
@ -6107,16 +6165,16 @@ vcol_attribute:
UNIQUE_SYM UNIQUE_SYM
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->type|= UNIQUE_FLAG; lex->last_field->flags|= UNIQUE_FLAG;
lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
} }
| UNIQUE_SYM KEY_SYM | UNIQUE_SYM KEY_SYM
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->type|= UNIQUE_KEY_FLAG; lex->last_field->flags|= UNIQUE_FLAG;
lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
} }
| COMMENT_SYM TEXT_STRING_sys { Lex->comment= $2; } | COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; }
; ;
parse_vcol_expr: parse_vcol_expr:
@ -6138,23 +6196,41 @@ parse_vcol_expr:
virtual_column_func: virtual_column_func:
remember_name expr remember_end remember_name expr remember_end
{ {
Lex->vcol_info= new Virtual_column_info(); Virtual_column_info *v= new Virtual_column_info();
if (!Lex->vcol_info) if (!v)
{ {
mem_alloc_error(sizeof(Virtual_column_info)); mem_alloc_error(sizeof(Virtual_column_info));
MYSQL_YYABORT; MYSQL_YYABORT;
} }
uint expr_len= (uint)($3 - $1) - 1; uint expr_len= (uint)($3 - $1) - 1;
Lex->vcol_info->expr_str.str= (char* ) thd->memdup($1 + 1, expr_len); v->expr_str.str= (char* ) thd->memdup($1 + 1, expr_len);
Lex->vcol_info->expr_str.length= expr_len; v->expr_str.length= expr_len;
Lex->vcol_info->expr_item= $2; v->expr_item= $2;
Lex->last_field->vcol_info= v;
} }
; ;
type: field_type:
int_type opt_field_length field_options { $$=$1; } int_type opt_field_length field_options { $$=$1; }
| real_type opt_precision field_options { $$=$1; } | real_type opt_precision field_options { $$=$1; }
| FLOAT_SYM float_options field_options { $$=MYSQL_TYPE_FLOAT; } | FLOAT_SYM float_options field_options
{
$$=MYSQL_TYPE_FLOAT;
if (Lex->length && !Lex->dec)
{
int err;
ulonglong tmp_length= my_strtoll10(Lex->length, NULL, &err);
if (err || tmp_length > PRECISION_FOR_DOUBLE)
{
my_error(ER_WRONG_FIELD_SPEC, MYF(0),
Lex->last_field->field_name);
MYSQL_YYABORT;
}
else if (tmp_length > PRECISION_FOR_FLOAT)
$$= MYSQL_TYPE_DOUBLE;
Lex->length= 0;
}
}
| BIT_SYM | BIT_SYM
{ {
Lex->length= (char*) "1"; Lex->length= (char*) "1";
@ -6186,13 +6262,13 @@ type:
| nchar field_length opt_bin_mod | nchar field_length opt_bin_mod
{ {
$$=MYSQL_TYPE_STRING; $$=MYSQL_TYPE_STRING;
Lex->charset=national_charset_info; bincmp_collation(national_charset_info, $3);
} }
| nchar opt_bin_mod | nchar opt_bin_mod
{ {
Lex->length= (char*) "1"; Lex->length= (char*) "1";
$$=MYSQL_TYPE_STRING; $$=MYSQL_TYPE_STRING;
Lex->charset=national_charset_info; bincmp_collation(national_charset_info, $2);
} }
| BINARY field_length | BINARY field_length
{ {
@ -6212,7 +6288,7 @@ type:
| nvarchar field_length opt_bin_mod | nvarchar field_length opt_bin_mod
{ {
$$= MYSQL_TYPE_VARCHAR; $$= MYSQL_TYPE_VARCHAR;
Lex->charset=national_charset_info; bincmp_collation(national_charset_info, $3);
} }
| VARBINARY field_length | VARBINARY field_length
{ {
@ -6252,9 +6328,9 @@ type:
/* /*
Unlike other types TIMESTAMP fields are NOT NULL by default. Unlike other types TIMESTAMP fields are NOT NULL by default.
*/ */
Lex->type|= NOT_NULL_FLAG; Lex->last_field->flags|= NOT_NULL_FLAG;
$$= opt_mysql56_temporal_format ? $$= opt_mysql56_temporal_format ? MYSQL_TYPE_TIMESTAMP2
MYSQL_TYPE_TIMESTAMP2 : MYSQL_TYPE_TIMESTAMP; : MYSQL_TYPE_TIMESTAMP;
} }
} }
| DATETIME opt_field_length | DATETIME opt_field_length
@ -6274,7 +6350,7 @@ type:
{ {
#ifdef HAVE_SPATIAL #ifdef HAVE_SPATIAL
Lex->charset=&my_charset_bin; Lex->charset=&my_charset_bin;
Lex->uint_geom_type= (uint)$1; Lex->last_field->geom_type= $1;
$$=MYSQL_TYPE_GEOMETRY; $$=MYSQL_TYPE_GEOMETRY;
#else #else
my_error(ER_FEATURE_DISABLED, MYF(0), my_error(ER_FEATURE_DISABLED, MYF(0),
@ -6313,20 +6389,16 @@ type:
{ $$=MYSQL_TYPE_NEWDECIMAL;} { $$=MYSQL_TYPE_NEWDECIMAL;}
| FIXED_SYM float_options field_options | FIXED_SYM float_options field_options
{ $$=MYSQL_TYPE_NEWDECIMAL;} { $$=MYSQL_TYPE_NEWDECIMAL;}
| ENUM | ENUM '(' string_list ')' opt_binary
{Lex->interval_list.empty();}
'(' string_list ')' opt_binary
{ $$=MYSQL_TYPE_ENUM; } { $$=MYSQL_TYPE_ENUM; }
| SET | SET '(' string_list ')' opt_binary
{ Lex->interval_list.empty();}
'(' string_list ')' opt_binary
{ $$=MYSQL_TYPE_SET; } { $$=MYSQL_TYPE_SET; }
| LONG_SYM opt_binary | LONG_SYM opt_binary
{ $$=MYSQL_TYPE_MEDIUM_BLOB; } { $$=MYSQL_TYPE_MEDIUM_BLOB; }
| SERIAL_SYM | SERIAL_SYM
{ {
$$=MYSQL_TYPE_LONGLONG; $$=MYSQL_TYPE_LONGLONG;
Lex->type|= (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG | Lex->last_field->flags|= (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG |
UNIQUE_FLAG); UNIQUE_FLAG);
} }
; ;
@ -6419,8 +6491,8 @@ field_opt_list:
field_option: field_option:
SIGNED_SYM {} SIGNED_SYM {}
| UNSIGNED { Lex->type|= UNSIGNED_FLAG;} | UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG;}
| ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; } | ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
; ;
field_length: field_length:
@ -6450,42 +6522,42 @@ opt_attribute_list:
; ;
attribute: attribute:
NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; } NULL_SYM { Lex->last_field->flags&= ~ NOT_NULL_FLAG; }
| not NULL_SYM { Lex->type|= NOT_NULL_FLAG; } | not NULL_SYM { Lex->last_field->flags|= NOT_NULL_FLAG; }
| DEFAULT now_or_signed_literal { Lex->default_value=$2; } | DEFAULT now_or_signed_literal { Lex->last_field->def= $2; }
| ON UPDATE_SYM NOW_SYM opt_default_time_precision | ON UPDATE_SYM NOW_SYM opt_default_time_precision
{ {
Item *item= new (thd->mem_root) Item_func_now_local($4); Item *item= new (thd->mem_root) Item_func_now_local($4);
if (item == NULL) if (item == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
Lex->on_update_value= item; Lex->last_field->on_update= item;
} }
| AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; } | AUTO_INC { Lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; }
| SERIAL_SYM DEFAULT VALUE_SYM | SERIAL_SYM DEFAULT VALUE_SYM
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_FLAG; lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_FLAG;
lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
} }
| opt_primary KEY_SYM | opt_primary KEY_SYM
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG; lex->last_field->flags|= PRI_KEY_FLAG | NOT_NULL_FLAG;
lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
} }
| UNIQUE_SYM | UNIQUE_SYM
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->type|= UNIQUE_FLAG; lex->last_field->flags|= UNIQUE_FLAG;
lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
} }
| UNIQUE_SYM KEY_SYM | UNIQUE_SYM KEY_SYM
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->type|= UNIQUE_KEY_FLAG; lex->last_field->flags|= UNIQUE_KEY_FLAG;
lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX;
} }
| COMMENT_SYM TEXT_STRING_sys { Lex->comment= $2; } | COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; }
| COLLATE_SYM collation_name | COLLATE_SYM collation_name
{ {
if (Lex->charset && !my_charset_same(Lex->charset,$2)) if (Lex->charset && !my_charset_same(Lex->charset,$2))
@ -6496,52 +6568,46 @@ attribute:
} }
else else
{ {
Lex->charset=$2; Lex->last_field->charset= $2;
} }
} }
| IDENT_sys equal TEXT_STRING_sys | IDENT_sys equal TEXT_STRING_sys
{ {
new (thd->mem_root) new (thd->mem_root)
engine_option_value($1, $3, true, &Lex->option_list, engine_option_value($1, $3, true, &Lex->last_field->option_list,
&Lex->option_list_last); &Lex->option_list_last);
} }
| IDENT_sys equal ident | IDENT_sys equal ident
{ {
new (thd->mem_root) new (thd->mem_root)
engine_option_value($1, $3, false, &Lex->option_list, engine_option_value($1, $3, false, &Lex->last_field->option_list,
&Lex->option_list_last); &Lex->option_list_last);
} }
| IDENT_sys equal real_ulonglong_num | IDENT_sys equal real_ulonglong_num
{ {
new (thd->mem_root) new (thd->mem_root)
engine_option_value($1, $3, &Lex->option_list, engine_option_value($1, $3, &Lex->last_field->option_list,
&Lex->option_list_last, thd->mem_root); &Lex->option_list_last, thd->mem_root);
} }
| IDENT_sys equal DEFAULT | IDENT_sys equal DEFAULT
{ {
new (thd->mem_root) new (thd->mem_root)
engine_option_value($1, &Lex->option_list, &Lex->option_list_last); engine_option_value($1, &Lex->last_field->option_list, &Lex->option_list_last);
} }
; ;
type_with_opt_collate: type_with_opt_collate:
type opt_collate field_type opt_collate
{ {
$$= $1; $$= $1;
if (Lex->charset) /* Lex->charset is scanned in "type" */ if ($2)
{ {
if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2))) if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
else if ($2) Lex->set_last_field_type($1);
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"COLLATE with no CHARACTER SET "
"in SP parameters, RETURNS, DECLARE");
MYSQL_YYABORT;
}
} }
; ;
@ -6625,62 +6691,30 @@ opt_default:
| DEFAULT {} | DEFAULT {}
; ;
charset_or_alias:
ascii: charset charset_name { $$= $2; }
ASCII_SYM { Lex->charset= &my_charset_latin1; } | ASCII_SYM { $$= &my_charset_latin1; }
| BINARY ASCII_SYM | UNICODE_SYM
{ {
Lex->charset= &my_charset_latin1_bin; if (!($$= get_charset_by_csname("ucs2", MY_CS_PRIMARY,MYF(0))))
}
| ASCII_SYM BINARY
{
Lex->charset= &my_charset_latin1_bin;
}
;
unicode:
UNICODE_SYM
{
if (!(Lex->charset=get_charset_by_csname("ucs2",
MY_CS_PRIMARY,MYF(0))))
{ {
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2"); my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
MYSQL_YYABORT; MYSQL_YYABORT;
} }
} }
| UNICODE_SYM BINARY
{
if (!(Lex->charset= mysqld_collation_get_by_name("ucs2_bin")))
MYSQL_YYABORT;
}
| BINARY UNICODE_SYM
{
if (!(Lex->charset= mysqld_collation_get_by_name("ucs2_bin")))
MYSQL_YYABORT;
}
; ;
opt_binary: opt_binary:
/* empty */ { Lex->charset=NULL; } /* empty */ { bincmp_collation(NULL, false); }
| ascii | BYTE_SYM { bincmp_collation(&my_charset_bin, false); }
| unicode | charset_or_alias opt_bin_mod { bincmp_collation($1, $2); }
| BYTE_SYM { Lex->charset=&my_charset_bin; } | BINARY { bincmp_collation(NULL, true); }
| charset charset_name opt_bin_mod { Lex->charset=$2; } | BINARY charset_or_alias { bincmp_collation($2, true); }
| BINARY
{
Lex->charset= NULL;
Lex->type|= BINCMP_FLAG;
}
| BINARY charset charset_name
{
Lex->charset= $3;
Lex->type|= BINCMP_FLAG;
}
; ;
opt_bin_mod: opt_bin_mod:
/* empty */ { } /* empty */ { $$= false; }
| BINARY { Lex->type|= BINCMP_FLAG; } | BINARY { $$= true; }
; ;
ws_nweights: ws_nweights:
@ -7051,8 +7085,8 @@ opt_component:
; ;
string_list: string_list:
text_string { Lex->interval_list.push_back($1); } text_string { Lex->last_field->interval_list.push_back($1); }
| string_list ',' text_string { Lex->interval_list.push_back($3); }; | string_list ',' text_string { Lex->last_field->interval_list.push_back($3); };
/* /*
** Alter table ** Alter table
@ -7522,7 +7556,6 @@ add_column:
ADD opt_column opt_if_not_exists ADD opt_column opt_if_not_exists
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->change=0;
lex->alter_info.flags|= Alter_info::ALTER_ADD_COLUMN; lex->alter_info.flags|= Alter_info::ALTER_ADD_COLUMN;
} }
; ;
@ -7542,44 +7575,17 @@ alter_list_item:
Lex->alter_info.flags|= Alter_info::ALTER_ADD_COLUMN | Lex->alter_info.flags|= Alter_info::ALTER_ADD_COLUMN |
Alter_info::ALTER_ADD_INDEX; Alter_info::ALTER_ADD_INDEX;
} }
| CHANGE opt_column opt_if_exists field_ident | CHANGE opt_column opt_if_exists field_ident field_spec opt_place
{
LEX *lex=Lex;
lex->change= $4.str;
lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN;
lex->option_list= NULL;
}
field_spec opt_place
{ {
Lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN;
Lex->create_last_non_select_table= Lex->last_table(); Lex->create_last_non_select_table= Lex->last_table();
Lex->last_field->change= $4.str;
} }
| MODIFY_SYM opt_column opt_if_exists field_ident | MODIFY_SYM opt_column opt_if_exists field_spec opt_place
{
LEX *lex=Lex;
lex->length=lex->dec=0; lex->type=0;
lex->default_value= lex->on_update_value= 0;
lex->comment=null_lex_str;
lex->charset= NULL;
lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN;
lex->vcol_info= 0;
lex->option_list= NULL;
}
field_def
{
LEX *lex=Lex;
if (add_field_to_list(lex->thd,&$4,
$6.type,
$6.length, $6.dec, lex->type,
lex->default_value, lex->on_update_value,
&lex->comment,
$4.str, &lex->interval_list, $6.charset,
lex->uint_geom_type,
lex->vcol_info, lex->option_list))
MYSQL_YYABORT;
}
opt_place
{ {
Lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN;
Lex->create_last_non_select_table= Lex->last_table(); Lex->create_last_non_select_table= Lex->last_table();
Lex->last_field->change= Lex->last_field->field_name;
} }
| DROP opt_column opt_if_exists field_ident opt_restrict | DROP opt_column opt_if_exists field_ident opt_restrict
{ {
@ -9083,7 +9089,9 @@ dyncol_type:
$$= DYN_COL_DECIMAL; $$= DYN_COL_DECIMAL;
Lex->charset= NULL; Lex->charset= NULL;
} }
| char opt_binary | char
{ Lex->charset= thd->variables.collation_connection; }
opt_binary
{ {
LEX *lex= Lex; LEX *lex= Lex;
$$= DYN_COL_STRING; $$= DYN_COL_STRING;
@ -10414,7 +10422,9 @@ in_sum_expr:
cast_type: cast_type:
BINARY opt_field_length BINARY opt_field_length
{ $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; } { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; }
| CHAR_SYM opt_field_length opt_binary | CHAR_SYM opt_field_length
{ Lex->charset= thd->variables.collation_connection; }
opt_binary
{ $$=ITEM_CAST_CHAR; Lex->dec= 0; } { $$=ITEM_CAST_CHAR; Lex->dec= 0; }
| NCHAR_SYM opt_field_length | NCHAR_SYM opt_field_length
{ $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; } { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; }
@ -13259,8 +13269,7 @@ opt_ignore_lines:
; ;
lines_or_rows: lines_or_rows:
LINES { } LINES { }
| ROWS_SYM { } | ROWS_SYM { }
; ;
@ -16233,31 +16242,13 @@ sf_tail:
RETURNS_SYM /* $9 */ RETURNS_SYM /* $9 */
{ /* $10 */ { /* $10 */
LEX *lex= Lex; LEX *lex= Lex;
lex->charset= NULL; lex->init_last_field(&lex->sphead->m_return_field_def, NULL,
lex->length= lex->dec= NULL; thd->variables.collation_database);
lex->interval_list.empty();
lex->type= 0;
lex->vcol_info= 0;
} }
type_with_opt_collate /* $11 */ type_with_opt_collate /* $11 */
{ /* $12 */ { /* $12 */
LEX *lex= Lex; if (Lex->sphead->fill_field_definition(thd, Lex, $11,
sp_head *sp= lex->sphead; Lex->last_field))
/*
This was disabled in 5.1.12. See bug #20701
When collation support in SP is implemented, then this test
should be removed.
*/
if (($11 == MYSQL_TYPE_STRING || $11 == MYSQL_TYPE_VARCHAR)
&& (lex->type & BINCMP_FLAG))
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation");
MYSQL_YYABORT;
}
if (sp->fill_field_definition(thd, lex,
(enum enum_field_types) $11,
&sp->m_return_field_def))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
sp_c_chistics /* $13 */ sp_c_chistics /* $13 */

View File

@ -2395,6 +2395,7 @@ bool unpack_vcol_info_from_frm(THD *thd,
Query_arena *backup_stmt_arena_ptr; Query_arena *backup_stmt_arena_ptr;
Query_arena backup_arena; Query_arena backup_arena;
Query_arena *vcol_arena= 0; Query_arena *vcol_arena= 0;
Create_field vcol_storage; // placeholder for vcol_info
Parser_state parser_state; Parser_state parser_state;
LEX *old_lex= thd->lex; LEX *old_lex= thd->lex;
LEX lex; LEX lex;
@ -2458,7 +2459,8 @@ bool unpack_vcol_info_from_frm(THD *thd,
if (init_lex_with_single_table(thd, table, &lex)) if (init_lex_with_single_table(thd, table, &lex))
goto err; goto err;
thd->lex->parse_vcol_expr= TRUE; lex.parse_vcol_expr= TRUE;
lex.last_field= &vcol_storage;
/* /*
Step 3: Use the parser to build an Item object from vcol_expr_str. Step 3: Use the parser to build an Item object from vcol_expr_str.
@ -2468,7 +2470,7 @@ bool unpack_vcol_info_from_frm(THD *thd,
goto err; goto err;
} }
/* From now on use vcol_info generated by the parser. */ /* From now on use vcol_info generated by the parser. */
field->vcol_info= thd->lex->vcol_info; field->vcol_info= vcol_storage.vcol_info;
/* Validate the Item tree. */ /* Validate the Item tree. */
if (fix_vcol_expr(thd, table, field)) if (fix_vcol_expr(thd, table, field))

View File

@ -22,6 +22,8 @@
This code needs extra visibility in the lexer structures This code needs extra visibility in the lexer structures
*/ */
#define MYSQL_LEX 1
#include "my_global.h" #include "my_global.h"
#include "my_sys.h" #include "my_sys.h"
#include "pfs_instr.h" #include "pfs_instr.h"
@ -35,7 +37,6 @@
#include <string.h> #include <string.h>
/* Generated code */ /* Generated code */
#include "../sql/sql_yacc.h"
#include "../storage/perfschema/pfs_lex_token.h" #include "../storage/perfschema/pfs_lex_token.h"
/* Name pollution from sql/sql_lex.h */ /* Name pollution from sql/sql_lex.h */