diff options
author | Sergei Golubchik <serg@mariadb.org> | 2014-11-08 17:37:19 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2014-12-04 16:09:34 +0100 |
commit | 227510e039b4ec6bff3096a4b9b39847551dab1a (patch) | |
tree | 2c40cbba45ca53e688d3f5cd388dbcd032c82984 | |
parent | d1522af72dad1965b8a8a37415545014ba743f49 (diff) | |
download | mariadb-git-227510e039b4ec6bff3096a4b9b39847551dab1a.tar.gz |
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
30 files changed, 572 insertions, 663 deletions
diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index c81af134add..29f5f0cf2d5 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -796,3 +796,26 @@ DATE("foo") NULL Warnings: 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 diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 3250d3cb838..740319a9dcd 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -5535,3 +5535,12 @@ a aa # # 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 +# diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 71fab8c9654..7569673c68c 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1411,7 +1411,7 @@ end| ERROR 0A000: Not allowed to return a result set from a function drop function if exists bug20701; 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"; drop function bug20701; create procedure proc_26503_error_1() diff --git a/mysql-test/r/sp-ucs2.result b/mysql-test/r/sp-ucs2.result index 605fe4ed151..c7a3ed6e46a 100644 --- a/mysql-test/r/sp-ucs2.result +++ b/mysql-test/r/sp-ucs2.result @@ -106,20 +106,20 @@ RETURNS VARCHAR(64) CHARACTER SET ucs2 BEGIN RETURN 'str'; 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) RETURNS VARCHAR(64) COLLATE ucs2_unicode_ci BEGIN RETURN 'str'; 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) RETURNS VARCHAR(64) CHARACTER SET ucs2 BEGIN DECLARE f2 VARCHAR(64) COLLATE ucs2_unicode_ci; RETURN 'str'; 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; DROP FUNCTION IF EXISTS bug48766; CREATE FUNCTION bug48766 () diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 56d8ea62f44..4fa43e82a1d 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3548,7 +3548,10 @@ begin set f1= concat( 'hello', f1 ); return f1; 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| create procedure bug12849_1(inout x char) select x into x| set @var='a'| @@ -7858,3 +7861,22 @@ v1 DROP PROCEDURE p1; DROP TABLE t1; # 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| diff --git a/mysql-test/suite/funcs_1/r/storedproc.result b/mysql-test/suite/funcs_1/r/storedproc.result index 4ec9bfbd512..f316bdb7ba2 100644 --- a/mysql-test/suite/funcs_1/r/storedproc.result +++ b/mysql-test/suite/funcs_1/r/storedproc.result @@ -142,7 +142,7 @@ BEGIN SET @v1 = f1; SELECT @v1; 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// Warnings: Note 1305 PROCEDURE db_storedproc.sp1 does not exist @@ -152,7 +152,7 @@ BEGIN SET @v1 = f1; SELECT @v1; 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// Warnings: Note 1305 PROCEDURE db_storedproc.sp1 does not exist @@ -1407,12 +1407,12 @@ BEGIN SELECT f1; END// Warnings: -Note 1291 Column '' has duplicated value 'value1' in ENUM +Note 1291 Column 'f1' has duplicated value 'value1' in ENUM CALL sp1( "value1" ); f1 value1 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'; 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 @@ -1423,12 +1423,12 @@ BEGIN SELECT f1; END// Warnings: -Note 1291 Column '' has duplicated value 'value1' in SET +Note 1291 Column 'f1' has duplicated value 'value1' in SET CALL sp1( "value1, value1" ); f1 value1 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 SHOW PROCEDURE STATUS WHERE db = 'db_storedproc'; Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation @@ -1440,12 +1440,12 @@ BEGIN SELECT f1; END// Warnings: -Note 1291 Column '' has duplicated value 'value1' in ENUM +Note 1291 Column 'f1' has duplicated value 'value1' in ENUM CALL sp1( "value1" ); f1 value1 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'; 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 @@ -1548,7 +1548,7 @@ BEGIN SET f1 = 1000000 + f1; RETURN f1; 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 ); ERROR 42000: FUNCTION db_storedproc.fn1 does not exist CREATE FUNCTION fn1( f1 DECIMAL(63, 30) ) RETURNS DECIMAL(63, 30) @@ -1570,7 +1570,7 @@ BEGIN RETURN f1; END// Warnings: -Note 1291 Column '' has duplicated value 'value1' in ENUM +Note 1291 Column 'f1' has duplicated value 'value1' in ENUM SELECT fn1( "value1" ); fn1( "value1" ) 1.000000000000000000000000000000 @@ -1584,7 +1584,7 @@ BEGIN RETURN f1; END// Warnings: -Note 1291 Column '' has duplicated value 'value1' in SET +Note 1291 Column 'f1' has duplicated value 'value1' in SET SELECT fn1( "value1, value1" ); fn1( "value1, value1" ) 1.000000000000000000000000000000 @@ -3119,10 +3119,7 @@ return f1; DROP FUNCTION IF EXISTS fn1; CREATE FUNCTION fn1(f1 char binary ) returns char binary return f1; -ERROR 42000: This version of MariaDB doesn't yet support 'return value collation' DROP FUNCTION IF EXISTS fn1; -Warnings: -Note 1305 FUNCTION db_storedproc.fn1 does not exist CREATE FUNCTION fn1(f1 char ascii ) returns char ascii return f1; DROP FUNCTION IF EXISTS fn1; @@ -5836,7 +5833,7 @@ fetch cur1 into e; SELECT x, y, z, a, b, c, d, e; close cur1; 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(); ERROR 42000: PROCEDURE db_storedproc.sp6 does not exist DROP PROCEDURE IF EXISTS sp6; diff --git a/mysql-test/suite/funcs_1/t/storedproc.test b/mysql-test/suite/funcs_1/t/storedproc.test index 69406a57a00..ff417957c85 100644 --- a/mysql-test/suite/funcs_1/t/storedproc.test +++ b/mysql-test/suite/funcs_1/t/storedproc.test @@ -2155,7 +2155,6 @@ CREATE FUNCTION fn1(f1 char ) returns char return f1; DROP FUNCTION IF EXISTS fn1; ---error ER_NOT_SUPPORTED_YET CREATE FUNCTION fn1(f1 char binary ) returns char binary return f1; diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index b6c37cacd8a..58f91571ebb 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -456,3 +456,19 @@ SELECT CAST(TIME('10:20:30') AS DATE) + INTERVAL 1 DAY; SET SQL_MODE=ALLOW_INVALID_DATES; 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)); + diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 33d41e9bc4c..1dee393b90b 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -914,7 +914,16 @@ SELECT CONCAT(CONVERT('pi=' USING ucs2),PI()) AS PI; SET NAMES utf8, character_set_connection=ucs2; SELECT 'a','aa'; - --echo # --echo # End of 10.0 tests --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 # diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 711e639191e..a16ef1205b9 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2051,13 +2051,8 @@ delimiter ;| --disable_warnings drop function if exists bug20701; --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"; +drop function bug20701; create function bug20701() returns varchar(25) return "test"; drop function bug20701; diff --git a/mysql-test/t/sp-ucs2.test b/mysql-test/t/sp-ucs2.test index f6f70c3c103..3532169e5a1 100644 --- a/mysql-test/t/sp-ucs2.test +++ b/mysql-test/t/sp-ucs2.test @@ -114,7 +114,7 @@ DROP FUNCTION f1| # # 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) RETURNS VARCHAR(64) CHARACTER SET ucs2 BEGIN @@ -125,7 +125,7 @@ END| # # 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) RETURNS VARCHAR(64) COLLATE ucs2_unicode_ci BEGIN @@ -136,7 +136,7 @@ END| # # 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) RETURNS VARCHAR(64) CHARACTER SET ucs2 BEGIN diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 5179bb1b03d..3f635acaac9 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4355,17 +4355,14 @@ begin return f1; end| 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 begin set f1= concat( 'hello', f1 ); return f1; end| +select collation(bug9048("foo"))| +drop function bug9048| # Bug #12849 Stored Procedure: Crash on procedure call with CHAR type # 'INOUT' parameter @@ -9303,3 +9300,27 @@ DROP PROCEDURE p1; DROP TABLE t1; --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 ;| diff --git a/sql/field.cc b/sql/field.cc index 7467aa63a26..a9bd1fe2dc0 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9163,96 +9163,100 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, } -/** - 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 +static inline bool is_item_func(Item* x) +{ + return x != NULL && x->type() == Item::FUNC_ITEM; +} - @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) +bool Create_field::check(THD *thd) { + const uint conditional_type_modifiers= AUTO_INCREMENT_FLAG; uint sign_len, allowed_type_modifier= 0; ulong max_field_charlength= MAX_FIELD_CHARLENGTH; - const bool on_update_is_function= - (fld_on_update_value != NULL && - fld_on_update_value->type() == Item::FUNC_ITEM); + DBUG_ENTER("Create_field::check"); + + if (vcol_info) + { + vcol_info->set_field_type(sql_type); + sql_type= (enum enum_field_types)MYSQL_TYPE_VIRTUAL; + } + + if (length > MAX_FIELD_BLOBLENGTH) + { + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, MAX_FIELD_BLOBLENGTH); + DBUG_RETURN(1); + } + + 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); + } - DBUG_ENTER("Create_field::init()"); + if (def) + { + /* + Default value should be literal => basic constants => + no need fix_fields() - field= 0; - field_name= fld_name; - flags= fld_type_modifier; - option_list= create_opt; + 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 (fld_default_value != NULL && fld_default_value->type() == Item::FUNC_ITEM) + if (is_item_func(def)) { /* There is a function default for insertions. */ 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_DN_FIELD); // only for insertions. } else { /* No function default for insertions. Either NULL or a constant. */ - def= fld_default_value; - if (on_update_is_function) + if (is_item_func(on_update)) unireg_check= Field::TIMESTAMP_UN_FIELD; // function default for updates else - unireg_check= ((fld_type_modifier & AUTO_INCREMENT_FLAG) != 0 ? + unireg_check= ((flags & AUTO_INCREMENT_FLAG) ? Field::NEXT_NUMBER : // Automatic increment. Field::NONE); } - decimals= fld_decimals ? (uint)atoi(fld_decimals) : 0; - if (decimals >= NOT_FIXED_DEC) + if (on_update && + (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, - static_cast<ulong>(NOT_FIXED_DEC - 1)); - DBUG_RETURN(TRUE); + my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name); + DBUG_RETURN(1); } - 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 */ - if ((uchar)fld_type == (uchar)MYSQL_TYPE_VIRTUAL) + if (sql_type == MYSQL_TYPE_VIRTUAL) { DBUG_ASSERT(vcol_info && vcol_info->expr_item); 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 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 it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP. */ - if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) && - (fld_type_modifier & NOT_NULL_FLAG) && !is_timestamp_type(fld_type)) + if (!def && unireg_check == Field::NONE && + (flags & NOT_NULL_FLAG) && !is_timestamp_type(sql_type)) flags|= NO_DEFAULT_VALUE_FLAG; - if (fld_length != NULL) - { - 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) - fld_length= NULL; /* purecov: inspected */ - } + sign_len= flags & UNSIGNED_FLAG ? 0 : 1; - sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1; - - switch (fld_type) { + switch (sql_type) { case MYSQL_TYPE_TINY: - if (!fld_length) + if (!length) length= MAX_TINYINT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; case MYSQL_TYPE_SHORT: - if (!fld_length) + if (!length) length= MAX_SMALLINT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; case MYSQL_TYPE_INT24: - if (!fld_length) + if (!length) length= MAX_MEDIUMINT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; case MYSQL_TYPE_LONG: - if (!fld_length) + if (!length) length= MAX_INT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; case MYSQL_TYPE_LONGLONG: - if (!fld_length) + if (!length) length= MAX_BIGINT_WIDTH; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; @@ -9331,18 +9321,17 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, my_decimal_trim(&length, &decimals); if (length > DECIMAL_MAX_PRECISION) { - my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast<int>(length), - fld_name, static_cast<ulong>(DECIMAL_MAX_PRECISION)); + my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name, + DECIMAL_MAX_PRECISION); DBUG_RETURN(TRUE); } 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); } length= - my_decimal_precision_to_length(length, decimals, - fld_type_modifier & UNSIGNED_FLAG); + my_decimal_precision_to_length(length, decimals, flags & UNSIGNED_FLAG); pack_length= my_decimal_get_binary_size(length, decimals); 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_MEDIUM_BLOB: case MYSQL_TYPE_GEOMETRY: - if (fld_default_value) + if (def) { /* Allow empty as default value. */ 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 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()) { my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), - fld_name); /* purecov: inspected */ + field_name); /* purecov: inspected */ DBUG_RETURN(TRUE); } 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, ER_BLOB_CANT_HAVE_DEFAULT, ER(ER_BLOB_CANT_HAVE_DEFAULT), - fld_name); + field_name); } def= 0; } flags|= BLOB_FLAG; break; case MYSQL_TYPE_YEAR: - if (!fld_length || length != 2) + if (!length || length != 2) length= 4; /* Default length */ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; break; case MYSQL_TYPE_FLOAT: /* change FLOAT(precision) to FLOAT or DOUBLE */ allowed_type_modifier= AUTO_INCREMENT_FLAG; - if (fld_length && !fld_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) + if (!length && !decimals) { length= MAX_FLOAT_STR_LENGTH; 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 && 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); } break; case MYSQL_TYPE_DOUBLE: allowed_type_modifier= AUTO_INCREMENT_FLAG; - if (!fld_length && !fld_decimals) + if (!length && !decimals) { length= DBL_DIG+7; 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 && 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); } break; @@ -9445,7 +9416,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, case MYSQL_TYPE_TIMESTAMP2: 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); 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: 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); 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: 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); DBUG_RETURN(TRUE); } length+= MAX_DATETIME_WIDTH + (length ? 1 : 0); break; case MYSQL_TYPE_SET: - { - pack_length= get_set_pack_length(fld_interval_list->elements); - - 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; - } + pack_length= get_set_pack_length(interval_list.elements); + break; case MYSQL_TYPE_ENUM: - { - /* Should be safe. */ - pack_length= get_enum_pack_length(fld_interval_list->elements); - - 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; - } + /* Should be safe. */ + pack_length= get_enum_pack_length(interval_list.elements); + break; case MYSQL_TYPE_VAR_STRING: DBUG_ASSERT(0); /* Impossible. */ break; case MYSQL_TYPE_BIT: { - if (!fld_length) + if (!length) length= 1; 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)); 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: DBUG_ASSERT(0); /* Was obsolete */ - } + } /* Remember the value of length */ char_length= length; if (!(flags & BLOB_FLAG) && - ((length > max_field_charlength && fld_type != MYSQL_TYPE_SET && - fld_type != MYSQL_TYPE_ENUM && - (fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) || - ((length == 0) && - fld_type != MYSQL_TYPE_STRING && - fld_type != MYSQL_TYPE_VARCHAR && fld_type != MYSQL_TYPE_GEOMETRY))) - { - my_error((fld_type == MYSQL_TYPE_VAR_STRING || - fld_type == MYSQL_TYPE_VARCHAR || - fld_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH : + ((length > max_field_charlength && + (sql_type != MYSQL_TYPE_VARCHAR || def)) || + (length == 0 && + sql_type != MYSQL_TYPE_ENUM && sql_type != MYSQL_TYPE_SET && + sql_type != MYSQL_TYPE_STRING && sql_type != MYSQL_TYPE_VARCHAR && + sql_type != MYSQL_TYPE_GEOMETRY))) + { + my_error((sql_type == MYSQL_TYPE_VAR_STRING || + sql_type == MYSQL_TYPE_VARCHAR || + sql_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH : ER_TOO_BIG_DISPLAYWIDTH, MYF(0), - fld_name, max_field_charlength); /* purecov: inspected */ + field_name, max_field_charlength); /* purecov: inspected */ DBUG_RETURN(TRUE); } - fld_type_modifier&= AUTO_INCREMENT_FLAG; - if ((~allowed_type_modifier) & fld_type_modifier) + if ((~allowed_type_modifier) & flags & conditional_type_modifiers) { - 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(FALSE); /* success */ } - enum_field_types get_blob_type_from_length(ulong length) { enum_field_types type; diff --git a/sql/field.h b/sql/field.h index dabb6c6b0e0..c813fa2d48e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2835,13 +2835,13 @@ public: const char *change; // If done with alter table const char *after; // Put column after this one LEX_STRING comment; // Comment for field - Item *def; // Default value + Item *def, *on_update; // Default value enum enum_field_types sql_type; /* At various stages in execution this can be length of field in bytes or max number of characters. */ - ulong length; + ulonglong length; /* 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. @@ -2877,9 +2877,13 @@ public: */ bool stored_in_db; - Create_field() :after(0), option_list(NULL), option_struct(NULL), - create_if_not_exists(FALSE) - {} + Create_field() :after(0), pack_length(0), key_length(0), interval(0), + 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); /* Used to make a clone of this object for ALTER/CREATE TABLE */ Create_field *clone(MEM_ROOT *mem_root) const; @@ -2891,12 +2895,7 @@ public: bool maybe_null, bool is_unsigned, uint pack_length = ~0U); - bool init(THD *thd, char *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 *option_list, bool check_exists); + bool check(THD *thd); bool field_flags_are_binary() { diff --git a/sql/item_create.cc b/sql/item_create.cc index 65678ebe1b7..a53a369de12 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -53,13 +53,12 @@ static const char* item_name(Item *a, String *str) static void wrong_precision_error(uint errcode, Item *a, - ulonglong number, ulong maximum) + ulonglong number, uint maximum) { char buff[1024]; String buf(buff, sizeof(buff), system_charset_info); - my_error(errcode, MYF(0), (uint) MY_MIN(number, UINT_MAX32), - item_name(a, &buf), maximum); + my_error(errcode, MYF(0), number, item_name(a, &buf), maximum); } @@ -87,9 +86,9 @@ bool get_length_and_scale(ulonglong length, ulonglong decimals, return 1; } - *out_length= (ulong) length; *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) { diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 389d9d5380c..c9d99908014 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1628,8 +1628,8 @@ bool Item_func_curtime::fix_fields(THD *thd, Item **items) { if (decimals > TIME_SECOND_PART_DIGITS) { - my_error(ER_TOO_BIG_PRECISION, MYF(0), decimals, func_name(), - TIME_SECOND_PART_DIGITS); + my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast<ulonglong>(decimals), + func_name(), TIME_SECOND_PART_DIGITS); return 1; } 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) { - my_error(ER_TOO_BIG_PRECISION, MYF(0), decimals, func_name(), - TIME_SECOND_PART_DIGITS); + my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast<ulonglong>(decimals), + func_name(), TIME_SECOND_PART_DIGITS); return 1; } return Item_temporal_func::fix_fields(thd, items); diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index c11bf671cb1..d4f1ae19bc6 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -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)) { diff --git a/sql/my_decimal.h b/sql/my_decimal.h index fa85b41d70c..a2cce862f1a 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -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*/ diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 2bc7bb1c7a7..653f053ba38 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -5472,8 +5472,8 @@ ER_TOO_BIG_SCALE 42000 S1009 eng "Too big scale %u specified for '%-.192s'. Maximum is %lu." ger "Zu großer Skalierungsfaktor %u für '%-.192s' angegeben. Maximum ist %lu" ER_TOO_BIG_PRECISION 42000 S1009 - eng "Too big precision %u specified for '%-.192s'. Maximum is %lu." - ger "Zu große Genauigkeit %u für '%-.192s' angegeben. Maximum ist %lu" + eng "Too big precision %llu specified for '%-.192s'. Maximum is %u." + ger "Zu große Genauigkeit %llu für '%-.192s' angegeben. Maximum ist %u" 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')." ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.192s')" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 21f8726eb34..9f42e83d7f2 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2216,16 +2216,6 @@ sp_head::reset_lex(THD *thd) sublex->trg_table_fields.empty(); 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. */ 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, Create_field *field_def) { - LEX_STRING cmt = { 0, 0 }; uint unused1= 0; - if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec, - 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)) + if (field_def->check(thd)) return TRUE; if (field_def->interval_list.elements) diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 11954921e06..6afca24231b 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -183,13 +183,10 @@ sp_variable *sp_pcontext::find_variable(uint offset) const } -sp_variable *sp_pcontext::add_variable(THD *thd, - LEX_STRING name, - enum enum_field_types type, - sp_variable::enum_mode mode) +sp_variable *sp_pcontext::add_variable(THD *thd, LEX_STRING name) { 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) return NULL; diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 4d8623108aa..efe9531c3a0 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -63,12 +63,11 @@ public: Create_field field_def; public: - sp_variable(LEX_STRING _name, enum_field_types _type, enum_mode _mode, - uint _offset) + sp_variable(LEX_STRING _name, uint _offset) :Sql_alloc(), name(_name), - type(_type), - mode(_mode), + type(MYSQL_TYPE_NULL), + mode(MODE_IN), offset(_offset), default_value(NULL) { } @@ -340,14 +339,9 @@ public: /// /// @param thd Thread context. /// @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. - sp_variable *add_variable(THD *thd, - LEX_STRING name, - enum enum_field_types type, - sp_variable::enum_mode mode); + sp_variable *add_variable(THD *thd, LEX_STRING name); /// Retrieve full type information about SP-variables in this parsing /// context and its children. diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d1aa2464210..0240f338da3 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -125,6 +125,7 @@ struct LEX_TYPE #if MYSQL_LEX #include "item_func.h" /* Cast_target used in sql_yacc.h */ #include "sql_get_diagnostics.h" /* Types used in sql_yacc.h */ +#include "sp_pcontext.h" #include "sql_yacc.h" #define LEX_YYSTYPE YYSTYPE * #else @@ -2380,7 +2381,10 @@ struct LEX: public Query_tables_list /* Query Plan Footprint of a currently running select */ Explain_query *explain; - char *length,*dec,*change; + // type information + char *length,*dec; + CHARSET_INFO *charset; + LEX_STRING name; char *help_arg; char *backup_dir; /* For RESTORE/BACKUP */ @@ -2389,18 +2393,15 @@ struct LEX: public Query_tables_list String *wild; /* Wildcard in SHOW {something} LIKE 'wild'*/ sql_exchange *exchange; select_result *result; - Item *default_value, *on_update_value; LEX_STRING comment, ident; LEX_USER *grant_user; XID *xid; THD *thd; - Virtual_column_info *vcol_info; /* maintain a list of used plugins for this LEX */ DYNAMIC_ARRAY plugins; plugin_ref plugins_static_buffer[INITIAL_LEX_PLUGIN_LIST_SIZE]; - CHARSET_INFO *charset; bool text_string_is_7bit; /** 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> ref_list; - List<String> interval_list; List<LEX_USER> users_list; List<LEX_COLUMN> columns; 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_options; - uint uint_geom_type; uint grant, grant_tot_col, which_columns; enum Foreign_key::fk_match_opt fk_match_option; 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 @@ -2806,6 +2813,10 @@ struct LEX: public Query_tables_list int print_explain(select_result_sink *output, uint8 explain_flags, bool is_analyze, bool *printed_anything); 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); }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 63a1d69a083..360360d4425 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7097,113 +7097,6 @@ bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length) #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. */ void store_position_for_column(const char *name) @@ -9138,3 +9031,18 @@ merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl) } 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; +} diff --git a/sql/sql_parse.h b/sql/sql_parse.h index da024a5e746..0620e278b79 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -73,6 +73,7 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg, uint max_char_length, CHARSET_INFO *cs, bool no_error); 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_identifier_name(LEX_STRING *str, uint max_char_length, 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); void execute_init_command(THD *thd, LEX_STRING *init_command, 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); void add_join_on(TABLE_LIST *b,Item *expr); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields, diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 1874fb5e66d..343527ab030 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3077,7 +3077,9 @@ void plugin_thdvar_init(THD *thd) intern_plugin_unlock(NULL, old_table_plugin); intern_plugin_unlock(NULL, old_tmp_table_plugin); mysql_mutex_unlock(&LOCK_plugin); - } else { + } + else + { thd->variables.table_plugin= NULL; thd->variables.tmp_table_plugin= NULL; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c29394ed88d..12f30d9fd6e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3248,18 +3248,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, */ sql_field->length= sql_field->char_length; /* Set field charset. */ - save_cs= sql_field->charset= get_sql_field_charset(sql_field, - create_info); + save_cs= sql_field->charset= get_sql_field_charset(sql_field, create_info); if ((sql_field->flags & BINCMP_FLAG) && - !(sql_field->charset= get_charset_by_csname(sql_field->charset->csname, - 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); + !(sql_field->charset= find_bin_collation(sql_field->charset))) DBUG_RETURN(TRUE); - } /* Convert the default value from client character diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 52b7db7e617..8a56a86f1bf 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -45,7 +45,6 @@ #include "lex_symbol.h" #include "item_create.h" #include "sp_head.h" -#include "sp_pcontext.h" #include "sp_rcontext.h" #include "sp.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.flags= Alter_info::ALTER_ADD_INDEX; lex->col_list.empty(); - lex->change= NullS; lex->option_list= NULL; 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 { 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_ptr; LEX_SYMBOL symbol; - LEX_TYPE lex_type; Table_ident *table; char *simple_string; Item *item; @@ -888,6 +964,8 @@ static bool sp_create_assignment_instr(THD *thd, bool no_lookahead) enum enum_var_type var_type; Key::Keytype key_type; enum ha_key_alg key_alg; + enum enum_field_types field_type; + enum Field::geometry_type geom_type; handlerton *db_type; enum row_type row_type; 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; LEX *lex; class my_var *myvar; - sp_head *sphead; + class sp_head *sphead; + class sp_variable *spvar; struct p_elem_val *p_elem_value; enum index_hint_type index_hint; enum enum_filetype filetype; enum Foreign_key::fk_option m_fk_option; enum enum_yes_no_unknown m_yes_no_unk; + enum sp_variable::enum_mode spvar_mode; Diag_condition_item_name diag_condition_item_name; Diagnostics_information::Which_area diag_area; Diagnostics_information *diag_info; @@ -1643,14 +1723,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <string> 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 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 table_option opt_if_not_exists create_or_replace opt_no_write_to_binlog 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 union_opt select_derived_init transaction_access_mode_types 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 opt_time_precision kill_type kill_option int_num opt_default_time_precision - case_stmt_body + case_stmt_body opt_bin_mod /* Bit field of MYSQL_START_TRANS_OPT_* flags. @@ -1763,6 +1845,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <charset> opt_collate charset_name + charset_or_alias charset_name_or_default old_or_new_charset_name 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 opt_limit_clause delete_limit_clause fields opt_values values procedure_list procedure_list2 procedure_item - handler + field_def handler opt_generated_always opt_precision opt_ignore opt_column opt_restrict 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 opt_delete_options opt_delete_option varchar nchar nvarchar 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> 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 <spblock> sp_decls sp_decl %type <lex> sp_cursor_stmt %type <spname> sp_name %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 <num> index_hint_clause normal_join inner_join %type <filetype> data_or_xml @@ -2379,7 +2464,6 @@ create: MYSQL_YYABORT; lex->alter_info.reset(); lex->col_list.empty(); - lex->change=NullS; bzero((char*) &lex->create_info,sizeof(lex->create_info)); /* 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_fdparam - | sp_fdparam - ; - -sp_init_param: - /* Empty */ - { - 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_fdparams ',' sp_param_name_and_type + | sp_param_name_and_type ; -sp_fdparam: - ident sp_init_param type_with_opt_collate +sp_param_name_and_type: + ident { LEX *lex= Lex; sp_pcontext *spc= lex->spcont; @@ -2873,19 +2936,27 @@ sp_fdparam: MYSQL_YYABORT; } - sp_variable *spvar= spc->add_variable(thd, - $1, - (enum enum_field_types) $3, - sp_variable::MODE_IN); + sp_variable *spvar= spc->add_variable(thd, $1); - if (lex->sphead->fill_field_definition(thd, lex, - (enum enum_field_types) $3, - &spvar->field_def)) + lex->init_last_field(&spvar->field_def, $1.str, + thd->variables.collation_database); + $<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; } spvar->field_def.field_name= spvar->name.str; spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; + + $$= spvar; } ; @@ -2901,30 +2972,7 @@ sp_pdparams: ; sp_pdparam: - sp_opt_inout sp_init_param ident type_with_opt_collate - { - 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_param_name_and_type { $2->mode=$1; } ; sp_opt_inout: @@ -2978,9 +3026,17 @@ sp_decl: DECLARE_SYM sp_decl_idents { 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->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 sp_opt_default @@ -2988,7 +3044,7 @@ sp_decl: LEX *lex= Lex; sp_pcontext *pctx= lex->spcont; 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; if (!dflt_value_item) @@ -3003,12 +3059,17 @@ sp_decl: { uint var_idx= pctx->var_context2runtime(i); sp_variable *spvar= pctx->find_variable(var_idx); + bool last= i == num_vars - 1; if (!spvar) MYSQL_YYABORT; + if (!last) + spvar->field_def= *lex->last_field; + spvar->type= var_type; spvar->default_value= dflt_value_item; + spvar->field_def.field_name= spvar->name.str; if (lex->sphead->fill_field_definition(thd, lex, var_type, &spvar->field_def)) @@ -3016,7 +3077,6 @@ sp_decl: MYSQL_YYABORT; } - spvar->field_def.field_name= spvar->name.str; spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; /* The last instruction is responsible for freeing LEX. */ @@ -3027,7 +3087,7 @@ sp_decl: dflt_value_item, var_type, lex, - (i == num_vars - 1)); + last); if (is == NULL || lex->sphead->add_instr(is)) MYSQL_YYABORT; @@ -3581,10 +3641,7 @@ sp_decl_idents: my_error(ER_SP_DUP_VAR, MYF(0), $1.str); MYSQL_YYABORT; } - spc->add_variable(thd, - $1, - MYSQL_TYPE_DECIMAL, - sp_variable::MODE_IN); + spc->add_variable(thd, $1); $$= 1; } | sp_decl_idents ',' ident @@ -3599,10 +3656,7 @@ sp_decl_idents: my_error(ER_SP_DUP_VAR, MYF(0), $3.str); MYSQL_YYABORT; } - spc->add_variable(thd, - $3, - MYSQL_TYPE_DECIMAL, - sp_variable::MODE_IN); + spc->add_variable(thd, $3); $$= $1 + 1; } ; @@ -6038,58 +6092,62 @@ field_spec: field_ident { 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->vcol_info= 0; - lex->option_list= NULL; + Create_field *f= new Create_field(); + + if (check_string_char_length(&$1, "", NAME_CHAR_LEN, + system_charset_info, 1)) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); + MYSQL_YYABORT; + } + + if (!f) + MYSQL_YYABORT; + + lex->init_last_field(f, $1.str, NULL); } + field_type { Lex->set_last_field_type($3); } field_def { LEX *lex=Lex; - if (add_field_to_list(lex->thd, &$1, $3.type, - $3.length, $3.dec, lex->type, - lex->default_value, lex->on_update_value, - &lex->comment, - lex->change, &lex->interval_list, $3.charset, - lex->uint_geom_type, - lex->vcol_info, lex->option_list)) + Create_field *f= lex->last_field; + + if (f->check(thd)) 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: - type opt_attribute - { $$.set($1, Lex->length, Lex->dec, Lex->charset); } - | type opt_generated_always AS - { $<lex_type>$.set($1, Lex->length, Lex->dec, Lex->charset); } - '(' 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_attribute + | opt_generated_always AS + '(' virtual_column_func ')' + vcol_opt_specifier vcol_opt_attribute ; opt_generated_always: - /* empty */ + /* empty */ {} | GENERATED_SYM ALWAYS_SYM {} ; vcol_opt_specifier: /* empty */ { - Lex->vcol_info->set_stored_in_db_flag(FALSE); + Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE); } | VIRTUAL_SYM { - Lex->vcol_info->set_stored_in_db_flag(FALSE); + Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE); } | 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 { LEX *lex=Lex; - lex->type|= UNIQUE_FLAG; + lex->last_field->flags|= UNIQUE_FLAG; lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } | UNIQUE_SYM KEY_SYM { LEX *lex=Lex; - lex->type|= UNIQUE_KEY_FLAG; + lex->last_field->flags|= UNIQUE_FLAG; 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: @@ -6138,23 +6196,41 @@ parse_vcol_expr: virtual_column_func: remember_name expr remember_end { - Lex->vcol_info= new Virtual_column_info(); - if (!Lex->vcol_info) + Virtual_column_info *v= new Virtual_column_info(); + if (!v) { mem_alloc_error(sizeof(Virtual_column_info)); MYSQL_YYABORT; } uint expr_len= (uint)($3 - $1) - 1; - Lex->vcol_info->expr_str.str= (char* ) thd->memdup($1 + 1, expr_len); - Lex->vcol_info->expr_str.length= expr_len; - Lex->vcol_info->expr_item= $2; + v->expr_str.str= (char* ) thd->memdup($1 + 1, expr_len); + v->expr_str.length= expr_len; + v->expr_item= $2; + Lex->last_field->vcol_info= v; } ; -type: +field_type: int_type opt_field_length 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 { Lex->length= (char*) "1"; @@ -6186,13 +6262,13 @@ type: | nchar field_length opt_bin_mod { $$=MYSQL_TYPE_STRING; - Lex->charset=national_charset_info; + bincmp_collation(national_charset_info, $3); } | nchar opt_bin_mod { Lex->length= (char*) "1"; $$=MYSQL_TYPE_STRING; - Lex->charset=national_charset_info; + bincmp_collation(national_charset_info, $2); } | BINARY field_length { @@ -6212,7 +6288,7 @@ type: | nvarchar field_length opt_bin_mod { $$= MYSQL_TYPE_VARCHAR; - Lex->charset=national_charset_info; + bincmp_collation(national_charset_info, $3); } | VARBINARY field_length { @@ -6252,9 +6328,9 @@ type: /* Unlike other types TIMESTAMP fields are NOT NULL by default. */ - Lex->type|= NOT_NULL_FLAG; - $$= opt_mysql56_temporal_format ? - MYSQL_TYPE_TIMESTAMP2 : MYSQL_TYPE_TIMESTAMP; + Lex->last_field->flags|= NOT_NULL_FLAG; + $$= opt_mysql56_temporal_format ? MYSQL_TYPE_TIMESTAMP2 + : MYSQL_TYPE_TIMESTAMP; } } | DATETIME opt_field_length @@ -6274,7 +6350,7 @@ type: { #ifdef HAVE_SPATIAL Lex->charset=&my_charset_bin; - Lex->uint_geom_type= (uint)$1; + Lex->last_field->geom_type= $1; $$=MYSQL_TYPE_GEOMETRY; #else my_error(ER_FEATURE_DISABLED, MYF(0), @@ -6313,20 +6389,16 @@ type: { $$=MYSQL_TYPE_NEWDECIMAL;} | FIXED_SYM float_options field_options { $$=MYSQL_TYPE_NEWDECIMAL;} - | ENUM - {Lex->interval_list.empty();} - '(' string_list ')' opt_binary + | ENUM '(' string_list ')' opt_binary { $$=MYSQL_TYPE_ENUM; } - | SET - { Lex->interval_list.empty();} - '(' string_list ')' opt_binary + | SET '(' string_list ')' opt_binary { $$=MYSQL_TYPE_SET; } | LONG_SYM opt_binary { $$=MYSQL_TYPE_MEDIUM_BLOB; } | SERIAL_SYM { $$=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); } ; @@ -6419,8 +6491,8 @@ field_opt_list: field_option: SIGNED_SYM {} - | UNSIGNED { Lex->type|= UNSIGNED_FLAG;} - | ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; } + | UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG;} + | ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; } ; field_length: @@ -6450,42 +6522,42 @@ opt_attribute_list: ; attribute: - NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; } - | not NULL_SYM { Lex->type|= NOT_NULL_FLAG; } - | DEFAULT now_or_signed_literal { Lex->default_value=$2; } + NULL_SYM { Lex->last_field->flags&= ~ NOT_NULL_FLAG; } + | not NULL_SYM { Lex->last_field->flags|= NOT_NULL_FLAG; } + | DEFAULT now_or_signed_literal { Lex->last_field->def= $2; } | ON UPDATE_SYM NOW_SYM opt_default_time_precision { Item *item= new (thd->mem_root) Item_func_now_local($4); if (item == NULL) 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 { 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; } | opt_primary KEY_SYM { 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; } | UNIQUE_SYM { LEX *lex=Lex; - lex->type|= UNIQUE_FLAG; + lex->last_field->flags|= UNIQUE_FLAG; lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } | UNIQUE_SYM KEY_SYM { LEX *lex=Lex; - lex->type|= UNIQUE_KEY_FLAG; + lex->last_field->flags|= UNIQUE_KEY_FLAG; 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 { if (Lex->charset && !my_charset_same(Lex->charset,$2)) @@ -6496,52 +6568,46 @@ attribute: } else { - Lex->charset=$2; + Lex->last_field->charset= $2; } } | IDENT_sys equal TEXT_STRING_sys { 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); } | IDENT_sys equal ident { 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); } | IDENT_sys equal real_ulonglong_num { 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); } | IDENT_sys equal DEFAULT { 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 opt_collate + field_type opt_collate { $$= $1; - if (Lex->charset) /* Lex->charset is scanned in "type" */ + if ($2) { if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2))) MYSQL_YYABORT; } - else if ($2) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), - "COLLATE with no CHARACTER SET " - "in SP parameters, RETURNS, DECLARE"); - MYSQL_YYABORT; - } + Lex->set_last_field_type($1); } ; @@ -6625,62 +6691,30 @@ opt_default: | DEFAULT {} ; - -ascii: - ASCII_SYM { Lex->charset= &my_charset_latin1; } - | BINARY ASCII_SYM - { - Lex->charset= &my_charset_latin1_bin; - } - | ASCII_SYM BINARY +charset_or_alias: + charset charset_name { $$= $2; } + | ASCII_SYM { $$= &my_charset_latin1; } + | UNICODE_SYM { - Lex->charset= &my_charset_latin1_bin; - } - ; - -unicode: - UNICODE_SYM - { - if (!(Lex->charset=get_charset_by_csname("ucs2", - MY_CS_PRIMARY,MYF(0)))) + if (!($$= get_charset_by_csname("ucs2", MY_CS_PRIMARY,MYF(0)))) { my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2"); 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: - /* empty */ { Lex->charset=NULL; } - | ascii - | unicode - | BYTE_SYM { Lex->charset=&my_charset_bin; } - | charset charset_name opt_bin_mod { Lex->charset=$2; } - | BINARY - { - Lex->charset= NULL; - Lex->type|= BINCMP_FLAG; - } - | BINARY charset charset_name - { - Lex->charset= $3; - Lex->type|= BINCMP_FLAG; - } + /* empty */ { bincmp_collation(NULL, false); } + | BYTE_SYM { bincmp_collation(&my_charset_bin, false); } + | charset_or_alias opt_bin_mod { bincmp_collation($1, $2); } + | BINARY { bincmp_collation(NULL, true); } + | BINARY charset_or_alias { bincmp_collation($2, true); } ; opt_bin_mod: - /* empty */ { } - | BINARY { Lex->type|= BINCMP_FLAG; } + /* empty */ { $$= false; } + | BINARY { $$= true; } ; ws_nweights: @@ -7051,8 +7085,8 @@ opt_component: ; string_list: - text_string { Lex->interval_list.push_back($1); } - | string_list ',' text_string { Lex->interval_list.push_back($3); }; + text_string { Lex->last_field->interval_list.push_back($1); } + | string_list ',' text_string { Lex->last_field->interval_list.push_back($3); }; /* ** Alter table @@ -7522,7 +7556,6 @@ add_column: ADD opt_column opt_if_not_exists { LEX *lex=Lex; - lex->change=0; 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 | Alter_info::ALTER_ADD_INDEX; } - | CHANGE opt_column opt_if_exists field_ident - { - LEX *lex=Lex; - lex->change= $4.str; - lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN; - lex->option_list= NULL; - } - field_spec opt_place + | CHANGE opt_column opt_if_exists field_ident field_spec opt_place { + Lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN; Lex->create_last_non_select_table= Lex->last_table(); + Lex->last_field->change= $4.str; } - | MODIFY_SYM opt_column opt_if_exists field_ident - { - 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 + | MODIFY_SYM opt_column opt_if_exists field_spec opt_place { + Lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN; 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 { @@ -9083,7 +9089,9 @@ dyncol_type: $$= DYN_COL_DECIMAL; Lex->charset= NULL; } - | char opt_binary + | char + { Lex->charset= thd->variables.collation_connection; } + opt_binary { LEX *lex= Lex; $$= DYN_COL_STRING; @@ -10414,7 +10422,9 @@ in_sum_expr: cast_type: BINARY opt_field_length { $$=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; } | NCHAR_SYM opt_field_length { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; } @@ -13259,8 +13269,7 @@ opt_ignore_lines: ; lines_or_rows: - LINES { } - + LINES { } | ROWS_SYM { } ; @@ -16233,31 +16242,13 @@ sf_tail: RETURNS_SYM /* $9 */ { /* $10 */ LEX *lex= Lex; - lex->charset= NULL; - lex->length= lex->dec= NULL; - lex->interval_list.empty(); - lex->type= 0; - lex->vcol_info= 0; + lex->init_last_field(&lex->sphead->m_return_field_def, NULL, + thd->variables.collation_database); } type_with_opt_collate /* $11 */ { /* $12 */ - LEX *lex= Lex; - sp_head *sp= lex->sphead; - /* - 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)) + if (Lex->sphead->fill_field_definition(thd, Lex, $11, + Lex->last_field)) MYSQL_YYABORT; } sp_c_chistics /* $13 */ diff --git a/sql/table.cc b/sql/table.cc index 0e616bea6ef..50d331c49b3 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2395,6 +2395,7 @@ bool unpack_vcol_info_from_frm(THD *thd, Query_arena *backup_stmt_arena_ptr; Query_arena backup_arena; Query_arena *vcol_arena= 0; + Create_field vcol_storage; // placeholder for vcol_info Parser_state parser_state; LEX *old_lex= thd->lex; LEX lex; @@ -2458,7 +2459,8 @@ bool unpack_vcol_info_from_frm(THD *thd, if (init_lex_with_single_table(thd, table, &lex)) 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. @@ -2468,7 +2470,7 @@ bool unpack_vcol_info_from_frm(THD *thd, goto err; } /* 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. */ if (fix_vcol_expr(thd, table, field)) diff --git a/storage/perfschema/pfs_digest.cc b/storage/perfschema/pfs_digest.cc index bafc22e4b75..1fbf72c19c8 100644 --- a/storage/perfschema/pfs_digest.cc +++ b/storage/perfschema/pfs_digest.cc @@ -22,6 +22,8 @@ This code needs extra visibility in the lexer structures */ +#define MYSQL_LEX 1 + #include "my_global.h" #include "my_sys.h" #include "pfs_instr.h" @@ -35,7 +37,6 @@ #include <string.h> /* Generated code */ -#include "../sql/sql_yacc.h" #include "../storage/perfschema/pfs_lex_token.h" /* Name pollution from sql/sql_lex.h */ |